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. -- http://mail.python.org/mailman/listinfo/python-list