分类目录:《系统学习Python》总目录
静态方法的概念在Python2.X和Python3.X中都是相同的,但是,它的实现需求在Python3.X中有所发展。我们现在先来看看两种模型背后的不同。Python2.X和Python3.X总是向一个通过实例被调用的方法中传人一个实例。然而,Python3.X对待从一个类直接获取的方法,与Python2.X有所不同一一一这是一个在Python系列中跟新式类无关的版本差异:
换句话说,Python2.X的类方法总是要求传人一个实例,不管是通过一个实例或一个类来调用它们。相反,在Python3.X中,只有当一个方法期待实例的时候,我们才需要给它传人一个实例一一一没有一个实例参数的方法可以通过类调用而不需要传人一个实例。也就是说,Python3.X允许类中的简单函数,只要它们不期待并且也不被传人一个实例参数。最终的效果是:
例如,假设我们想使用类属性去计数从一个类产生了多少实例。下面的,文件进行了第一次的尝试。它的类把一个计数器存储为类属性,每次创建一个新的实例的时候,构造函数都会对计数器加1,同时有一个显示计数器值的方法。记住,类属性是由所有实例共享的。因此我们可以把计数器放在类对象内,从而确保它可以在所有的实例中使用:
class Spam:
numInstances = 0
def __init__(self):
Spam.numInstances = Spam.numInstances + 1
def printNumInstances():
print(Spam.numInstances)
这里的printNumInstances
方法旨在处理类数据而不是实例数据。它是关于所有实例的,而不是某个特定的实例。因此,我们希望在不必传人一个实例的情况下调用它。实际上,我们不想为了获取实例的数目而专门生成一个实例,因为这么做可能会改变我们想要获取的实例的数目。换句话说,我们想要一个无self
的静态方法。
然而,这段代码中的printNumInstances
是否有效,取决于我们所使用的Python版本,以及我们调用方法的方式一一是通过类还是通过一个实例。在Python2.X中,通过类或者实例来调用无self
方法函数都将失效。这是因为在Python2.X中非绑定的实例方法并不完全等同于简单数。即便在def
头部没有参数,该方法在调用的时候仍然期待传人一个实例,因为该函数与一个类相关。在Python3.X中,通过一个类对一个无self
方法的调用能够成功,但通过实例调用却会失效,我们先新建三个实例:
a = Spam()
b = Spam()
c = Spam()
然后再通过类方法计数:
Spam.printNumInstances()
输出:
3
通过实例方法计数:
a.printNumInstances()
输出:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 a.printNumInstances()
TypeError: printNumInstances() takes 0 positional arguments but 1 was given
也就是说,对于printNumInstances
这样的无实例方法的调用,在Python2.X中通过类进行调用将会失效,但是在Python3.X中将有效。另一方面,通过一个实例调用在两个版本的Python中都会失效,因为一个实例会自动传递给方法,而该方法却没有一个参数来接收它。
Spam.printNumInstances() #Fails in Python2.X and works in Python3.X
instance.printNumInstances() #FaiIs in both Python2.X and Python3.X
如果我们使用Python3.X并且坚持只通过类调用无self
方法,我们就已经得到了一个静态方法的功能。然而,要让无self
方法能在Python2.X中通过类调用,并且在Python2.X和Python3.X中都通过实例调用,我们就需要采取其他设计,或是对这样的方法进行特殊标记。
参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.