Difference between staticmethod and classmethod

后端 未结 28 2141
一整个雨季
一整个雨季 2020-11-21 06:11

What is the difference between a function decorated with @staticmethod and one decorated with @classmethod?

相关标签:
28条回答
  • 2020-11-21 06:43

    To decide whether to use @staticmethod or @classmethod you have to look inside your method. If your method accesses other variables/methods in your class then use @classmethod. On the other hand, if your method does not touches any other parts of the class then use @staticmethod.

    class Apple:
    
        _counter = 0
    
        @staticmethod
        def about_apple():
            print('Apple is good for you.')
    
            # note you can still access other member of the class
            # but you have to use the class instance 
            # which is not very nice, because you have repeat yourself
            # 
            # For example:
            # @staticmethod
            #    print('Number of apples have been juiced: %s' % Apple._counter)
            #
            # @classmethod
            #    print('Number of apples have been juiced: %s' % cls._counter)
            #
            #    @classmethod is especially useful when you move your function to other class,
            #       you don't have to rename the class reference 
    
        @classmethod
        def make_apple_juice(cls, number_of_apples):
            print('Make juice:')
            for i in range(number_of_apples):
                cls._juice_this(i)
    
        @classmethod
        def _juice_this(cls, apple):
            print('Juicing %d...' % apple)
            cls._counter += 1
    
    0 讨论(0)
  • 2020-11-21 06:44

    @staticmethod just disables the default function as method descriptor. classmethod wraps your function in a container callable that passes a reference to the owning class as first argument:

    >>> class C(object):
    ...  pass
    ... 
    >>> def f():
    ...  pass
    ... 
    >>> staticmethod(f).__get__(None, C)
    <function f at 0x5c1cf0>
    >>> classmethod(f).__get__(None, C)
    <bound method type.f of <class '__main__.C'>>
    

    As a matter of fact, classmethod has a runtime overhead but makes it possible to access the owning class. Alternatively I recommend using a metaclass and putting the class methods on that metaclass:

    >>> class CMeta(type):
    ...  def foo(cls):
    ...   print cls
    ... 
    >>> class C(object):
    ...  __metaclass__ = CMeta
    ... 
    >>> C.foo()
    <class '__main__.C'>
    
    0 讨论(0)
  • 2020-11-21 06:45

    Another consideration with respect to staticmethod vs classmethod comes up with inheritance. Say you have the following class:

    class Foo(object):
        @staticmethod
        def bar():
            return "In Foo"
    

    And you then want to override bar() in a child class:

    class Foo2(Foo):
        @staticmethod
        def bar():
            return "In Foo2"
    

    This works, but note that now the bar() implementation in the child class (Foo2) can no longer take advantage of anything specific to that class. For example, say Foo2 had a method called magic() that you want to use in the Foo2 implementation of bar():

    class Foo2(Foo):
        @staticmethod
        def bar():
            return "In Foo2"
        @staticmethod
        def magic():
            return "Something useful you'd like to use in bar, but now can't" 
    

    The workaround here would be to call Foo2.magic() in bar(), but then you're repeating yourself (if the name of Foo2 changes, you'll have to remember to update that bar() method).

    To me, this is a slight violation of the open/closed principle, since a decision made in Foo is impacting your ability to refactor common code in a derived class (ie it's less open to extension). If bar() were a classmethod we'd be fine:

    class Foo(object):
        @classmethod
        def bar(cls):
            return "In Foo"
    
    class Foo2(Foo):
        @classmethod
        def bar(cls):
            return "In Foo2 " + cls.magic()
        @classmethod
        def magic(cls):
            return "MAGIC"
    
    print Foo2().bar()
    

    Gives: In Foo2 MAGIC

    0 讨论(0)
  • 2020-11-21 06:45

    staticmethod has no access to attibutes of the object, of the class, or of parent classes in the inheritance hierarchy. It can be called at the class directly (without creating an object).

    classmethod has no access to attributes of the object. It however can access attributes of the class and of parent classes in the inheritance hierarchy. It can be called at the class directly (without creating an object). If called at the object then it is the same as normal method which doesn't access self.<attribute(s)> and accesses self.__class__.<attribute(s)> only.

    Think we have a class with b=2, we will create an object and re-set this to b=4 in it. Staticmethod cannot access nothing from previous. Classmethod can access .b==2 only, via cls.b. Normal method can access both: .b==4 via self.b and .b==2 via self.__class__.b.

    We could follow the KISS style (keep it simple, stupid): Don't use staticmethods and classmethods, don't use classes without instantiating them, access only the object's attributes self.attribute(s). There are languages where the OOP is implemented that way and I think it is not bad idea. :)

    0 讨论(0)
  • 2020-11-21 06:48

    Official python docs:

    @classmethod

    A class method receives the class as implicit first argument, just like an instance method receives the instance. To declare a class method, use this idiom:

    class C:
        @classmethod
        def f(cls, arg1, arg2, ...): ... 
    

    The @classmethod form is a function decorator – see the description of function definitions in Function definitions for details.

    It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class. If a class method is called for a derived class, the derived class object is passed as the implied first argument.

    Class methods are different than C++ or Java static methods. If you want those, see staticmethod() in this section.

    @staticmethod

    A static method does not receive an implicit first argument. To declare a static method, use this idiom:

    class C:
        @staticmethod
        def f(arg1, arg2, ...): ... 
    

    The @staticmethod form is a function decorator – see the description of function definitions in Function definitions for details.

    It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class.

    Static methods in Python are similar to those found in Java or C++. For a more advanced concept, see classmethod() in this section.

    0 讨论(0)
  • 2020-11-21 06:48

    @classmethod : can be used to create a shared global access to all the instances created of that class..... like updating a record by multiple users.... I particulary found it use ful when creating singletons as well..:)

    @static method: has nothing to do with the class or instance being associated with ...but for readability can use static method

    0 讨论(0)
提交回复
热议问题