Why property works only for objects?
Michal Kwiatkowski
ruby at no.spam
Fri Mar 10 20:54:40 EST 2006
Bruno Desthuilliers napisał(a):
>> Let me understand it clearly. If I change __class__ of an object,
>> existing attributes (so methods as well) of an object are still
>> accessible the same way and don't change its values. Only resolution of
>> attributes/methods not found in object is changed, as it uses new
>> version of __class__ to lookup names. Is this right?
>
> Attributes, yes. Not methods. Methods are looked up in the class.
My experience shows exactly the opposite. Any attribute/method you try
to access is first looked up in object dictionary, then inside class
definition.
import types
class C(object):
def f(self):
print "old method f()"
obj = C()
def f(self):
print "new method f()"
obj.f = types.MethodType(f, C)
obj.f() # => "new method f()"
Since that works, intuitively for me would be to assign object's
descriptors like that:
obj.x = property(types.MethodType(lambda self: 42, C))
But I just get a property object. So, it seems descriptors have little
bit of magic, as they don't work identically for classes and objects.
The same goes for special methods and attributes (written as __*__). So
I cannot change __getattr__/__setattr__/__metaclass__ or any other
attribute that starts with __ for a single object. It's not so bad
except for situations were class of an object defines its own
__getattribute__ method, which takes control of an object from us. To
get/set any attribute of an object we must use object type methods:
class C(object):
def __getattribute__(self, name):
return 42
obj = C()
obj.a = 5
print obj.a # => 42
print object.__getattribute__(obj, 'a') # => 5
I gets even more strange when you try to modify, say __len__ or
__repr__. Docstring for object.__repr__ says:
"x.__repr__() <==> repr(x)" which doesn't seem to be always true:
class C(object):
def __repr__(self):
return "class repr"
obj = C()
obj.__repr__ = types.MethodType(lambda self: "instance repr", C)
print repr(obj) # => class repr
print obj.__repr__() # => instance repr
Maybe the manual should say "x.__class__.__repr__() <==> repr(x)" instead?
I'm trying to understand attributes lookups made by Python, having
properties and special methods in mind. So far I've come up with kind of
reasoning I've coded below. I would appreciate any comments and
suggestions.
def lookup_name(obj, name):
get = lambda obj, name: object.__getattribute__(obj, name)
has = lambda obj, name: name in get(obj, '__dict__')
# assume C is a new style class
C = get(obj, '__class__')
# 1) use class' __getattribute__ method
try:
if has(C, '__getattribute__'):
return get(C, '__getattribute__')(obj, name)
except AttributeError: pass
# 2) lookup in object's dictionary
try:
if has(obj, name):
return get(obj, name)
except AttributeError: pass
# 3) lookup in classes
for c in obj.__class__.mro():
try:
if has(c, name):
desc = get(c, name)
# 3a) handle descriptors
try:
return get(desc, '__get__')(obj)
except: pass
# 3b) no descriptors -> use value
return desc
except AttributeError: pass
raise AttributeError, "Not found!"
mk
--
. o . >> http://joker.linuxstuff.pl <<
. . o It's easier to get forgiveness for being wrong
o o o than forgiveness for being right.
More information about the Python-list
mailing list