Static methods in Python?

后端 未结 10 743
悲&欢浪女
悲&欢浪女 2020-11-22 02:36

Is it possible to have static methods in Python which I could call without initializing a class, like:

ClassName.static_method()
相关标签:
10条回答
  • 2020-11-22 02:55

    You don't really need to use the @staticmethod decorator. Just declaring a method (that doesn't expect the self parameter) and call it from the class. The decorator is only there in case you want to be able to call it from an instance as well (which was not what you wanted to do)

    Mostly, you just use functions though...

    0 讨论(0)
  • 2020-11-22 02:55

    I encounter this question from time to time. The use case and example that I am fond of is:

    jeffs@jeffs-desktop:/home/jeffs  $ python36
    Python 3.6.1 (default, Sep  7 2017, 16:36:03) 
    [GCC 6.3.0 20170406] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import cmath
    >>> print(cmath.sqrt(-4))
    2j
    >>>
    >>> dir(cmath)
    ['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
    >>> 
    

    It does not make sense to create an object of class cmath, because there is no state in a cmath object. However, cmath is a collection of methods that are all related in some way. In my example above, all of the functions in cmath act on complex numbers in some way.

    0 讨论(0)
  • I think that Steven is actually right. To answer the original question, then, in order to set up a class method, simply assume that the first argument is not going to be a calling instance, and then make sure that you only call the method from the class.

    (Note that this answer refers to Python 3.x. In Python 2.x you'll get a TypeError for calling the method on the class itself.)

    For example:

    class Dog:
        count = 0 # this is a class variable
        dogs = [] # this is a class variable
    
        def __init__(self, name):
            self.name = name #self.name is an instance variable
            Dog.count += 1
            Dog.dogs.append(name)
    
        def bark(self, n): # this is an instance method
            print("{} says: {}".format(self.name, "woof! " * n))
    
        def rollCall(n): #this is implicitly a class method (see comments below)
            print("There are {} dogs.".format(Dog.count))
            if n >= len(Dog.dogs) or n < 0:
                print("They are:")
                for dog in Dog.dogs:
                    print("  {}".format(dog))
            else:
                print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
    
    fido = Dog("Fido")
    fido.bark(3)
    Dog.rollCall(-1)
    rex = Dog("Rex")
    Dog.rollCall(0)
    

    In this code, the "rollCall" method assumes that the first argument is not an instance (as it would be if it were called by an instance instead of a class). As long as "rollCall" is called from the class rather than an instance, the code will work fine. If we try to call "rollCall" from an instance, e.g.:

    rex.rollCall(-1)
    

    however, it would cause an exception to be raised because it would send two arguments: itself and -1, and "rollCall" is only defined to accept one argument.

    Incidentally, rex.rollCall() would send the correct number of arguments, but would also cause an exception to be raised because now n would be representing a Dog instance (i.e., rex) when the function expects n to be numerical.

    This is where the decoration comes in: If we precede the "rollCall" method with

    @staticmethod
    

    then, by explicitly stating that the method is static, we can even call it from an instance. Now,

    rex.rollCall(-1)
    

    would work. The insertion of @staticmethod before a method definition, then, stops an instance from sending itself as an argument.

    You can verify this by trying the following code with and without the @staticmethod line commented out.

    class Dog:
        count = 0 # this is a class variable
        dogs = [] # this is a class variable
    
        def __init__(self, name):
            self.name = name #self.name is an instance variable
            Dog.count += 1
            Dog.dogs.append(name)
    
        def bark(self, n): # this is an instance method
            print("{} says: {}".format(self.name, "woof! " * n))
    
        @staticmethod
        def rollCall(n):
            print("There are {} dogs.".format(Dog.count))
            if n >= len(Dog.dogs) or n < 0:
                print("They are:")
                for dog in Dog.dogs:
                    print("  {}".format(dog))
            else:
                print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))
    
    
    fido = Dog("Fido")
    fido.bark(3)
    Dog.rollCall(-1)
    rex = Dog("Rex")
    Dog.rollCall(0)
    rex.rollCall(-1)
    
    0 讨论(0)
  • 2020-11-22 03:04

    Yep, using the staticmethod decorator

    class MyClass(object):
        @staticmethod
        def the_static_method(x):
            print(x)
    
    MyClass.the_static_method(2)  # outputs 2
    

    Note that some code might use the old method of defining a static method, using staticmethod as a function rather than a decorator. This should only be used if you have to support ancient versions of Python (2.2 and 2.3)

    class MyClass(object):
        def the_static_method(x):
            print(x)
        the_static_method = staticmethod(the_static_method)
    
    MyClass.the_static_method(2)  # outputs 2
    

    This is entirely identical to the first example (using @staticmethod), just not using the nice decorator syntax

    Finally, use staticmethod sparingly! There are very few situations where static-methods are necessary in Python, and I've seen them used many times where a separate "top-level" function would have been clearer.


    The following is verbatim from the documentation::

    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().

    For more information on static methods, consult the documentation on the standard type hierarchy in The standard type hierarchy.

    New in version 2.2.

    Changed in version 2.4: Function decorator syntax added.

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