【问题标题】:Static methods in Python?Python中的静态方法?
【发布时间】:2026-01-01 12:30:01
【问题描述】:

是否有可能在 Python 中有静态方法,我可以在不初始化类的情况下调用,例如:

ClassName.static_method()

【问题讨论】:

    标签: python static-methods


    【解决方案1】:

    是的,请查看 staticmethod 装饰器:

    >>> class C:
    ...     @staticmethod
    ...     def hello():
    ...             print "Hello World"
    ...
    >>> C.hello()
    Hello World
    

    【讨论】:

    • 上面的许多答案都被否决了,因为它们只是一个例子。为什么会有所不同?
    【解决方案2】:

    是的,使用 staticmethod 装饰器

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

    请注意,某些代码可能使用定义静态方法的旧方法,将staticmethod 用作函数而不是装饰器。仅当您必须支持 Python 的旧版本(2.2 和 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
    

    这与第一个示例完全相同(使用@staticmethod),只是没有使用漂亮的装饰器语法

    最后,请谨慎使用staticmethod!在 Python 中很少有需要静态方法的情况,我已经看到它们被多次使用,而单独的“*”函数会更清晰。


    The following is verbatim from the documentation::

    静态方法不接收隐式的第一个参数。要声明静态方法,请使用以下习惯用法:

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

    @staticmethod 形式是一个函数decorator - 详见Function definitions 中函数定义的描述。

    它可以在类(如C.f())或实例(如C().f())上调用。该实例被忽略,除了它的类。

    Python 中的静态方法类似于 Java 或 C++ 中的静态方法。如需更高级的概念,请参阅classmethod()

    有关静态方法的更多信息,请参阅The standard type hierarchy 中有关标准类型层次结构的文档。

    2.2 版中的新功能。

    在 2.4 版中更改:添加了函数装饰器语法。

    【讨论】:

    • 当您可以简单地避免第一个 self 参数时,为什么要添加 @staticmethod 装饰或使用函数指针?好吧,对于 a 的对象,您将无法调用 a.your_static_method(),这在其他语言中是允许的,但无论如何这被认为是一种不好的做法,编译器总是会发出警告
    • 我正在使用 python 2.7.12,使用 @staticmethod 装饰器我无法调用定义的第一个静态方法。它的错误:TypeError: 'staticmethod' object is not callable
    • @SomethingSomething,如果您不使用变量名“self”,但不添加装饰器,则第一个参数(例如 arg1)仍将是对 self 实例的引用。名称 self 只是一个约定。
    • @GeorgeMoutsopoulos - 普遍同意。但是-无论如何,您都可以将方法称为ClassName.methodName(),就好像它是静态方法一样,然后不会向该方法提供self。正如您所说,仍然可以将此方法称为ClassInstance.methodName(),并且self将作为第一个参数提供,无论其名称如何。
    • @SomethingSomething 这么多答案、博客文章和参考资料,似乎没有人回答这个问题。我完全同意你所说的一切。既不应该写self.staticMethod() 也不应该写instance.staticMethod()。我发现的唯一例外是当您使用继承并希望覆盖 staticMethod 时,这似乎在 Python 中有效。现在调用self.staticMethod() 承认self 的类类型...这可能对类中需要的工厂方法或克隆很有趣,但可能仍然很少见
    【解决方案3】:

    您实际上并不需要使用 @staticmethod 装饰器。只需声明一个方法(不需要 self 参数)并从类中调用它。装饰器仅在您希望能够从实例中调用它的情况下才存在(这不是您想要做的)

    大多数情况下,您只是使用函数...

    【讨论】:

    • 这不适用于 python 2.5.2 class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1() 输出:来自 static2 Traceback:文件“ll.py”,第 46 行,在 Dummy.static1 () TypeError: unbound method static1() must be called with Dummy instance 作为第一个参数(什么都没有)
    • 这在类中不起作用。 Python 会将self 作为第一个参数传递,除非你告诉它不要这样做。 (参见:装饰器)
    • 实际上这在 2.7 中是错误的,并且在 3.X 中是合法的(在 3.2 中测试良好)。也就是说,在 2.7 及更低版本中,如果没有 @staticmethod 装饰器,您就无法从类的上下文中调用方法。在 3.2 中,它可以工作,并将根据其调用方式适当地插入一个 self 引用。测试用例:pastebin.com/12DDV7DB.
    • 技术上准确,但是一个糟糕的解决方案。 staticmethod 装饰器允许在类和实例上调用函数(在实例上调用函数时此解决方案失败)。
    • 可以像使用点符号的对象的任何其他属性一样调用方法。class C: def callme(): print('called'); C.callme()
    【解决方案4】:

    我认为Steven is actually right。为了回答最初的问题,为了设置类方法,只需假设第一个参数不会是调用实例,然后确保您只从类中调用方法。

    (请注意,此答案指的是 Python 3.x。在 Python 2.x 中,您将获得一个 TypeError 用于调用类本身的方法。)

    例如:

    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)
    

    在这段代码中,“rollCall”方法假定第一个参数不是一个实例(如果它是由一个实例而不是一个类调用的)。只要从类而不是实例调用“rollCall”,代码就可以正常工作。如果我们尝试从实例中调用“rollCall”,例如:

    rex.rollCall(-1)
    

    但是,它会引发异常,因为它会发送两个参数:自身和 -1,并且“rollCall”仅定义为接受一个参数。

    顺便说一句,rex.rollCall() 会发送正确数量的参数,但也会引发异常,因为现在当函数期望 n 为数字时,n 将表示 Dog 实例(即 rex)。

    这就是装饰的用武之地: 如果我们在“rollCall”方法之前加上

    @staticmethod
    

    然后,通过明确声明该方法是静态的,我们甚至可以从实例中调用它。现在,

    rex.rollCall(-1)
    

    会起作用的。然后,在方法定义之前插入@staticmethod 会阻止实例将自身作为参数发送。

    您可以通过尝试以下代码来验证这一点,无论是否注释掉 @staticmethod 行。

    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)
    

    【讨论】:

    • 第一个示例(在没有@staticmethod 的情况下按类调用)在 Python 2.7 上对我不起作用。我得到“TypeError: unbound method rollCall() must be called with Dog instance as first argument (得到 int instance)”
    • 这不起作用。 Dog.rollCall(-1) 和 rex.rollCall(-1) 返回相同的 TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
    • @MestreLion 我认为这不是一个巨大的好处,因为它所做的只是混淆了静态和实例方法,并使一个看起来像另一个。如果你知道一个方法是静态的,你应该将它作为一个静态方法来访问。无论您在何处使用该方法,该方法不需要或不使用您的实例这一事实应该是不言而喻的。我总是使用T.my_static_method()type(my_t_instance).my_static_method(),因为这样更清楚,并且很明显我正在调用静态方法。
    【解决方案5】:

    除了 static method objects 行为方式的特殊性之外,在组织模块级代码时,您还可以使用它们来发挥某种美感。

    # garden.py
    def trim(a):
        pass
    
    def strip(a):
        pass
    
    def bunch(a, b):
        pass
    
    def _foo(foo):
        pass
    
    class powertools(object):
        """
        Provides much regarded gardening power tools.
        """
        @staticmethod
        def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
            return 42
    
        @staticmethod
        def random():
            return 13
    
        @staticmethod
        def promise():
            return True
    
    def _bar(baz, quux):
        pass
    
    class _Dice(object):
        pass
    
    class _6d(_Dice):
        pass
    
    class _12d(_Dice):
        pass
    
    class _Smarter:
        pass
    
    class _MagicalPonies:
        pass
    
    class _Samurai:
        pass
    
    class Foo(_6d, _Samurai):
        pass
    
    class Bar(_12d, _Smarter, _MagicalPonies):
        pass
    

    ...

    # tests.py
    import unittest
    import garden
    
    class GardenTests(unittest.TestCase):
        pass
    
    class PowertoolsTests(unittest.TestCase):
        pass
    
    class FooTests(unittest.TestCase):
        pass
    
    class BarTests(unittest.TestCase):
        pass
    

    ...

    # interactive.py
    from garden import trim, bunch, Foo
    
    f = trim(Foo())
    bunch(f, Foo())
    

    ...

    # my_garden.py
    import garden
    from garden import powertools
    
    class _Cowboy(garden._Samurai):
        def hit():
            return powertools.promise() and powertools.random() or 0
    
    class Foo(_Cowboy, garden.Foo):
        pass
    

    它现在变得更加直观和自我记录,在哪些上下文中使用某些组件,并且它非常适合命名不同的测试用例,以及有一个简单的方法来说明测试模块如何映射到实际模块纯粹主义者的测试。

    我经常发现将这种方法应用于组织项目的实用程序代码是可行的。很多时候,人们会立即冲上去创建一个utils 包,最终得到 9 个模块,其中一个有 120 个 LOC,其余的最多是两打 LOC。我更喜欢从这个开始并将其转换为一个包并仅为真正值得它们的野兽创建模块:

    # utils.py
    class socket(object):
        @staticmethod
        def check_if_port_available(port):
            pass
    
        @staticmethod
        def get_free_port(port)
            pass
    
    class image(object):
        @staticmethod
        def to_rgb(image):
            pass
    
        @staticmethod
        def to_cmyk(image):
            pass
    

    【讨论】:

      【解决方案6】:

      也许最简单的选择就是将这些函数放在类之外:

      class Dog(object):
          def __init__(self, name):
              self.name = name
      
          def bark(self):
              if self.name == "Doggy":
                  return barking_sound()
              else:
                  return "yip yip"
      
      def barking_sound():
          return "woof woof"
      

      使用此方法,可以将修改或使用内部对象状态(具有副作用)的函数保留在类中,并将可重用的实用程序函数移出。

      假设这个文件名为dogs.py。要使用这些,您需要调用 dogs.barking_sound() 而不是 dogs.Dog.barking_sound

      如果你真的需要一个静态方法作为类的一部分,你可以使用staticmethod 装饰器。

      【讨论】:

        【解决方案7】:

        Python 中的静态方法?

        是否可以在 Python 中使用静态方法,以便我可以调用它们 无需初始化类,例如:

        ClassName.StaticMethod()
        

        是的,可以像这样创建静态方法(尽管使用下划线而不是 CamelCase 来表示方法有点多Pythonic):

        class ClassName(object):
        
            @staticmethod
            def static_method(kwarg1=None):
                '''return a value that is a function of kwarg1'''
        

        上面使用了装饰器语法。此语法等价于

        class ClassName(object):
        
            def static_method(kwarg1=None):
                '''return a value that is a function of kwarg1'''
        
            static_method = staticmethod(static_method)
        

        这可以像你描述的那样使用:

        ClassName.static_method()
        

        静态方法的内置示例是 Python 3 中的 str.maketrans(),它是 Python 2 中 string 模块中的一个函数。


        您描述的另一个可以使用的选项是classmethod,不同之处在于classmethod将类作为隐式第一个参数,如果是子类,那么它将子类作为隐式第一个参数。

        class ClassName(object):
        
            @classmethod
            def class_method(cls, kwarg1=None):
                '''return a value that is a function of the class and kwarg1'''
        

        请注意,cls 不是第一个参数的必需名称,但如果您使用其他任何名称,大多数有经验的 Python 编码人员会认为它做得不好。

        这些通常用作替代构造函数。

        new_instance = ClassName.class_method()
        

        一个内置的例子是dict.fromkeys():

        new_dict = dict.fromkeys(['key1', 'key2'])
        

        【讨论】:

          【解决方案8】:

          我不时遇到这个问题。我喜欢的用例和例子是:

          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']
          >>> 
          

          创建 cmath 类的对象没有意义,因为 cmath 对象中没有状态。然而, cmath 是一个方法的集合,它们都以某种方式相关。在我上面的示例中,cmath 中的所有函数都以某种方式作用于复数。

          【讨论】:

          • 您没有回答问题,而是提供了一个示例。
          【解决方案9】:

          Python 静态方法可以通过两种方式创建。

          1. 使用 staticmethod()

            class Arithmetic:
                def add(x, y):
                    return x + y
            # create add static method
            Arithmetic.add = staticmethod(Arithmetic.add)
            
            print('Result:', Arithmetic.add(15, 10))
            

          输出:

          结果:25

          1. 使用@staticmethod

            class Arithmetic:
            
            # create add static method
            @staticmethod
            def add(x, y):
                return x + y
            
            print('Result:', Arithmetic.add(15, 10))
            

          输出:

          结果:25

          【讨论】:

          • 您刚刚提供了示例并分享了如何您可以做到的方式。您没有解释这些方法的含义。
          【解决方案10】:

          因此,静态方法是可以在不创建类对象的情况下调用的方法。 例如:-

              @staticmethod
              def add(a, b):
                  return a + b
          
          b = A.add(12,12)
          print b
          

          在上面的示例方法中,add 被类名 A 调用,而不是对象名。

          【讨论】:

            【解决方案11】:

            总结别人的答案并补充,python中声明静态方法或变量的方式有很多种。

            1. 使用staticmethod()作为装饰器: 可以简单地将装饰器放在声明的方法(函数)之上,使其成为静态方法。例如。
            class Calculator:
                @staticmethod
                def multiply(n1, n2, *args):
                    Res = 1
                    for num in args: Res *= num
                    return n1 * n2 * Res
            
            print(Calculator.multiply(1, 2, 3, 4))              # 24
            
            1. 使用staticmethod()作为参数函数: 此方法可以接收函数类型的参数,并返回传递的函数的静态版本。例如。
            class Calculator:
                def add(n1, n2, *args):
                    return n1 + n2 + sum(args)
            
            Calculator.add = staticmethod(Calculator.add)
            print(Calculator.add(1, 2, 3, 4))                   # 10
            
            1. 使用classmethod()作为装饰器: @classmethod 对函数的影响与 @staticmethod 类似,但是 这一次,需要在函数中接受一个额外的参数(类似于实例变量的 self 参数)。例如。
            class Calculator:
                num = 0
                def __init__(self, digits) -> None:
                    Calculator.num = int(''.join(digits))
            
                @classmethod
                def get_digits(cls, num):
                    digits = list(str(num))
                    calc = cls(digits)
                    return calc.num
            
            print(Calculator.get_digits(314159))                # 314159
            
            1. 使用classmethod()作为参数函数: @classmethod 也可以用作参数函数,以防不想修改类定义。例如。
            class Calculator:
                def divide(cls, n1, n2, *args):
                    Res = 1
                    for num in args: Res *= num
                    return n1 / n2 / Res
            
            Calculator.divide = classmethod(Calculator.divide)
            
            print(Calculator.divide(15, 3, 5))                  # 1.0
            
            1. 直接声明 在所有其他方法之外但在类内部声明的方法/变量自动是静态的。
            class Calculator:   
                def subtract(n1, n2, *args):
                    return n1 - n2 - sum(args)
            
            print(Calculator.subtract(10, 2, 3, 4))             # 1
            

            整个程序

            class Calculator:
                num = 0
                def __init__(self, digits) -> None:
                    Calculator.num = int(''.join(digits))
                
                
                @staticmethod
                def multiply(n1, n2, *args):
                    Res = 1
                    for num in args: Res *= num
                    return n1 * n2 * Res
            
            
                def add(n1, n2, *args):
                    return n1 + n2 + sum(args)
                
            
                @classmethod
                def get_digits(cls, num):
                    digits = list(str(num))
                    calc = cls(digits)
                    return calc.num
            
            
                def divide(cls, n1, n2, *args):
                    Res = 1
                    for num in args: Res *= num
                    return n1 / n2 / Res
            
            
                def subtract(n1, n2, *args):
                    return n1 - n2 - sum(args)
                
            
            
            
            Calculator.add = staticmethod(Calculator.add)
            Calculator.divide = classmethod(Calculator.divide)
            
            print(Calculator.multiply(1, 2, 3, 4))              # 24
            print(Calculator.add(1, 2, 3, 4))                   # 10
            print(Calculator.get_digits(314159))                # 314159
            print(Calculator.divide(15, 3, 5))                  # 1.0
            print(Calculator.subtract(10, 2, 3, 4))             # 1
            

            参考Python Documentation掌握python中的OOP。

            【讨论】: