Mam zmienną x
i chcę wiedzieć, czy wskazuje ona na funkcję, czy nie.
Miałem nadzieję, że uda mi się zrobić coś takiego:
>>> isinstance(x, function)
Ale to daje mi:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'function' is not defined
Wybrałem to dlatego, że
>>> type(x)
<type 'function'>
insepct.getsource
na różnych obiektach, i nie ma znaczenia, czy obiekt można wywoływać, ale czy może to dać „funkcję”type(obj)
. Ponieważ go tu doprowadziłem, powiedziałbym, że komentarz AsTeR był najbardziej przydatną odpowiedzią (dla mnie). W Internecie znajduje się wiele innych miejsc do odkrycia__call__
lubcallable
.Odpowiedzi:
Jeśli dotyczy to Python 2.x lub Python 3.2+, możesz także użyć
callable()
. Kiedyś był przestarzały, ale teraz jest nieaktualny, więc możesz go użyć ponownie. Możesz przeczytać dyskusję tutaj: http://bugs.python.org/issue10518 . Możesz to zrobić za pomocą:Jeśli dotyczy to języka Python 3.x, ale wcześniejszego niż 3.2, sprawdź, czy obiekt ma
__call__
atrybut. Możesz to zrobić za pomocą:Często sugerowane
types.FunctionTypes
podejście jest niepoprawne, ponieważ nie obejmuje wielu przypadków, które prawdopodobnie powinny zostać przekazane, tak jak w przypadku wbudowanych:Właściwym sposobem sprawdzenia właściwości obiektów typu kaczka jest zapytanie ich, czy kwakają, a nie sprawdzenie, czy mieszczą się w pojemniku wielkości kaczki. Nie używaj,
types.FunctionType
chyba że masz bardzo konkretne pojęcie o funkcji.źródło
Wbudowane typy, które nie mają konstruktorów we wbudowanej przestrzeni nazw (np. Funkcje, generatory, metody) znajdują się w
types
module. Można używaćtypes.FunctionType
wisinstance
rozmowy:Zauważ, że używa to bardzo specyficznego pojęcia „funkcji”, które zwykle nie jest tym, czego potrzebujesz. Na przykład odrzuca
zip
(technicznie klasę):open
(wbudowane funkcje mają inny typ):oraz
random.shuffle
(technicznie metoda ukrytejrandom.Random
instancji):Jeśli robisz coś specyficznego dla
types.FunctionType
instancji, np. Dekompilujesz ich kod bajtowy lub sprawdzasz zmienne zamknięcia, użyjtypes.FunctionType
, ale jeśli potrzebujesz tylko obiektu, który będzie można wywoływać jak funkcję, użyjcallable
.źródło
isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial))
lub sprawdzanief.func
w takim przypadku.@foo
, którego mogę używać zarówno jako, jak@foo
i jako@foo(some_parameter)
. Następnie musi sprawdzić, co się nazywa, np. Funkcję dekorowania (pierwszy przypadek) lub parametr (drugi przypadek, w którym musi zwrócić kolejny dekorator).types.BuiltinFunctionType
jest także rodzajem („normalnych”) wbudowanych metod , na które prawdopodobnie nie chcesz pozwolić, jeśli nie jedzieszcallable
trasą.Od wersji Python 2.1 możesz importować
isfunction
zinspect
modułu.źródło
open
ihasattr
.inspect.isfunction
: „Zwróć wartość true, jeśli obiekt jest funkcją zdefiniowaną przez użytkownika”.Przyjęta odpowiedź była w chwili, gdy została uznana za poprawną. Jak się okazuje, nie ma substytutu dla
callable()
, który powraca w Pythonie 3.2: W szczególnościcallable()
sprawdzatp_call
pole obiektu badanego. Nie ma zwykłego odpowiednika w języku Python. Większość sugerowanych testów jest poprawna przez większość czasu:Możemy wrzucić do tego klucz małpki, usuwając go
__call__
z klasy. Żeby było wyjątkowo ekscytująco, dodaj fałszywkę__call__
do instancji!Zauważ, że tak naprawdę nie można wywołać:
callable()
zwraca poprawny wynik:Ale
hasattr
jest źle :can_o_spam
ma przecież ten atrybut; nie jest po prostu używany podczas wywoływania instancji.Jeszcze bardziej subtelne,
isinstance()
również robi to źle:Ponieważ użyliśmy tego sprawdzenia wcześniej, a później usunęliśmy metodę,
abc.ABCMeta
buforuje wynik. Prawdopodobnie jest to błądabc.ABCMeta
. Powiedział, że tam naprawdę nie możliwy sposób to mogło wytworzyć dokładniejsze wyniki niż wynik niż przy użyciucallable()
siebie, ponieważtypeobject->tp_call
metoda gniazdo nie jest dostępny w jakikolwiek inny sposób.Po prostu użyj
callable()
źródło
hasattr(o, '__call__')
podejścia i dlaczegocallable()
, jeśli jest dostępna, jest lepsza.Poniższe powinno zwrócić wartość logiczną:
źródło
Narzędzie Python 2to3 ( http://docs.python.org/dev/library/2to3.html ) sugeruje:
Wygląda na to, że wybrano tę
hasattr(x, '__call__')
metodę zamiast metody z powodu http://bugs.python.org/issue7006 .źródło
callable()
py3.3: bugs.python.org/issue10518#msg122309callable(x)
będzie return true jeśli obiekt przeszedł można nazwać w Pythonie, ale funkcja nie istnieje w Pythonie 3.0, a właściwie mówiąc nie rozróżniają:Dostaniesz
<class 'A'> True
i<type function> True
jako wynik.isinstance
działa doskonale, aby określić, czy coś jest funkcją (spróbujisinstance(b, types.FunctionType)
); jeśli naprawdę chcesz wiedzieć, czy coś można nazwać, możesz użyćhasattr(b, '__call__')
lub po prostu spróbować.To oczywiście nie powie ci, czy jest to możliwe do wywołania, ale rzuca a,
TypeError
kiedy się wykonuje, czy też nie. To może nie mieć znaczenia dla ciebie.źródło
Jeśli chcesz wykryć wszystko, co syntaktycznie wygląda jak funkcja: funkcja, metoda, wbudowane fun / met, lambda ... ale wyklucz obiekty, które można wywoływać (obiekty ze
__call__
zdefiniowaną metodą), spróbuj tego:Porównałem to z kodem
is*()
kontroli winspect
module i powyższe wyrażenie jest znacznie bardziej kompletne, szczególnie jeśli Twoim celem jest odfiltrowanie jakichkolwiek funkcji lub wykrycie regularnych właściwości obiektu.źródło
types
modułu. Testowałemmake_stemmer()
fabrykę, która czasami zwraca funkcję, a czasemStemmer
instancję na żądanie i musiałem wykryć różnicę.Spróbuj użyć
callable(x)
.źródło
Jeśli się nauczyłeś
C++
, musisz znaćfunction object
lubfunctor
oznacza dowolny obiekt, który możebe called as if it is a function
.W C ++
an ordinary function
jest obiektem funkcji, podobnie jak wskaźnik funkcji; bardziej ogólnie, więc jest to obiekt klasy, który definiujeoperator()
. W C ++ 11 i nowszychthe lambda expression
jest tofunctor
samo.Podobieństwo w Pythonie
functors
to wszystkocallable
.An ordinary function
może być wywoływany,a lambda expression
może być wywoływany,functional.partial
może być wywoływany, przypadkiclass with a __call__() method
mogą być wywoływane.Ok, wróć do pytania:
I have a variable, x, and I want to know whether it is pointing to a function or not.
Następnie wykonuję eksperyment przy użyciu następującego kodu:
Rysuję tabelę typów wywoływanych funktorów na podstawie danych.
Jak na przykład:
źródło
Jako przyjętą odpowiedź John Feminella stwierdził, że:
Chociaż istnieją dwie biblioteki do ścisłego rozróżnienia funkcji, rysuję wyczerpującą, porównywalną tabelę:
8,9 typy - Dynamiczne tworzenie typów i nazwy dla typów wbudowanych - Dokumentacja Python 3.7.0
30,13. inspekcja - inspekcja obiektów aktywnych - dokumentacja Python 3.7.0
„Pisanie kaczką” jest preferowanym rozwiązaniem ogólnego zastosowania:
Jeśli chodzi o funkcję wbudowaną
Po przejściu jeszcze jednego kroku, aby sprawdzić, czy funkcja wbudowana lub funkcja zdefiniowana przez użytkownika
Ustal, czy
builtin function
Podsumowanie
Zatrudniamy
callable
rodzaju kaczki sprawdzanie funkcjiZastosowanie
types.BuiltinFunctionType
jeśli dalej określone zapotrzebowanie.źródło
Funkcja to tylko klasa z
__call__
metodą, więc możesz to zrobićNa przykład:
Jest to „najlepszy” sposób na zrobienie tego, ale w zależności od tego, dlaczego musisz wiedzieć, czy jest to możliwe do wywołania, czy notatki, możesz po prostu umieścić to w bloku try / execpt:
Można argumentować, jeśli próba / wyjątek jest bardziej Python'y niż robienie
if hasattr(x, '__call__'): x()
. Powiedziałbym, żehasattr
jest bardziej dokładny, ponieważ przypadkowo nie złapie złego TypeError, na przykład:źródło
Oto kilka innych sposobów:
Oto jak wymyśliłem drugi:
źródło
Zamiast sprawdzania
'__call__'
(co nie jest wyłącznie do funkcji), można sprawdzić, czy funkcja zdefiniowana przez użytkownika posiada atrybutyfunc_name
,func_doc
itp to nie działa dla metod.Innym sposobem sprawdzenia jest użycie
isfunction()
metody zinspect
modułu.Aby sprawdzić, czy obiekt jest metodą, użyj
inspect.ismethod()
źródło
Ponieważ klasy mają również
__call__
metodę, polecam inne rozwiązanie:źródło
hasattr(obj, '__call__')
jest niejednoznaczna.Zauważ, że klasy Python są również wywoływalne.
Aby uzyskać funkcje (a przez funkcje rozumiemy standardowe funkcje i lambdy) użyj:
źródło
Jakakolwiek funkcja jest klasą, możesz wziąć nazwę klasy instancji x i porównać:
źródło
Rozwiązania wykorzystujące
hasattr(obj, '__call__')
icallable(.)
wspomniane w niektórych odpowiedziach mają główną wadę: oba zwracają się równieżTrue
do klas i instancji klas za pomocą__call__()
metody. Na przykład.Jednym z prawidłowych sposobów sprawdzenia, czy obiekt jest funkcją zdefiniowaną przez użytkownika (i nic poza tym), jest użycie
isfunction(.)
:Jeśli chcesz sprawdzić inne typy, spójrz na inspekcja - Sprawdź obiekty na żywo .
źródło
Dokładny kontroler funkcji
callable to bardzo dobre rozwiązanie. Chciałem jednak potraktować to w odwrotny sposób niż John Feminella. Zamiast traktować to w ten sposób, mówiąc:
Potraktujemy to w następujący sposób:
Jak moglibyśmy to wdrożyć
Moduł „typów” ma wiele klas do wykrywania funkcji, z których najbardziej użyteczne są typy , ale istnieje również wiele innych, takich jak typ metody, typ wbudowany i typ lambda. Rozważymy również obiekt „funkools.partial” jako funkcję.
Prostym sposobem sprawdzenia, czy jest to funkcja, jest użycie warunku isinstance na wszystkich tych typach. Wcześniej chciałem stworzyć klasę bazową, która dziedziczy po wszystkich powyższych, ale nie jestem w stanie tego zrobić, ponieważ Python nie pozwala nam dziedziczyć po niektórych z powyższych klas.
Oto tabela klas, które mogą klasyfikować funkcje:
Powyższa tabela funkcji autorstwa kinght- 金
Kod, który to robi
To jest kod, który wykonuje całą pracę opisaną powyżej.
Jedynym fałszem było is_function (częściowe), ponieważ to jest klasa, a nie funkcja, i to są dokładnie funkcje, a nie klasy. Oto podgląd, z którego możesz wypróbować kod.
Wniosek
callable (obj) jest preferowaną metodą sprawdzania, czy obiekt jest funkcją, jeśli chcesz przejść przez pisanie kaczką ponad absolutami .
Nasza niestandardowa funkcja is_funkcja (obj) , być może z niektórymi zmianami jest preferowaną metodą sprawdzania, czy obiekt jest funkcją, jeśli nie policzymy instancji klasy wywoływalnej jako funkcji, ale tylko funkcje zdefiniowane jako wbudowane lub z lambda , def lub częściowe .
I myślę, że to wszystko podsumowuje. Miłego dnia!
źródło
W Python3 wymyśliłem,
type (f) == type (lambda x:x)
który daje,True
jeślif
jest funkcją, aFalse
jeśli nie jest. Ale myślę, że wolęisinstance (f, types.FunctionType)
, co wydaje się mniej ad hoc. Chciałem to zrobićtype (f) is function
, ale to nie działa.źródło
Po poprzednich odpowiedziach wymyśliłem to:
źródło
Możesz spróbować:
lub nawet coś bardziej dziwnego:
źródło
Jeśli kod będzie kontynuował wykonywanie połączenia, jeśli wartość jest możliwa do wywołania, po prostu wykonaj połączenie i złap
TypeError
.źródło
x
.Poniżej znajduje się „sposób powtórzenia”, aby to sprawdzić. Działa również z lambda.
źródło
To działa dla mnie:
źródło
"<type 'function'>"
, dla liczby całkowitej,"<type 'int'>"
więc nie rozumiem, jak to działa dla ciebie: /open
funkcję należy uznać za funkcję?str(type(open))
daje<class 'builtin_function_or_method'>
w Pythonie 3.