静态方法
有时候,我们需要处理与类而不是与实例相关的数据。比如记录由类生产实例的数目,这种信息与类相关,而与实例无关,也就是说,这种信息通常存储在类自身上,不需要由实例来处理。
对于这样的任务,一个类之外的简单函数可以胜任。然而,要更好地把这样的代码与一个类联系起来,并且允许这样的过程可以继承,在类自身之中编写这类函数将会更好。为了做到这一点,我们需要一个类中的方法没有self实例参数。
静态方法可以用来实现这一目标:静态方法就是嵌入在类中没有self参数的函数,并且旨在操作类属性而不是实例属性。
在Python3以后的版本中,如果方法只通过一个类调用的话,我们没必要将这样的方法声明为静态的,但是要通过一个实例来调用它,我们就必须这样做。
例如,我们想使用类特性去计算从一个类产生了多少实例。下面的spam.py模块把一个计数器作为类特性,每次创建一个新的实例,初始化函数都会对计数器加1,还有另外一个方法用于显示计数器的值。记住,类属性是由所有实例共享。
class Spam:
numInstances = 0
def __init__(self):
Spam.numInstances = Spam.numInstances+1
def printNumInstances():
print("Number of instancescreated:",Spam.numInstances)
方法printNumInstances旨在打印类数据而不是实例数据,它关乎所有实例而非某个特定实例。因此,我们想要不传递一个实例就可以调用它。实际上,如果想生成一个实例来获取实例数目,是会改变要获取的实例数目的!我们想要一个无self的静态方法。
我们来运行一下看看:
>>> a =Spam()
>>> b =Spam()
>>> c =Spam()
>>>Spam.printNumInstances()
Number ofinstances created: 3
直接通过类来调用方法是可以的。
>>>a.printNumInstances()
Traceback (mostrecent call last):
File "
", line 1,in
a.printNumInstances()
TypeError:printNumInstances() takes 0 positional arguments but 1 was given
通过实例来调用方法则会出错:printNumInstances()没有位置参数,但却传递了一个参数。如果我们希望用实例来调用并且得出正确答案,可以使用内建的函数staticmethod:
class Spam:
numInstances = 0
def __init__(self):
Spam.numInstances = Spam.numInstances+1
def printNumInstances():
print("Number of instancescreated:",Spam.numInstances)
printNumInstances =staticmethod(printNumInstances)
来调用一下:
>>> a,b,c= Spam(),Spam(),Spam()
>>>Spam.printNumInstances()
Number of instances created: 3
>>>a.printNumInstances()
Number ofinstances created: 3
通过staticmethod函数作用后,静态方法圆满解决了问题。我们把staticmethod函数称作装饰器函数,可以这样标记:
@staticmethod
defprintNumInstances():
print("Number of instancescreated:",Spam.numInstances)
它与等效与:
defprintNumInstances():
print("Number of instancescreated:",Spam.numInstances)
printNumInstances =staticmethod(printNumInstances)
所以,可以把类写成:
class Spam:
numInstances = 0
def __init__(self):
Spam.numInstances = Spam.numInstances+1
@staticmethod
def printNumInstances():
print("Number of instancescreated:",Spam.numInstances)
验证一下结果:
>>> a,b,c =Spam(),Spam(),Spam()
>>>Spam.printNumInstances()
Number of instances created: 3
>>>a.printNumInstances()
Number of instances created: 3
没问题!
当然,你也可以把这个printNumInstances()函数放在类外来实现,但此法有一些瑕疵:
首先,它给该文件的作用域添加了一个额外的名字,此外该函数与类直接关联很小,而
且次函数不能通过继承定制,它们位于类的名字空间之外:子类不能通过重新定义这样
的一个函数来直接替代或扩展它。