返回介绍

重访基于委托的 Manager

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

第27章的面向对象教程展示了一个Manager类,它使用对象嵌套和方法委托来定制它的超类,而不是使用继承。这里再次引用那段代码,删除了一些不相关的测试:

这个文件末尾的注释展示了对于一行的操作调用哪个方法。特别是,注意lastName调用如何在Manager中是未定义的,并由此指向通用的__getattr__,又从那里到了嵌入的Person对象。如下是这段脚本的输出——Sue从Person那里接收了10%的加薪,但Tom得到了20%的加薪,因为giveRaise在Manager中定制了:

相反,注意当我们在这段脚本末尾打印Manager的时候发生了什么:调用了包装类的__str__,并且它委托到嵌入的Person对象的__str__。记住这一点,看看如果我们在代码中删除了Manager.__str__方法,将会发生什么事情:

现在,在Python 3.0下,针对Manager对象,打印不会通过通用的__getattr__拦截器指向其属性获取。相反,继承自类的隐式object超类的一个默认__str__显示方法,被查找到并运行(sue仍然正确地打印,因为Person有一个显式的__str__):

奇怪的是,像这样没有一个__str__运行,在Python 2.6中却会触发__getattr__,因为操作符重载属性通过这个方法指向,并且类不会为__str__继承一个默认版本:

切换到__getattribute__在这里也不会对Python 3.0有所帮助——像__getattr__一样,对于Python 2.6和Python 3.0中内置操作所暗示的操作符重载属性,它都不会运行:

不管在Python 3.0中使用哪个属性拦截方法,我们仍然必须在Manager中包含一个重新定义的__str__(如上面所示),以便拦截打印操作并将它们指向嵌入的Person对象:

注意,__getattribute__针对方法获得两次调用——一次针对方法名,另一次针对self.person嵌入对象获取。我们可以用一种不同的编码方式来避免如此,但是,我们仍然必须重定义__str__以捕获打印,尽管这里有所不同(self.person将导致__getattribute__失效):

运行这一替代方案的时候,我们的对象正确地打印了,但是只是因为我们已经在包装类中添加了一个显式的__str__——这个属性仍然没有指向通用的属性拦截方法:

这里简单介绍了像Manager这样的基于委托的类,在Python 3.0中必须重定义某些操作符重载方法(例如__str__)才能将它们指向嵌套的对象,但是,在Python 2.6中不必,除非使用了新式类。我们唯一的直接选择似乎是使用__getattr__和Python 2.6,或者在Python 3.0中在包装类中冗余地重定义操作符重载方法。

再一次说明,这不是一个不可能的任务。很多包装类可以预计所需的操作符重载方法的集合,并且工具和超类可以将这个任务的一部分自动化。此外,并非所有的类都使用操作符重载方法(实际上,大多数应用程序类通常不会使用)。然而,对于在Python 3.0中使用的委托编码模式,需要记住一些事情。当操作符重载方法是一个对象的接口的一部分时,包装类必须通过在本地重新定义它们来容纳它们。

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

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

发布评论

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