O ile się nie mylę, tworzenie funkcji w Pythonie działa w następujący sposób:
def my_func(param1, param2):
# stuff
Jednak nie podajesz typów tych parametrów. Ponadto, o ile pamiętam, Python jest silnie typowanym językiem, dlatego wydaje się, że Python nie powinien przekazywać parametru innego typu niż oczekiwany przez twórcę funkcji. Skąd jednak Python wie, że użytkownik funkcji przekazuje odpowiednie typy? Czy program po prostu umrze, jeśli jest niewłaściwy, zakładając, że funkcja faktycznie używa parametru? Czy musisz podać typ?
python
function
parameters
Leif Andersen
źródło
źródło
Odpowiedzi:
Python jest silnie typowany, ponieważ każdy obiekt ma typ, każdy obiekt zna swój typ, niemożliwe jest przypadkowe lub celowe użycie obiektu typu „tak jakby” był to obiekt innego typu, a wszystkie podstawowe operacje na obiekcie są przekazane do tego typu.
To nie ma nic wspólnego z nazwami . Nazwa w Pythonie nie „ma typ”: czy i kiedy zdefiniowana nazwa, nazwa odnosi się do obiektu , a obiekt ma typ (ale w rzeczywistości nie życie typ o nazwie : A imię to imię).
Nazwa w Pythonie może doskonale odnosić się do różnych obiektów w różnych momentach (jak w większości języków programowania, choć nie we wszystkich) - i nie ma żadnych ograniczeń co do nazwy, więc jeśli kiedyś odwoływała się do obiektu typu X, jest wtedy na zawsze ograniczone, aby odnosić się tylko do innych obiektów typu X. Ograniczenia dotyczące nazw nie są częścią koncepcji „silnego pisania”, chociaż niektórzy entuzjaści pisania statycznego (gdzie nazwy są ograniczone, a przy statycznej kompilacji AKA- czas, moda też) niewłaściwie używaj tego terminu.
źródło
try
/except
) pojawi się, gdy i jeśli zostanie podjęta operacja, której obiekt nie obsługuje. W Pythonie 3.5 możesz teraz opcjonalnie „określić typy” argumentów, ale sam błąd nie wystąpi, jeśli specyfikacja zostanie naruszona; notacja typowania ma na celu jedynie pomoc w oddzieleniu narzędzi wykonujących analizy itp. Nie zmienia ona zachowania samego Pythona.Inne odpowiedzi wykonały dobrą robotę wyjaśniając pisanie kaczek i prostą odpowiedź tzot :
Jednak jedna interesująca rzecz zmieniła się od 2010 roku (kiedy pytanie zostało zadane po raz pierwszy), a mianowicie implementacja PEP 3107 (zaimplementowana w Pythonie 3). Możesz teraz właściwie określić typ parametru i typ zwracanego typu funkcji:
Widzimy tutaj, że
pick
bierze 2 parametry, listęl
i liczbę całkowitąindex
. Powinien także zwrócić liczbę całkowitą.Tutaj sugeruje się, że
l
jest to lista liczb całkowitych, które możemy zobaczyć bez większego wysiłku, ale w przypadku bardziej złożonych funkcji może być nieco mylące, co powinna zawierać lista. Chcemy również, aby domyślna wartość wynosiłaindex
0. Aby rozwiązać ten problem, możeszpick
zamiast tego napisać w następujący sposób:Zauważ, że teraz wstawiamy ciąg jako typ
l
, który jest składniowo dozwolony, ale nie nadaje się do parsowania programowego (do którego wrócimy później).Ważne jest, aby pamiętać, że Python nie podniesie wartości,
TypeError
jeśli przejdziesz do floatindex
, przyczyną tego jest jeden z głównych punktów filozofii projektowania Pythona: „Wszyscy zgadzamy się tutaj na dorosłych” , co oznacza, że oczekuje się bądź świadomy tego, co możesz przekazać do funkcji, a czego nie. Jeśli naprawdę chcesz napisać kod, który wyrzuca błędy TypeErrors, możesz użyćisinstance
funkcji, aby sprawdzić, czy przekazany argument jest poprawnego typu lub jego podklasy w następujący sposób:Więcej o tym, dlaczego tak rzadko powinieneś to robić, a o tym, co powinieneś zrobić, omówiono w następnej sekcji i w komentarzach.
PEP 3107 nie tylko poprawia czytelność kodu, ale ma także kilka pasujących przypadków użycia, o których możesz przeczytać tutaj .
Adnotacja typu zyskała dużo większą uwagę w Pythonie 3.5 dzięki wprowadzeniu PEP 484, który wprowadza standardowy moduł do wskazówek typu.
Te wskazówki dotyczące typów pochodzą od mypy sprawdzania typu ( GitHub ), która jest teraz zgodna z PEP 484 .
Z modułem do pisania dołączony jest dość obszerny zbiór wskazówek dotyczących typów, w tym:
List
,Tuple
,Set
,Map
- dolist
,tuple
,set
imap
odpowiednio.Iterable
- przydatne dla generatorów.Any
- kiedy może być cokolwiek.Union
- kiedy może to być cokolwiek w ramach określonego zestawu typów, w przeciwieństwie doAny
.Optional
- kiedy może to być Brak. Stenografia dlaUnion[T, None]
.TypeVar
- stosowany z lekami generycznymi.Callable
- używany głównie do funkcji, ale może być wykorzystany do innych wywołań.Są to najczęstsze wskazówki dotyczące typów. Pełną listę można znaleźć w dokumentacji modułu do pisania .
Oto stary przykład wykorzystujący metody adnotacji wprowadzone w module pisania:
Jedną z potężnych funkcji jest
Callable
możliwość wpisywania metod adnotacji, które przyjmują funkcję jako argument. Na przykład:Powyższy przykład może stać się bardziej precyzyjny z użyciem
TypeVar
zamiastAny
, ale zostało to pozostawione jako ćwiczenie dla czytelnika, ponieważ uważam, że już wypełniłem moją odpowiedź zbyt dużą ilością informacji o cudownych nowych funkcjach włączonych przez podpowiedzi typu.Wcześniej, gdy udokumentowano jeden kod Pythona, na przykład Sphinx, niektóre z powyższych funkcji można było uzyskać pisząc dokumenty w formacie takim jak ten:
Jak widać, wymaga to kilku dodatkowych wierszy (dokładna liczba zależy od tego, jak wyraźny chcesz być i jak formatujesz dokumenty). Ale teraz powinno być dla ciebie jasne, w jaki sposób PEP 3107 stanowi alternatywę, która jest na wiele (wszystkich?) Sposobów lepsza. Jest to szczególnie prawdziwe w połączeniu z PEP 484, który, jak widzieliśmy, zapewnia standardowy moduł, który definiuje składnię dla tego typu wskazówek / adnotacji, które mogą być używane w taki sposób, że są jednoznaczne i precyzyjne, a jednocześnie elastyczne, tworząc potężna kombinacja.
Moim osobistym zdaniem jest to jedna z największych funkcji Pythona w historii. Nie mogę się doczekać, aż ludzie zaczną wykorzystywać jego moc. Przepraszam za długą odpowiedź, ale tak się dzieje, kiedy się ekscytuję.
Przykład kodu Pythona, który intensywnie korzysta z podpowiedzi typu, można znaleźć tutaj .
źródło
TypeError
, jaki jest sens używaniapick(l: list, index: int) -> int
takiego jak definiowanie jednowierszowe? Albo źle to zrozumiałem, nie wiem.__annotations__
atrybucie obiektu funkcyjnego).def f(a) -> Tuple[int, int]:
Nie określasz typu. Metoda zawiedzie (w czasie wykonywania) tylko wtedy, gdy spróbuje uzyskać dostęp do atrybutów, które nie są zdefiniowane w przekazywanych parametrach.
Więc ta prosta funkcja:
... nie zawiedzie, bez względu na to, jakie dwa argumenty zostaną przekazane.
Jednak ta funkcja:
... nie powiedzie się, jeśli w czasie wykonywania
param1
iparam2
nie mają zarówno cechy wywołalnych nazwanychquack
.źródło
Wiele języków ma zmienne, które są określonego typu i mają wartość. Python nie ma zmiennych; ma obiekty i używasz nazw, aby odwoływać się do tych obiektów.
W innych językach, kiedy mówisz:
następnie zmienna (zwykle całkowita) zmienia swoją zawartość na wartość 1.
W Pythonie
oznacza „użyj nazwy a, aby odnieść się do obiektu 1 ”. W interaktywnej sesji Pythona możesz wykonać następujące czynności:
Funkcja
type
jest wywoływana z obiektem1
; ponieważ każdy obiekt zna swój typ, łatwotype
jest znaleźć wspomniany typ i zwrócić go.Podobnie za każdym razem, gdy definiujesz funkcję
funkcja otrzymuje dwa obiekty i nazywa je
param1
orazparam2
niezależnie od ich typów. Jeśli chcesz się upewnić, że otrzymane obiekty są określonego typu, zakoduj swoją funkcję tak, jakby były wymaganych typów i wychwytuj wyjątki, które są zgłaszane, jeśli nie są. Zgłoszone wyjątki to zwykleTypeError
(użyto niepoprawnej operacji) iAttributeError
(próbowano uzyskać dostęp do nieistniejącego elementu (metody też są członkami)).źródło
Python nie jest mocno wpisany w sensie statycznego lub sprawdzania typu podczas kompilacji.
Większość kodu Pythona podlega tak zwanemu „Typowaniu kaczkowatemu” - na przykład szukasz metody
read
na obiekcie - nie obchodzi cię, czy obiekt jest plikiem na dysku czy gnieździe, po prostu chcesz odczytać N bajty z tego.źródło
Jak wyjaśnia Alex Martelli ,
Przeczytaj resztę jego postu, aby uzyskać przydatne informacje.
źródło
Python nie przejmuje się tym, co przekazujesz jego funkcjom. Kiedy zadzwonisz
my_func(a,b)
, zmienne param1 i param2 będą wówczas zawierać wartości aib. Python nie wie, że wywołujesz funkcję z odpowiednimi typami i oczekuje, że programista się tym zajmie. Jeśli twoja funkcja zostanie wywołana z różnymi typami parametrów, możesz owinąć kod uzyskując do nich dostęp blokami try / oprócz i ocenić parametry w dowolny sposób.źródło
Nigdy nie podajesz typu; Python ma pojęcie pisania kaczego ; w zasadzie kod, który przetwarza parametry, przyjmie pewne założenia na ich temat - być może przez wywołanie pewnych metod, które parametr ma zaimplementować. Jeśli parametr jest niewłaściwego typu, zostanie zgłoszony wyjątek.
Zasadniczo od twojego kodu zależy, czy przekazujesz obiekty odpowiedniego typu - nie ma kompilatora, który wymusiłby to z wyprzedzeniem.
źródło
Jest jeden notoryczny wyjątek od wpisywania kaczek, o których warto wspomnieć na tej stronie.
Gdy
str
funkcja wywołuje__str__
metodę class, subtelnie sprawdza jej typ:Jakby Guido podpowiadał nam, który wyjątek powinien zgłosić program, jeśli napotka nieoczekiwany typ.
źródło
W Pythonie wszystko ma swój typ. Funkcja Python zrobi wszystko, o co jest poproszony, jeśli obsługuje ją typ argumentów.
Przykład:
foo
doda wszystko, co można__add__
edytować;) nie martwiąc się zbytnio o jego typ. Oznacza to, że aby uniknąć niepowodzenia, powinieneś dostarczyć tylko te rzeczy, które obsługują dodawanie.źródło
Nie widziałem tego w innych odpowiedziach, więc dodam to do puli.
Jak powiedzieli inni, Python nie wymusza typu na parametrach funkcji lub metody. Zakłada się, że wiesz, co robisz, i jeśli naprawdę musisz wiedzieć, jaki rodzaj przekazu został przekazany, sprawdzisz to i zdecydujesz, co zrobić dla siebie.
Jednym z głównych narzędzi do tego celu jest funkcja isinstance ().
Na przykład, jeśli napiszę metodę, która spodziewa się uzyskać surowe binarne dane tekstowe, zamiast normalnych ciągów zakodowanych w utf-8, mógłbym sprawdzić typ parametrów po drodze i albo dostosować się do tego, co znajdę, albo podnieść wyjątek do odmowy.
Python zapewnia również wszelkiego rodzaju narzędzia do kopania w obiektach. Jeśli jesteś odważny, możesz nawet użyć importlib do tworzenia własnych obiektów dowolnych klas w locie. Zrobiłem to, aby odtworzyć obiekty z danych JSON. Coś takiego byłoby koszmarem w statycznym języku, takim jak C ++.
źródło
Aby efektywnie korzystać z modułu pisania (nowość w Pythonie 3.5), należy zastosować all (
*
).I będziesz gotowy do użycia:
Jednak nadal można używać nazw typu jak
int
,list
,dict
, ...źródło
Zaimplementowałem opakowanie, jeśli ktoś chciałby określić typy zmiennych.
Użyj go jako:
EDYTOWAĆ
Powyższy kod nie działa, jeśli żaden z typów argumentów (lub return) nie został zadeklarowany. Następująca edycja może pomóc, z drugiej strony, działa tylko dla kwargs i nie sprawdza argumentów.
źródło