2017-01-22 81 views
0

如何在Python類型註釋中引用'任何子類爲父類的對象?Python 3類型註釋和子類

示例:FooBase是抽象基類,其中Foo1,Foo2等被分類。我希望函數接受FooBase的任何後裔。這是否會做:

def do_something(self, bar:FooBase): 
    pass 

還是將只接受FooBase類的對象,這當然是不可能的因爲FooBase是抽象的?在這種情況下,我是否需要構建所有案例的Union(請上帝,我希望不是!),還是我可以通過其他方式抽象地表達這種關係?

回答

1

註解做不是有意思。您可以使用bar:str,該功能仍將接受任何類型的對象。它們只是文檔的一種形式。

無論如何,它們通常被定義爲包含子類。請考慮靜態類型語言中的情況:在C++或Java中,編寫f(T param)意味着您可以傳遞類型爲T的參數param的子類。否則,所有子類都有什麼意義?

+0

您是否瞭解[PEP 484](https://www.python.org/dev/peps/pep-0484/)? *有*定義的含義。僅僅因爲它在運行時沒有被強制執行,並不意味着你寫的東西沒有意義。 – poke

0

這隻會接受類FooBase的對象嗎?

不,這也可以接受任何子類。這也在暗示型PEP的理論指出,特別是summary of Gradual Typing section

A型t1是一種t2如果t1一致的是t2一個亞型。 (但不是反過來。)

當處理類型提示時,請查看它以獲取更多指針。

我需要建立所有案例的聯盟嗎?

即使你做了,所有的子類都將從Union中消除,並且子類將被跳過。嘗試創建Union你提到:

typing.Union[Foo1, Foo2, FooBar] 

,其結果應該是FooBar。它是一個抽象類的事實在這裏沒有什麼區別,Python本身在typing模塊中使用了許多抽象類。

以例如Sized abc;暗示的功能與Sized允許任何虛擬子類(定義__len__類)來取代:

def foo(obj: Sized): pass 

foo([1, 2, 3, 4]) # ok 
foo([2, 3, 4, 5]) # ok 
0

繼承也適用於註解的類型。Foo的任何實例,它是FooBase的子類型,也是FooBase類型的有效對象。所以你可以傳遞一個FooBase對象,但也可以傳遞一個Foo對象。

如果你想限制功能只FooBar,你可以看看在Type[C]結構:The type of class objects