@yanglt7
2018-12-03T07:28:54.000000Z
字数 2923
阅读 619
Python
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
s.score = 90
>>> 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
class Student(object):
pass
>>> s = Student()
>>> s.name = 'Michael' # 动态给实例绑定一个属性
>>> print(s.name)
Michael
>>> def set_age(self, age): # 定义一个函数作为实例方法
... self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25
>>> s2 = Student() # 创建新的实例
>>> s2.set_age(25) # 尝试调用方法
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'set_age'
>>> def set_score(self, score):
... self.score = score
...
>>> Student.set_score = set_score
>>> s.set_score(100)
>>> s.score
100
>>> s2.set_score(99)
>>> s2.score
99
限制实例的属性:
class Student(object):
__slots__ = ('name', 'age') # 用 tuple 定义允许绑定的属性名称
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性 'name'
>>> s.age = 25 # 绑定属性 'age'
>>> s.score = 99 # 绑定属性 'score'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
使用 __slots__ 要注意,__slots__ 定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:
>>> class GraduateStudent(Student):
... pass
...
>>> g = GraduateStudent()
>>> g.score = 9999
除非在子类中也定义 __slots__,这样,子类实例允许定义的属性就是自身的 __slots__ 加上父类的 __slots__。
Python 内置的 @property 装饰器就是负责把一个方法变成属性调用的:
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self,value):
if not isinstance(value,int):
raise ValueError('score must be an integer!')
if value<0 or value>100:
raise ValueError('score must between 0~100!')
self._score=value
把一个 getter 方法变成属性,只需要加上 @property 就可以了,此时,@property 本身又创建了另一个装饰器 @score.setter,负责把一个 setter 方法变成属性赋值,于是,我们就拥有一个可控的属性操作:
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
还可以定义只读属性,只定义 getter 方法,不定义 setter 方法就是一个只读属性:
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self,value):
self._birth=value
@property
def age(self):
return 2015-self._birth
>>> s=Student()
>>> s.birth=1998
>>> s.birth
1998
>>> s.age
17
利用 @property 给一个 Screen 对象加上 width 和 height 属性,以及一个只读属性 resolution:
>>> class Screen(object):
... @property
... def width(self):
... return self._width
... @width.setter
... def width(self,value):
... self._width=value
... @property
... def height(self):
... return self._height
... @height.setter
... def height(self,value):
... self._height=value
... @property
... def resolution(self):
... return self._width*self._height
...
>>> s=Screen()
>>> s.width=1024
>>> s.height=768
>>> s.resolution
786432