一、类属性 vs 实例属性
1、访问类属性
>>> class C(object): # 定义类
version = 1.2 # 静态成员
(1) 当用实例来访问类属性时,Python会先在实例中搜索名字version,然后是类,再就是继承树中的基类。
(2) 通过类才能更新它的值
>>> c = C() # 实例化
>>> C.version # 通过类来访问
1.2
>>> c.version # 通过实例来访问
1.2
>>> C.version += 0.1 # 通过类来更新(只能这样)
>>> C.version # 类访问
1.3
>>> c.version # 实例访问它,其值已被改变
1.3
2、通过实例访问类的属性
任何对实例属性的赋值都会创建一个实例属性(如果不存在的话),并且对其赋值。
如果类属性中存在同名的属性,会产生副作用>>> c.version += 0.2 # 尝试更新类属性 等价于 c.version = C.version + 0.2
>>> c.version # 只是创建了一个新的实例属性
1.5
>>> C.version # 没有更新类属性,只是创建了一个新的实例属性
1.3
>>> del c.version # 删除实例属性
>>> c.version # 又可以访问到类属性
1.3
>>> C.version
1.3
3、在类属性可变的情况下,通过实例可以更新类属性
>>> class Foo(object):
... x = {2003: 'yes'} # 字典类型,可以修改
>>> foo = Foo() # 实例化
>>> foo.x
{2003: 'yes'}
>>> foo.x[2004] = 'no' # 通过实例修改类属性,生效
>>> foo.x
{2003: 'yes', 2004: 'no'}
>>> Foo.x # 修改生效
{2003: 'yes', 2004: 'no'}
>>> del foo.x # 没有遮蔽所以不能删除掉
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: x
二、绑定和方法调用
1、方法
(1) 方法仅仅是类内部定义的函数(是类属性,不是实例属性)
(2) 方法只有在其所属的类拥有实例时,才能被调用
(3) 任何一个方法定义中的第一个参数都是变量self,它表示调用此方法的实例对象。
2、调用绑定方法
MyClass类和实例mc,想要调用MyClass中的方法foo,只需调用mc.foo()即可。
3、调用非绑定方法
当没有实例并且需要调用一个非绑定方法时,必须传递self参数
def __init__(self, nm, ph, id, em):
AddrBookEntry.__init__(self, nm, ph) # 通过父类名来调用
self.empid = id
self.email = em
三、静态方法 vs 类成员方法
静态方法可以被类或实例访问,不能访问类变量,不能访问实例变量。
类成员方法可以被类或实例访问,可以访问类变量,不能访问实例变量。
class MyClass(object):
val1 = 'abcd' # 类属性
def __init__(self):
self.val2 = 'a1b2c3' # 实例属性
@staticmethod # 使用装饰器定义静态方法
def staticMd():
print("static method, can't access val1 and val2")
@classmethod # 使用装饰器定义类成员方法
def classMd(cls):
print("class method, class: %s, val1 = %s, can't access val1" % (str(cls), cls.val1))
>>> mc = MyClass() # 实例化
>>> mc.staticMd() # 通过实例访问静态方法
static method, can't access val1 and val2
>>> MyClass.staticMd() # 通过类访问静态方法
static method, can't access val1 and val2
>>> mc.classMd() # 通过实例访问类成员方法
class method, class: <class 'MyData.MyClass'>, val1 = abcd, can't access val1
>>> MyClass.classMd() # 通过类访问类成员方法
class method, class: <class 'MyData.MyClass'>, val1 = abcd, can't access val1
>>> mc.val1 # 实例访问类属性
'abcd'
>>> MyClass.val1 # 类访问类属性
'abcd'
>>> mc.val2 # 实例访问实例属性
'a1b2c3'
>>> MyClass.val2 # 类无法访问实例属性
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'MyClass' has no attribute 'val2'
>>> mc.val1 = "haha" # 创建了一个实例属性 val1
>>> mc.val1 # 访问实例属性 val1
'haha'
>>> MyClass.val1 # 此时类属性val1并没有改变
'abcd'
>>> MyClass.val1 = "a1b1c1" # 通过类更新类属性
>>> MyClass.val1 # 类属性已经更新
'a1b1c1'
>>> mc.val1 # 实例属性val1没有改变
'haha'
>>> del mc.val1 # 删除实例属性val1
>>> mc.val1 # 此时可以通过实例访问类属性
'a1b1c1'