2017-09-23 63 views
1

我想在Python中創建自己的參數化類型爲類型提示使用:如何在Python中創建自己的「參數化」類型(如`Optional [T]`)?

class MaybeWrapped: 
    # magic goes here 

T = TypeVar('T') 

assert MaybeWrapped[T] == Union[T, Tuple[T]] 

不要介意人爲的例子;我怎樣才能實現這個?我查看了Union和Optional的源代碼,但它看起來像是我想避免的一些相當低級的hackery。

文檔中的唯一建議來自example re-implementation of Mapping[KT,VT] that inherits from Generic。但是這個例子更多的是關於__getitem__方法而不是關於類本身。

回答

1

如果您只是試圖創建泛型類或函數,請嘗試看一下documentation on mypy-lang.org about generic types - 這是相當全面的,並且更詳細,然後是標準庫打字文檔。

如果你想實現你的具體的例子,這是值得指出的是type aliases work with typevars - 你可以簡單地做:

from typing import Union, TypeVar, Tuple 

T = TypeVar('T') 

MaybeWrapped = Union[T, Tuple[T]] 

def foo(x: int) -> MaybeWrapped[str]: 
    if x % 2 == 0: 
     return "hi" 
    else: 
     return ("bye",) 

# When running mypy, the output of this line is: 
# test.py:13: error: Revealed type is 'Union[builtins.str, Tuple[builtins.str]]' 
reveal_type(foo(3)) 

不過,如果你想建立一個泛型類型與真正的新語義學,你很可能不幸運。其它的選擇是:

  1. 構建某種自定義的類/元類東西,PEP兼容484型跳棋可以理解和使用。
  2. 修改類型檢查你使用某種方式(mypy有一個實驗性的「插件」系統,例如)
  3. 信訪修改PEP 484,包括新的,自定義類型(您可以通過打開的問題做到這一點typing module repo)。
+0

謝謝,這裏使用'TypeVar'就是我所缺少的。非常神奇的是,仿製藥「就這樣工作」。 – shadowtalker

2

這正是__getitem__方法,所有的魔法。

這是在您使用[]括號來訂閱一個名稱時調用的方法。

所以,你需要在你的類的類中有一個__getitem__方法 - 也就是它的元類,它將作爲參數在括號內得到。該方法負責動態創建(或檢索緩存副本)的任何你想要生成的,並返回它。

我只是不可能想象如何你想要這種類型的暗示,因爲打字庫似乎涵蓋所有合理的情況下(我想不出一個他們沒有覆蓋的例子)。但是,讓你想一類返回其自身的副本,但與參數anotated作爲其type_屬性的假設:

class MyMeta(type): 
    def __getitem__(cls, key): 
     new_cls = types.new_class(f"{cls.__name__}_{key.__name__}", (cls,), {}, lambda ns: ns.__setitem__("type", key)) 
     return new_cls 

class Base(metaclass=MyMeta): pass 

而在交互模式嘗試這一點,可以這樣做:

In [27]: Base[int] 
Out[27]: types.Base_int 
+0

謝謝,雖然我還不確定這是如何工作的。你能說一說我的問題嗎?你的答案中的例子與我正在做的事情有點不同。 – shadowtalker

+1

@jsbueno - 我不認爲你的答案有效。您提出的代碼當然是一種構建*看起來像* PEP 484類型的方法,但由於它不是,PEP 484兼容類型檢查器不會理解如何處理您的'MyMeta'或'Base'類。 – Michael0x2a

相關問題