分类目录:《系统学习Python》总目录

还要注意前面的代码装饰了一个用户定义的类,我们也可以使用装饰器包装一个像列表这样的内置类型,只要我们通过子类化来允许装饰器语法,或者手动地执行装饰一一装饰器语法要求每一@行都有一条class语句。在下面的代码中,由于装饰的间接作用,x实际又是一个Wrapper:

def Tracer(aClass):

class Wrapper:

def __init__(self, *args, **kwargs):

self.fetches = 0

self.wrapped = aClass(*args, **kwargs)

def __getattr__(self, attrname):

print('Trace:' + attrname)

self.fetches += 1

return getattr(self.wrapped, attrname)

return Wrapper

输入:

@Tracer

class MyList(list):

pass

x = MyList([1, 2, 3])

x.append(4)

输出:

Trace:append

输入:

x.wrapped

输出:

[1, 2, 3, 4]

这种装饰器方法允许我们把实例创建移动到装饰器自身之中,而不是要求传入一个预先生成的对象。尽管这好像是一个细小的差别,但它允许我们保留常规的实例创建语法,并且通常实现装饰器的所有优点。我们只需要用装饰器语法来扩展类定义,而不是要求所有的实例创建调用都通过一个包装器来手动地指向对象:

bob = Person('Bob', 40, 10)

sue = Person('Sue', 50, 15)

bob = Wrapper(Person('Bob', 40, 10))

sue = Wrapper(Person('Sue', 50, 15))

假设我们将会产生类的多个实例,并且想要扩增类的每一个实例,装饰器通常将会在代码大小和代码可维护性上取得双赢。

属性版本差异提示:前面的跟踪者装饰器在所有的Python版本上都对显式访问的属性名称起作用。在python2.X的默认经典类中,__getattr__会拦截内置函数对__str__和__repr__这样的运算符重载方 法的隐式访问,但是在Python3.X的新式类中不会拦截。在Python3.X的类中,类实例会从类中继承这些方法中的一些,而不是继承全部的默认形式(实际上,是从object父类中继承)。此外,在Python3.X中,针对打印和+这样的内置操作隐式地调用属性并不会通过__getattr__或其姊妹__getattribute__来发送。在新式类中,内置函数在类上开始这样的搜索,并且完全省略常规的实例查找。

此处意味着,对于像这样在Python2.X中编写的内置咱数,基于__getattr__的跟踪包装器将会自动跟踪和传播运算符重载调用,但是在Python3.X中不会如此。要看到这一点,直接在前面的交互式会话的末尾显示x一一一在Python2.X中,属性__repr__被跟踪并且该列表如预期的那样打印出来,但是在Python3.X中,不会发生跟踪并且列表打印为Wrapper类使用一个默认显示。要在Python3.X中同样工作,运算符重载方法通常必须在包装类中冗余地重新定义,要么手动定义,要么通过工具定义,或者通过在父类中定义。我们将在本章稍后的一个Private`装饰器中再次看到该方法的作用一一一那里我们还将学习在Python3.X中添加这样的代码所需要的方法的途径。

参考文献: [1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.

文章来源

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。