[Python-Dev] PEP 447: add type.locallookup (original) (raw)
Steve Dower Steve.Dower at microsoft.com
Fri Sep 13 18:19:19 CEST 2013
- Previous message: [Python-Dev] PEP 447: add type.__locallookup__
- Next message: [Python-Dev] PEP 447: add type.__locallookup__
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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.
- It directly replaces obj.dict[name] everywhere that is done, including internally in the interpreter.
- 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().getfoo() # skips A.getattribute Traceback (most recent call last): File "", line 1, in File "", 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().getfoo() # 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
- Previous message: [Python-Dev] PEP 447: add type.__locallookup__
- Next message: [Python-Dev] PEP 447: add type.__locallookup__
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]