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?

Author: Peter Mortensen, 2015-09-14

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?

  1. 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.
  2. 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.
  3. 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 .

Z drugiej strony, uruchamiając to z 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.

 392
Author: Dimitris Fasarakis Hilliard,
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ż:

  1. wpisz aliasing.
  2. wpisz hinting dla funkcji zwrotnych.
  3. Generics - abstrakcyjne klasy bazowe zostały rozszerzony w celu obsługi subskrypcji oznaczającej oczekiwane typy elementów kontenera.
  4. typy generyczne zdefiniowane przez Użytkownika - Klasa zdefiniowana przez użytkownika może być zdefiniowana jako klasa generyczna.
  5. any type - Każdy typ jest podtypem Any.
 65
Author: Ani Menon,
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.

 27
Author: tsvenson,
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'
 1
Author: Leon Chang,
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.

 -2
Author: Noah F. SanTsorvutz,
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