python 类中的方法
首先,方法是类内部定义的函数,所以方法是类的属性而不是实例的属性。
其次,方法只能在所属的类拥有实例的时候才能被调用。当存在一个实例的时候,我们可以说方法被绑定到实例。如果没有实例,那么我们就说方法是未绑定的。
最后,任何一个方法定义的第一个参数都是self。self是调用此方法的实例。
再强调一下绑定与未绑定。不管绑定与否。方法的代码都是一样的,区别只是是否存在一个实例来调用这个方法。
ok。我们用例子来理解一下上面的话。首先是第一句。
>>> class A: ... def foo(self): ... print 'foo running' ... >>> >>> a=A() >>> a.attr1=1 >>> a.attr2=2 >>> >>> a.__dict__ {'attr2': 2, 'attr1': 1} >>> A.__dict__ {'__module__': '__main__', 'foo': <function foo at 0x7f4456f5bb90>, '__doc__': None}
我们创建一个类A,其有一个函数foo。 我们实例化类A并赋给变量a。 然后看变量a的属性有 attr1,attr2。但是并没有foo函数。 而A的属性里面有函数foo。所以符合第一句话,foo是类的属性不是实例的属性。
其次是第二句,只有类在拥有实例的时候才可以调用方法。否则是未绑定的。
>>> A.foo() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method foo() must be called with A instance as first argument (got nothing instead) >>> A().foo() foo running >>>
看到A直接调用foo出错。 但是实例化后就可以调用。 不过我们再看一个例子。这就是一个未绑定调用的例子。
>>> class addrEntry: ... def __init__(self,nm,ph): ... self.name=nm ... self.phone=ph ... >>> class EmpAddrEntry(addrEntry): ... def __init__(self,nm,ph,email): ... addrEntry.__init__(self,nm,ph) ... self.email=email ...
这个例子中,EmpAddrEntry以addrEntry为base class。在定义自己的 __init__的时候调用了父类的__init__但是这时候父类还没有 实例,所以这就是一个未绑定调用。 未绑定调用会出错是因为函数一般要求一个类的实例作为第一个参数。如果没有就会出错。这里是把子类的实例传递进来,所以没有报错。 不过调用仍然是用类直接调用的。所以是未绑定调用。 下面又是一个例子,虽然是未绑定调用,但是仍然会执行。
>>> class A: ... def foo(self): ... print 'foo running' ... >>> a=A() >>> a.foo() foo running >>> >>> A.foo() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method foo() must be called with A instance as first argument (got nothing instead) >>> A.foo(a) foo running
最后, 第三句就不用解释了吧。 不过也有函数的第一个方法不是 self。 比如 __new__ 。这是因为 __new__ 是python 新类中的特性。 python 在2.2版本的时候对类做了调整。上面的内容是旧式类的特性。 新式类中有下面两个概念。 静态方法和类方法。 下面我们了解一下这两个概念:
首先我们看一下创建静态方法和类方法的例子:
>>> class TestStaticMethod: ... def foo(): ... print 'calling static method foo()' ... foo = staticmethod(foo) ... >>> class TestClassMethod: ... def foo(cls): ... print 'calling class method foo()' ... print 'foo() is part of class:', cls.__name__ ... foo = classmethod(foo) ...
注意这里面用到了两个内建函数 staticmethod() 和 classmethod()。 这两个函数会把对应的方法转化成静态函数和类函数。 否则的话,你在调用的时候,系统会认为他们是普通的方法,会报没有self的错误。