0

Reading Python Standard Library. Trying to understanding classmethod.

class C:
    @classmethod
    def f(x,y):
        print('words')

When I type:

print(classmethod(C))

It returns:

<classmethod object at 0x00FAD930>

How would see what the classmethod returns instead of a generator of the classmethod?

Phoenix
  • 4,386
  • 10
  • 40
  • 55

4 Answers4

4

You are producing a classmethod descriptor object:

print(classmethod(C))

returns the class C wrapped in a new classmethod object. This is not a generator, this is what Python actually stores in your class when you decorate a method with it.

Remember that a @decorator_expression line above a function or class is just syntactic sugar for an extra function call replacing that object; @classmethod above def f(...) just means that Python will replace f with f = classmethod(f).

You can see the same type of object when looking at the C.__dict__['f'] value; that's same type of object:

>>> class C:
...     @classmethod
...     def f(x,y):
...         print('words')
... 
>>> C.__dict__['f']
<classmethod object at 0x107d00810>
>>> C.__dict__['f'].__get__(None, C)
<bound method type.f of <class '__main__.C'>>
>>> C.f
<bound method type.f of <class '__main__.C'>>

It is the __get__ method on the descriptor object that is invoked when you try and access the C.f attribute.

Functions themselves are descriptors too; a classmethod bypasses the function's .__get__ method to provide a binding to the class instead of the normal binding to an instance.

See the descriptor HOWTO to understand what a descriptor is, and how a classmethod object works.

To see what an the method itself returns, just call it on the class or on an instance:

>>> class C:
...     @classmethod
...     def f(*args, **kw):
...         return args, kw
...     def regular(*args, **kw):
...         return args, kw
... 
>>> C.f()
((<class '__main__.C'>,), {})
>>> C().f()
((<class '__main__.C'>,), {})
>>> C.regular()
((), {})
>>> C().regular()
((<__main__.C object at 0x1085b0790>,), {})

Instead of the usual self instance object, the method is instead passed a reference to the class. For both the C.f() call (directly on the class) and the C().f() (on an instance of C), the first argument to f() is C itself.

Compare this to the C.regular() method; this is a normal method and when called directly on the class with C.regular() no arguments were passed in, when called on an instance with C().regular() a first argument, the instance, was passed in. This is what you normally would use self for in the method signature.

For class methods, then the first argument is usually named cls when declaring your method.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
2

If you want to call the classmethod f you have created on C, you should do:

C.f(...)

classmethod is the decorator function, it will wrap whatever you pass to it and return a classmethod object:

>>> classmethod(1)
<classmethod object at 0x02FA6370>

Note that the first to a classmethod is the class itself, called cls by convention:

class C:
    @classmethod
    def f(cls, x, y):
        print("words")

This gives:

>>> C.f(1, 2)
words

Alternatively return the value and print it outside the function:

class C:
    @classmethod
    def f(cls, x, y):
        return "words"

>>> print(C.f(1, 2))
words
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
1

classmethod is useful when sharing the value across all different objects being created.

class Classtest:
    a =10
    @classmethod
    def hi(cls, x):
        cls.a= cls.a+x
        print cls.a

h = Classtest()
h.hi(10)

b = Classtest()
b.hi(30)

c = Classtest()
c.hi(40)

>>> ================================ RESTART     ================================
>>>  
20
50
90

Here the value of variable a is shared across all different objects that are being created and not just limited to one instance

vijay
  • 107
  • 1
  • 7
0

Change to:

class C:
    @classmethod
    def f(cls, x, y):
        return 'words'

Unlike traditional class methods where the first argument is a self reference, a class method receives the class as implicit first argument, just like an instance method receives the instance.

Also, you need to return a value to print it.

Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132