绑定和方法调用
现在我们需要再次阐述Python中绑定(binding)的概念,它主要与方法调用相关联。
方法是类内部定义的函数,这意味着方法是类属性而不是实例属性。
其次,方法只有在其所属的类拥有实例时,才能被调用。当存在一个实例时,方法才被认为是绑定到那个实例了,没有实例时,方法就是未绑定的。
任何一个方法定义中都有一个参数是变量self。它表示调用此方法的实例对象。
核心笔记:
self变量用于在类实例方法中引用方法所绑定的实例。方法的实例在任何方法调用中总是作为第一参数传递的,self代表方法的实例。你必须在方法声明中放上self,如果你的方法中没有用到self,那么考虑创建一个常规函数,除非有特殊的原因。毕竟,方法代码中没有使用实例,没有与类关联其功能,这使它看起来像一个常规函数。
调用绑定方法
一个实例可以调用绑定的方法,调用时,不需要明确地传入self了,只需要传入其他参数,这是因为我们遵循了声明时self必须作为第一参数的一个报酬。
调用非绑定方法
调用非绑定方法并不经常用到。这种方法的主要场景是:你在派生一个子类,而且你要覆盖父类的方法,这是你需要调用那个父类中想要覆盖掉的构造方法。
class EmplAddrBookEntry(AddrBookEntry): 'Employee Address Book Entry Class' def __init__ (self, nm, ph, ph) AddrBookEntry.__init__(self, nm, ph) self.empid = id self.email = em
我们重构了子类的构造器,但想尽可能多地重用代码而不是复制粘贴代码,所以调用了父类的构造器。
当一个EmplAddrBookEntry被实例化后,调用__init__(),虽然我们没有AddrBookEntry的实例,但依然可以调用这样的方法。
这就是调用非绑定方法的最佳地方了。我们在子类构造器中调用父类构造器并且明确地传递父类构造器所需要的self参数。子类中__init__()的第一行就是对父类__init__()的调用。我们通过父类名来调用它,一旦调用返回,我们再定义那些仅在子类中使用的定制。
静态方法和类方法
静态方法仅是类中的函数(不需要实例),通常的方法需要一个实例(self)作为第一个参数,对于绑定的方法调用来说,self是自动传递给这个方法的。而对于类方法而言,需要类而不是实例作为第一个参数,它是由解释器传给方法,类不需要特别地命名,类似self,不过很多人使用cls作为变量名字。
staticmethod()和classmethod()内建函数
我们来创建一下静态方法和类方法:
>>> class TestStaticMethod(object): def foo(): print 'calling static method foo()' >>> >>> a = TestStaticMethod() >>> a.foo() Traceback (most recent call last): File "<pyshell#15>", line 1, in <module> a.foo() TypeError: foo() takes no arguments (1 given)
当我们调用这个方法时,解释器出现错误,显示需要带self的常规方法声明。那应该如何做呢?
>>> class TestStaticMethod: def foo(): print 'calling static method foo()' foo = staticmethod(foo) >>> a = TestStaticMethod() >>> a.foo() calling static method foo() >>> TestStaticMethod.foo() calling static method foo()
我们用了staticmethod()内建函数,就能正常通过类或者实例访问这个方法。
同理,类方法需要这样定义:
>>> class TestClassMethod(object): def foo(cls): print 'calling class method foo()' print 'foo() is part of class:', cls.__name__ foo = classmethod(foo) >>> TestClassMethod.foo() calling class method foo() foo() is part of class: TestClassMethod >>> b = TestClassMethod() >>> b.foo() calling class method foo() foo() is part of class: TestClassMethod
这里用了cls作为类方法的第一个参数,当然这不是必须的。
使用函数修饰符
看到像foo=staticmethod(foo)这样的无意义的语法会让人心烦。它只是临时的,有待社区对这些语义进行处理。
我们可以把函数修饰符用到这个函数对象上,用它来整理语法。如上面的,我们可以使用这样写防止重新赋值:
class TestStaticMethod(object): @staticmethod def foo(): print 'calling static method foo()' class TestClassMethod(object): @classmethod def foo(cls): print 'calling class method foo()' print 'foo() is part of class:', cls.__name__