Any
i object
są powierzchownie podobny, ale w rzeczywistości są całkowicie przeciwnym w rozumieniu.
object
to root hierarchii metaclass Pythona. Każda klasa dziedziczy po object
. Oznacza to, że object
jest w pewnym sensie najbardziej restrykcyjnym typem, który można podać. Jeśli masz wartość typu object
, jedynymi metodami, które możesz wywołać, są te, które są częścią każdego pojedynczego obiektu. Na przykład:
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))
Natomiast Any
jest klapa ucieczka rozumie, co pozwala na dynamiczną i wymieszać statycznie wpisany kod. Any
to najmniej restrykcyjny typ - dozwolona jest każda możliwa metoda lub operacja na wartości typu Any
. Na przykład:
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))
Należy generalnie spróbować skorzystać Any
tylko w przypadkach, gdy ...
- Jako sposób mieszania ze sobą dynamiczny i statycznie wpisany kod. Na przykład, jeśli masz wiele dynamicznych i złożonych funkcji, i nie masz czasu, aby w pełni statycznie wpisać wszystkie, możesz zadecydować, że po prostu dasz im typ zwracający Any, aby nominalnie wprowadzić je do pracy typu. (Innymi słowy, Any jest użytecznym narzędziem pomagającym w migracji faz testowych do wcześniej wpisanego codebase etapami).
- Jako sposób nadania typowi wyrażenia, które jest trudne do wpisania. Na przykład adnotacje typu Python obecnie nie obsługują typów rekursywnych, co sprawia, że pisanie takich rzeczy jak dowolne dyktando JSON-a jest trudne. Jako tymczasowy środek, możesz chcieć dać swojemu JSONowi dyktando typu
Dict[str, Any]
, który jest trochę lepszy niż nic.
W przeciwieństwie do tego, należy używać object
dla przypadków, w których chcesz wskazać w sposób bezpieczny, że wartość MUSI dosłownie działać z dowolnym istniejącym obiektem.
Moja rekomendacja to unikanie używania Any
, z wyjątkiem przypadków, w których nie ma alternatywy. Any
to koncesja - mechanizm umożliwiający dynamikę tam, gdzie naprawdę wolimy żyć w świecie bezpiecznych typów.
Aby uzyskać więcej informacji, patrz:
dla konkretnego przykładu, użyłbym TypeVars, a następnie albo przedmiot lub wylejesz. To, co chcesz zrobić, to wskazać, że chcesz zwrócić typ tego, co zawiera się na liście. Jeśli lista będzie zawsze zawierają ten sam typ (co jest typowe w przypadku), co chcesz zrobić:
from typing import List, TypeVar
T = TypeVar('T')
def get_item(L: List[T], i: int) -> T:
return L[i]
ten sposób czynność get_item
zwróci najbardziej dokładny typ jak to możliwe.
To interesujące, jeszcze jeden szczególny przypadek dla struktury 'object' /' type'. Jeszcze raz dziękuję Martijn! :) –
Niestety, nie jest to poprawne - zobacz moją odpowiedź poniżej. W szczególności kluczową rzeczą jest to, że 'Any' ma być w pełni nieograniczony - każda operacja jest dozwolona dla wartości typu" Any ". Natomiast obiekt jest najbardziej ograniczonym typem. Jeśli masz wartość typu "Any", jedynymi operacjami, które możesz wykonać, są te, które są częścią interfejsu 'object' (rzeczy takie jak' __str__' i inne). "Obiekt jest podklasą Any i vice versa" istnieje głównie po to, aby wyjaśnić, dlaczego wszystkie wartości są zgodne z "Any", mimo że nie są technicznie podklasą lub nadklasą tego typu. – Michael0x2a
@ Michael0x2a: racja, więc z punktu widzenia pisania "Any" pozwala "funkcja używać' obiektu .__ missing__', a 'object' nie, ponieważ ta metoda jest opcjonalna. W ten sposób 'Any' dokumentuje, w jaki sposób funkcja użyje argumentu, a nie tylko suchego zastosowania testu isinstance. W praktyce te dwa elementy pozostają takie same, ponieważ test 'isinstance()' używany w 'typing' przejdzie w dowolny sposób. –