Python面向对象高级特性
给实例绑定属性或者方法
给实例绑定一个参数
class Student:
pass
s = Student()
s.name = 'Michael'
print(s.name)
Michael
给实例绑定一个方法
def set_age(self, age):
self.age = age
set_age(s, 25)
print(s.age) # 25
from types import MethodType
s.set_age = MethodType(set_age, s)
s.set_age(26)
print(s.age) # 26
25
26
给一个实例绑定方法,对另一个实例不起作用。
为了给所有实例绑定方法,给class绑定方法,直接绑定即可,不需要调用MethodType
.
动态绑定允许我们在程序运行的过程中给class加上功能,这在静态语言中很难实现
def set_score(self, score):
self.score = score
Student.set_score = set_score
s.set_score(100)
print(s.score) # 100
s2 = Student()
s2.set_score(90)
print(s2.score) # 90
100
90
使用 __slots__
定义一个特殊的__slots__
变量,限制该class能添加的属性
class Student2:
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
s2 = Student2()
s2.name = 'Fan'
s2.age = 25
s2.score = 100 # 绑定属性'score'出错
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-25-173421d01b95> in <module>
5 s2.name = 'Fan'
6 s2.age = 25
----> 7 s2.score = 100 # 绑定属性'score'出错
AttributeError: 'Student2' object has no attribute 'score'
__slot__
仅对当前实例起作用,对继承的子类不起作用
class GraduateStudent(Student2):
pass
g = GraduateStudent()
g.score = 88
print(g.score)
88
使用@property
在给实例设置属性时,想要加入检查参数的功能,可以在setter
和getter
方法中加入参数检查。
有没有一种既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?
Python内置的@property装饰器负责把一个方法变成属性调用的:
class Student3:
@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
方法变成给属性赋值。
s3 = Student3()
s3.score = 60
print(s.score) # ok, output: 60
s3.score = 999 # error
100
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-32-2abed7221698> in <module>
2 s3.score = 60
3 print(s.score) # ok, output: 60
----> 4 s3.score = 999 # error
<ipython-input-29-a430806470af> in score(self, value)
10 raise ValueError('score must be an integer!')
11 if value < 0 or value > 100:
---> 12 raise ValueError('score must between 0 ~ 100!')
13 self._score = value
ValueError: score must between 0 ~ 100!
如果只定义getter方法,不定义setter方法,这样就可以定义一个只读属性
class Student4:
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2020 - self._birth
s4 = Student4()
s4.birth = 1994
print(s4.age)
26
练习:请利用@property
给一个Screen
对象加上width
和height
属性,以及一个只读属性resolution
:
class Screen:
@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
print('resolution =', s.resolution)
if s.resolution == 786432:
print('测试通过!')
else:
print('测试失败!')
resolution = 786432
测试通过!