Jaki jest najlepszy sposób sprawdzenia, czy dany obiekt jest określonego typu? Co powiesz na sprawdzenie, czy obiekt dziedziczy po danym typie?
Powiedzmy, że mam przedmiot o
. Jak sprawdzić, czy to jest str
?
Jaki jest najlepszy sposób sprawdzenia, czy dany obiekt jest określonego typu? Co powiesz na sprawdzenie, czy obiekt dziedziczy po danym typie?
Powiedzmy, że mam przedmiot o
. Jak sprawdzić, czy to jest str
?
Odpowiedzi:
Aby sprawdzić, czy o
jest instancją str
lub jakąkolwiek podklasą str
, użyj isinstance (byłby to sposób „kanoniczny”):
if isinstance(o, str):
Aby sprawdzić, czy typ o
jest dokładnie str
(wyklucz podklasy):
if type(o) is str:
Następujące działania również działają i mogą być przydatne w niektórych przypadkach:
if issubclass(type(o), str):
Zobacz funkcje wbudowane w Python Library Reference istotnych informacji.
Jeszcze jedna uwaga: w tym przypadku, jeśli używasz Python 2, możesz chcieć użyć:
if isinstance(o, basestring):
ponieważ będzie to również złapać ciągi Unicode ( unicode
nie jest podklasą str
; oba str
i unicode
są podklasy basestring
). Zauważ, że basestring
nie istnieje już w Pythonie 3, gdzie istnieje ścisłe oddzielenie ciągów ( str
) i danych binarnych ( bytes
).
Alternatywnie, isinstance
akceptuje krotkę klas. Zwróci to, True
jeśli o
jest instancją dowolnej podklasy dowolnej z (str, unicode)
:
if isinstance(o, (str, unicode)):
type(a) is Object
to nie jest prawdą, że tak isinstance(a, Object)
. Jeśli jednak type(a) is SubClassOfObject
to type(a) is Object == False
, ale isinstance(a, Object) == True
. Dobrze?
a is b
oznacza, że aib są dokładnie tym samym, tzn. odniesienia do tego samego bytu w pamięci. Więc a
i b
musiałaby być dokładnie taka sama klasa, a nie podklasy, jak w przypadku isinstance()
. Zobacz na przykład stackoverflow.com/a/133024/1072212
Najbardziej pythonowy sposób sprawdzić typ obiektu jest ... nie to sprawdzić.
Ponieważ Python zachęca do pisania kaczego , powinieneś po prostu try...except
używać metod obiektu tak, jak chcesz. Więc jeśli twoja funkcja szuka zapisywalnego obiektu pliku, nie sprawdzaj, czy jest to podklasa file
, po prostu spróbuj użyć jego .write()
metody!
Oczywiście czasami te ładne abstrakcje rozpadają się i isinstance(obj, cls)
są tym, czego potrzebujesz. Ale używaj oszczędnie.
if hasattr(ob, "write") and callable(ob.write):
lub zapisać dostęp do func = getattr(ob, "write", None)
if callable(func): ...
hasattr
tylko błąd AttributeError - patrz: docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)
zwróci, True
jeśli o
jest str
lub jest typu, który dziedziczy str
.
type(o) is str
wróci, True
jeśli i tylko jeśli o
jest str. Zwróci, False
jeśli o
jest typu, który dziedziczy str
.
isinstance
i type(var) == type('')
nie jest wyraźna.
Po zadaniu pytania i udzieleniu odpowiedzi do Pythona dodano wskazówki typu . Wskazówki dotyczące typów w Pythonie umożliwiają sprawdzanie typów, ale w zupełnie inny sposób niż w przypadku języków typowanych statycznie. Wskazówki dotyczące typów w Pythonie kojarzą oczekiwane typy argumentów z funkcjami jako dane dostępne w czasie wykonywania powiązane z funkcjami, co pozwala na sprawdzenie typów. Przykład składni podpowiedzi typu:
def foo(i: int):
return i
foo(5)
foo('oops')
W tym przypadku chcemy, aby wystąpił błąd, foo('oops')
ponieważ typ argumentu z adnotacją to int
. Dodana wskazówka typu nie powoduje wystąpienia błędu, gdy skrypt jest uruchamiany normalnie. Dodaje jednak atrybuty do funkcji opisującej oczekiwane typy, które inne programy mogą wyszukiwać i wykorzystywać do sprawdzania błędów typów.
Jednym z tych innych programów, za pomocą których można znaleźć błąd typu, jest mypy
:
mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(Może być konieczne zainstalowanie mypy
z poziomu menedżera pakietów. Nie wydaje mi się, aby zawierał CPython, ale wydaje się, że ma pewien poziom „oficjalności”).
Sprawdzanie typów w ten sposób różni się od sprawdzania typów w statycznie skompilowanych językach kompilowanych. Ponieważ typy są dynamiczne w Pythonie, sprawdzanie typów musi być wykonywane w czasie wykonywania, co nakłada koszty - nawet na prawidłowe programy - jeśli nalegamy, aby zdarzyło się to przy każdej okazji. Jawne sprawdzanie typu może być również bardziej restrykcyjne niż to konieczne i powodować niepotrzebne błędy (np. Czy argument naprawdę musi być dokładnie tego samego list
typu, czy może wystarczy iterowalne powtórzenie?).
Zaletą jawnego sprawdzania typów jest to, że może wcześniej wychwytywać błędy i dawać wyraźniejsze komunikaty o błędach niż pisanie kaczych znaków. Dokładne wymagania dla typu kaczki można wyrazić tylko za pomocą dokumentacji zewnętrznej (mam nadzieję, że jest to dokładne i dokładne), a błędy z niekompatybilnych typów mogą wystąpić daleko od miejsca, z którego pochodzą.
Wskazówki dotyczące typów w Pythonie mają na celu zaoferowanie kompromisu, w którym typy można określać i sprawdzać, ale nie ma dodatkowych kosztów podczas zwykłego wykonywania kodu.
Te typing
zmienne oferty Rodzaj opakowania, które mogą być stosowane w podpowiedzi typu zachowań potrzebnych do wyrażenia bez potrzeby poszczególnych rodzajów. Na przykład zawiera zmienne takie jak Iterable
i Callable
podpowiedzi, aby określić potrzebę dowolnego typu z tymi zachowaniami.
Chociaż wskazówki dotyczące typów są najbardziej Pythońskim sposobem sprawdzania typów, często jeszcze bardziej Pythonic w ogóle nie sprawdza typów i polega na pisaniu kaczek. Podpowiedzi do czcionek są stosunkowo nowe, a jury jest nadal aktywne, gdy są najbardziej pythonicznym rozwiązaniem. Względnie niekontrowersyjne, ale bardzo ogólne porównanie: Podpowiedzi dotyczące typów zapewniają formę dokumentacji, którą można egzekwować, pozwalają na wcześniejsze generowanie kodu i łatwiejsze do zrozumienia błędy, mogą wychwycić błędy, których nie można wpisać podczas pisania kaczki, i można je sprawdzić statycznie (w nietypowy sposób sens, ale wciąż jest poza środowiskiem uruchomieniowym). Z drugiej strony, pisanie kaczką było od dawna sposobem Pythona, nie narzuca poznawczego pisania statycznego, jest mniej gadatliwe i akceptuje wszystkie możliwe typy, a potem niektóre.
mypy
są modułem Pythona używającym importlib
dostępu do tych danych. To, czy jest to „statyczne sprawdzanie typu”, jest filozoficznym pytaniem, ale różni się od tego, czego większość by się spodziewała, ponieważ zaangażowany jest zwykły tłumacz języka i maszyny importujące.
Oto przykład, dlaczego pisanie kaczek jest złe, nie wiedząc, kiedy jest niebezpieczne. Na przykład: Oto kod Pythona (być może pomijający właściwe wcięcia), zauważ, że takiej sytuacji można uniknąć, zajmując się funkcjami isinstance i issclassof, aby upewnić się, że kiedy naprawdę potrzebujesz kaczki, nie dostaniesz bomby.
class Bomb:
def __init__(self):
""
def talk(self):
self.explode()
def explode(self):
print "BOOM!, The bomb explodes."
class Duck:
def __init__(self):
""
def talk(self):
print "I am a duck, I will not blow up if you ask me to talk."
class Kid:
kids_duck = None
def __init__(self):
print "Kid comes around a corner and asks you for money so he could buy a duck."
def takeDuck(self, duck):
self.kids_duck = duck
print "The kid accepts the duck, and happily skips along"
def doYourThing(self):
print "The kid tries to get the duck to talk"
self.kids_duck.talk()
myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()
class EvilDuck(Duck)
i zastąpić talk (). Lub bardziej prawdopodobne, class ChineseCancerDuck(Duck)
z nieprzyjemnym efektem ubocznym, który pojawia się dopiero po latach. Lepiej byłoby po prostu nadzorować swoje dziecko (i dokładnie testować jej zabawki :)
__file__
atrybut (zwykle używany do identyfikowania obiektów podobnych do plików) i oznaczający coś innego.
isinstance(o, str)
Myślę, że fajną rzeczą w używaniu dynamicznego języka takiego jak Python jest to, że naprawdę nie powinieneś sprawdzać czegoś takiego.
Po prostu wywołałbym wymagane metody na twoim obiekcie i złapał AttributeError
. Później pozwoli ci to wywoływać swoje metody z innymi (pozornie niezwiązanymi) obiektami w celu wykonania różnych zadań, takich jak wyśmiewanie obiektu do testowania.
Używałem tego bardzo często podczas pobierania danych z Internetu, za pomocą urllib2.urlopen()
których zwracany jest obiekt typu plik . To z kolei można przekazać do prawie każdej metody, która czyta z pliku, ponieważ implementuje tę samą read()
metodę, co prawdziwy plik.
Ale jestem pewien, że jest czas i miejsce do korzystania isinstance()
, w przeciwnym razie prawdopodobnie nie byłoby tam :)
W przypadku bardziej złożonych walidacji typów podoba mi się podejście walidatora typeguard oparte na adnotacjach typu python:
from typeguard import check_type
from typing import List
try:
check_type('mylist', [1, 2], List[int])
except TypeError as e:
print(e)
Możesz przeprowadzać bardzo złożone weryfikacje w bardzo czysty i czytelny sposób.
check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo)
Możesz sprawdzić typ zmiennej, używając __name__ typu.
Dawny:
>>> a = [1,2,3,4]
>>> b = 1
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'
Do Hugo:
Prawdopodobnie masz na myśli list
raczej niż array
, ale wskazuje to na cały problem ze sprawdzaniem typu - nie chcesz wiedzieć, czy przedmiotowy obiekt jest listą, chcesz wiedzieć, czy jest to jakaś sekwencja, czy pojedynczy obiekt. Spróbuj więc użyć go jak sekwencji.
Powiedz, że chcesz dodać obiekt do istniejącej sekwencji lub jeśli jest to sekwencja obiektów, dodaj je wszystkie
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
Jedna sztuczka polega na tym, jeśli pracujesz z ciągami i / lub sekwencjami ciągów - to podchwytliwe, ponieważ ciąg jest często uważany za pojedynczy obiekt, ale jest to również ciąg znaków. Gorzej, ponieważ tak naprawdę jest to ciąg ciągów o jednej długości.
Zwykle wybieram takie zaprojektowanie interfejsu API, aby akceptował tylko jedną wartość lub sekwencję - to ułatwia. W [ ]
razie potrzeby nie jest trudno obliczyć wartość pojedynczą, gdy ją przekażesz.
(Chociaż może to powodować błędy w łańcuchach, ponieważ wyglądają jak (są) sekwencjami.)
Prostym sposobem sprawdzenia typu jest porównanie go z czymś, kogo znasz.
>>> a = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True
Myślę, że najlepszym sposobem jest dobre wpisanie zmiennych. Możesz to zrobić, korzystając z biblioteki „pisania”.
Przykład:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313
) `
Możesz sprawdzić w poniższym wierszu, aby sprawdzić, jaki typ znaku jest podana wartość:
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)