新聞中心
Zope.interface 可以幫助聲明存在哪些接口,是由哪些對(duì)象提供的,以及如何查詢這些信息。
zope.interface 庫(kù)可以克服 Python 接口設(shè)計(jì)中的歧義性。讓我們來(lái)研究一下。
隱式接口不是 Python 之禪
Python 之禪 很寬松,但是有點(diǎn)自相矛盾,以至于你可以用它來(lái)例證任何東西。讓我們來(lái)思考其中最著名的原則之一:“顯示勝于隱式”。
傳統(tǒng)上,在 Python 中會(huì)隱含的一件事是預(yù)期的接口。比如函數(shù)已經(jīng)記錄了它期望一個(gè)“類文件對(duì)象”或“序列”。但是什么是類文件對(duì)象呢?它支持 .writelines嗎?.seek 呢?什么是一個(gè)“序列”?是否支持步進(jìn)切片,例如 a[1:10:2]?
最初,Python 的答案是所謂的“鴨子類型”,取自短語(yǔ)“如果它像鴨子一樣行走,像鴨子一樣嘎嘎叫,那么它可能就是鴨子”。換句話說(shuō),“試試看”,這可能是你能得到的最具隱式的表達(dá)。
為了使這些內(nèi)容顯式地表達(dá)出來(lái),你需要一種方法來(lái)表達(dá)期望的接口。Zope Web 框架是最早用 Python 編寫的大型系統(tǒng)之一,它迫切需要這些東西來(lái)使代碼明確呈現(xiàn)出來(lái),例如,期望從“類似用戶的對(duì)象”獲得什么。
zope.interface 由 Zope 開發(fā),但作為單獨(dú)的 Python 包發(fā)布。Zope.interface 可以幫助聲明存在哪些接口,是由哪些對(duì)象提供的,以及如何查詢這些信息。
想象編寫一個(gè)簡(jiǎn)單的 2D 游戲,它需要各種東西來(lái)支持精靈界面(LCTT 譯注:“精靈 Sprite”是指游戲面板中各個(gè)組件)。例如,表示一個(gè)邊界框,但也要表示對(duì)象何時(shí)與一個(gè)框相交。與一些其他語(yǔ)言不同,在 Python 中,將屬性訪問(wèn)作為公共接口一部分是一種常見(jiàn)的做法,而不是實(shí)現(xiàn) getter 和 setter。邊界框應(yīng)該是一個(gè)屬性,而不是一個(gè)方法。
呈現(xiàn)精靈列表的方法可能類似于:
def render_sprites(render_surface, sprites):"""sprites 應(yīng)該是符合 Sprite 接口的對(duì)象列表:* 一個(gè)名為 "bounding_box" 的屬性,包含了邊界框* 一個(gè)名為 "intersects" 的方法,它接受一個(gè)邊界框并返回 True 或 False"""pass # 一些做實(shí)際渲染的代碼
該游戲?qū)⒕哂性S多處理精靈的函數(shù)。在每個(gè)函數(shù)中,你都必須在隨附文檔中指定預(yù)期。
此外,某些函數(shù)可能期望使用更復(fù)雜的精靈對(duì)象,例如具有 Z 序的對(duì)象。我們必須跟蹤哪些方法需要 Sprite 對(duì)象,哪些方法需要 SpriteWithZ 對(duì)象。
如果能夠使精靈是顯式而直觀的,這樣方法就可以聲明“我需要一個(gè)精靈”,并有個(gè)嚴(yán)格定義的接口,這不是很好嗎?來(lái)看看 zope.interface。
from zope import interfaceclass ISprite(interface.Interface):bounding_box = interface.Attribute("邊界框")def intersects(box):"它和一個(gè)框相交嗎?"
乍看起來(lái),這段代碼有點(diǎn)奇怪。這些方法不包括 self,而包含 self 是一種常見(jiàn)的做法,并且它有一個(gè)屬性。這是在 zope.interface 中聲明接口的方法。這看起來(lái)很奇怪,因?yàn)榇蠖鄶?shù)人不習(xí)慣嚴(yán)格聲明接口。
這樣做的原因是接口顯示了如何調(diào)用方法,而不是如何定義方法。因?yàn)榻涌诓皇浅?,所以它們可以用?lái)聲明數(shù)據(jù)屬性。
下面是一個(gè)能帶有圓形精靈的接口的一個(gè)實(shí)現(xiàn):
@implementer(ISprite)@attr.s(auto_attribs=True)class CircleSprite:x: floaty: floatradius: float@propertydef bounding_box(self):return (self.x - self.radius,self.y - self.radius,self.x + self.radius,self.y + self.radius,)def intersects(self, box):# 當(dāng)且僅當(dāng)至少一個(gè)角在圓內(nèi)時(shí),方框與圓相交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 Truereturn False
這顯式聲明了實(shí)現(xiàn)了該接口的 CircleSprite 類。它甚至能讓我們驗(yàn)證該類是否正確實(shí)現(xiàn)了接口:
from zope.interface import verifydef test_implementation():sprite = CircleSprite(x=0, y=0, radius=1)verify.verifyObject(ISprite, sprite)
這可以由 pytest、nose 或其他測(cè)試框架運(yùn)行,它將驗(yàn)證創(chuàng)建的精靈是否符合接口。測(cè)試通常是局部的:它不會(huì)測(cè)試僅在文檔中提及的內(nèi)容,甚至不會(huì)測(cè)試方法是否可以在沒(méi)有異常的情況下被調(diào)用!但是,它會(huì)檢查是否存在正確的方法和屬性。這是對(duì)單元測(cè)試套件一個(gè)很好的補(bǔ)充,至少可以防止簡(jiǎn)單的拼寫錯(cuò)誤通過(guò)測(cè)試。
網(wǎng)頁(yè)題目:借助zope.interface深入了解Python接口
URL鏈接:http://www.dlmjj.cn/article/cooicgs.html


咨詢
建站咨詢

