面向对象的高级编程

跟着廖雪峰老师敲一敲代码


一、使用__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
测试通过!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值