[Michael McLay] > I was suprised by a change to the order of evaluation of members > in the new object type. I haven't found an explanation for why the > change was made. Read PEP 252, paying special attention to the section containing: When a dynamic attribute (one defined in a regular object's __dict__) has the same name as a static attribute (one defined by a meta-object in the inheritance graph rooted at the regular object's __class__), the static attribute has precedence if it is a descriptor that defines a __set__ method (see below); otherwise (if there is no __set__ method) the dynamic attribute has precedence. In other words, for data attributes (those with a __set__ method), the static definition overrides the dynamic definition, but for other attributes, dynamic overrides static. Rationale: we can't have a simple rule like "static overrides dynamic" or "dynamic overrides static", because ... > ... > With the new slots mechanism the order has been reversed. The > class level dictionary is searched and then the slots are evaluated. I should hope so! The *point* of __slots__ (which is what you're really talking about, not the general concept of "slots") is that the class, not the object, is responsible for doing the attribute name->storage_address mapping, and in intended use an object of a class with __slots__ doesn't even have a __dict__ (each __slot__ attribute is allocated at a fixed offset from the start of the object, saving tons of storage). >>> class C(object): ... __slots__ = ['a'] Now objects of type C don't have a dict: storage for one attribute 'a' is allocated directly in C objects. >>> c = C() >>> c.__dict__ Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: 'C' object has no attribute '__dict__' You can set and get 'a': >>> c.a = 12 >>> c.a 12 C.a is a special beast: >>> C.a <member 'a' of 'C' objects> What makes it special isn't that it came from __slots__, though, but that it has a __set__ method (reread the quoted text above until your eyes bleed <wink>: this is a deadly simple protocol, so simple that it can be hard to understand at first (shades of the metaclass hook and continuations, there)): >>> dir(C.a) ['__class__', '__delattr__', '__doc__', '__get__', '__getattribute__', ^^^^^^^ C.a.__get__ is called when c.a is referenced. '__hash__', '__init__', '__name__', '__new__', '__objclass__', '__reduce__', '__repr__', '__set__', '__setattr__', '__str__'] ^^^^^^^ C.a.__set__ is called when c.a is bound or del'ed. Objects of C type can't grow new attributes: >>> c.b =12 Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: 'C' object has no attribute 'b' > >>> class B(object): > __slots__ = ['a','b','c'] > > >>> b = B() > >>> b.a = 4 > >>> b.a > 4 > >>> B.a = 6 Here you overwrote the descriptor that allows b.a to mean something sensible (you nuked the <member 'a' of 'B' objects> thingie that maps 'a' to its storage address). Now B.a is an ordinary class attribute, and remember that b doesn't have a __dict__ (which you asked for, by using __slots__; you're not required to use __slots__). > >>> b.a > 6 > >>> b.a = 8 > Traceback (most recent call last): > File "<pyshell#61>", line 1, in ? > b.a = 8 > AttributeError: 'B' object attribute 'a' is read-only I agree it's an odd msg, but I'm not sure it can do better easily: by overwriting B.a (which was nuts -- you're exploring pathologies here, not intended usage), you've left b as an object with an 'a' attribute inherited from its class, but also as an object that can't grow new attributes of its own. Python looks at "hmm, I *can't* set 'a', but I do *have* an 'a'", and comes up with "read-only". Try your example again without using __slots__ (you do *not* want __slots__ if you intend an object's namespace to be dynamic -- __slots__ announces that you guarantee the set of object attributes is fixed at class creation time): >>> class B(object): pass ... >>> b = B() >>> b.a = 4 >>> B.a = 6 >>> b.a 4 >>> b.a = 8 >>> b.a 8 >>> B.a 6 >>> IOW, don't use new features if you don't want new semantics, and things look much the same. If you want __slots__, though, there was no way to get its effect prior to 2.2 short of writing an ExtensionClass in C.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4