http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143186739713011a09b63dcbd42cc87f907a778b3ac73000
由于Python是动态语言,根据类创建的实例可以任意绑定属性。
给实例绑定属性的方法是通过实例变量,或者通过self变量:
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
s.score = 90
但是,如果Student类本身需要绑定一个属性呢?可以直接在class中定义属性,这种属性是类属性,归Student类所有:
class Student(object):
name = 'Student'
当我们定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到。来测试一下:
>>> class Student(object):
... name = 'Student'
...
>>> s = Student() # 创建实例s
>>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
Student
>>> print(Student.name) # 打印类的name属性
Student
>>> s.name = 'Michael' # 给实例绑定name属性
>>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Michael
>>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
Student
>>> del s.name # 如果删除实例的name属性
>>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
Student
从上面的例子可以看出,在编写程序的时候,千万不要把实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。
第一,slots只能限制添加属性,不能限制通过添加方法来添加属性:
def set_city(self, city):
self.city=city
class Student(object):
slots = ('name', 'age', 'set_city')
pass
Student.set_city = MethodType(set_city, Student)
a = Student()
a.set_city(Beijing)
a.city
上段代码中,Student类限制两个属性name 和 age,但可以通过添加方法添加一个city属性(甚至可以添加很多属性,只要set_city方法里有包括)
第二,属性分实例属性和类属性,多个实例同时更改类属性,值是最后更改的一个
def set_age(self,age):
self.age=age
class Stu(object):
pass
s=Stu()
a=Stu()
from types import MethodType
Stu.set_age=MethodType(set_age,Stu)
a.set_age(15) \通过set_age方法,设置的类属性age的值
s.set_age(11) \也是设置类属性age的值,并把上个值覆盖掉
print(s.age,a.age) \由于a和s自身没有age属性,所以打印的是类属性age的值
a.age = 10 \给实例a添加一个属性age并赋值为10
s.age = 20 \给实例b添加一个属性age并赋值为20
\这两个分别是实例a和s自身的属性,仅仅是与类属性age同名,并没有任何关系
print(s.age,a.age) \打印的是a和s自身的age属性值,不是类age属性值
所以,
1,slots并不能严格限制属性的添加,可通过在方法里定义限制之外的属性来添加本不能添加的属性(当然,前提是方法没有被限制)
2,类属性是公共属性,所有实例都可以引用的,前提是实例自身没有同名的属性,因此类属性不能随意更改(别的实例可能在引用类属性的值),就是说不能随便用a.set_age()更改age的值(因为调用此方法更改的是类属性age的值,不是实例a自身的age属性值)