method names in __slots__ ??

J

John Machin

I have stumbled across some class definitions which include all/most
method names in a __slots__ "declaration". A cut-down and disguised
example appears at the end of this posting.

Never mind the __private_variables and the getter/setter approach, look
at the list of methods in the __slots__.

I note that all methods in an instance of a slotted class are read-only
irrespective of whether their names are included in __slots__ or not:
Given a = Adder(),
a.tally = 0
gets AttributeError: 'Adder' object attribute 'tally' is read-only
a.notinslots = 1
gets AttributeError: 'Adder' object attribute 'notinslots' is read-only

So is there some magic class-fu going down here, or is this just a
waste of memory space in the instances?

=== example ===
# class with method names in __slots__

class Adder(object):

__slots__ = [
# methods
'__init_',
'get_foo',
'get_value',
'set_foo',
'tally',
# private variables
'__foo',
'__value',
# public variables
'bar',
'zot',
]

def __init__(self, start=0):
self.__value = start
self.__foo = 666
self.bar = None
self.zot = 42

def tally(self, amount):
self.__value += amount

def get_value(self):
return self.__value

def set_foo(self, arg):
self.__foo = arg

def get_foo(self):
return self.__foo

def notinslots(self):
pass
=== end of example ===
 
R

Rob Williscroft

John Machin wrote in 73g2000cwn.googlegroups.com in comp.lang.python:
Given a = Adder(),
a.tally = 0
gets AttributeError: 'Adder' object attribute 'tally' is read-only
a.notinslots = 1
gets AttributeError: 'Adder' object attribute 'notinslots' is read-only

So is there some magic class-fu going down here, or is this just a
waste of memory space in the instances?

Haven't you, with your 2 examples above, answered your own question ?

Clearly from your example it doesn't make any difference if you add
a class attribute to the slots, one way or another its as if you
hadn't put it in there in the first place.

This will give the same error, which shows its about class attributes
and not just methods:

class Adder(object):

__slots__ = [
'class_name'
]

class_name = 3


a = Adder()

a.class_name = 2

It would seem that the interpreter removes any names it finds as class
attribute names from the list it finds in __slots__ before it creates
the instance.

Of course if my guessing above isn't good enough, we could look at
the documentation:

http://docs.python.org/ref/slots.html#l2h-218

__slots__ are implemented at the class level by creating descriptors
(3.4.2) for each variable name. As a result, class attributes cannot be
used to set default values for instance variables defined by __slots__;
otherwise, the class attribute would overwrite the descriptor assignment.

So its that the __slots__ assignment makes the descriptors and then the
subsiquent method defenitions and class attribute bindings remove them.

Rob.
 
J

John Machin

Rob said:
John Machin wrote in 73g2000cwn.googlegroups.com in comp.lang.python:


Haven't you, with your 2 examples above, answered your own question ?
No.


Clearly from your example it doesn't make any difference if you add
a class attribute to the slots, one way or another its as if you
hadn't put it in there in the first place.

Clearly? Not so. It takes up memory. A list of 1 million Adder
instances takes up about 68 Mb (Python 2.5 on Windows XP). With the
method names removed from the __slots__, it takes only about 44 Mb.
[For comparison: with no __slots__ at all, it takes about 180 Mb]
This will give the same error, which shows its about class attributes
and not just methods:

class Adder(object):

__slots__ = [
'class_name'
]

class_name = 3


a = Adder()

a.class_name = 2

It would seem that the interpreter removes any names it finds as class
attribute names from the list it finds in __slots__ before it creates
the instance.

It doesn't seem so to me. If it did that, the memory usage would not
increase.
Of course if my guessing above isn't good enough, we could look at
the documentation:

http://docs.python.org/ref/slots.html#l2h-218

__slots__ are implemented at the class level by creating descriptors
(3.4.2) for each variable name. As a result, class attributes cannot be
used to set default values for instance variables defined by __slots__;
otherwise, the class attribute would overwrite the descriptor assignment.

I have read that, before I posted. Asides:
(1) It would be useful if it stated the empirically determined fact
that the result is that the class attribute is thusly made read-only.
(2) The second sentence is not a model of clarity.

In any case I can't see how the paragraph gives any support for your
next statement:
So its that the __slots__ assignment makes the descriptors and then the
subsiquent method defenitions and class attribute bindings remove them.

Errrmmm ... if the descriptors are removed, how is it that the
behaviour is read-only?

Cheers,
John
 
R

Rob Williscroft

John Machin wrote in
in
comp.lang.python:
Rob said:
John Machin wrote in 73g2000cwn.googlegroups.com in comp.lang.python:


Haven't you, with your 2 examples above, answered your own question ?
No.


Clearly from your example it doesn't make any difference if you add
a class attribute to the slots, one way or another its as if you
hadn't put it in there in the first place.

Clearly? Not so. It takes up memory. A list of 1 million Adder
instances takes up about 68 Mb (Python 2.5 on Windows XP). With the
method names removed from the __slots__, it takes only about 44 Mb.
[For comparison: with no __slots__ at all, it takes about 180 Mb]

68 - 44 = 24
24 / 4 = 6

So thats 6 pointers for 5 methods, probably 5 pointers and and 4 bytes
round up to the nearest allocation unit.

So the slots in the instance are staying arround, even though they
are no longer accesable (see below).

[snip]
It would seem that the interpreter removes any names it finds as

It doesn't seem so to me. If it did that, the memory usage would not
increase.

It was a guess, and an incorrect guess, but thats why I quoted the
docs below.
I have read that, before I posted. Asides:
(1) It would be useful if it stated the empirically determined fact
that the result is that the class attribute is thusly made read-only.
(2) The second sentence is not a model of clarity.

In any case I can't see how the paragraph gives any support for your
next statement:


Errrmmm ... if the descriptors are removed, how is it that the
behaviour is read-only?

The descriptors are part of the class object, they are removed
when the class attributes are rebound, further rebinding of
the class attributes will work fine:

Adder.tally = 0

They are not assignable in the instance as the class descriptors
that would have forwarded the assignment to the instances slots have
been replaced.

The memory usage is higher because the slots in the instance are
still there even though the descriptors that would allow them to
be assigned have been removed.

Rob.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top