借助 zope.interface 深入了解 Python 接口
创始人
2024-03-02 04:22:07
0

Zope.interface 可以帮助声明存在哪些接口,是由哪些对象提供的,以及如何查询这些信息。

Snake charmer cartoon with a yellow snake and a blue snake

zope.interface 库可以克服 Python 接口设计中的歧义性。让我们来研究一下。

隐式接口不是 Python 之禅

Python 之禅 很宽松,但是有点自相矛盾,以至于你可以用它来例证任何东西。让我们来思考其中最著名的原则之一:“显示胜于隐式”。

传统上,在 Python 中会隐含的一件事是预期的接口。比如函数已经记录了它期望一个“类文件对象”或“序列”。但是什么是类文件对象呢?它支持 .writelines吗?.seek 呢?什么是一个“序列”?是否支持步进切片,例如 a[1:10:2]

最初,Python 的答案是所谓的“鸭子类型”,取自短语“如果它像鸭子一样行走,像鸭子一样嘎嘎叫,那么它可能就是鸭子”。换句话说,“试试看”,这可能是你能得到的最具隐式的表达。

为了使这些内容显式地表达出来,你需要一种方法来表达期望的接口。Zope Web 框架是最早用 Python 编写的大型系统之一,它迫切需要这些东西来使代码明确呈现出来,例如,期望从“类似用户的对象”获得什么。

zope.interface 由 Zope 开发,但作为单独的 Python 包发布。Zope.interface 可以帮助声明存在哪些接口,是由哪些对象提供的,以及如何查询这些信息。

想象编写一个简单的 2D 游戏,它需要各种东西来支持精灵界面(LCTT 译注:“ 精灵 Sprite ”是指游戏面板中各个组件)。例如,表示一个边界框,但也要表示对象何时与一个框相交。与一些其他语言不同,在 Python 中,将属性访问作为公共接口一部分是一种常见的做法,而不是实现 getter 和 setter。边界框应该是一个属性,而不是一个方法。

呈现精灵列表的方法可能类似于:

def render_sprites(render_surface, sprites):
    """
    sprites 应该是符合 Sprite 接口的对象列表:
    * 一个名为 "bounding_box" 的属性,包含了边界框
    * 一个名为 "intersects" 的方法,它接受一个边界框并返回 True 或 False
    """
    pass # 一些做实际渲染的代码

该游戏将具有许多处理精灵的函数。在每个函数中,你都必须在随附文档中指定预期。

此外,某些函数可能期望使用更复杂的精灵对象,例如具有 Z 序的对象。我们必须跟踪哪些方法需要 Sprite 对象,哪些方法需要 SpriteWithZ 对象。

如果能够使精灵是显式而直观的,这样方法就可以声明“我需要一个精灵”,并有个严格定义的接口,这不是很好吗?来看看 zope.interface

from zope import interface

class ISprite(interface.Interface):

    bounding_box = interface.Attribute(
        "边界框"
    )

    def intersects(box):
        "它和一个框相交吗?"

乍看起来,这段代码有点奇怪。这些方法不包括 self,而包含 self 是一种常见的做法,并且它有一个属性。这是在 zope.interface 中声明接口的方法。这看起来很奇怪,因为大多数人不习惯严格声明接口。

这样做的原因是接口显示了如何调用方法,而不是如何定义方法。因为接口不是超类,所以它们可以用来声明数据属性。

下面是一个能带有圆形精灵的接口的一个实现:

@implementer(ISprite)
@attr.s(auto_attribs=True)
class CircleSprite:
    x: float
    y: float
    radius: float

    @property
    def bounding_box(self):
        return (
            self.x - self.radius,
            self.y - self.radius,
            self.x + self.radius,
            self.y + self.radius,
        )

    def intersects(self, box):
        # 当且仅当至少一个角在圆内时,方框与圆相交
        top_left, bottom_right = box[:2], box[2:]
        for choose_x_from (top_left, bottom_right):
            for choose_y_from (top_left, bottom_right):
                x = choose_x_from[0]
                y = choose_y_from[1]
                if (((x - self.x) ` 2 + (y - self.y) ` 2) <=
                    self.radius ` 2):
                     return True
        return False

显式声明了实现了该接口的 CircleSprite 类。它甚至能让我们验证该类是否正确实现了接口:

from zope.interface import verify

def test_implementation():
    sprite = CircleSprite(x=0, y=0, radius=1)
    verify.verifyObject(ISprite, sprite)

这可以由 pytest、nose 或其他测试框架运行,它将验证创建的精灵是否符合接口。测试通常是局部的:它不会测试仅在文档中提及的内容,甚至不会测试方法是否可以在没有异常的情况下被调用!但是,它会检查是否存在正确的方法和属性。这是对单元测试套件一个很好的补充,至少可以防止简单的拼写错误通过测试。


via: https://opensource.com/article/19/9/zopeinterface-python-package

作者:Moshe Zadka 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

相关内容

AI+Python数据分析...
教学大纲 01 课程性质和目的 数据分析与可视化为数据科学与大数据...
2026-05-06 20:23:25
什么是miniQMT,相比...
什么是miniQMT,相比大QMT有什么特点? 迅投 miniQM...
2026-01-22 09:51:16
Java、Python等开...
IT之家 9 月 24 日消息,开源安全基金会(OpenSSF)昨...
2025-09-24 14:25:34
python基础语法【迭代...
1.迭代器 1.什么是迭代器(iter)...
2025-06-01 20:30:55
手把手教你使用Flask框...
目录前言0、Flask框架的详细介绍一、Flask 框架封装接口1...
2025-06-01 17:11:00
【练习题】python函数...
写一个匿名函数,判断指定的年是否是闰年 (先直接用普...
2025-06-01 15:13:03

热门资讯

“Linux 中国” 开源社区... 这是一个艰难的决定 —— 这不是调侃,而是当你真正做出改变了你十几年生活轨迹的决定时,你就会明白这个...
硬核观察 #1263 德国铁路... #1 德国铁路公司招聘 Windows for Workgroups 3.11 管理员该职位要求了解...
人工智能教程(七):Sciki... 在本系列的 上一篇文章 中,我们用 TensorFlow 构建了第一个神经网络,然后还通过 Kera...
关闭 WSL 中正在运行的 L... 以下是使用 WSL 关闭在 Windows 内运行的 Linux 系统的不同方法。你使用 WSL 在...
MX Linux 23.2 “... 最新的 MX Linux 23.2 小版本更新带来了基本的改进和新增功能。MX Linux 推出了 ...
硬核观察 #1262 网络上最... #1 网络上最古老的软件存档库之一即将关闭美国新墨西哥州立大学(NMSU)最近宣布,即将于 2024...
如何在 RHEL 上通过绑定配... 在 Linux 中,你可以根据自己的需要创建高级网络设置,如 网络绑定 Network Bondin...
Linux Matrix 消息... Matrix 用户可以升级 Fractal 6 了!Fractal 是目前 最好的 Matrix 客...
如何通过 VLC 使用字幕 使用 VLC 媒体播放器播放和管理字幕的新手指南。我是一个超级动漫迷,如果你想观看最新的剧集,那么你...
硬核观察 #1261 X 计划... #1 X 计划在奥斯汀建立内容审核总部据报道,该部门将招聘 100 名全职员工,将主要关注 CSE ...