After initializing an object attribute to point to an object method, the variable will not be evaluated as being the same (using 'is') as the object method. It will still be evaluated as having equality (==) with the method.
class SomeClass:
def __init__(self):
self.command = self.do_something
def do_stuff(self):
print('c1:', id(self.command))
print('c2:', id(self.do_something))
if self.command is self.do_something:
return 'Commands match (is)'
elif self.command == self.do_something:
return 'Commands match (==)'
return 'Commands do not match at all'
def do_something(self):
pass
some_object = SomeClass()
print(some_object.do_stuff())
print()
def some_func():
pass
command = some_func
print('c1:', id(some_func))
print('c2:', id(command))
if some_func is command:
print('Commands match (is)')
else:
'Commands do not match at all'
I was expecting the ids of self.command and self.do_something to be the same just like some_func and command ids are the same.
CodePudding user response:
Each time you access a method via an instance, you get back a new instance of method
that wraps both the instance and the underlying function. Two method
instances compare as equal if they wrap the same instance and the same function. (This is not documented anywhere as far as I know—it's not mentioned in the documentation for instance method objects—but can be seen in the CPython source code.)
So even though self.command
(a previously created bound method) and self.do_something
are distinct instances of method
, they both wrap the same instance (self
) of SomeClass
and the same function (SomeClass.do_something
).
Details on how function
values produce method
instances can be found in the Descriptor HowTo guide.
(Instance method objects are documented in Section 3.2 of the language documentation.)