凭借zope.interface深入了解Python接口
Moshe Zadka   Linux中华   2020-01-06

凭借zope.interface深入了解Python接口

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

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。边界框应该是一番属性,而不是一番艺术。

呈现精灵列表的主意可能类似于:

     
  1. def render_sprites(render_surface, sprites):
  2.     """
  3.     sprites 有道是是符合 Sprite 接口的目标列表:
  4.     * 一度名为 "bounding_box" 的习性,包含了鄂框
  5.     * 一度名为 "intersects" 的主意,他接受一个边界框并返回 True 或 False
  6.     """
  7.     pass # 一部分做具体渲染的编码

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

另外,少数函数可能期望使用更复杂的灵敏对象,例如具有 Z 先后的目标。咱们必须跟踪哪些方法需要 Sprite 目标,哪些方法需要 SpriteWithZ 目标。

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

     
  1. from zope import interface
  2.  
  3. class ISprite(interface.Interface):
  4.  
  5.     bounding_box = interface.Attribute(
  6.         "边界框"
  7.     )
  8.  
  9.     def intersects(box):
  10.         "他和一个框相交吗?"

乍看起来,这段代码有点奇怪。该署办法不包括 self,而包含 self 是一种普遍的作法,并且它有一度属性。这是在 zope.interface 官方声明接口的主意。这看起来很奇怪,因为大多数人口不习惯严格声明接口。

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

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

     
  1. @implementer(ISprite)
  2. @attr.s(auto_attribs=True)
  3. class CircleSprite:
  4.     x: float
  5.     y: float
  6.     radius: float
  7.  
  8.     @property
  9.     def bounding_box(self):
  10.         return (
  11.             self.x - self.radius,
  12.             self.y - self.radius,
  13.             self.x + self.radius,
  14.             self.y + self.radius,
  15.         )
  16.  
  17.     def intersects(self, box):
  18.         # 顶且仅当至少一个天在圆内时,方框与圆相交
  19.         top_left, bottom_right = box[:2], box[2:]
  20.         for choose_x_from (top_left, bottom_right):
  21.             for choose_y_from (top_left, bottom_right):
  22.                 x = choose_x_from[0]
  23.                 y = choose_y_from[1]
  24.                 if (((x - self.x) ` 2 + (y - self.y) ` 2) <=
  25.                     self.radius ` 2):
  26.                      return True
  27.         return False

显式声明了贯彻了该接口的 CircleSprite 类。他甚至能让咱检验该类是否正确贯彻了接口:

     
  1. from zope.interface import verify
  2.  
  3. def test_implementation():
  4.     sprite = CircleSprite(x=0, y=0, radius=1)
  5.     verify.verifyObject(ISprite, sprite)

这可以由 pytest、nose 或其它测试框架运行,他将验证创建的灵敏是否符合接口。高考通常是部分的:他不会测试仅在文档中提出之情节,甚至不会测试方法是否可以在没有特殊的情况下被调用!但是,他会检查是否存在正确的主意和总体性。这是对单元测试套件一个很好的补给,至少可以防止简单的拼写错误通过测试。 

【义务编辑: 庞桂玉 TEL:(010)68476606】

 

分享到朋友圈 分享到微博
  • Python
  • zope.interface
  • 编程语言
  • 相关推荐

    开源项目的称谓背下都有哪些故事?

    2020-01-30 14:38:41

    你可能不知晓的 Python 技术

    2020-01-29 19:40:36

    关于Python列表操作,比起广泛的10个问题

    2020-01-29 19:13:25

    Copyright © 2005-2020 51CTO.COM 必发娱乐登入
    情节话题
    必发娱乐登入 移步 传感器 系统 安全 网络 必发娱乐登录 虚拟化 付出
    热门产品
    51CTO必发娱乐登录 51CTO高招 移步开发者服务联盟网+ 51CTO博客 WOT碰头会
    <nav id="26081864"></nav>


    
       
        
       
       
       
  •