Jak poznać typ zwracanej funkcji i typy argumentów?

91

Chociaż zdaję sobie sprawę z koncepcji pisania kaczego w Pythonie, czasami zmagam się z typem argumentów funkcji lub typem wartości zwracanej przez funkcję.

Otóż, jeśli sam napisałem tę funkcję, WIEMY typy. Ale co, jeśli ktoś chce używać i wywoływać moje funkcje, skąd ma znać typy? Zwykle umieszczam informacje o typie w dokumentacji funkcji (na przykład: "...the id argument should be an integer..."i "... the function will return a (string, [integer]) tuple.")

Ale czy wyszukiwanie informacji w dokumentacji (i umieszczanie ich tam, jako programista) naprawdę jest tak, jak powinno być zrobione?

Edycja: większość odpowiedzi wydaje się kierować w stronę „tak, dokument!” Uważam, że nie zawsze jest to łatwe w przypadku „złożonych” typów.
Na przykład: jak zwięźle opisać w łańcuchu dokumentacyjnym, że funkcja zwraca listę krotek, z każdą krotką w postaci (identyfikator_węzła, nazwa_węzła, uptime_minutes) i że elementy są odpowiednio łańcuchem, łańcuchem i liczbą całkowitą?
Dokumentacja dokumentacyjna PEP nie zawiera żadnych wytycznych w tym zakresie.
Wydaje mi się, że kontrargumentem będzie to, że w takim przypadku należy użyć klas, ale uważam, że Python jest bardzo elastyczny, ponieważ pozwala na przekazywanie tych rzeczy za pomocą list i krotek, tj. Bez klas.

Rabarberskiego
źródło
2
Krótka odpowiedź brzmi „tak”. Długa odpowiedź brzmi „tak, oczywiście”. Nie wiem, czy obejrzałeś dużo kodu w Pythonie, ale prawdopodobnie powinieneś zaktualizować pytanie, aby wskazać, jakich pakietów faktycznie używasz, abyśmy mogli skierować Cię do kodu, który możesz przeczytać, aby zobaczyć, jak są zrobione rzeczy w kodzie biblioteki faktycznie używam teraz.
S.Lott,
@ S.Lott: Obecnie zmagam się z pakietem mechanize, ale wydaje mi się, że jest on po prostu (niestety) słabo udokumentowany.
Rabarberski
6
Python jest fajny, ponieważ możesz szybko napisać dużo kodu i nie musisz martwić się o przyziemne rzeczy, takie jak typy zwracane, typy argumentów, wydajność w czasie wykonywania, ludzie, którzy muszą używać i utrzymywać twój kod spaghetti przez następne 10 lat itp. Westchnienie .
jarmod

Odpowiedzi:

128

Cóż, od 2011 roku trochę się zmieniło! Teraz w Pythonie 3.5 są wskazówki dotyczące typów, których możesz użyć do adnotacji argumentów i zwrócenia typu swojej funkcji. Na przykład to:

def greeting(name):
  return 'Hello, {}'.format(name)

można teraz zapisać w ten sposób:

def greeting(name: str) -> str:
  return 'Hello, {}'.format(name)

Jak widzisz teraz typy, istnieje pewne opcjonalne sprawdzanie typów statycznych, które pomoże Tobie i Twojemu kontrolerowi typów zbadać kod.

Aby uzyskać więcej wyjaśnień, proponuję zapoznać się z wpisem na blogu dotyczącym podpowiedzi typu na blogu PyCharm .

Rsh
źródło
Zauważ, że typ podpowiedzi składni została również zasugerował dla Pythona 2.7 tutaj w tym samym PEP-0484. I działa w PyCharm, przynajmniej od wersji 2017.3.
viddik13
1
Jeśli funkcja pozdrowienia o dokładnie takiej samej definicji zwróci obiekt typu int, nie zostanie zgłoszony żaden błąd. Więc jakie jest użycie tego rodzaju sprawdzania typu, jeśli wyraźnie podasz zwracany typ, ale nie przestrzegasz reguły i zwracasz inny typ obiektu?
Arashsyh
3
@Arashsyh: Tak, masz rację, podpowiedzi do typów nie zmieniają Pythona w statycznie typowany język, to od Ciebie zależy, czy użyjesz odpowiednich typów we właściwy sposób. A te wskazówki dotyczące typów pomagają - w szybszym opracowywaniu, samodzielnym dokumentowaniu kodu lub otrzymywaniu ostrzeżeń, gdy coś zepsujesz. Zwłaszcza gdy używasz PyCharm (lub podobnego IDE), ostrzeże Cię, jeśli użyjesz innego typu i pomoże w kilku innych rzeczach. Polecam przeczytać post na blogu zasugerowany w powyższej odpowiedzi.
Nerxis
1
Czy jest to szybsze obliczeniowo?
Bryce Wayne
18

Tak działają języki dynamiczne. Nie zawsze jest to jednak dobre, zwłaszcza jeśli dokumentacja jest słaba - ktoś próbował użyć słabo udokumentowanego frameworka Pythona? Czasami trzeba wrócić do czytania źródła.

Oto kilka strategii pozwalających uniknąć problemów z pisaniem na klawiaturze:

  • utwórz język dla swojej problematycznej domeny
  • pomoże ci to poprawnie nazwać rzeczy
  • używaj typów do reprezentowania pojęć w języku Twojej domeny
  • nazwać parametry funkcji przy użyciu słownictwa języka domeny

Również jeden z najważniejszych punktów:

  • przechowuj dane jak najbardziej lokalnie!

Powinno być przekazywanych tylko kilka dobrze zdefiniowanych i udokumentowanych typów. Cokolwiek innego powinno być oczywiste, patrząc na kod: nie używaj dziwnych typów parametrów pochodzących z daleka, których nie możesz zrozumieć, patrząc w pobliże kodu ...

Powiązana (a także związana z dokumentacją) jest w Pythonie technika o nazwie doctests. Skorzystaj z tego, aby udokumentować, w jaki sposób Twoje metody mają być używane - i jednocześnie mieć ładne pokrycie testów jednostkowych!

Daren Thomas
źródło
1
Dokumentacja Numpy jest dobrym reprezentatywnym przykładem filozofii zawartej w powyższej odpowiedzi.
Jerry Ajay
7

Byłam na kursie coursera, była lekcja, na której uczono nas o przepisie na projekt.

Poniższy format docstrów okazał się przydatny.

def area (base, height):
    '' '(liczba, liczba) -> liczba # ** TypeContract **
    Zwróć obszar tringu z wymiarami podstawa # ** Opis **
    i wysokość

    >>> obszar (10,5) # ** Przykład **
    25,0
    >> obszar (2.5,3)
    3,75
    '' '
    powrót (podstawa * wysokość) / 2 

Myślę, że napisanie w ten sposób ciągów dokumentów może bardzo pomóc programistom.

Link do wideo [Obejrzyj wideo] : https://www.youtube.com/watch?v=QAPg6Vb_LgI

Sumit Murari
źródło
5

Tak, powinieneś używać ciągów dokumentacyjnych, aby uczynić swoje klasy i funkcje bardziej przyjaznymi dla innych programistów:

Więcej: http://www.python.org/dev/peps/pep-0257/#what-is-a-docstring

Niektóre edytory umożliwiają wyświetlanie ciągów dokumentów podczas pisania, więc naprawdę ułatwia to pracę.

Maciej Ziarko
źródło
+1: udokumentuj to, to jedyny rozsądny sposób, tak samo jest w przypadku języków statycznych. Typy zwrotów stanowią nieznaczną część całego obrazu.
detly
Bardzo lubię moje typy, dziękuję bardzo. Dokumentacja + typy = niebo
masm64
2

Tak to jest.

W Pythonie funkcja nie zawsze musi zwracać zmienną tego samego typu (chociaż twój kod będzie bardziej czytelny, jeśli twoje funkcje zawsze zwracają ten sam typ). Oznacza to, że nie możesz określić jednego typu zwracanego dla funkcji.

W ten sam sposób parametry nie zawsze muszą być tego samego typu.

thomson_matt
źródło
1

Na przykład: jak zwięźle opisać w łańcuchu dokumentacyjnym, że funkcja zwraca listę krotek, z każdą krotką w postaci (identyfikator_węzła, nazwa_węzła, minuty_ uptime) i że elementy są odpowiednio łańcuchem, łańcuchem i liczbą całkowitą?

Um ... Nie ma żadnego „zwięzłego” opisu tego. To skomplikowane. Zaprojektowałeś to jako złożone. I wymaga złożonej dokumentacji w dokumentacji.

Przepraszamy, ale złożoność jest - cóż - złożona.

S.Lott
źródło
3
DOBRZE. Nie na temat (w pewnym sensie): ale jaki byłby w takim razie bardziej przejrzysty projekt? Zajęcia?
Rabarberski
@Rabarberski: Niekoniecznie. Złożoność brzmi tutaj nieunikniona. Zwięzłość nie zawsze jest osiągalna, a nawet pożądana.
S.Lott,
1
Oczywistym sposobem udokumentowania tego typu rzeczy jest użycie czegoś podobnego do generycznych Java, na przykład: list <tuple <int, str, int >>. Ale to nie jest sposób Pythona, na dobre i na złe.
Skyler,
0

Tak, ponieważ jest to język typu dynamicznego;)

Przeczytaj to w celach informacyjnych: PEP 257

Alois Cochard
źródło
0

Dokumenty (i ogólnie dokumentacja). Python 3 wprowadza (opcjonalne) adnotacje funkcji, jak opisano w PEP 3107 (ale nie pomijaj ciągów dokumentów)

Steven
źródło