Unexpected Name Lookup On Properties
Solution 1:
Because f.func
where f
is an instance of Foo
and func
is a property
descriptor triggers
Foo.func.__get__(f)
(see Descriptor protocol).
self.__dict__['func'] = 1
modifies the underlying dictionary of the f
instance. It doesn't change the func
attribute of the Foo
class.
Foo.func
takes precedence over f.func
(= 1, newly created instance variable) because
If an instance’s dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence.
(copied from the link above).
You'll have to assign something to Foo.func
if you want to replace the property:
classFoo(object):
@propertydeffunc(self):
Foo.func = 1return2
f = Foo()
print(f.func) # 2print(f.func) # 1
Solution 2:
According to this post, the attribute lookup process goes in this order:
- If attrname is a special (i.e. Python-provided) attribute for objectname, return it.
- Check objectname.__class__.__dict__ for attrname. If it exists and is a data-descriptor, return the descriptor result. Search all bases of objectname.__class__ for the same case.
- Check objectname.__dict__ for attrname, and return if found. If objectname is a class, search its bases too. If it is a class and a descriptor exists in it or its bases, return the descriptor result.
- Check objectname.__class__.__dict__ for attrname. If it exists and is a non-data descriptor, return the descriptor result. If it exists, and is not a descriptor, just return it. If it exists and is a data descriptor, we shouldn't be here because we would have returned at point 2. Search all bases of objectname.__class__ for same case.
- Raise AttributeError.
The property decorator adds a key-value pair to the object's class' __dict__
, so it gets found in step 2. Names added to the object's __dict__
are checked in step 3. So between the two, properties take precedence.
Post a Comment for "Unexpected Name Lookup On Properties"