[Python-ideas] Simpler Customization of Class Creation - PEP 487

Sjoerd Job Postmus sjoerdjob at sjec.nl
Mon Feb 8 05:00:39 EST 2016


On Mon, Feb 08, 2016 at 10:28:17AM +0100, Martin Teichmann wrote:
> While I think that you're correct that a better example would be a good
> idea, you example for me hints to that __set_owner__ does an initialization
> of the attribute at object creation time, but it does it at class creation time.
> I'll sleep over it, maybe I find a nice example.
> 
> It's also important to note that the new thing about the metaclass is
> not that it supplies the attribute with the owner, but that it tell
> the attribute
> about its name. The owner was already shipped to __get__ and __set__,
> but not the name within that class. I am not aware of a way to find out
> the attribute name from within a descriptor. (That's not true: a year ago
> some ideas how to do that were posted here, but they used undocumented
> internal features of CPython, not necessarily a reasonable way).
> This is why the name __set_owner__ also might be misleading, but
> __set_name__ also doesn't sound right to me, any better calls? For
> the meantime I stick with __set_owner__.

It would cause backwards-incompatibility, but would it not be an option
to call __get__ and __set__ (and __del__) with an extra parameter: the
name of the attribute that is supposed to be accessed? (This can
probably be worked around by inspecting the signature of __get__/... to
see how many arguments it takes).

Because right now, if the descriptor itself does not maintain any state,
it is possible to assign the same descriptor to multiple class
attributes, maybe even to multiple classes. (On the other hand, in that
case it would probably not need `__set_owner__` either).

The question to me is: can __set_owner__ give us something that can not
be done by adding a name parameter to __get__/... . The weakref proxy
(with callback) looks to be one of those cases, but is not really:

    def __set__(self, owner, value, attr):
        def _cb(arg):
            callback = getattr(owner, 'attribute_collected')
            if callback is note None:
                callback(attr)

        instance.__dict__[self.name] = weakref.proxy(value, callback)


Calling desc.__set__(owner, value, attr) instead of desc.__set__(owner,
value) can probably also be implemented by a custom metaclass which
walks over all the values in the generated namespace, and replaces a
descriptor with a NameCallingDescriptor(val, attr).

    for attr, val in namespace.items():
        if is_descriptor(val):
            if descriptor_wants_attribute_name(val):
                namespace[attr] = NameCallingDescriptor(val, attr)

Is there anything that __set_owner__ brings that can not be done by
changing __get__/__set__/...?


More information about the Python-ideas mailing list