
Raymond Hettinger wrote:
class Pane(object): __slots__ = ('background', 'foreground', 'size', 'content') background = 'black' foreground = 'white' size = (80, 25) ...which doesn't work since the class variable overwrites the __slots__ descriptor.
Aahz replies:
Why not do the initializing in __init__?
I presume that Raymond's concern was not that there wouldn't be a way to do initialization, but that this would become a new c.l.p FAQ and point of confusion for newbies. Unfortunately, I fear that it will. Already I am seeing that people are "discovering" class variables as a sort of "initialized instance variable" instead of using __init__ as they "ought" to. Of course, it's NOT an initialized instance variable, but newbies stumble across it and seem to prefer it to using __init__. Combine this with the fact that newbies from staticly typed languages tend to think of __slots__ as "practically mandatory" (because it prevents the use of instance variables not pre-declared, which they erroniously think is a good thing) rather than the special purpose performance hack that it REALLY is, and you have a recipe for trouble. I'm not quite sure how to present things so as to steer them right, but there's definitely a potential pitfall here. -- Michael Chermside

Michael Chermside <mcherm@mcherm.com> writes:
Combine this with the fact that newbies from staticly typed languages tend to think of __slots__ as "practically mandatory" (because it prevents the use of instance variables not pre-declared, which they erroniously think is a good thing) rather than the special purpose performance hack that it REALLY is, and you have a recipe for trouble.
Unrelated to *this* topic, but Andrew's "What's new in Python 2.2" still presents __slots__ as a way to constrain the instance variables: A new-style class can define a class attribute named __slots__ to constrain the list of legal attribute names. http://www.python.org/doc/current/whatsnew/sect-rellinks.html#SECTION0003400... This should probably be fixed. Thomas

Aahz replies:
Why not do the initializing in __init__?
Michael: I presume that Raymond's concern was not that there wouldn't be a way to do initialization, but that this would become a new c.l.p FAQ and point of confusion for newbies. Unfortunately, I fear that it will.
Yes. Since it "works" with classic classes and unslotted newstyle classes, it isn't terribly unreasonable to believe it would work with __slots__. Further, there is no reason it couldn't work (either through an autoinit upon instance creation or through a default entry that references the class variable).
Michael: Already I am seeing that people are "discovering" class variables as a sort of "initialized instance variable" instead of using __init__ as they "ought" to. Of course, it's NOT an initialized instance variable, but newbies stumble across it and seem to prefer it to using __init__.
Perhaps I skipped school the day they taught that was bad, but it seems perfectly reasonable to me and I'm sure it is a common practice. I even find it to be clearer and more maintainable than using __init__. The only downside I see is that self.classvar += 1 reads from and writes to a different place. So, a reworded version of my question is "why not?". What is the downside of providing behavior that is similar to non-slotted classes? What is gained by these blocking an assignment and reporting a read-only error? When I find an existing class can be made lighter by using __slots__, it would be nice to transform it with a single line. From: class Tree(object): left = None right = None def __init__(self, value): self.value = value adding only one line: __slots__ = ('left', 'right', 'value') It would be a bummer to also have to move the left/right = None into __init__ and transform them into self.left = self.right = None.
Duncan Booth: The following works, but I can't remember whether you're supposed to be able to use a dict in __slots__ or if it just happens to be allowed:
class Pane(object): __slots__ = { 'background': 'black', 'foreground': 'white', 'size': (80, 25) } def __init__(self): for k, v in self.__slots__.iteritems(): setattr(self, k, v)
__slots__ accepts any iterable. So, yes, you're allowed eventhough that particular use was not intended. There are several possible workarounds including metaclasses. My question is why there needs to be a workaround at all.
Thomas Heller: Unrelated to *this* topic, but Andrew's "What's new in Python 2.2" still presents __slots__ as a way to constrain the instance variables:
A new-style class can define a class attribute named __slots__ to constrain the list of legal attribute names.
Though I think of __slots__ as a way to make lighter weight instances, constraining instance variables is also one of its functions. Raymond Hettinger

Yes. Since it "works" with classic classes and unslotted newstyle classes, it isn't terribly unreasonable to believe it would work with __slots__. Further, there is no reason it couldn't work (either through an autoinit upon instance creation or through a default entry that references the class variable).
Really? The metaclass would have to copy the initializers to a safekeeping place, because they compete with the slot descriptors. Don't forget that when you write __slots__ = ['a', 'b', 'c'], descriptors named a, b and c are inserted into the class dict by the metaclass. And then the metaclass would have to add a hidden initializer that initializes the slot. Very messy...
Michael: Already I am seeing that people are "discovering" class variables as a sort of "initialized instance variable" instead of using __init__ as they "ought" to. Of course, it's NOT an initialized instance variable, but newbies stumble across it and seem to prefer it to using __init__.
Perhaps I skipped school the day they taught that was bad, but it seems perfectly reasonable to me and I'm sure it is a common practice. I even find it to be clearer and more maintainable than using __init__. The only downside I see is that self.classvar += 1 reads from and writes to a different place.
It's also a bad idea for initializers that aren't immutable, because the initial values are shared between all instances (another example of the "aliasing" problem, also known from default argument values).
So, a reworded version of my question is "why not?". What is the downside of providing behavior that is similar to non-slotted classes? What is gained by these blocking an assignment and reporting a read-only error?
It's not like I did any work to prevent what you want from working. Rather, what you seem to want would be hard to implement (see above).
When I find an existing class can be made lighter by using __slots__, it would be nice to transform it with a single line. From:
class Tree(object): left = None right = None def __init__(self, value): self.value = value
adding only one line: __slots__ = ('left', 'right', 'value')
It would be a bummer to also have to move the left/right = None into __init__ and transform them into self.left = self.right = None.
Maybe I should remove slots from the language? <0.5 wink> They seem to be the most widely misunderstood feature of Python 2.2. If you don't understand how they work, please don't use them.
Duncan Booth: The following works, but I can't remember whether you're supposed to be able to use a dict in __slots__ or if it just happens to be allowed:
class Pane(object): __slots__ = { 'background': 'black', 'foreground': 'white', 'size': (80, 25) } def __init__(self): for k, v in self.__slots__.iteritems(): setattr(self, k, v)
__slots__ accepts any iterable. So, yes, you're allowed eventhough that particular use was not intended.
This loophole was intentionally left for people to find a good use for.
There are several possible workarounds including metaclasses. My question is why there needs to be a workaround at all.
I hope that has been answered by now.
Thomas Heller: Unrelated to *this* topic, but Andrew's "What's new in Python 2.2" still presents __slots__ as a way to constrain the instance variables:
A new-style class can define a class attribute named __slots__ to constrain the list of legal attribute names.
Though I think of __slots__ as a way to make lighter weight instances, constraining instance variables is also one of its functions.
Not true. That is at best an unintended side effect of slots. And there's nothing against having __slots__ include __dict__, so your instance has a __dict__ as well as slots. --Guido van Rossum (home page: http://www.python.org/~guido/)

It's also a bad idea for initializers that aren't immutable, because the initial values are shared between all instances (another example of the "aliasing" problem, also known from default argument values).
Right. I once knew that and had forgotten.
Though I think of __slots__ as a way to make lighter weight instances, constraining instance variables is also one of its functions.
Not true. That is at best an unintended side effect of slots. And there's nothing against having __slots__ include __dict__, so your instance has a __dict__ as well as slots.
That's something I never knew but wish I had known (and I *have* read the source). Live and learn. Raymond

Not true. That is at best an unintended side effect of slots. And there's nothing against having __slots__ include __dict__, so your instance has a __dict__ as well as slots.
That's something I never knew but wish I had known (and I *have* read the source). Live and learn.
Actually I think that's new in 2.3. --Guido van Rossum (home page: http://www.python.org/~guido/)
participants (4)
-
Guido van Rossum
-
Michael Chermside
-
Raymond Hettinger
-
Thomas Heller