Difference between @classmethod and a method in python

This question already has an answer here:

  • What's an example use case for a Python classmethod? 6 answers

  • Let's assume you have a class Car which represents the Car entity within your system.

    A classmethod is a method that works for the class Car not on one of any of Car 's instances. The first parameter to a function decorated with @classmethod , usually called cls , is therefore the class itself. Example:

    class Car(object):    
        colour = 'red'
    
        @classmethod
        def blue_cars(cls):
            # cls is the Car class
            # return all blue cars by looping over cls instances
    

    A function acts on a particular instance of the class; the first parameter usually called self is the instance itself:

    def get_colour(self):
        return self.colour
    

    To sum up:

  • use classmethod to implement methods that work on a whole class (and not on particular class instances):

    Car.blue_cars()
    
  • use instance methods to implement methods that work on a particular instance:

    my_car = Car(colour='red')
    my_car.get_colour() # should return 'red'
    

  • If you define a method inside a class, it is handled in a special way: access to it wraps it in a special object which modifies the calling arguments in order to include self , a reference to the referred object:

    class A(object):
        def f(self):
            pass
    
    a = A()
    a.f()
    

    This call to af actually asks f (via the descriptor protocol) for an object to really return. This object is then called without arguments and deflects the call to the real f , adding a in front.

    So what af() really does is calling the original f function with (a) as arguments.

    In order to prevent this, we can wrap the function

  • with a @staticmethod decorator,
  • with a @classmethod decorator,
  • with one of other, similiar working, self-made decorators.
  • @staticmethod turns it into an object which, when asked, changes the argument-passing behaviour so that it matches the intentions about calling the original f :

    class A(object):
        def method(self):
            pass
        @staticmethod
        def stmethod():
            pass
        @classmethod
        def clmethod(cls):
            pass
    
    a = A()
    a.method() # the "function inside" gets told about a
    A.method() # doesn't work because there is no reference to the needed object
    a.clmethod() # the "function inside" gets told about a's class, A
    A.clmethod() # works as well, because we only need the classgets told about a's class, A
    a.stmethod() # the "function inside" gets told nothing about anything
    A.stmethod() # works as well
    

    So @classmethod and @staticmethod have in common that they "don't care about" the concrete object they were called with; the difference is that @staticmethod doesn't want to know anything at all about it, while @classmethod wants to know its class.

    So the latter gets the class object the used object is an instance of. Just replace self with cls in this case.

    Now, when to use what?

    Well, that is easy to handle:

  • If you have an access to self , you clearly need an instance method.
  • If you don't access self , but want to know about its class, use @classmethod . This may for example be the case with factory methods. datetime.datetime.now() is such an example: you can call it via its class or via an instance, but it creates a new instance with completely different data. I even used them once for automatically generating subclasses of a given class.
  • If you need neither self nor cls , you use @staticmethod . This can as well be used for factory methods, if they don't need to care about subclassing.

  • @classmethod takes the class as first argument while function takes instance of the class

    >>> class Test(object):
    ...     def func(self):
    ...         print self
    ...     @classmethod
    ...     def meth(self):
    ...         print self
    
    >>> t = Test()
    >>> t.func()
    <__main__.Test object at 0x00000000027238D0>
    >>> t.meth()
    <class '__main__.Test'>
    

    I've used self argument in meth intentionally so it would be very close in syntax to the func . But usually you'd better use cls as argument:

    ...     @classmethod
    ...     def meth(cls):
    ...         print cls
    
    链接地址: http://www.djcxy.com/p/9208.html

    上一篇: 在C#中完成/处理模式

    下一篇: @classmethod和python中的方法之间的区别