返回介绍

跟踪对象接口

发布于 2024-01-29 22:24:14 字数 2630 浏览 0 评论 0 收藏 0

前面小节的单体示例使用类装饰器来管理一个类的所有实例。类装饰器的另一个常用场景是每个产生实例的接口。类装饰器基本上可以在实例上安装一个包装器逻辑层,来以某种方式管理对其接口的访问。

例如,在第30章中,__getattr__运算符重载方法作为包装嵌入的实例的整个对象接口的一种方法,以便实现委托编码模式。我们在前一章介绍的管理的属性中看到过类似的例子。还记得吧,当获取未定义的属性名的时候,__getattr__会运行;我们可以使用这个钩子来拦截一个控制器类中的方法调用,并将它们传递给一个嵌入的对象。

为了便于参考,这里给出最初的非装饰器委托示例,它在两个内置类型对象上工作:

在这段代码中,Wrapper类拦截了对任何包装的对象的属性的访问,打印出一条跟踪信息,并且使用内置函数getattr来终止对包装对象的请求。它特别跟踪包装的对象的类之外发出的属性访问。在包装的对象内部访问其方法不会被捕获,并且会按照设计正常运行。这种整体接口模型和函数装饰器的行为不同,装饰器只包装一个特定的方法。

类装饰器为编写这种__getattr__技术来包装一个完整接口提供了一个替代的、方便的方法。例如,在Python 2.6和Python 3.0中,前面的类示例可能编写为一个类装饰器,来触发包装的实例创建,而不是把一个预产生的实例传递到包装器的构造函数中(在这里也用**kargs扩展了,以支持关键字参数,并且统计进行访问的次数):

这里与我们前面在“编写函数装饰器”一节中遇到的跟踪器装饰器有很大不同,注意到这点很重要,在那里,我们看到了装饰器可以使我们跟踪和计时对一个给定函数或方法的调用。相反,通过拦截实例创建调用,这里的类装饰器允许我们跟踪整个对象接口,例如,对其任何属性的访问。

下面是这段代码在Python 2.6和Python 3.0下的输出:Spam和Person类的实例上的属性获取都会调用Wrapper类中的__getattr__逻辑,由于food和bob确实都是Wrapper的实例,得益于装饰器的实例创建调用重定向:

注意,前面的代码装饰了一个用户定义的类。就像是在本书第30章最初的例子中一样,我们也可以使用装饰器来包装一个内置的类型,例如列表,只要我们的子类允许装饰器语法,或者手动地执行装饰——装饰器语法对于@行需要一条class语句。

在下面的代码中,由于装饰的间接作用,x实际是一个Wrapper(我把装饰器类放到了模块文件tracer.py中,以便以这种方式重用它):

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

假设你将会产生类的多个实例,装饰器通常将会在代码大小和代码可维护性上双赢。

注意:属性版本差异:正如我们在本书第37章所了解到的,在Python 2.6中,__getattr__将会拦截对__str__和__repr__这样的运算符重载方法的访问,但是,在Python 3.0中不会这样。

在Python 3.0中,类实例会从类中继承这些方法中的一些(而不是全部)的默认形式(实际上,是从自动对象超类),因为所有的类都是“新式的”。此外,在Python 3.0中,针对打印和+这样的内置操作显式地调用属性并不会通过__getattr__(或其近亲__getattribute__)路由。新式类在类中查找这样的方法,并且完全省略常规的实例查找。

此处意味着,在Python 2.6中,基于__getattr__的跟踪包装器将会自动跟踪和传递运算符重载,但是,在Python 3.0中不会如此。要看到这一点,直接在交互式会话的前面的末尾显示"x",在Python 2.6中,属性__repr__被跟踪并且该列表如预期的那样打印出来,但是在Python 3.0中,不会发生跟踪并且列表打印为Wrapper类使用一个默认显示:

要在Python 3.0中同样工作,运算符重载方法通常需要在包装类中冗余地重新定义,要么手动定义,要么通过工具定义,或者通过在超类中定义。只有简单命名的属性会在两种版本中都同样工作。我们将在本章稍后的一个Private装饰器中再次看到版本差异的作用。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文