当前位置: 首页 > 工具软件 > Zope > 使用案例 >

使用zope.interface深入了解Python接口

柴意智
2023-12-01

zope.interface库是一种克服Python接口设计中的歧义的方法。 让我们来看看它。

隐式接口不是zen

PythonZen足够宽松,并且自相矛盾,因此您可以从中证明一切。 让我们沉思其最著名的原则之一:“显式胜于隐式”。

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

最初,Python的答案是所谓的“鸭型”,它取自短语“如果它像鸭子一样行走,而像鸭子一样嘎嘎叫,那可能就是鸭子。” 换句话说,“尝试一下然后看”,这可能是您可能获得的最隐式的。

Zope Web框架,它迫切需要这些东西以使其变得明显,例如,“类用户对象”所期望的呈现代码。

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

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

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


   
   
def render_sprites ( render_surface , sprites ) :
    """
    sprites should be a list of objects complying with the Sprite interface:
    * An attribute "bounding_box", containing the bounding box.
    * A method called "intersects", that accepts a box and returns
      True or False
    """
    pass # some code that would actually render

游戏将具有许多处理精灵的功能。 在每个文件中,您都必须在文档字符串中指定期望的合同。

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

能够使sprite是显式且显而易见的,这样方法可以声明“我需要一个sprite”并严格定义该接口,这不是很好吗? 输入zope.interface


   
   
from zope import interface

class ISprite ( interface. Interface ) :

    bounding_box = interface. Attribute (
        "The bounding box"
    )

    def intersects ( box ) :
        "Does this intersect with a box"

乍一看,这段代码看起来有些奇怪。 这些方法不包括self ,这是一种常见的做法,它具有Attribute属性 。 这是在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 ) :
        # A box intersects a circle if and only if
        # at least one corner is inside the circle.
        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鼻子或其他测试运行程序可以运行此程序 ,它将验证所创建的sprite是否符合该接口。 测试通常是局部的:它不会测试文档中仅提及的任何内容,甚至不会测试可以无例外地调用方法! 但是,它会检查是否存在正确的方法和属性。 这是对单元测试套件的一个很好的补充,并且至少可以防止简单的拼写错误通过测试。

翻译自: https://opensource.com/article/19/9/zopeinterface-python-package

 类似资料: