Python中的静态方法?
是否有可能在Python中有静态方法,所以我可以在不初始化类的情况下调用它们,如:
ClassName.StaticMethod ( )
是的,使用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中很less需要静态方法,而且在单独的“顶层”函数更清晰的情况下,我已经看到了很多情况。
以下是从文档逐字 ::
静态方法不会收到隐式的第一个参数。 为了声明一个静态方法,使用这个习惯用法:
class C: @staticmethod def f(arg1, arg2, ...): ...
@staticmethodforms是一个函数装饰器 – 详细信息请参阅函数定义中函数定义的描述。
它可以在类(如
Cf()
)或实例(如C().f()
)上调用。 该实例被忽略,除了它的类。Python中的静态方法类似于Java或C ++中的方法。 有关更高级的概念,请参见
classmethod()
。有关静态方法的更多信息,请参阅标准types层次结构中标准types层次结构的文档。
2.2版本中的新function
在版本2.4中更改:添加了函数装饰器语法。
我认为史蒂文其实是对的。 为了回答最初的问题,为了build立一个类方法,简单地假定第一个参数不会是一个调用实例,然后确保只调用该方法。
(请注意,这个答案是指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)
然而,它会引发exception,因为它会发送两个参数:自身和-1,而“rollCall”只被定义为接受一个参数。
顺便说一句,rex.rollCall()会发送正确数量的参数,但也会导致引发exception,因为现在当函数期望n是数字时,n将代表Dog实例(即rex)。
这是装饰进来的地方:如果我们在“rollCall”方法之前
@staticmethod
那么通过明确指出方法是静态的,我们甚至可以从一个实例中调用它。 现在,
rex.rollCall(-1)
会工作。 在方法定义之前插入@staticmethod,然后阻止实例将自己作为参数发送。
您可以通过尝试使用以下代码来validation此情况,而不使用@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
装饰器。 只要声明一个方法(不期望自我参数),并从类中调用它。 装饰者只是在那里,如果你想能够从一个实例调用它(这不是你想要做的)
大多数情况下,你只是使用函数,但…
Python中的静态方法?
是否有可能在Python中有静态方法,所以我可以在不初始化类的情况下调用它们,如:
ClassName.StaticMethod()
是的,可以像这样创build静态方法(尽pipe使用下划线而不是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'])
除了静态方法对象的特性之外,在组织模块级代码时,还可以使用某种美观方法。
# 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
现在,它变得更加直观和自我logging,在这种情况下,某些组件将被使用,理想地命名为不同的testing用例,以及直接testing模块如何映射到纯粹主义者testing的实际模块。
我经常发现应用这种方法来组织项目的实用程序代码是可行的。 通常情况下,人们会立即冲击并创build一个utils
包,最终得到9个模块,其中一个具有120个LOC,其余的则是最多两个LOC。 我更喜欢从这开始,并将其转换为一个包,并创build模块只为真正值得他们的野兽:
# 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
也许最简单的select就是把这些function放在课外:
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装饰器。