[Python-Dev] PEP 447 (type.__getdescriptor__)

Ronald Oussoren ronaldoussoren at mac.com
Sun Jul 26 09:14:47 CEST 2015


> On 25 Jul 2015, at 17:39, Mark Shannon <mark at hotpy.org> wrote:
> 
> Hi,
> 
> On 22/07/15 09:25, Ronald Oussoren wrote:> Hi,
>> 
>> Another summer with another EuroPython, which means its time again to 
>> try to revive PEP 447…
>> 
> 
> IMO, there are two main issues with the PEP and implementation.
> 
> 1. The implementation as outlined in the PEP is infinitely recursive, since the
> lookup of "__getdescriptor__" on type must necessarily call
> type.__getdescriptor__.
> The implementation (in C) special cases classes that inherit "__getdescriptor__"
> from type. This special casing should be mentioned in the PEP.

Sure.  An alternative is to slightly change the the PEP: use __getdescriptor__ when
present and directly peek into __dict__ when it is not, and then remove the default
__getdescriptor__. 

The reason I didn’t do this in the PEP is that I prefer a programming model where
I can explicitly call the default behaviour. 

> 
> 2. The actual implementation in C does not account for the case where the class
> of a metaclass implements __getdescriptor__ and that method returns a value when
> called with "__getdescriptor__" as the argument.

Isn’t that the same problem as with all slots, even when using __getattribute__? That is,
a meta class that implements __getattribute__ to return implementations for (say)
__getitem__ won’t work because the interpreter won’t call __getattribute__ to get that
implementation unless it already knows that the attribute is present.  Class creation,
and __setattr__ on type will not only fill __dict__, but also set slots in the type structure
as appropriate.  The interpreter than uses those slots to determine if a special method
is present.

In code:

class Meta1 (type):
    def __getitem__(self, key):
        return "<{} {}>".format(self.__name__, key)

class Class1 (metaclass=Meta1):
    pass



class Meta2 (type):
    def __getattribute__(self, name):
        if name == "__getitem__":
            return lambda key: "<{} {}>".format(self.__name__, key)

        return super().__getattribute__(name)

class Class2 (metaclass=Meta2):
    pass

print(Class1.__getitem__("hello"))
print(Class1["hello"])

print(Class2.__getitem__("hello"))
print(Class2["hello"])

The last line causes an exception:

Traceback (most recent call last):
  File "demo-getattr.py", line 24, in <module>
    print(Class2["hello"])
TypeError: 'Meta2' object is not subscriptable

I agree that this should be mentioned in the PEP as it can be confusing.

> 
> 
> 
> Why was "__getattribute_super__" rejected as an alternative? No reason is given.
> 
> "__getattribute_super__" has none of the problems listed above.

Not really. I initially used __getattribute_super__ as the name, but IIRC with
the same  semantics.

> Making super(t, obj) delegate to t.__super__(obj) seems consistent with other
> builtin method/classes and doesn't add corner cases to the already complex
> implementation of PyType_Lookup().

A disadvantage of delegation is t.__super__ then reproduce the logic dealing
with the MRO, while my proposal allows the metaclass to just deal with lookup
in a specific class object. 

Implementation complexity is an issue, but it seems to be acceptable so far. The main
problem w.r.t. additional complexity is that PyType_Lookup can now fail
with an exception other than an implied AttributeError and that causes
changes elsewhere in the implementation.

BTW. The patch for that part is slightly uglier than it needs to be, I currently
test for PyErr_Occurred() instead of using return codes in a number of places
to minimise the number of lines changes to make code review easier.  That 
needs to be changed before the code would actually be committed.

Ronald

P.S. Are you at the EP sprints? I’ll be there until early in the afternoon.

> 
> Cheers,
> Mark
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/ronaldoussoren%40mac.com

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20150726/063926a5/attachment.html>


More information about the Python-Dev mailing list