Python的静态方法和类成员方法均可以被类或实例访问,二者概念不容易理清,但仍是有区别的:
1)静态方法无需传入self参数,类成员方法需传入表明本类的cls参数;
2)从第1条,静态方法是没法访问实例变量的,而类成员方法也一样没法访问实例变量,但能够访问类变量;
3)静态方法有点像函数工具库的做用,而类成员方法则更接近相似Java面向对象概念中的静态方法。
实现静态方法和类方法的两种方式
1、在Python 2.3及以前,用staticmethod和classmethod类型对象包装实现
例子以下(注意print里的说明):
class MyClass:
val1 = 'Value 1'
def __init__(self):
self.val2 = 'Value 2'
def staticmd():
print '静态方法,没法访问val1和val2'
smd = staticmethod(staticmd)
def classmd(cls):
print '类方法,类:' + str(cls) + ',val1:' + cls.val1 + ',没法访问val2的值'
cmd = classmethod(classmd)
执行:
>>> mc = MyClass()
>>> mc.smd()
>>> mc.cmd()
>>> MyClass.smd()
>>> MyClass.cmd()
2、在Python 2.4及以后,用装饰器(decorators)实现
装饰器使用@操做符,例子以下:
class MyClass:
val1 = 'Value 1'
def __init__(self):
self.val2 = 'Value 2'
@staticmethod
def staticmd():
print '静态方法,没法访问val1和val2'
@classmethod
def classmd(cls):
print '类方法,类:' + str(cls) + ',val1:' + cls.val1 + ',没法访问val2的值'
无论是以上两种方式中的哪种,执行状况都是同样的,以方式二执行结果
为例
分析以下:
执行:
>>> mc = MyClass() # 实例化
>>> mc.staticmd() # 实例调用静态方法,没法访问实例变量val1和val2
>>>
静态方法,没法访问val1和val2
>>> mc.classmd() # 实例调用类方法,注意,这里访问的是类MyClass的变量val1的值,不是实例化后mc的实例变量val1,这里容易混淆,往下看就会明白。val2一直是实例变量,因此没法访问
>>>
类方法,类:__main__.MyClass,val1:Value 1,没法访问val2的值
>>> MyClass.staticmd() # 类直接调用静态方法,结果同上面的实例调用,不管是类变量仍是实例变量都没法访问
>>>
静态方法,没法访问val1和val2
>>> MyClass.classmd() # 类直接调用类方法,结果同上面的实例调用
>>>
类方法,类:__main__.MyClass,val1:Value 1,没法访问val2的值
>>> mc.val1 = 'Value changed' # 改变实例变量val1的值
>>> mc.classmd() # 实例调用类方法,注意到cls.val1的值没变,因此,这时的cls.val1是类变量val1,而非实例变量val1
>>>
类方法,类:__main__.MyClass,val1:Value 1,没法访问val2的值
>>> MyClass.classmd() # 类直接调用类方法,结果同上面的实例调用
>>>
类方法,类:__main__.MyClass,val1:Value 1,没法访问val2的值
>>> MyClass.val1 = 'Class Value changed' # 改变类变量val1的值
>>> mc.classmd() # 实例调用类方法,注意到cls.val1的值变了,因此,进一步证实了这时的cls.val1是类变量val1,而非实例变量val1
>>>
类方法,类:__main__.MyClass,val1:Class Value changed,没法访问val2的值
>>> MyClass.classmd() # 类直接调用类方法,结果同上面的实例调用
>>>
类方法,类:__main__.MyClass,val1:Class Value changed,没法访问val2的值
结论
若是上述执行过程太复杂,记住如下两点就行了:
静态方法:没法访问类属性、实例属性,至关于一个相对独立的方法,跟类其实没什么关系,换个角度来说,其实就是放在一个类的做用域里的函数而已。
类成员方法:能够访问类属性,没法访问实例属性。上述的变量val1,在类里是类变量,在实例中又是实例变量,因此容易混淆。