打字時使用typing.Any
而不是object
有什麼區別?例如:打字。任何對象?
def get_item(L: list, i: int) -> typing.Any:
return L[i]
相比:
def get_item(L: list, i: int) -> object:
return L[i]
打字時使用typing.Any
而不是object
有什麼區別?例如:打字。任何對象?
def get_item(L: list, i: int) -> typing.Any:
return L[i]
相比:
def get_item(L: list, i: int) -> object:
return L[i]
是的,是有區別的。儘管在Python 3中,所有對象都是object
的實例,包括object
本身,但只有Any
文檔返回值應該被類型檢查器忽略。
該對象的Any
類型文檔字符串狀態是Any
,反之亦然一個子類:
>>> import typing
>>> print(typing.Any.__doc__)
Special type indicating an unconstrained type.
- Any object is an instance of Any.
- Any class is a subclass of Any.
- As a special case, Any and object are subclasses of each other.
然而,適當的typechecker(一個超越isinstance()
檢查,來檢查該對象實際上是如何在函數中使用)可以輕易反對object
,其中Any
總是被接受。
注意到一個更精確的類型分配
Any
類型的值時,沒有類型檢查被執行。
和
對比度
Any
與object
行爲的行爲。類似於Any
,每種類型都是object
的子類型。但是,與Any
不同,反之並非如此:對象不是其他類型的子類型。這意味着當一個值的類型是
object
時,類型檢查器將會拒絕幾乎所有的操作,並將它分配給一個更專用類型的變量(或用它作爲返回值)是一個類型錯誤。
並從mypy文檔部分Any vs. object:
類型
object
是另一種類型,其可具有任意類型的值的一個實例。與Any
不同,object
是一種普通的靜態類型(它類似於Java中的Object
),並且只有對所有類型有效的操作才被接受用於對象值。
object
可以cast到一個更具體的類型,而Any
的真正含義任何事情都會發生和類型檢查任何使用對象(的脫離,即使你以後這樣的對象分配給一個名稱是 typechecked)。
您已經通過接受list
將您的功能繪製到未輸入的角落,這歸結爲與List[Any]
相同的情況。類型檢查器在那裏脫節並且返回值不再重要,但由於您的函數接受包含Any
對象的列表,因此此處的正確返回值爲Any
。
要正確參與類型檢查的代碼,您需要將輸入標記爲List[T]
(泛型類型的容器),以便類型檢查器能夠關注返回值。你的情況是T
,因爲你從列表中檢索一個值。從TypeVar
創建T
:
from typing import TypeVar, List
T = TypeVar('T')
def get_item(L: List[T], i: int) -> T:
return L[i]
Any
和object
是表面上相似,但實際上是完全相反在意義。
object
是Python的元類層次結構的根。每個班級都繼承object
。這意味着object
在某種意義上是您可以給出的最具限制性的值。如果您有一個類型爲object
的值,則允許調用的唯一方法是每個對象的一部分。例如:
foo = 3 # type: object
# Error, not all objects have a method 'hello'
bar = foo.hello()
# OK, all objects have a __str__ method
print(str(foo))
相比之下,Any
是逃生艙口意味着允許你混合在一起的動態和靜態類型的代碼。 Any
是限制性最小的類型 - 對Any
類型的值允許任何可能的方法或操作。例如:
from typing import Any
foo = 3 # type: Any
# OK, foo could be any type, and that type might have a 'hello' method
# Since we have no idea what hello() is, `bar` will also have a type of Any
bar = foo.hello()
# Ok, for similar reasons
print(str(foo))
通常你應該嘗試使用Any
僅供情況下...
Dict[str, Any]
,這比稍微好一點。相比之下,使用object
爲您希望在一個類型安全的方式,一個值必須字面上存在任何可能的對象來表示的情況。
我的建議是避免使用Any
,除非沒有其他選擇。 Any
是一種讓步 - 讓我們真正寧願生活在類型安全的世界裏的活力的機制。
欲瞭解更多信息,請參見:
爲了您的具體的例子,我會用TypeVars,而不是兩個對象或任何。你想要做的是表明你想要返回列表中包含的任何類型。如果列表中總是包含相同的類型(這通常是這種情況),你會想做的事:
from typing import List, TypeVar
T = TypeVar('T')
def get_item(L: List[T], i: int) -> T:
return L[i]
這樣,你的get_item
函數將返回最精確的類型成爲可能。
列表[T]不會將列表限制爲同質的,例如, '[沒有,1,'foo']'是非法的,因爲那個列表中沒有*一個*類型?通過使用「列表」作爲接受的類型,嬰兒已經被洗澡水抽出;包含的值沒有設置約束。 –
@MartijnPieters - 不一定 - 「T」可以被限制爲「Any」或「Union [None,int,str]」。這兩種替代方法都會使你成爲'[None,1,'foo']'typecheck的例子。但是,如你所說,將類型設置爲「list」相當於做「List [Any]」。 – Michael0x2a
正確的,其他地方的聲明*列表來源應正確定義列表內容。我同意在這裏實際限制好得多;任何''會殺死類型檢查器,以便隨後使用'get_item()'的返回值(你可以將返回值賦值給一個先前約束的變量,並且它會正常工作)。 –
有趣的是,'object' /'type'結構還有一個特例。再次感謝Martijn! :) –
不幸的是,這不是很正確 - 請參閱下面的答案。特別是,關鍵是「Any」意味着完全不受限制 - 任何操作都允許使用「Any」類型的值。相反,對象是最受限制的類型。如果你有一個'Any'類型的值,那麼你允許做的唯一操作就是'object'接口的一部分(像'__str__'之類的東西)。 「對象是Any的子類,反之亦然」的存在主要是爲了解釋爲什麼所有的值都與'Any'兼容,即使它們在技術上不是該類型的子類或超類。 – Michael0x2a
@ Michael0x2a:對,從打字的角度來看,'Any''允許'函數使用'object .__ missing__',而'object'不會是可選方法。這樣'Any'記錄函數如何使用參數,而不是乾脆應用isinstance測試。在實踐中,兩者保持不變,因爲'typing'中使用的'isinstance()'測試將以任何方式通過。 –