Difference between staticmethod and classmethod

后端 未结 28 2142
一整个雨季
一整个雨季 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:53

    I think giving a purely Python version of staticmethod and classmethod would help to understand the difference between them at language level.

    Both of them are non-data descriptors (It would be easier to understand them if you are familiar with descriptors first).

    class StaticMethod(object):
        "Emulate PyStaticMethod_Type() in Objects/funcobject.c"
    
        def __init__(self, f):
            self.f = f
    
        def __get__(self, obj, objtype=None):
            return self.f
    
    
    class ClassMethod(object):
        "Emulate PyClassMethod_Type() in Objects/funcobject.c"
        def __init__(self, f):
            self.f = f
    
        def __get__(self, obj, cls=None):
            def inner(*args, **kwargs):
                if cls is None:
                    cls = type(obj)
                return self.f(cls, *args, **kwargs)
            return inner
    
    0 讨论(0)
  • 2020-11-21 06:55

    Class methods, as the name suggests, are used to make changes to classes and not the objects. To make changes to classes, they will modify the class attributes(not object attributes), since that is how you update classes. This is the reason that class methods take the class(conventionally denoted by 'cls') as the first argument.

    class A(object):
        m=54
    
        @classmethod
        def class_method(cls):
            print "m is %d" % cls.m
    

    Static methods on the other hand, are used to perform functionalities that are not bound to the class i.e. they will not read or write class variables. Hence, static methods do not take classes as arguments. They are used so that classes can perform functionalities that are not directly related to the purpose of the class.

    class X(object):
        m=54 #will not be referenced
    
        @staticmethod
        def static_method():
            print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."
    
    0 讨论(0)
  • 2020-11-21 06:57

    I started learning programming language with C++ and then Java and then Python and so this question bothered me a lot as well, until I understood the simple usage of each.

    Class Method: Python unlike Java and C++ doesn't have constructor overloading. And so to achieve this you could use classmethod. Following example will explain this

    Let's consider we have a Person class which takes two arguments first_name and last_name and creates the instance of Person.

    class Person(object):
    
        def __init__(self, first_name, last_name):
            self.first_name = first_name
            self.last_name = last_name
    

    Now, if the requirement comes where you need to create a class using a single name only, just a first_name, you can't do something like this in Python.

    This will give you an error when you will try to create an object (instance).

    class Person(object):
    
        def __init__(self, first_name, last_name):
            self.first_name = first_name
            self.last_name = last_name
    
        def __init__(self, first_name):
            self.first_name = first_name
    

    However, you could achieve the same thing using @classmethod as mentioned below

    class Person(object):
    
        def __init__(self, first_name, last_name):
            self.first_name = first_name
            self.last_name = last_name
    
        @classmethod
        def get_person(cls, first_name):
            return cls(first_name, "")
    

    Static Method: This is rather simple, it's not bound to instance or class and you can simply call that using class name.

    So let's say in above example you need a validation that first_name should not exceed 20 characters, you can simply do this.

    @staticmethod  
    def validate_name(name):
        return len(name) <= 20
    

    and you could simply call using class name

    Person.validate_name("Gaurang Shah")
    
    0 讨论(0)
  • 2020-11-21 06:57

    One pretty important practical difference occurs when subclassing. If you don't mind, I'll hijack @unutbu's example:

    class A: 
        def foo(self, x): 
            print("executing foo(%s, %s)" % (self, x)) 
     
        @classmethod
        def class_foo(cls, x): 
            print("executing class_foo(%s, %s)" % (cls, x))
     
        @staticmethod 
        def static_foo(x): 
            print("executing static_foo(%s)" % x)
    
    class B(A):
        pass
    

    In class_foo, the method knows which class it is called on:

    A.class_foo(1)
    # => executing class_foo(<class '__main__.A'>, 1)
    B.class_foo(1)
    # => executing class_foo(<class '__main__.B'>, 1)
    

    In static_foo, there is no way to determine whether it is called on A or B:

    A.static_foo(1)
    # => executing static_foo(1)
    B.static_foo(1)
    # => executing static_foo(1)
    

    Note that this doesn't mean you can't use other methods in a staticmethod, you just have to reference the class directly, which means subclasses' staticmethods will still reference the parent class:

    class A:
        @classmethod
        def class_qux(cls, x):
            print(f"executing class_qux({cls}, {x})")
        
        @classmethod
        def class_bar(cls, x):
            cls.class_qux(x)
    
        @staticmethod
        def static_bar(x):
            A.class_qux(x)
    
    class B(A):
        pass
    
    A.class_bar(1)
    # => executing class_qux(<class '__main__.A'>, 1)
    B.class_bar(1)
    # => executing class_qux(<class '__main__.B'>, 1)
    A.static_bar(1)
    # => executing class_qux(<class '__main__.A'>, 1)
    B.static_bar(1)
    # => executing class_qux(<class '__main__.A'>, 1)
    
    0 讨论(0)
提交回复
热议问题