Home > database >  Do python methods belong to object or class?
Do python methods belong to object or class?

Time:10-08

When an instance is created via a python class, does this object have its own methods in memory along with its instance variables? I imagine that this isn't the case because a lot of memory would be used if it were. When an object invokes a method from the class which the object was created from, how does the method lookup work? Does it work similarly to the process in which class variable is used when instance's variable with the same name doesn't exist? According to the following code, jane.full_name have the same id as john.full_name yet they are !=

class Person:

    last_name = "doe"
    
    def __init__(self, name):
        self.name = name
    
    def full_name(self):
        print(f"{self.name} {self.last_name}")
    
jane = Person("jane")
john = Person("john")
jane.full_name()

print(jane.full_name == john.full_name)  # False
print(jane.full_name is john.full_name)  # False
print(id(jane.full_name), id(john.full_name))  # 139827998611904 139827998611904  

CodePudding user response:

No, methods belong to the class, but when you access a Python method from an instance, the descriptor protocol for function objects bind the instance as the first argument and return a bound method. This is a distinct object each time you do the attribute access:

>>> class Foo:
...     def bar(self): return 42
...
>>> foo1 = Foo()
>>> bound_method = foo1.bar
>>> bound_method
<bound method Foo.bar of <__main__.Foo object at 0x10ca01be0>>
>>> bound_method is foo1.bar
False
>>> bound_method()
42
>>> foo1.bar()
42

Note, you can introspect the instance versus the class namespaces:

>>> vars(foo1)
{}
>>> vars(Foo)
mappingproxy({'__module__': '__main__', 'bar': <function Foo.bar at 0x10cbbb0d0>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None})

The instance namespace is empty - there are no instance attributes.

CodePudding user response:

Methods belong to the class. They are, in fact, simply function-valued class attributes that, due to the descriptor protocol, produce a callable method object when invoked from an instance of the class.

>>> type(Person.full_name)
<class 'function'>
>>> type(jane.full_name)
<class 'method'>

More specifically, Person.full_name is equivalent to Person.__dict__['full_name'].__get__(None, Person), while jane.full_name is equivalent to Person.__dict__['full_name'].__get__(jane).

The method object wraps both the function and the instance (jane, in this case) that accessed the attribute.

>>> jane.full_name.__self__ is jane
True
>>> jane.full_name.__func__ is Person.full_name
True

The above is true for instance methods. Class methods and static methods are simply class attributes of type classmethod and staticmethod, respectively. The sole purpose of the two classes is to override __get__ to modify the object returned. classmethod.__get__ always returns a method instance that wraps the class, and staticmethod.__get__ always returns the function itself.

  • Related