系统学习Python——类(class):静态方法(staticmethod)和类方法(classmethod)-[初识Python中的静态方法]

分类目录:《系统学习Python》总目录
相关文章:
· 静态方法(staticmethod)和类方法(classmethod):基础知识
· 静态方法(staticmethod)和类方法(classmethod):使用静态方法和类方法的原因
· 静态方法(staticmethod)和类方法(classmethod):初识Python中的静态方法
· 静态方法(staticmethod)和类方法(classmethod):静态方法备选方案
· 静态方法(staticmethod)和类方法(classmethod):使用静态方法和类方法
· 静态方法(staticmethod)和类方法(classmethod):用静态方法计数实例
· 静态方法(staticmethod)和类方法(classmethod):用类方法计数实例
· 静态方法(staticmethod)和类方法(classmethod):使用类方法统计每个类的实例个数实例


静态方法的概念在Python2.X和Python3.X中都是相同的,但是,它的实现需求在Python3.X中有所发展。我们现在先来看看两种模型背后的不同。Python2.X和Python3.X总是向一个通过实例被调用的方法中传人一个实例。然而,Python3.X对待从一个类直接获取的方法,与Python2.X有所不同一一一这是一个在Python系列中跟新式类无关的版本差异:

  • 在Python2.X和Python3.X中,当一个方法通过实例被获取的时候,都会产生一个绑定方法。
  • 在Python2.X中,从一个类中获取一个方法会产生一个非绑定方法,如果不手动地传入一个实例就不能调用这个方法。
  • 在Python3.X中,从一个类中获取一个方法会产生一个简单函数,该函数在没有传入一个实例的时候也可以正常地被调用。

换句话说,Python2.X的类方法总是要求传人一个实例,不管是通过一个实例或一个类来调用它们。相反,在Python3.X中,只有当一个方法期待实例的时候,我们才需要给它传人一个实例一一一没有一个实例参数的方法可以通过类调用而不需要传人一个实例。也就是说,Python3.X允许类中的简单函数,只要它们不期待并且也不被传人一个实例参数。最终的效果是:

  • 在Python2.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.

你可能感兴趣的:(系统学习Python,Python,python,staticmethod,classmethod,静态方法,类方法,类)