当前位置: 首页 > 科技观察

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

时间:2023-03-14 11:22:08 科技观察

Zope.interface可以帮助声明存在哪些接口,哪些对象提供它们,以及如何查询这些信息。zope.interface库克服了Python界面设计中的歧义。让我们调查一下。隐式接口不是Python的禅宗Python的禅宗是如此松散,但又如此自相矛盾,以至于您可以使用它来实例化任何东西。让我们考虑其中最著名的原则之一:“显式优于隐式”。传统上在Python中隐含的一件事是预期的接口。例如,该函数已记录它需要一个“类文件对象”或“序列”。但是什么是类文件对象呢?它支持.writelines吗?.seek呢?什么是“序列”?是否支持步进切片,比如a[1:10:2]?最初,Python的回答是所谓的“鸭子打字”,取自“如果它走路像鸭子,叫声像鸭子,那么它可能是鸭子”这句话。换句话说,“试一试”可能是你能得到的最含蓄的表达方式。为了明确这一点,您需要一种表达所需接口的方法。Zope网络框架是最早用Python编写的大型系统之一,它迫切需要这些东西来使代码明确,例如,对“类似用户的对象”有什么期望。zope.interface由Zope开发,但作为单独的Python包分发。Zope.interface可以帮助声明哪些接口存在,哪些对象提供它们,以及如何查询这些信息。想象写一个简单的2D游戏,需要各种东西来支持sprite界面(LCTT译注:“Sprite”指的是游戏面板中的各种组件)。例如,表示边界框,也表示对象何时与框相交。与其他一些语言不同,在Python中,通常的做法是将属性访问作为公共接口的一部分,而不是实现getter和setter。边界框应该是一个属性,而不是一个方法。渲染sprite列表的方法可能类似于:defrender_sprites(render_surface,sprites):"""sprites应该是符合Sprite接口的对象列表:*包含边界框的名为“bounding_box”的属性*属性称为“intersects”方法,它接受一个边界框并返回True或False"""pass#一些执行实际渲染的代码游戏将有很多处理精灵的函数。在每个函数中,您必须在随附的文档中指定期望值。此外,某些功能可能需要更复杂的精灵对象,例如具有Z顺序的精灵对象。我们必须跟踪哪些方法需要Sprite对象,哪些方法需要SpriteWithZ对象。能够使sprite明确和直观,以便方法可以说“我需要一个sprite”并具有严格定义的接口不是很好吗?看看zope.interface。fromzopeimportinterfaceclassISprite(interface.Interface):bounding_box=interface.Attribute("boundingbox")defintersects(box):"它与一个框相交吗?"乍一看,这段代码看起来有点奇怪。这些方法不包括self,这是一种常见的做法,它有一个属性。这就是您在zope.interface中声明接口的方式。这看起来很奇怪,因为大多数人不习惯严格声明接口。这样做的原因是接口展示了如何调用方法,而不是如何定义方法。因为接口不是超类,所以它们可以用来声明数据属性。这是一个可以有圆形精灵的接口的实现:@implementer(ISprite)@attr.s(auto_attribs=True)classCircleSprite:x:floaty:floatradius:float@propertydefbounding_box(self):return(self.x-self.radius,self.y-self.radius,self.x+self.radius,self.y+self.radius,)defintersects(self,box):#当且仅当至少有一个角框在圆内时与圆相交top_left,bottom_right=box[:2],box[2:]forchoose_x_from(top_left,bottom_right):forchoose_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):returnTruereturnFalse这显式声明了实现接口的CircleSprite类。它甚至可以让我们验证该类是否正确实现了接口:fromzope.interfaceimportverifydeftest_implementation():sprite=CircleSprite(x=0,y=0,radius=1)verify.verifyObject(ISprite,sprite)ThisworksRun通过pytest、nose或其他测试框架,它会验证创建的精灵是否符合界面。测试通常是部分的:它不测试文档中只提到的内容,它甚至不测试该方法是否可以无异常地调用!但是,它会检查是否存在正确的方法和属性。这是对单元测试套件的一个很好的补充,至少可以防止简单的拼写错误通过测试。