藉助 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 譯註:“精靈”是指遊戲皮膚中各個元件)。例如,表示一個邊界框,但也要表示物件何時與一個框相交。與一些其他語言不同,在 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
訂閱“Linux 中國”官方小程式來檢視
相關文章
- Python3 原始碼閱讀-深入瞭解Python GILPython原始碼
- 深入瞭解原型原型
- 深入瞭解ConcurrentHashMapHashMap
- JavaScript——深入瞭解thisJavaScript
- 營銷大資料如何幫助企業深入瞭解客戶大資料
- 藉助AI力量,谷歌解開生命奧祕?AI谷歌
- 藉助Gradle Plugin解決模組化開發中模組如何對外暴露介面GradlePlugin
- 藉助babel理解jsxBabelJS
- 深入瞭解babel(一)Babel
- [譯] 深入瞭解 FlutterFlutter
- 深入瞭解Synchronized原理synchronized
- 深入瞭解SCN(轉)
- 如何藉助 Django 來編寫一個 Python Web APIDjangoPythonWebAPI
- 藉助Python 函式進行模組化程式碼Python函式
- 深入瞭解Python的非同步IO:概念和歷史Python非同步
- 深入瞭解Python的Dask分散式排程程式 - selectfromPython分散式
- python進階(16)深入瞭解GIL鎖(最詳細)Python
- 深入瞭解解析Https - 從瞭解到放棄HTTP
- 深入瞭解Object.definePropertyObject
- 深入瞭解MySQL的索引MySql索引
- 深入瞭解 Object.definePropertyObject
- 深入瞭解 Builder 模式 - frankelUI模式
- 深入瞭解Zookeeper核心原理
- 瞭解pythonPython
- 如何在終端介面藉助圖形化工具進行資料分析
- Golang介面簡單瞭解Golang
- 藉助dockerSwarm搭建叢集部署DockerSwarm
- 深入瞭解JavaScript中的物件JavaScript物件
- 前端進階-深入瞭解物件前端物件
- Nginx深入瞭解-基礎(一)Nginx
- Nginx深入瞭解-基礎(三)Nginx
- 深入瞭解機器學習機器學習
- 深入瞭解SpringMVC原始碼解析SpringMVC原始碼
- 深入瞭解Python為什麼慢(翻譯自Why Python is Slow: Looking Under the Hood)Python
- 藉助 DSL 來簡化 Loadgen 配置
- 藉助Radamsa變異資料(初探)
- 深入瞭解Redis資料結構Redis資料結構
- 深入瞭解 iOS 的初始化iOS