跟着廖雪峰老师敲一敲代码
一、使用__slots__
#正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。
#给一个实例绑定的方法,对另一个实例是不起作用的
#为了给所有实例都绑定方法,可以给class绑定方法
#限制实例的属性:
class Student(object):
pass
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
#仅对当前类实例起作用,对继承的子类是不起作用的:
class GraduateStudent(Student):
pass
s=GraduateStudent()
s.score = 9999 #子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
print(s.score)
运行结果:
9999
二、使用@property
2.1 装饰器相关知识补充
在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator),简单来说就是接受一个函数作为参数,并返回一个函数。
2.1.1 示例
#三层嵌套
import functools
def log(text):
def decorator(func):
@functools.wraps(func)#把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')#相当于执行now = log('execute')(now)
def now():
print('2015-3-25')
now()
print(now.__name__)
运行结果:
execute now():
2015-3-25
now
2.1.2 练习
请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:
代码如下(示例):
import time,functools
def metric(fn):
@functools.wraps(fn)
def wrapper(*args,**kw):
btime = time.time()
res = fn(*args,**kw)
print('%s executed in %s ms' % (fn.__name__, (time.time()-btime)*1000))
return res
return wrapper
@metric
def fast(x, y):
time.sleep(0.0012)
return x + y;
@metric
def slow(x, y, z):
time.sleep(0.1234)
return x * y * z;
f = fast(11, 22)
s = slow(11, 22, 33)
if f != 33:
print('测试失败!')
elif s != 7986:
print('测试失败!')
运行结果:
fast executed in 12.375831604003906 ms
slow executed in 124.66216087341309 ms
2.2 OOP的装饰模式
#既能检查参数,又可以用类似属性这样简单的方式来访问类的变量
# Python内置的@property装饰器就是负责把一个方法变成属性调用的
class Student(object):
@property
def score(self):
return self._score #属性的方法名不要和实例变量重名
@score.setter #@property本身又创建了另一个装饰器@score.setter,负责把一个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
s1 = Student()
s1.score = 60 #实际转化为s.set_score(60)
print(s1.score) #实际转化为s.get_score()
s2 = Student()
s2.score = 110
print(s2.score)
s3 = Student()
s3.score = 70.2
print(s3.score)
运行结果
60
Traceback (most recent call last):
File "D:/py/面向对象编程/使用@property.py", line 90, in <module>
s2.score = 110
File "D:/py/面向对象编程/使用@property.py", line 83, in score
raise ValueError('score must between 0 ~ 100!')
ValueError: score must between 0 ~ 100!
File "D:/py/面向对象编程/使用@property.py", line 91, in <module>
s3.score = 70.2
File "D:/py/面向对象编程/使用@property.py", line 81, in score
raise ValueError('score must be an integer!')
ValueError: score must be an integer!
2.3 练习
请利用@property给一个Screen对象加上width和height属性,以及一个只读属性resolution:
class Screen(object):
@property
def width(self):
return self._width
@property
def height(self):
return self._height
@width.setter
def width(self,value):
self._width = value
@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
测试通过!