[Python-Dev] PEP 447: add type.locallookup (original) (raw)

Steve Dower Steve.Dower at microsoft.com
Fri Sep 13 18:19:19 CEST 2013


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().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



More information about the Python-Dev mailing list