有没有可能在Python中有静态方法,这样我就可以调用它们而不初始化一个类,如:
1 | ClassName.StaticMethod ( ) |
是的,使用静态方法装饰器
1 2 3 4 5 6 | class MyClass(object): @staticmethod def the_static_method(x): print x MyClass.the_static_method(2) # outputs 2 |
注意,有些代码可能使用旧的方法来定义静态方法,使用
1 2 3 4 5 6 | class MyClass(object): def the_static_method(x): print x the_static_method = staticmethod(the_static_method) MyClass.the_static_method(2) # outputs 2 |
这与第一个示例完全相同(使用
最后,要节约使用
以下是文档中的逐字记录::
A static method does not receive an implicit first argument. To declare a static method, use this idiom:
1
2
3 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 asC().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.
我认为史蒂文是对的。要回答最初的问题,那么,为了设置一个类方法,只需假设第一个参数不是一个调用实例,然后确保只从类中调用方法。
(注意,这个答案指的是Python 3.x。在Python中2。你会得到一个
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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",例如:
1 | rex.rollCall(-1) |
但是,它会引发异常,因为它会发送两个参数:本身和-1,并且"rollCall"只定义为接受一个参数。
顺便提一下,rex.rollCall()会发送正确数量的参数,但也会引发异常,因为现在n表示Dog实例(即当函数期望n为数值时。
这就是装饰的作用:如果我们在"rollCall"方法之前加上
1 | @staticmethod |
然后,通过显式声明方法是静态的,我们甚至可以从实例调用它。现在,
1 | rex.rollCall(-1) |
是可行的。然后,在方法定义之前插入@staticmethod可以阻止实例将自己作为参数发送。
您可以通过尝试以下代码来验证这一点,其中包含和不包含注释掉的@staticmethod行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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) |
是的,看看静态方法装饰器:
1 2 3 4 5 6 7 | >>> class C: ... @staticmethod ... def hello(): ... print"Hello World" ... >>> C.hello() Hello World |
您实际上不需要使用
大多数情况下,你只是使用函数…
Static methods in Python?
Is it possible to have static methods in Python so I can call them
without initializing a class, like:
1 ClassName.StaticMethod()
是的,静态方法可以这样创建(尽管对方法使用下划线而不是CamelCase更符合python风格):
1 2 3 4 5 | class ClassName(object): @staticmethod def static_method(kwarg1=None): '''return a value that is a function of kwarg1''' |
上面的代码使用装饰器语法。这个语法等价于
1 2 3 4 5 6 | class ClassName(object): def static_method(kwarg1=None): '''return a value that is a function of kwarg1''' static_method = staticmethod(static_method) |
正如你所描述的:
1 | ClassName.static_method() |
静态方法的内置示例是Python 3中的
您描述的另一个选项是
1 2 3 4 5 | class ClassName(object): @classmethod def class_method(cls, kwarg1=None): '''return a value that is a function of the class and kwarg1''' |
注意,
它们通常用作替代构造函数。
1 | new_instance = ClassName.class_method() |
一个内置的例子是
1 | new_dict = dict.fromkeys(['key1', 'key2']) |
也许最简单的选择就是把这些函数放到类外:
1 2 3 4 5 6 7 8 9 10 11 12 | 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" |
使用这种方法,修改或使用内部对象状态(有副作用)的函数可以保存在类中,可重用的实用函数可以移到外部。
假设这个文件名为
如果确实需要静态方法作为类的一部分,可以使用staticmethod装饰器。
除了静态方法对象行为的特殊性之外,在组织模块级代码时,您还可以利用它们展现出某种美。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | # 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 |
…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # 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 |
…
1 2 3 4 5 | # interactive.py from garden import trim, bunch, Foo f = trim(Foo()) bunch(f, Foo()) |
…
1 2 3 4 5 6 7 8 9 10 | # 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 |
现在它变得更加直观和自文档化了,在这种情况下,特定的组件将被使用,并且理想地用于命名不同的测试用例,以及为纯粹主义者提供测试模块如何映射到测试下的实际模块的直接方法。
我经常发现将这种方法应用于组织项目的实用程序代码是可行的。通常,人们会立即创建一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 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 |
1 2 3 4 5 6 | class Stuff(object): @staticmethod def show(): print("Done") Stuff.show() |
Python静态方法可以通过两种方式创建。
使用staticmethod ()
1 2 3 4 5 6 7 | 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
1 2 3 4 5 6 7 8 | class Arithmetic: # create add static method @staticmethod def add(x, y): return x + y print('Result:', Arithmetic.add(15, 10)) |
输出:
结果:25
在Python 3:
下面是使用非静态方法的另一个好处,因为它们是静态方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Account: # here is the main class # a non-static method def login(self, url, email, password): # as a convention self is passed as a # placeholder for the class Object itself self.login_url = url self.user_email = email self.user_password = password print(self.login_url, self.user_email, self.user_password) |
调用一个非静态方法作为静态
1 2 3 4 5 6 7 | """ * Referencing the Account.login(self, url, email, password) * Just call the `Account` object as the self """ Account.login(Account,"https://example.com/login","[email protected]","password_example") :$ https://example.com/login email@example.com password_example |
我时常遇到这个问题。我喜欢的用例和例子是:
1 2 3 4 5 6 7 8 9 10 11 | 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中的所有函数都以某种方式作用于复数。