On Fri, 2009-03-20 at 11:20 -0700, Emanuele D'Arrigo wrote: > Hi everybody, > > I was unit testing some code today and I eventually stumbled on one of > those "is" issues quickly solved replacing the "is" with "==". Still, > I don't quite see the sense of why these two cases are different: > > >>> def aFunction(): > ... pass > ... > >>> f = aFunction > >>> f is aFunction > True <--- Ok, this seems reasonable. Nevertheless, I suspect I > shouldn't quite rely on it. > > >>> class MyClass(object): > ... def myMethod(self): > ... pass > ... > >>> c = MyClass() > >>> m = c.myMethod > >>> m is c.myMethod > False <--- What? Why is that? > > In my mind I was expecting that when the method is assigned to "m" all > that it happens is that its address is assigned to the name "m" so > that effectively the same address is now pointed to by two names, like > in the function case. I googled around for some hint but I wouldn't > exactly say I'm clear on the issue just yet... > > Can anybody shed some light? Or point to a resource to look at? Or > what's the bit of python's source code that is responsible for dealing > with those assignments? > > Manu >
So here's a f'rinstance counterexample for you: class TempAttributeClass(object): def __init__(self): self.temp = True def foo(self, x): return len(x) + 1 def __getattribute__(self, attr): attribute = object.__getattribute__(self,attr) if hasattr(attribute, '__call__'): if object.__getattribute__(self, 'temp'): self.temp = False return len else: return attribute else: return attribute The first time a method is accessed from an instance of this class, it will return len instead. >>> print TempAttributeClass.foo <unbound method TempAttributeClass.foo> >>> c = TempAttributeClass() >>> l = [1,2,3] >>> x = c.foo >>> x(l) 3 >>> c.foo 4 >>> x == c.foo False >>> print x <built-in function len> >>> print y <bound method TempAttributeClass.foo of <__main__.TempAttributeClass object at 0x7f672b35e290>> c.foo is a bound attribute, but what has it been bound to? Well, I guess it technically, it's bound to the instance c, but what has it been bound from? That depends first on what it encounters when traversing its base classes, and second on how it's accessing its attributes. As the example above shows, python is too dynamic to make any guarantees about any of that. Another way you could mess with that is by changing the __class__ attribute on c. class A(object): x = 4 def __init__(self): self.y = 5 class B(object): x = u'cow' def __init__(self): self.y = u'goat' >>> c = A() >>> c.x 4 >>> c.y 5 >>> c.__class__ = B >>> # Note that neither c nor x were changed in the last step ... c.x # Class attribute found on B now u'cow' >>> c.y # Instance attribute: already initialized from A.__init__ 5 >>> c.__init__() # Reinitialize c, now using B.__init__ >>> c.y # Re-initialized instance attribute u'goat' Cheers, Cliff -- http://mail.python.org/mailman/listinfo/python-list