From: Kevin Jacobs [mailto:jacobs@penguin.theopalgroup.com]
FWIW, I disagree with this completely. I would expect slots with a particular name in derived classes to hide the same-named slots in base classes. Whether or not the base class slot is available via some sort of "super" shenannigans is less relevant. But hiding semantics is critical. How do you expect to reliably make it possible to derive from a class with slots otherwise? Perl gets into this sort of mess with its implementation of objects.
Attributes currently have a flat namespace, and the construct that I feel is most natural would maintain that characteristic. e.g.:
Oops. Sorry, I got that completely wrong. OK, I side with silent re-use. That's what attributes do. [Meta-meta comment: the rule should be to work "just like" attributes.] So why did you feel the need to separate this point from your point (3)? It gives the impression that this point differs from attributes, in contrast to the things mentioned in (3).
Agreed - up to a point. I don't see a need for a way to distinguish between slots and "normal" attributes, personally. But I don't do anything fancy here, so my experience isn't very indicative.
Without a more formal reflection API, the traditional way to get all normal dictionary attributes is by using instance.__dict__.keys().
The official, and supported, way is to use dir(). This was hashed out on python-dev at the time. As I understand it, dir() always "worked", and was extended to support slots when they were added. __dict__ clearly only handles dict-based attributes, and so cannot be extended to include slots. The official advice on reflection was therefore modified to point out that dir() and __dict__.keys() were no longer equivalent, and dir() was "the way" to get the full set. (Whether this advice was included into the formal documentation, I couldn't confirm, but it was written down - arguing "if it's not in the documentation, it's not official", is a little naive, given the new and relatively experimental status of the whole area...)
All I'm proposing is that instance.__slotattrs__ (or possibly instance.__class__.__slotattrs__) returns a list of objects that reveal the name of all slots in the instance (including those declared in base classes).
Do you have any reason why you would need to get a list of only slots, or only dict-based attributes? Given that I'm arguing that the two should work exactly the same (apart from storage and efficiency details), it seems unreasonable to want to make the distinction (unless you're doing something incestuous and low-level, when you're on your own...) Remember, instance.__dict__['attrname'] is now regarded as incomplete in the face of slots. Again, I point you to the descrintro document, just below the discussion of slots, in the paragraphs starting from "The correct way to get any attribute from self inside __getattribute__ is to call the base class's __getattribute__ method".
The only issue that concerns me is that I am not sure if the slot to slot name mapping should be fixed.
I haven't melted my brain enough to understand the PEPs, but I believe that there are ways of doing all sorts of low-level hacking with descriptors, if you really want to. I don't believe that making this easy for "normal" users is a good thing. [BTW, this reminds me of your point on what is documented. I believe that the PEPs and descrintro count as the canonical documentation of these features. If they haven't been fully migrated into the Python documentation set yet, that's a secondary issue. The PEPs *are* the definition of what was agreed - people had time to comment on the PEPs at the time. And the descrintro document is the current draft of the user-level documentation. You can assume it will end up in the manuals. That's my view...]
EXACTLY! I want to use slots (or slotattrs, or whatever you call them) to be solely an allocation declaration. For small objects that you expect to create many, many instance of, they make a huge difference.
In which case, you are giving the impression of wanting large changes, when you really want things to stay as they are (modulo some relatively non-controversial (IMHO) bugs). If you read the descrintro document on slots, you will see that it presents an identical viewpoint. OK, there are some technical restrictions, which will always apply because of the nature of the optimisation, but the intention is clear. And it matches yours... Paul.
Moore, Paul writes:
[BTW, this reminds me of your point on what is documented. I believe that the PEPs and descrintro count as the canonical documentation of these features. If they haven't been fully migrated into the Python documentation set yet, that's a secondary issue. The PEPs *are* the definition of what was agreed - people had time to comment on the PEPs at the time. And the descrintro document is the current draft of the user-level documentation. You can assume it will end up in the manuals. That's my view...]
This is my perspective as well. I'm not in a hurry to document relatively volatile feature that may change and (hopefully!) be available using a nicer syntax in the future. -Fred -- Fred L. Drake, Jr. <fdrake at acm.org> PythonLabs at Zope Corporation
On Wed, 20 Feb 2002, Fred L. Drake, Jr. wrote:
Moore, Paul writes:
[BTW, this reminds me of your point on what is documented. I believe that the PEPs and descrintro count as the canonical documentation of these features. If they haven't been fully migrated into the Python documentation set yet, that's a secondary issue. The PEPs *are* the definition of what was agreed - people had time to comment on the PEPs at the time. And the descrintro document is the current draft of the user-level documentation. You can assume it will end up in the manuals. That's my view...]
This is my perspective as well. I'm not in a hurry to document relatively volatile feature that may change and (hopefully!) be available using a nicer syntax in the future.
Then what is the criterion for deciding when to apply the standard Python deprecation procedures when things like super() and the __slots__ change? # Python 2.3? from __future__ import super_as_builtin from __future__ import hidden_slots I had (possibly incorrectly) assumed that the criterion was when it was officially documented in a release. -Kevin -- Kevin Jacobs The OPAL Group - Enterprise Systems Architect Voice: (216) 986-0710 x 19 E-mail: jacobs@theopalgroup.com Fax: (216) 986-0714 WWW: http://www.theopalgroup.com
Kevin Jacobs <jacobs@penguin.theopalgroup.com> writes:
Then what is the criterion for deciding when to apply the standard Python deprecation procedures when things like super() and the __slots__ change?
It may be that the change does not need to involve deprecation of anything; first let's see the new feature, then decide how to deprecate the exiting one. Regards, Martin
On Wed, 20 Feb 2002, Moore, Paul wrote:
Oops. Sorry, I got that completely wrong. OK, I side with silent re-use. That's what attributes do. [Meta-meta comment: the rule should be to work "just like" attributes.] So why did you feel the need to separate this point from your point (3)? It gives the impression that this point differs from attributes, in contrast to the things mentioned in (3).
('c', 'd')
Having a flat namespace (i.e., no hidden slots), and having all 'reachable' slots in a single list are really two separate issues. Right now, we have this situation: class Foo(object): __slots__ = ('a','b') class Bar(Foo): __slots__ = ('c','d') bar=Bar() print bar.__slots__ print bar.__class__.__base__.__slots__
('a', 'b')
I content that bar.__slots__ should be:
('a', 'b', 'c', 'd')
I think somewhere along the line I may have mixed up which 'flatness' I was talking about.
The official, and supported, way is to use dir().
I agree, but that "official" support has clear limitations. Right now, there are several examples in the Python standard library where we use obj.__dict__.keys() -- most significantly in pickle and cPickle. There is also the vars(obj), which may be the better reflection method, though it currently doesn't know about slots.
(Whether this advice was included into the formal documentation, I couldn't confirm, but it was written down - arguing "if it's not in the documentation, it's not official", is a little naive, given the new and relatively experimental status of the whole area...)
Naive, maybe, but saying "undocumented" is equivalent to "unsupported implementation detail" saves us from having to maintain backward compatibility and following the official Python deprecation process.
Do you have any reason why you would need to get a list of only slots, or only dict-based attributes?
Yes. Dict-based attributes always have values, while slot-based attributes can be unset and raise AttributeErrors when trying to access them. e.g., here is how I would handle pickling (excerpt from pickle.py): try: getstate = object.__getstate__ except AttributeError: stuff = object.__dict__ # added to support slots if hasattr(object.__slots__): for slot in object.__slots__: if hasattr(object, slot): stuff[slot] = getattr(object, slot) else: stuff = getstate() _keep_alive(stuff, memo) save(stuff) write(BUILD)
Given that I'm arguing that the two should work exactly the same (apart from storage and efficiency details), it seems unreasonable to want to make the distinction (unless you're doing something incestuous and low-level, when you're on your own...)
I'm not suggesting anything more incestuous and low-level than what is already done in many, many, many places. A larger, more-encompassing proposal is definitely welcome.
EXACTLY! I want to use slots (or slotattrs, or whatever you call them) to be solely an allocation declaration. For small objects that you expect to create many, many instance of, they make a huge difference.
In which case, you are giving the impression of wanting large changes, when you really want things to stay as they are (modulo some relatively non-controversial (IMHO) bugs). If you read the descrintro document on slots, you will see that it presents an identical viewpoint. OK, there are some technical restrictions, which will always apply because of the nature of the optimisation, but the intention is clear. And it matches yours...
Well, I've not found resounding agreement on the first two of my three basic issues/bugs I've raised so far: 1) Flat slot namespaces: Objects should not hiding slots when inherited by classes implementing the same slot name. 2) Flat slot descriptions: object.__slots__ being an immutable flat tuple of all slot names (including inherited ones), as opposed to being a potentially mutable sequence of only the slots defined by the most derived class. 3) First class status for slot reflection: making slots picklable by default, returned by vars(object), and made part of other relevant reflection APIs and standard implementations. The good news is that once Guido and others have spoken, I can have patches that accomplish all of this fairly quickly. I just don't want to do a lot of unnecessary work if it won't be accepted. Thanks, -Kevin -- Kevin Jacobs The OPAL Group - Enterprise Systems Architect Voice: (216) 986-0710 x 19 E-mail: jacobs@theopalgroup.com Fax: (216) 986-0714 WWW: http://www.theopalgroup.com
participants (4)
-
Fred L. Drake, Jr. -
Kevin Jacobs -
martin@v.loewis.de -
Moore, Paul