是否可以在 Python 中有静态方法,我可以在不初始化类的情况下调用这些方法,例如:
ClassName.static_method()
是的,使用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 中很少有需要静态方法的情况,而且我已经看到它们多次使用,其中单独的“顶级”函数会更清晰。
静态方法不接收隐式的第一个参数。要声明静态方法,请使用以下习惯用法:
class C: @staticmethod def f(arg1, arg2, ...): ...
@staticmethod 形式是一个函数装饰器——详见函数定义中函数定义的描述。
它可以在类(例如
C.f()
)或实例(例如C().f()
)上调用。该实例被忽略,除了它的类。Python 中的静态方法类似于 Java 或 C++ 中的静态方法。有关更高级的概念,请参阅
classmethod()
。有关静态方法的更多信息,请参阅标准类型层次结构中有关标准类型层次结构的文档。
2.2 版中的新功能。
在 2.4 版更改: 添加了函数装饰器语法。
我认为史蒂文实际上是对的。为了回答最初的问题,为了设置类方法,只需假设第一个参数不会是调用实例,然后确保您只从类中调用该方法。
(请注意,此答案指的是 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装饰器:
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
你真的不需要使用@staticmethod
装饰器。只需声明一个方法(不需要 self 参数)并从类中调用它。装饰器仅在您希望能够从实例中调用它的情况下才存在(这不是您想要做的)
大多数情况下,你只是使用函数......
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中有一个静态方法的内置示例,它是Python 2 模块中str.maketrans()
的一个函数。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'])
除了静态方法对象行为方式的特殊性之外,在组织模块级代码时,您还可以使用它们来发挥某种美感。
# 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
也许最简单的选择就是将这些函数放在类之外:
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装饰器。
因此,静态方法是无需创建类的对象即可调用的方法。例如 :-
@staticmethod
def add(a, b):
return a + b
b = A.add(12,12)
print b
在上面的示例中,方法add
是由类名A
而不是对象名调用的。
总结其他人的答案并补充,有很多方法可以在python中声明静态方法或变量。
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
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
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
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
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 文档以掌握 Python 中的 OOP。
我不时遇到这个问题。我喜欢的用例和示例是:
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 中的所有函数都以某种方式作用于复数。
Python 静态方法可以通过两种方式创建。
使用静态方法()
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
使用@staticmethod
class Arithmetic:
# create add static method
@staticmethod
def add(x, y):
return x + y
print('Result:', Arithmetic.add(15, 10))
输出:
结果:25