Czym są podpowiedzi typu w Pythonie 3.5?
Jedną z najczęściej omawianych funkcji w Pythonie 3.5 jest type hints.
Przykład podpowiedzi typu jest wymieniony w Ten artykułi Ten, a także wspomnieć, aby używać podpowiedzi typu odpowiedzialnie. Czy ktoś może wyjaśnić więcej na ich temat i kiedy powinny być używane, a kiedy nie?
5 answers
Sugerowałbym przeczytanie PEP 483 i PEP 484 i obejrzenie tej prezentacji autorstwa Guido na hintingu typu.
W skrócie: Typ hinting jest dosłownie tym, co oznaczają słowa. Wskazujesz typ obiektu(obiektów), którego (których) używasz .
Ze względu na dynamiczną naturę Pythona, wnioskowanie lub sprawdzanie typu używanego obiektu jest szczególnie trudne. Fakt ten utrudnia programistom zrozumieć, co dokładnie dzieje się w kodzie, którego nie napisali i, co najważniejsze, dla narzędzi do sprawdzania typów znalezionych w wielu Idach (PyCharm I PyDev {64]} przychodzą na myśl), które są ograniczone ze względu na fakt, że nie mają żadnego wskaźnika, jakiego typu są obiekty. W rezultacie uciekają się do próby wywnioskowania typu z (jak wspomniano w prezentacji) około 50% skutecznością.
Aby wziąć dwa ważne slajdy z rodzaju hinting prezentacja:
po co pisać podpowiedzi?
- pomaga sprawdzaczom typów: podpowiadając, jakiego typu obiekt ma być, sprawdzacz typów może łatwo wykryć, czy na przykład przekazujesz obiekt z typem, który nie jest oczekiwany.
-
pomaga w dokumentacji: trzecia osoba przeglądająca Twój kod będzie wiedziała, czego się spodziewać, gdzie, ergo, jak go używać bez otrzymywania
TypeErrors
. -
pomaga IDEs rozwijać się bardziej dokładne i solidne narzędzia: [74] Środowiska programistyczne będą lepiej dopasowane do sugerowania odpowiednich metod, gdy będą wiedzieć, jakiego typu jest obiekt. Prawdopodobnie doświadczyłeś tego z jakimś IDE w pewnym momencie, uderzając
.
i pojawiając metody / atrybuty, które nie są zdefiniowane dla obiektu.
dlaczego warto używać statycznych sprawdzaczy typów?
- Znajdź błędy wcześniej : to jest oczywiste, jak sądzę.
- the larger Twój projekt tym bardziej go potrzebujesz: znowu, ma sens. Języki statyczne oferują solidność i kontrolę, które brak języków dynamicznych. Im większa i bardziej złożona aplikacja, tym większa kontrola i przewidywalność (od aspekt behawioralny) wymagasz.
- duże zespoły już przeprowadzają analizę statyczną : zgaduję, że to weryfikuje dwa pierwsze punkty.
Na zakończenie tego małego wprowadzenia : jest to opcjonalna funkcja i, z tego co rozumiem, została wprowadzona w celu czerpania korzyści z typowania statycznego.
Generalnie nie musisz się o to martwić izdecydowanie nie musisz go używać (szczególnie w przypadkach, gdy używasz Pythona jako pomocniczego języka skryptowego). To powinno być pomocne przy tworzeniu dużych projektów, ponieważ oferuje bardzo potrzebną solidność, kontrolę i dodatkowe debugowanie możliwości .
Typ hinting z mypy :
Aby ta odpowiedź była bardziej kompletna, myślę, że mała demonstracja byłaby odpowiednia. Będę używał mypy
, biblioteka, która zainspirowała podpowiedzi typu, przedstawia je w PEP. Jest to napisane głównie dla każdego, kto wpada na to pytanie i zastanawia się, od czego zacząć.
Zanim to zrobię, powtórzę: PEP 484 niczego nie wymusza; jest po prostu ustawienie kierunku dla funkcji adnotacje i propozycje wytycznych dla jak sprawdzanie typu może / powinno być wykonywane. Możesz opisywać swoje funkcje i podpowiedz tyle rzeczy, ile chcesz; Twoje skrypty będą nadal działać niezależnie od obecności adnotacji, ponieważ sam Python ich nie używa.
W każdym razie, jak wspomniano w PEP, typy hintingu powinny zasadniczo przyjmować trzy formy:]}
- adnotacje funkcji (PEP 3107 ).
- pliki Stub dla modułów wbudowanych/użytkowników.
- specjalne
# type: type
komentarze, które uzupełniają dwie pierwsze formy. (Patrz: czym są adnotacje zmiennych? dla Pythona 3.6 aktualizacja dla# type: type
komentarze)
Dodatkowo, będziesz chciał użyć podpowiedzi typu w połączeniu z nowym typing
moduł wprowadzony w Py3.5
. W nim wiele (dodatkowych) ABCs (abstrakcyjne klasy bazowe) są zdefiniowane wraz z funkcjami pomocniczymi i dekoratorami do użytku w statycznych sprawdzam. Większość ABC w collections.abc
są włączone, ale w formie ogólne w celu umożliwienia subskrypcji (przez zdefiniowanie metody __getitem__()
).
Dla wszystkich zainteresowanych bardziej dogłębnym wyjaśnieniem tych mypy documentation
jest napisany bardzo ładnie i ma wiele próbek kodu demonstrujących / opisujących funkcjonalność ich checkera; zdecydowanie warto go przeczytać.
Adnotacje funkcji i komentarze specjalne:
[[62]}po pierwsze, warto obserwować niektóre z zachowanie możemy uzyskać przy użyciu specjalnych komentarzy. Specjalne# type: type
komentarze
może być dodawany podczas przypisywania zmiennych, aby wskazać typ obiektu, jeśli nie można go bezpośrednio wywnioskować. Proste zadania to
ogólnie łatwo wywnioskować, ale inne, jak listy (w odniesieniu do ich zawartości), nie mogą.
Uwaga: jeśli chcemy użyć dowolnej pochodnej kontenerów i musimy określić zawartość tego kontenera musimy użyć generic typy z modułu typing
. te wspierają indeksowanie.
# Generic List, supports indexing.
from typing import List
# In this case, the type is easily inferred as type: int.
i = 0
# Even though the type can be inferred as of type list
# there is no way to know the contents of this list.
# By using type: List[str] we indicate we want to use a list of strings.
a = [] # type: List[str]
# Appending an int to our list
# is statically not correct.
a.append(i)
# Appending a string is fine.
a.append("i")
print(a) # [0, 'i']
Jeśli dodamy te polecenia do pliku i wykonamy je za pomocą naszego interpretera, wszystko działa dobrze i print(a)
po prostu wyświetla
zawartość listy a
. Komentarze # type
zostały odrzucone, traktowane jako zwykłe komentarze, które nie mają dodatkowego znaczenia semantycznego .
mypy
, otrzymujemy następującą odpowiedź:
(Python3)jimmi@jim: mypy typeHintsCode.py
typesInline.py:14: error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"
Wskazując, że lista str
obiekty nie mogą zawierać int
, który, mówiąc statycznie, jest dźwiękiem. Można to ustalić, stosując Typ a
i tylko dodając str
obiektów lub zmieniając typ zawartości a
, aby wskazać, że dowolna wartość jest akceptowalna (intuicyjnie wykonywana z List[Any]
po zaimportowaniu Any
z typing
).
Adnotacje do funkcji są dodawane w formie param_name : type
po każdym parametrze w sygnaturze funkcji i typ zwracany jest za pomocą -> type
notacja przed dwukropkiem funkcji końcowej; wszystkie adnotacje są przechowywane w atrybucie __annotations__
dla tej funkcji w poręcznej formie słownika. Użycie trywialnego przykładu (który nie wymaga dodatkowych typów z modułu typing
):
def annotated(x: int, y: str) -> bool:
return x < y
Atrybut annotated.__annotations__
ma teraz następujące wartości:
{'y': <class 'str'>, 'return': <class 'bool'>, 'x': <class 'int'>}
Jeśli jesteśmy kompletnym nowicjuszem lub znamy pojęcia Pythona 2.7 i w konsekwencji nie jesteśmy świadomi czyhającego w porównaniu TypeError
annotated
, możemy wykonać kolejny statyczne sprawdzanie, Złap błąd i zaoszczędź nam trochę kłopotów:
(Python3)jimmi@jim: mypy typeHintsCode.py
typeFunction.py: note: In function "annotated":
typeFunction.py:2: error: Unsupported operand types for > ("str" and "int")
Między innymi wywołanie funkcji z nieprawidłowymi argumentami również zostanie przechwycone:
annotated(20, 20)
# mypy complains:
typeHintsCode.py:4: error: Argument 2 to "annotated" has incompatible type "int"; expected "str"
Można je rozszerzyć na praktycznie każdy przypadek użycia, a wykryte błędy wykraczają poza podstawowe wywołania i operacje. Typy ty
można sprawdzić, czy są naprawdę elastyczne, a ja tylko dałem mały sneak peak jego potencjału. Zajrzyj do modułu typing
,
PEPs lub mypy
dokumentacja da ci więcej kompleksowe wyobrażenie o oferowanych możliwościach.
Pliki Stub:
Pliki Stub mogą być używane w dwóch różnych, wzajemnie się wykluczających przypadkach:
- musisz wpisać check moduł, dla którego nie chcesz bezpośrednio zmieniać podpisów funkcji
- chcesz pisać moduły i sprawdzać Typ, ale dodatkowo chcesz oddzielić adnotacje od zawartości.
Czym są pliki stub (z rozszerzeniem .pyi
) jest interfejs z adnotacją moduł, który tworzysz/chcesz użyć. Zawierają
sygnatury funkcji, które chcesz wpisać-sprawdź z treścią odrzuconych funkcji. Aby poczuć to, biorąc pod uwagę zestaw
z trzech funkcji losowych w module o nazwie randfunc.py
:
def message(s):
print(s)
def alterContents(myIterable):
return [i for i in myIterable if i % 2 == 0]
def combine(messageFunc, itFunc):
messageFunc("Printing the Iterable")
a = alterContents(range(1, 20))
return set(a)
Możemy utworzyć plik stub randfunc.pyi
, w którym możemy umieścić pewne ograniczenia, jeśli chcemy to zrobić. Minusem jest to, że
ktoś, kto ogląda źródło bez Stuba, tak naprawdę nie otrzyma pomocy w adnotacji, gdy próbuje zrozumieć, co jest przypuszczalny
do przekazania gdzie.
W każdym razie, struktura pliku stub jest dość uproszczona: Dodaj wszystkie definicje funkcji z pustymi ciałami (pass
wypełnione) i
dostarcz adnotacje w oparciu o twoje wymagania. Załóżmy, że chcemy pracować tylko z typami int
dla naszych kontenerów.
# Stub for randfucn.py
from typing import Iterable, List, Set, Callable
def message(s: str) -> None: pass
def alterContents(myIterable: Iterable[int])-> List[int]: pass
def combine(
messageFunc: Callable[[str], Any],
itFunc: Callable[[Iterable[int]], List[int]]
)-> Set[int]: pass
Funkcja combine
wskazuje, dlaczego warto używać adnotacji w innym pliku, czasami zaśmiecają
kod i zmniejszyć czytelność (Duże Nie-Nie dla Pythona). Można oczywiście użyć aliasów typu, ale to czasem bardziej myli niż
pomaga (więc używaj ich mądrze).
To powinno cię zapoznać z podstawowymi pojęciami podpowiedzi typu w Pythonie. Mimo, że zastosowany kontroler typu został
mypy
powinieneś stopniowo zacząć widzieć więcej ich wyskakujących, niektóre wewnętrznie w Idach (PyCharm,) i inne jako standardowe moduły Pythona.
Postaram się dodać dodatkowe Warcaby/powiązane pakiety na poniższej liście kiedy i jeśli je znajdę (lub jeśli zasugeruję).
Warcaby, które znam:
- Mypy: jak opisano tutaj.
- PyType: przez Google, używa innej notacji niż to, co zbieram, prawdopodobnie warto zajrzeć.
Powiązane Pakiety / Projekty:
- typeshed: oficjalne repozytorium Pythona zawierające asortyment plików stub dla biblioteka standardowa.
Projekt typeshed
jest w rzeczywistości jednym z najlepszych miejsc, które możesz zobaczyć, jak można użyć hintingu typu w twoim własnym projekcie. Weźmy jako przykład __init__
dundery klasy Counter
w odpowiednim pliku .pyi
:
class Counter(Dict[_T, int], Generic[_T]):
@overload
def __init__(self) -> None: ...
@overload
def __init__(self, Mapping: Mapping[_T, int]) -> None: ...
@overload
def __init__(self, iterable: Iterable[_T]) -> None: ...
Gdzie _T = TypeVar('_T')
jest używany do definiowania klas ogólnych . Dla klasy Counter
widzimy, że może ona albo pobierać żadne argumenty w swoim inicjalizatorze, uzyskać pojedynczy Mapping
z dowolnego typu do int
lub weź Iterable
dowolnego typu.
Uwaga : jedną rzeczą, o której zapomniałem wspomnieć, jest to, że moduł typing
został wprowadzony na podstawie tymczasowo . Od PEP 411:
Tymczasowy pakiet może mieć zmodyfikowane API przed "ukończeniem" do stanu "stabilnego". Z jednej strony, stan ten zapewnia pakietowi korzyści wynikające z bycia formalnie częścią dystrybucji Pythona. Z drugiej strony rdzeń zespół programistów wyraźnie stwierdza, że nie składa się żadnych obietnic dotyczących stabilności API pakietu, które mogą ulec zmianie w następnym wydaniu. Chociaż jest to uważane za mało prawdopodobne, takie pakiety mogą być nawet usunięte z biblioteki standardowej bez okresu dezaktualizacji, jeśli obawy dotyczące ich API lub konserwacji okażą się zasadne.
Więc weź rzeczy tutaj ze szczyptą soli; wątpię, że zostaną usunięte lub zmienione w znaczący sposób, ale można nigdy nie wiadomo.
** zupełnie inny temat, ale ważny w zakresie typu-podpowiedzi: PEP 526
: składnia dla adnotacji zmiennych jest próbą zastąpienia komentarzy # type
poprzez wprowadzenie nowej składni, która pozwala użytkownikom na opisywanie typów zmiennych w prostych instrukcjach varname: type
.
Zobacz czym są adnotacje zmiennych?, jak wcześniej wspomniano, na małe wprowadzenie do nich.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-11 15:22:22
Dodanie do rozbudowanej odpowiedzi Jima :
Sprawdź typing
module -- Ten moduł obsługuje podpowiedzi typu określone przez PEP 484 .
Na przykład poniższa funkcja pobiera i zwraca wartości typu str
i jest opatrzona następującą adnotacją:
def greeting(name: str) -> str:
return 'Hello ' + name
Moduł typing
obsługuje również:
- wpisz aliasing.
- wpisz hinting dla funkcji zwrotnych.
- Generics - abstrakcyjne klasy bazowe zostały rozszerzony w celu obsługi subskrypcji oznaczającej oczekiwane typy elementów kontenera.
- typy generyczne zdefiniowane przez Użytkownika - Klasa zdefiniowana przez użytkownika może być zdefiniowana jako klasa generyczna.
- any type - Każdy typ jest podtypem Any.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-23 00:19:24
Nowo wydany PyCharm 5 obsługuje hinting typu. W swoim poście na blogu (zobacz Python 3.5 type hinting w PyCharm 5) oferują świetne Wyjaśnienie Czym są podpowiedzi typu, a nie wraz z kilkoma przykładami i ilustracjami, jak ich używać w kodzie.
DODATKOWO, jest on obsługiwany w Pythonie 2.7, jak wyjaśniono w Ten komentarz :
PyCharm obsługuje moduł typowania z PyPI dla Pythona 2.7, Pythona 3.2-3.4. dla 2.7 musisz dodać podpowiedzi typu *.pliki pyi stub, ponieważ adnotacje funkcji zostały dodane w Pythonie 3.0.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-16 13:53:03
Podpowiedzi typu służą do konserwacji i nie są interpretowane przez Pythona. W poniższym kodzie wiersz def add(self, ic:int)
nie powoduje błędu aż do następnej linii return...
:
class C1:
def __init__(self):
self.idn = 1
def add(self, ic: int):
return self.idn + ic
c1 = C1()
c1.add(2)
c1.add(c1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 5, in add
TypeError: unsupported operand type(s) for +: 'int' and 'C1'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-11 15:31:28
Typ podpowiedzi są niedawnym dodatkiem do dynamicznego języka, w którym przez dziesięciolecia ludzie przysięgli konwencje nazewnictwa tak proste jak Węgierski (obiekt etykieta z pierwszą literą b= logiczny, c = znak , D = słownik, i = liczba całkowita, l = lista, N = numeryczny, s = ciąg, t = krotka) nie były potrzebne, zbyt uciążliwe, ale teraz zdecydowali, że, oh wait ... używanie języka (type ()) do rozpoznawania obiektów jest zbyt kłopotliwe, a nasze wymyślne IDE potrzebują pomocy w robieniu wszystkiego, co tak skomplikowane, a to dynamicznie przypisywane wartości obiektów czynią je całkowicie bezużytecznymi, podczas gdy prosta konwencja nazewnictwa mogłaby rozwiązać to wszystko, dla każdego dewelopera, na pierwszy rzut oka.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-11 15:33:37