From: Steven D'Aprano > On Fri, Sep 13, 2013 at 04:26:06AM +0000, Steve Dower wrote: > >> Last I checked, looking up in the instance dict us exactly what it >> does. Even the example you posted is doing that. > > The example from the PEP shows: > > return cls.__dict__[name] > > not "self.__dict__[name]". It is true that "the instance" in this case refers > to > it being an instance of the metaclass, but that instance is, in fact, a > class/type. That's why we normally call it "cls" in a metaclass method rather > than "self".
Right, but where's the difference between these two? class A: def __tdb__(self, name): if name == 'some_attribute_on_my_instance_of_A': return its_value try: return self.__dict__[name] except KeyError: raise AttributeError(name) class MetaB: def __tdb__(cls, name): if name == 'some_attribute_on_my_class_B': return its_value try: return cls.__dict__[name] except KeyError: raise AttributeError(name) (Yes, either of these could be written with __getattribute__, but that function cannot be called by super().) As I see it, there are two (correct) ways to interpret what this method is for, which influences what it should be called. 1. It directly replaces obj.__dict__[name] everywhere that is done, including internally in the interpreter. 2. It is the same as __getattribute__ without the final call to object.__getattribute__ I guess it's also correct to view it as a special helper for super(), but it is more generally applicable than that. [...] > By the way, I think the PEP should have a more complex example. The > SillyObject > example is nice and easy to understand, but it doesn't really help with the > motivating use-case "dynamic classes that can grow new methods on demand". > Ronald, if you're reading this, can you add such an example please? Also, > there's a typo in the SillyObject M method ("fourtytwo" should not have a U in > it). Agreed. No harm in more examples. Here's a quick example of code that does not behave correctly at present. class A: def __getattribute__(self, name): if name == 'foo': return 'A.foo' return object.__getattribute__(self, name) class B(A): def get_foo(self): return super().foo >>> B().get_foo() # skips A.__getattribute__ Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in get_foo AttributeError: 'super' object has no attribute 'foo' >>> B().foo A.foo After changing to use the __tbd__ method: class A: def __getattribute__(self, name): '''Not strictly necessary for this example, but I would expect that most types overriding __tbd__ also want to override __getattribute__ to use it. Or maybe object.__getattribute__ should be changed to use __tbd__ too...?''' try: return self.__tbd__(name) except AttributeError: return object.__getattribute__(self, name) def __tbd__(self, name): # CHANGED if name == 'foo': return 'A.foo' try: return self.__dict__[name] except KeyError: raise AttributeError(name) # CHANGED class B(A): def get_foo(self): return super().foo >>> B().get_foo() # does not skip A.__tbd__ A.foo # hopefully this is the result :) >>> B().foo A.foo A full example of where this may realistically be needed is longer and certainly involves metaclasses, but fundamentally it's just the same as __getattribute__ with slightly different semantics. Cheers, Steve _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com