Chinmay Ghule
Chinmay Ghule

Reputation: 51

In Python, why does a class method override an instance method?

See code below:

class MyClass:

    # instance method.
    def printline(self):
        print('This is an instance method!')

    @classmethod
    def printline(cls):
        print('This is a class method!')


# class MyClass ends.

obj = MyClass()
obj.printline()

Output:

This is a class method!

So why is the class method overriding the instance method? Ignoring the fact that we can simply change the name of one of the method, how do access the instance method in the above code?

Upvotes: 1

Views: 635

Answers (4)

tdelaney
tdelaney

Reputation: 77347

Class function definitions are always placed on the class object itself. Decorators are really just a quick way to reassign a object with the named descriptor to the variable. The longer way to write your code is

class MyClass:

    # instance method.
    def printline(self):
        print('This is an instance method!')

    # make classmethod manually instead of using @classmethod
    def printline(cls):
        print('This is a class method!')
    printline = classmethod(printline)

obj = MyClass()
obj.printline()

The second printline overwrote the first printline on the class object after becoming a classmethod descriptor for the function.

Upvotes: 0

Algebra8
Algebra8

Reputation: 1365

You might get a clearer understanding if you were to look inside the class dictionary of MyClass:

>>> pp(MyClass.__dict__)
mappingproxy({'__dict__': <attribute '__dict__' of 'MyClass' objects>,
              '__doc__': None,
              '__module__': '__main__',
              '__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
              'printline': <classmethod object at 0x109d67dd0>})

Here you will see there is only one reference to the method printline. That is because you over-rode it - like a dictionary, a MappingProxy's keys are unique. Notice the classmethod value attached to it, if you were to do what @hobbs and @Arun suggested, you would see this:

>>> MyClass.__dict__['printline']
<function MyClass.printline at 0x10979a710>

Upvotes: 0

Arun Kaliraja Baskaran
Arun Kaliraja Baskaran

Reputation: 1086

The latest definition of the function will mask the previous one. If the instance method was defined like the 2nd example below, you would be calling it:

    In [1]: class MyClass:
       ...:
       ...:     # instance method.
       ...:     def printline(self):
       ...:         print('This is an instance method!')
       ...:
       ...:     @classmethod
       ...:     def printline(cls):
       ...:         print('This is a class method!')
       ...:

    In [2]: m =  MyClass()
    
    In [3]: m.printline()
    This is a class method!
    
    In [4]: class MyClass1:
       ...:
       ...:     @classmethod
       ...:     def printline(cls):
       ...:         print('This is a class method!')
       ...:
       ...:     # instance method.
       ...:     def printline(self):
       ...:         print('This is an instance method!')

    In [5]: m1 = MyClass1()
    
    In [6]: m1.printline()
    This is an instance method!

Upvotes: 5

hobbs
hobbs

Reputation: 239980

Because you defined printline twice, and the later definition wins. Class methods and instance methods are both just functions in the class, they don't have separate namespaces, so there can only be one function with a given name in a scope.

Upvotes: 1

Related Questions