Python中的静态方法?

我可以定义一个可以直接在类实例上调用的静态方法吗?例如,

MyClass.the_static_method()
1151596 次浏览

是的,看看静态方法装饰器:

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

是的,使用#0装饰器:

class MyClass(object):@staticmethoddef 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)完全相同,只是没有使用漂亮的装饰器语法。

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


以下内容摘自留档:

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

class C:@staticmethoddef f(arg1, arg2, ...): ...

@静态方法表单是一个函数装饰器-有关详细信息,请参阅函数定义中的函数定义描述。

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

Python中的静态方法类似于Java或C++中的方法。

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

新版本2.2。

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

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

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

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

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

例如:

class Dog:count = 0 # this is a class variabledogs = [] # this is a class variable
def __init__(self, name):self.name = name #self.name is an instance variableDog.count += 1Dog.dogs.append(name)
def bark(self, n): # this is an instance methodprint("{} 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)

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

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

class Dog:count = 0 # this is a class variabledogs = [] # this is a class variable
def __init__(self, name):self.name = name #self.name is an instance variableDog.count += 1Dog.dogs.append(name)
def bark(self, n): # this is an instance methodprint("{} says: {}".format(self.name, "woof! " * n))
@staticmethoddef 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)

除了静态方法对象行为的特殊性之外,在组织模块级代码时,您可以使用它们来实现某种美。

# garden.pydef 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."""@staticmethoddef answer_to_the_ultimate_question_of_life_the_universe_and_everything():return 42
@staticmethoddef random():return 13
@staticmethoddef 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.pyimport unittestimport garden
class GardenTests(unittest.TestCase):pass
class PowertoolsTests(unittest.TestCase):pass
class FooTests(unittest.TestCase):pass
class BarTests(unittest.TestCase):pass

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

# my_garden.pyimport gardenfrom 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,其余的最多有24个LOC。我更喜欢从这个开始,将其转换为一个包,并只为真正值得拥有的野兽创建模块:

# utils.pyclass socket(object):@staticmethoddef check_if_port_available(port):pass
@staticmethoddef get_free_port(port)pass
class image(object):@staticmethoddef to_rgb(image):pass
@staticmethoddef to_cmyk(image):pass

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

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

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

Python中的静态方法?

是否有可能在Python中有静态方法,所以我可以调用它们没有初始化类,例如:

ClassName.StaticMethod()

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

class ClassName(object):
@staticmethoddef 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,区别在于类方法将类作为隐式第一个参数获取,如果子类化,则它将子类作为隐式第一个参数获取。

class ClassName(object):
@classmethoddef 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'])

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

jeffs@jeffs-desktop:/home/jeffs  $ python36Python 3.6.1 (default, Sep  7 2017, 16:36:03)[GCC 6.3.0 20170406] on linuxType "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']>>>

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

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

  1. 使用静态方法()

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

Output:

Result: 25

  1. Using @staticmethod

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

Output:

Result: 25

因此,静态方法是无需创建类的对象即可调用的方法。例如:-

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

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

总结其他人的答案并添加,有很多方法可以在python中声明静态方法或变量。

  1. 使用静态方法作为装饰器:可以简单地将装饰器放在声明的方法(函数)之上,使其成为静态方法。例如。
class Calculator:@staticmethoddef multiply(n1, n2, *args):Res = 1for num in args: Res *= numreturn n1 * n2 * Res
print(Calculator.multiply(1, 2, 3, 4))              # 24
  1. 使用静态方法作为参数函数:此方法可以接收函数类型的参数,并返回传递的函数的静态版本。例如。
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. 使用类方法作为装饰器:在函数上,@class方法的效果与@static方法相似,但是这一次,需要在函数中接受一个额外的参数(类似于实例变量的self参数)。例如。
class Calculator:num = 0def __init__(self, digits) -> None:Calculator.num = int(''.join(digits))
@classmethoddef get_digits(cls, num):digits = list(str(num))calc = cls(digits)return calc.num
print(Calculator.get_digits(314159))                # 314159
  1. 使用类方法作为参数函数:在不想修改类定义的情况下,也可以用作参数函数。例如。
class Calculator:def divide(cls, n1, n2, *args):Res = 1for num in args: Res *= numreturn 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 = 0def __init__(self, digits) -> None:Calculator.num = int(''.join(digits))    
    
@staticmethoddef multiply(n1, n2, *args):Res = 1for num in args: Res *= numreturn n1 * n2 * Res

def add(n1, n2, *args):return n1 + n2 + sum(args)    

@classmethoddef get_digits(cls, num):digits = list(str(num))calc = cls(digits)return calc.num

def divide(cls, n1, n2, *args):Res = 1for num in args: Res *= numreturn 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))              # 24print(Calculator.add(1, 2, 3, 4))                   # 10print(Calculator.get_digits(314159))                # 314159print(Calculator.divide(15, 3, 5))                  # 1.0print(Calculator.subtract(10, 2, 3, 4))             # 1

请参阅python文档以掌握Python中的OOP。

您可以使用@静态方法定义如下所示的静态方法。详细地,我在Python中的@类方法与@静态方法Python中的“实例方法”是什么?4470227"><强>我的回答中解释了@静态方法@类方法,并在Python中的“实例方法”是什么?Python中的“实例方法”是什么?4482579"><强>我的回答中解释了实例方法

class Person:@staticmethod # Heredef test():print("Test")