Bagaimana cara mendeteksi apakah variabel Python adalah suatu fungsi?

686

Saya punya variabel,, xdan saya ingin tahu apakah itu menunjuk ke suatu fungsi atau tidak.

Saya berharap bisa melakukan sesuatu seperti:

>>> isinstance(x, function)

Tapi itu memberi saya:

Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'function' is not defined

Alasan saya memilih itu karena

>>> type(x)
<type 'function'>
Daniel H
sumber
37
Saya tertekan oleh jumlah jawaban yang mengatasi masalah dengan mencari beberapa atribut panggilan atau fungsi yang dapat dipanggil ... Cara yang bersih adalah tentang tipe (a) == types.functionType seperti yang disarankan oleh @ryan
AsTeR
44
@ ASTeR Cara yang tepat untuk memeriksa properti dari objek yang diketik bebek adalah dengan menanyakannya apakah mereka berdetak, tidak melihat apakah mereka muat dalam wadah berukuran bebek. Pendekatan "bandingkan secara langsung" akan memberikan jawaban yang salah untuk banyak fungsi, seperti bawaan.
John Feminella
3
@ JohnFeminella Sementara saya setuju dengan Anda pada prinsipnya. OP tidak bertanya apakah itu bisa dipanggil, hanya apakah itu sebuah fungsi. Mungkin bisa dikatakan bahwa dia membutuhkan perbedaan antara, misalnya, fungsi dan kelas?
McKay
3
Untuk tujuan saya, saya datang ke sini karena saya ingin menggunakan insepct.getsourceberbagai objek, dan sebenarnya tidak masalah apakah objek itu dapat dipanggil tetapi apakah itu sesuatu yang akan memberikan 'fungsi' untuk type(obj). Karena google membawa saya ke sini, saya akan mengatakan komentar AsTeR adalah jawaban yang paling berguna (untuk saya). Ada banyak tempat lain di internet bagi orang untuk menemukan __call__atau callable.
tsbertalan
4
@ ASTeR Ini adalah types.FunctionType, dengan huruf kapital F.
Ben Mares

Jawaban:

891

Jika ini untuk Python 2.x atau untuk Python 3.2+, Anda juga dapat menggunakan callable(). Dulu ditinggalkan, tetapi sekarang tidak ditinggalkan, sehingga Anda dapat menggunakannya lagi. Anda dapat membaca diskusi di sini: http://bugs.python.org/issue10518 . Anda dapat melakukan ini dengan:

callable(obj)

Jika ini untuk Python 3.x tetapi sebelum 3.2, periksa apakah objek memiliki __call__atribut. Anda dapat melakukan ini dengan:

hasattr(obj, '__call__')

Pendekatan yang sering disarankan types.FunctionTypestidak benar karena gagal untuk menutupi banyak kasus yang Anda mungkin ingin lulus, seperti dengan builtin:

>>> isinstance(open, types.FunctionType)
False

>>> callable(open)
True

Cara yang tepat untuk memeriksa properti dari objek yang diketik bebek adalah dengan menanyakannya apakah mereka berdetak, tidak melihat apakah mereka muat dalam wadah berukuran bebek. Jangan gunakan types.FunctionTypekecuali Anda memiliki ide yang sangat spesifik tentang apa fungsi itu.

John Feminella
sumber
73
Ini juga tidak akan memberi tahu Anda apakah itu suatu fungsi - hanya jika itu bisa dipanggil.
Chris B.
23
Tergantung pada aplikasi apakah perbedaan itu penting atau tidak; Saya menduga Anda benar bahwa itu bukan untuk pertanyaan awal, tetapi itu masih jauh dari pasti.
Chris B.
5
Kelas dapat memiliki fungsi panggilan yang melekat padanya. Jadi ini jelas bukan metode yang baik untuk membedakan. Metode Ryan lebih baik.
Brian Bruggeman
43
konsep "mengetik bebek" membuat ini jawaban yang lebih baik, misalnya "apa bedanya jika itu berfungsi selama itu berperilaku seperti itu?"
jcomeau_ictx
8
Ada usecases di mana perbedaan antara callable dan fungsi sangat penting, misalnya saat menulis dekorator (lihat komentar saya pada jawaban Ryan).
Turion
267

Tipe builtin yang tidak memiliki konstruktor di namespace built-in (mis. Fungsi, generator, metode) ada di typesmodul. Anda dapat menggunakan types.FunctionTypedalam isinstancepanggilan:

In [1]: import types
In [2]: types.FunctionType
Out[2]: <type 'function'>
In [3]: def f(): pass
   ...:
In [4]: isinstance(f, types.FunctionType)
Out[4]: True
In [5]: isinstance(lambda x : None, types.FunctionType)
Out[5]: True

Perhatikan bahwa ini menggunakan gagasan "fungsi" yang sangat spesifik yang biasanya bukan yang Anda butuhkan. Misalnya, ia menolak zip(secara teknis sebuah kelas):

>>> type(zip), isinstance(zip, types.FunctionType)
(<class 'type'>, False)

open (fungsi bawaan memiliki tipe yang berbeda):

>>> type(open), isinstance(open, types.FunctionType)
(<class 'builtin_function_or_method'>, False)

dan random.shuffle(secara teknis metode random.Randominstance tersembunyi ):

>>> type(random.shuffle), isinstance(random.shuffle, types.FunctionType)
(<class 'method'>, False)

Jika Anda melakukan sesuatu yang spesifik untuk types.FunctionTypeinstance, seperti mendekompilasi bytecode mereka atau memeriksa variabel closure, gunakan types.FunctionType, tetapi jika Anda hanya perlu objek yang dapat dipanggil seperti fungsi, gunakan callable.

Ryan
sumber
5
+1 menjawab pertanyaan. Namun, mencoba menebak apakah suatu objek adalah fungsi - atau bahkan jika itu adalah objek yang dapat dipanggil - biasanya merupakan kesalahan. Tanpa informasi lebih lanjut dari OP sulit untuk mengabaikan itu dari tangan tentu saja, tapi masih ...
bobince
47
Ini sebenarnya akan mengembalikan False untuk fungsi builtin, seperti 'terbuka' untuk misalnya. Jadi untuk lebih spesifik Anda harus menggunakan isinstance (f, (types.FunctionType, types.BuiltinFunctionType)). Dan tentu saja jika Anda benar-benar ingin hanya fungsi, bukan callable atau metode
Lukasz Korzybski
5
@ ŁukaszKorzybski dan untuk lebih berhati-hati ... Anda juga harus memeriksa functools.partial: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial))atau memeriksa f.funcdalam kasus seperti itu.
estani
3
@Bobince, bagaimana dengan usecase ini: Saya ingin menulis dekorator @fooyang dapat saya gunakan sebagai @foodan sebagai @foo(some_parameter). Kemudian perlu memeriksa apa yang dipanggil dengan, misalnya fungsi untuk menghias (kasus pertama) atau parameter (kasus kedua, di mana ia perlu mengembalikan dekorator lebih lanjut).
Turion
types.BuiltinFunctionTypejuga jenis ( "normal") built-in metode , yang Anda mungkin tidak ingin mengizinkan, jika Anda tidak akan dengan callablerute.
user2357112 mendukung Monica
92

Karena Python 2.1 Anda dapat mengimpor isfunctiondari inspectmodul.

>>> from inspect import isfunction
>>> def f(): pass
>>> isfunction(f)
True
>>> isfunction(lambda x: x)
True
Paolo
sumber
3
Bagus, tetapi sepertinya mengembalikan False untuk fungsi builtin seperti opendan hasattr.
Zecc
12
@Zecc isbuiltin untuk itu.
Paolo
13
Lihat inspect.isfunctiondocstring: "Kembalikan benar jika objek adalah fungsi yang ditentukan pengguna."
Mark Mikofski
4
Perhatikan bahwa 'isfungsi' tidak mengenali fungsi functool.partial.
ishmael
74

Jawaban yang diterima adalah pada saat itu ditawarkan dianggap benar. Ternyata, ada ada pengganti untuk callable(), yang kembali Python 3.2: Secara khusus, callable()pemeriksaan yang tp_callbidang objek yang sedang diuji. Tidak ada yang setara dengan Python. Sebagian besar tes yang disarankan sebagian besar benar:

>>> class Spam(object):
...     def __call__(self):
...         return 'OK'
>>> can_o_spam = Spam()


>>> can_o_spam()
'OK'
>>> callable(can_o_spam)
True
>>> hasattr(can_o_spam, '__call__')
True
>>> import collections
>>> isinstance(can_o_spam, collections.Callable)
True

Kita bisa melemparkan kunci inggris ke dalam ini dengan menghapus __call__dari kelas. Dan hanya untuk menjaga hal-hal ekstra menarik, tambahkan yang palsu __call__ke instance!

>>> del Spam.__call__
>>> can_o_spam.__call__ = lambda *args: 'OK?'

Perhatikan ini sebenarnya tidak bisa dipanggil:

>>> can_o_spam()
Traceback (most recent call last):
  ...
TypeError: 'Spam' object is not callable

callable() mengembalikan hasil yang benar:

>>> callable(can_o_spam)
False

Tapi hasattritu salah :

>>> hasattr(can_o_spam, '__call__')
True

can_o_spammemang memiliki atribut itu; itu tidak digunakan saat memanggil instance.

Bahkan lebih halus, ini isinstance()juga salah:

>>> isinstance(can_o_spam, collections.Callable)
True

Karena kami menggunakan pemeriksaan ini sebelumnya dan kemudian menghapus metode, abc.ABCMeta cache hasilnya. Bisa dibilang ini adalah bug di abc.ABCMeta. Yang mengatakan, benar-benar tidak ada cara yang mungkin bisa menghasilkan hasil yang lebih akurat daripada hasilnya daripada dengan menggunakan callable()sendiri, karena typeobject->tp_call metode slot tidak dapat diakses dengan cara lain.

Gunakan saja callable()

SingleNegationElimination
sumber
5
Ilustrasi yang luar biasa tentang perangkap hasattr(o, '__call__')pendekatan dan mengapa callable(), jika tersedia, lebih unggul.
MestreLion
39

Yang berikut harus mengembalikan boolean:

callable(x)
Nikhil Chelliah
sumber
1
Itu memecahkan masalahnya, tetapi dia masih menciptakan sebuah misteri: jika x adalah fungsi kelas 'di modul builtin , dan bantuan (x .__ class__) menjelaskan "fungsi kelas", mengapa "fungsi" tampaknya "tidak didefinisikan"?
Ken
1
"function" bukan kata kunci atau tipe bawaan. Jenis fungsi didefinisikan dalam modul "types", sebagai "types.FunctionType"
Chris B.
19

callable(x) akan mengembalikan true jika objek yang diteruskan dapat dipanggil dengan Python, tetapi fungsi tidak ada di Python 3.0, dan berbicara dengan benar tidak akan membedakan antara:

class A(object):
    def __call__(self):
        return 'Foo'

def B():
    return 'Bar'

a = A()
b = B

print type(a), callable(a)
print type(b), callable(b)

Anda akan mendapatkan <class 'A'> Truedan <type function> Truesebagai output.

isinstancebekerja dengan sangat baik untuk menentukan apakah ada fungsi (coba isinstance(b, types.FunctionType)); jika Anda benar-benar tertarik mengetahui apakah sesuatu dapat dipanggil, Anda dapat menggunakan hasattr(b, '__call__')atau hanya mencobanya.

test_as_func = True
try:
    b()
except TypeError:
    test_as_func = False
except:
    pass

Ini, tentu saja, tidak akan memberi tahu Anda apakah itu bisa dipanggil tetapi melempar TypeErrorketika dijalankan, atau tidak bisa dipanggil di tempat pertama. Itu mungkin tidak masalah bagi Anda.

Chris B.
sumber
8
Menyebutnya adalah ide yang buruk. Bagaimana jika ia memiliki efek samping, atau sebenarnya melakukan sesuatu tetapi membutuhkan waktu yang sangat lama?
penanggung jawab
@asmeurer - Kenapa lagi Anda perlu tahu apakah itu berfungsi jika Anda tidak memanggilnya?
detly
1
@detly: untuk debugging saya secara teratur ingin mencetak semua variabel dalam suatu objek, metode ini biasanya tidak berguna bagi saya jadi saya tidak ingin menjalankannya. Pada akhirnya saya hanya mendaftar setiap properti yang tidak dapat dipanggil dengan nilai yang sesuai :)
Wolph
2
Hanya karena Anda tidak meneleponnya bukan berarti itu tidak dipanggil. Mungkin Anda melakukan pengiriman.
penanggung jawab
4
Ada masalah besar dengan menggunakan pengecualian untuk mengetahui apakah itu bisa dipanggil atau tidak; bagaimana jika itu bisa dipanggil, tetapi memanggilnya menimbulkan pengecualian yang Anda cari? Anda berdua akan diam-diam mengabaikan kesalahan dan salah mendiagnosis apakah itu bisa dipanggil. Saat Anda menggunakan EAFP Anda benar-benar ingin menghindari terlalu banyak mencoba, tetapi tidak ada cara untuk melakukannya untuk use case ini.
Ben
15

Jika Anda ingin mendeteksi segala sesuatu yang secara sintaksis tampak seperti fungsi: fungsi, metode, kesenangan bawaan / met, lambda ... tetapi mengecualikan objek yang dapat dipanggil (objek dengan __call__metode yang ditentukan), lalu coba yang ini:

import types
isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))

Saya membandingkan ini dengan kode is*()cek dalam inspectmodul dan ungkapan di atas jauh lebih lengkap, terutama jika tujuan Anda memfilter fungsi apa pun atau mendeteksi properti biasa dari suatu objek.

Marcin Wojnarski
sumber
Terima kasih telah mengarahkan saya ke typesmodul. Saya sedang menguji sebuah make_stemmer()pabrik yang kadang-kadang mengembalikan fungsi dan kadang-kadang Stemmerinstance yang bisa dipanggil , dan saya perlu mendeteksi perbedaannya.
hobs
7

Coba gunakan callable(x).

maxyfc
sumber
6

Jika Anda telah belajar C++, Anda harus terbiasa dengan , function objectatau functorberarti benda apa pun yang bisa be called as if it is a function.

Dalam C ++, an ordinary functionadalah objek fungsi, dan begitu juga pointer fungsi; lebih umum, begitu juga objek kelas yang mendefinisikan operator(). Dalam C ++ 11 dan lebih besar, the lambda expressionadalah functorjuga.

Kesamaan, dalam Python, itu functorssemua callable. An ordinary functionbisa dipanggil, a lambda expressionbisa dipanggil, functional.partialbisa dipanggil, contoh class with a __call__() methodbisa dipanggil.


Oke, kembali ke pertanyaan: I have a variable, x, and I want to know whether it is pointing to a function or not.

Jika Anda ingin menilai cuaca objek bertindak seperti fungsi, maka callablemetode yang disarankan oleh @John Feminellaok.

Jika Anda ingin judge whether a object is just an ordinary function or not(bukan instance kelas yang bisa dipanggil, atau ekspresi lambda), maka yang xtypes.XXXdisarankan @Ryanadalah pilihan yang lebih baik.

Lalu saya melakukan percobaan menggunakan kode itu:

#!/usr/bin/python3
# 2017.12.10 14:25:01 CST
# 2017.12.10 15:54:19 CST

import functools
import types
import pprint

Tentukan kelas dan fungsi biasa.

class A():
    def __call__(self, a,b):
        print(a,b)
    def func1(self, a, b):
        print("[classfunction]:", a, b)
    @classmethod
    def func2(cls, a,b):
        print("[classmethod]:", a, b)
    @staticmethod
    def func3(a,b):
        print("[staticmethod]:", a, b)

def func(a,b):
    print("[function]", a,b)

Tentukan functors:

#(1.1) built-in function
builtins_func = open
#(1.2) ordinary function
ordinary_func = func
#(1.3) lambda expression
lambda_func  = lambda a : func(a,4)
#(1.4) functools.partial
partial_func = functools.partial(func, b=4)

#(2.1) callable class instance
class_callable_instance = A()
#(2.2) ordinary class function
class_ordinary_func = A.func1
#(2.3) bound class method
class_bound_method = A.func2
#(2.4) static class method
class_static_func = A.func3

Tentukan daftar fungsi dan daftar tipe:

## list of functors
xfuncs = [builtins_func, ordinary_func, lambda_func, partial_func, class_callable_instance, class_ordinary_func, class_bound_method, class_static_func]
## list of type
xtypes = [types.BuiltinFunctionType, types.FunctionType, types.MethodType, types.LambdaType, functools.partial]

Menilai apakah functor dapat dipanggil. Seperti yang Anda lihat, mereka semua bisa dipanggil.

res = [callable(xfunc)  for xfunc in xfuncs]
print("functors callable:")
print(res)

"""
functors callable:
[True, True, True, True, True, True, True, True]
"""

Menilai tipe functor (types.XXX). Maka jenis-jenis fungsi tidak semuanya sama.

res = [[isinstance(xfunc, xtype) for xtype in xtypes] for xfunc in xfuncs]

## output the result
print("functors' types")
for (row, xfunc) in zip(res, xfuncs):
    print(row, xfunc)

"""
functors' types
[True, False, False, False, False] <built-in function open>
[False, True, False, True, False] <function func at 0x7f1b5203e048>
[False, True, False, True, False] <function <lambda> at 0x7f1b5081fd08>
[False, False, False, False, True] functools.partial(<function func at 0x7f1b5203e048>, b=4)
[False, False, False, False, False] <__main__.A object at 0x7f1b50870cc0>
[False, True, False, True, False] <function A.func1 at 0x7f1b5081fb70>
[False, False, True, False, False] <bound method A.func2 of <class '__main__.A'>>
[False, True, False, True, False] <function A.func3 at 0x7f1b5081fc80>
"""

Saya menggambar tabel jenis functor yang bisa dipanggil menggunakan data.

masukkan deskripsi gambar di sini

Kemudian Anda dapat memilih jenis fungsi yang sesuai.

seperti:

def func(a,b):
    print("[function]", a,b)

>>> callable(func)
True
>>> isinstance(func,  types.FunctionType)
True
>>> isinstance(func, (types.BuiltinFunctionType, types.FunctionType, functools.partial))
True
>>> 
>>> isinstance(func, (types.MethodType, functools.partial))
False
Kinght 金
sumber
6

Sebagai jawaban yang diterima, John Feminella menyatakan bahwa:

Cara yang tepat untuk memeriksa properti dari objek yang diketik bebek adalah dengan menanyakannya apakah mereka berdetak, tidak melihat apakah mereka muat dalam wadah berukuran bebek. Pendekatan "bandingkan secara langsung" akan memberikan jawaban yang salah untuk banyak fungsi, seperti bawaan.

Meskipun, ada dua lib untuk membedakan fungsi secara ketat, saya menggambar tabel sebanding yang lengkap:

8.9. types - Penciptaan tipe dinamis dan nama untuk tipe bawaan - Dokumentasi Python 3.7.0

30.13. inspect - Periksa objek langsung - Dokumentasi Python 3.7.0

#import inspect             #import types
['isabstract',
 'isasyncgen',              'AsyncGeneratorType',
 'isasyncgenfunction', 
 'isawaitable',
 'isbuiltin',               'BuiltinFunctionType',
                            'BuiltinMethodType',
 'isclass',
 'iscode',                  'CodeType',
 'iscoroutine',             'CoroutineType',
 'iscoroutinefunction',
 'isdatadescriptor',
 'isframe',                 'FrameType',
 'isfunction',              'FunctionType',
                            'LambdaType',
                            'MethodType',
 'isgenerator',             'GeneratorType',
 'isgeneratorfunction',
 'ismethod',
 'ismethoddescriptor',
 'ismodule',                'ModuleType',        
 'isroutine',            
 'istraceback',             'TracebackType'
                            'MappingProxyType',
]

"Bebek mengetik" adalah solusi yang lebih disukai untuk tujuan umum:

def detect_function(obj):
    return hasattr(obj,"__call__")

In [26]: detect_function(detect_function)
Out[26]: True
In [27]: callable(detect_function)
Out[27]: True

Adapun fungsi builtins

In [43]: callable(hasattr)
Out[43]: True

Ketika melangkah satu langkah lagi untuk memeriksa apakah fungsi builtin atau fungsi yang ditentukan pengguna

#check inspect.isfunction and type.FunctionType
In [46]: inspect.isfunction(detect_function)
Out[46]: True
In [47]: inspect.isfunction(hasattr)
Out[47]: False
In [48]: isinstance(detect_function, types.FunctionType)
Out[48]: True
In [49]: isinstance(getattr, types.FunctionType)
Out[49]: False
#so they both just applied to judge the user-definded

Tentukan apakah builtin function

In [50]: isinstance(getattr, types.BuiltinFunctionType)
Out[50]: True
In [51]: isinstance(detect_function, types.BuiltinFunctionType)
Out[51]: False

Ringkasan

Dipekerjakan callableuntuk tipe bebek memeriksa fungsi,
Gunakan types.BuiltinFunctionTypejika Anda memiliki permintaan lebih lanjut yang ditentukan.

Kalkulus
sumber
5

Fungsi hanyalah kelas dengan __call__metode, jadi Anda bisa melakukannya

hasattr(obj, '__call__')

Sebagai contoh:

>>> hasattr(x, '__call__')
True

>>> x = 2
>>> hasattr(x, '__call__')
False

Itu adalah cara "terbaik" untuk melakukannya, tetapi tergantung pada mengapa Anda perlu tahu apakah itu dapat dipanggil atau dicatat, Anda bisa memasukkannya ke dalam blok try / execpt:

try:
    x()
except TypeError:
    print "was not callable"

Ini bisa diperdebatkan jika coba / kecuali lebih Python'y daripada melakukan if hasattr(x, '__call__'): x().. Saya akan mengatakan hasattrlebih akurat, karena Anda tidak sengaja menangkap TypeError yang salah, misalnya:

>>> def x():
...     raise TypeError
... 
>>> hasattr(x, '__call__')
True # Correct
>>> try:
...     x()
... except TypeError:
...     print "x was not callable"
... 
x was not callable # Wrong!
dbr
sumber
Gunakan penanganan pengecualian untuk melindungi dari perilaku yang tidak terduga saja, tidak pernah untuk aliran logika - yang jelas bukan Pythonic.
Gotgenes
Yah, pada dasarnya hasattr melakukan getattr di blok coba / kecuali (meskipun dalam C). blog.jancewicz.net/2007/10/reflection-hasattr.html
dbr
@ dbr: Tapi hasattr lebih estetis.
Nikhil Chelliah
5

Berikut beberapa cara lain:

def isFunction1(f) :
    return type(f) == type(lambda x: x);

def isFunction2(f) :
    return 'function' in str(type(f));

Inilah cara saya menemukan yang kedua:

>>> type(lambda x: x);
<type 'function'>
>>> str(type(lambda x: x));
"<type 'function'>"
# Look Maa, function! ... I ACTUALLY told my mom about this!
Sumukh Barve
sumber
Ini bagus! Harus bekerja pada semua versi python2.x dan python3.x!
Saurav Kumar
4

Alih-alih memeriksa '__call__'(yang tidak eksklusif untuk fungsi), Anda dapat memeriksa apakah fungsi yang ditetapkan pengguna memiliki atribut func_name, func_docdll ini tidak bekerja untuk metode.

>>> def x(): pass
... 
>>> hasattr(x, 'func_name')
True

Cara lain untuk memeriksa adalah menggunakan isfunction()metode dari inspectmodul.

>>> import inspect
>>> inspect.isfunction(x)
True

Untuk memeriksa apakah suatu objek adalah metode, gunakan inspect.ismethod()

Stefan van den Akker
sumber
4

Karena kelas juga memiliki __call__metode, saya merekomendasikan solusi lain:

class A(object):
    def __init__(self):
        pass
    def __call__(self):
        print 'I am a Class'

MyClass = A()

def foo():
    pass

print hasattr(foo.__class__, 'func_name') # Returns True
print hasattr(A.__class__, 'func_name')   # Returns False as expected

print hasattr(foo, '__call__') # Returns True
print hasattr(A, '__call__')   # (!) Returns True while it is not a function
guneysus
sumber
1
setuju dengan jawaban Anda, jawaban John Feminella hasattr(obj, '__call__')ambigu.
GoingMyWay
4

Perhatikan bahwa kelas Python juga bisa dipanggil.

Untuk mendapatkan fungsi (dan fungsi, maksud kami adalah fungsi standar dan lambdas) gunakan:

import types

def is_func(obj):
    return isinstance(obj, (types.FunctionType, types.LambdaType))


def f(x):
    return x


assert is_func(f)
assert is_func(lambda x: x)
Łukasz Rogalski
sumber
2

Apa pun fungsi adalah kelas sehingga Anda dapat mengambil nama kelas instance x dan membandingkan:


if(x.__class__.__name__ == 'function'):
     print "it's a function"
Katsu
sumber
2

Solusi yang menggunakan hasattr(obj, '__call__')dan callable(.)disebutkan dalam beberapa jawaban memiliki kelemahan utama: keduanya juga kembali Trueuntuk kelas dan contoh kelas dengan __call__()metode. Misalnya.

>>> import collections
>>> Test = collections.namedtuple('Test', [])
>>> callable(Test)
True
>>> hasattr(Test, '__call__')
True

Salah satu cara yang tepat untuk memeriksa apakah suatu objek adalah fungsi yang ditentukan pengguna (dan tidak lain adalah itu) adalah dengan menggunakan isfunction(.):

>>> import inspect
>>> inspect.isfunction(Test)
False
>>> def t(): pass
>>> inspect.isfunction(t)
True

Jika Anda perlu memeriksa jenis lain, lihat inspect - Periksa objek langsung .

Gerald Senarclens de Grancy
sumber
2

Pemeriksa Fungsi Tepat

callable adalah solusi yang sangat bagus. Namun, saya ingin memperlakukan ini dengan cara yang berlawanan dari John Feminella. Alih-alih memperlakukannya seperti pepatah ini:

Cara yang tepat untuk memeriksa properti dari objek yang diketik bebek adalah dengan menanyakannya apakah mereka berdetak, tidak melihat apakah mereka muat dalam wadah berukuran bebek. Pendekatan "bandingkan secara langsung" akan memberikan jawaban yang salah untuk banyak fungsi, seperti bawaan.

Kami akan memperlakukannya seperti ini:

Cara yang tepat untuk memeriksa apakah sesuatu itu bebek adalah bukan untuk melihat apakah itu bisa dukun, melainkan untuk melihat apakah itu benar-benar bebek melalui beberapa filter, alih-alih hanya memeriksa apakah itu tampak seperti bebek dari permukaan.

Bagaimana Kami Menerapkannya

Modul 'types' memiliki banyak kelas untuk mendeteksi fungsi-fungsi, tipe-tipe yang paling berguna. Tipe Function , tetapi ada juga banyak yang lain, seperti tipe metode, tipe bawaan , dan tipe lambda. Kami juga akan menganggap objek 'functools.partial' sebagai fungsi.

Cara sederhana kita memeriksa apakah itu suatu fungsi adalah dengan menggunakan kondisi isinstance pada semua jenis ini. Sebelumnya, saya ingin membuat kelas dasar yang mewarisi dari semua di atas, tetapi saya tidak dapat melakukan itu, karena Python tidak mengizinkan kita mewarisi dari beberapa kelas di atas.

Berikut adalah tabel kelas apa yang dapat mengklasifikasikan fungsi apa:

Tabel fungsi dari kinght- 金 Di atas tabel fungsi oleh kinght- 金

Kode Yang Melakukannya

Sekarang, ini adalah kode yang melakukan semua pekerjaan yang kami jelaskan dari atas.

from types import BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType
from functools import partial

def is_function(obj):
  return isinstance(obj, (BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType, partial))

#-------------------------------------------------

def my_func():
  pass

def add_both(x, y):
  return x + y

class a:
  def b(self):
    pass

check = [

is_function(lambda x: x + x),
is_function(my_func),
is_function(a.b),
is_function(partial),
is_function(partial(add_both, 2))

]

print(check)
>>> [True, True, True, False, True]

Yang salah adalah is_function (parsial), karena itu adalah kelas, bukan fungsi, dan ini persis fungsi, bukan kelas. Ini adalah preview untuk Anda coba kode dari.

Kesimpulan

callable (obj) adalah metode yang disukai untuk memeriksa apakah suatu objek adalah fungsi jika Anda ingin pergi dengan mengetik bebek di atas absolut .

Fungsi is_function (obj) kustom kami , mungkin dengan beberapa pengeditan adalah metode yang disukai untuk memeriksa apakah suatu objek adalah fungsi jika Anda tidak menghitung instance kelas yang dapat dipanggil sebagai fungsi, tetapi hanya fungsi yang didefinisikan built-in , atau dengan lambda , def , atau sebagian .

Dan saya pikir itu membungkus semuanya. Semoga harimu menyenangkan!

Korman
sumber
1

Dalam Python3 saya datang dengan type (f) == type (lambda x:x)yang menghasilkan Trueif fadalah fungsi dan Falsejika tidak. Tapi saya rasa saya lebih suka isinstance (f, types.FunctionType), yang terasa kurang ad hoc. Saya ingin melakukannya type (f) is function, tetapi itu tidak berhasil.

Harun
sumber
0

Mengikuti balasan sebelumnya, saya datang dengan ini:

from pprint import pprint

def print_callables_of(obj):
    li = []
    for name in dir(obj):
        attr = getattr(obj, name)
        if hasattr(attr, '__call__'):
            li.append(name)
    pprint(li)
Jabba
sumber
0

Anda bisa mencoba ini:

if obj.__class__.__name__ in ['function', 'builtin_function_or_method']:
    print('probably a function')

atau bahkan sesuatu yang lebih aneh:

if "function" in lower(obj.__class__.__name__):
    print('probably a function')
tinnick
sumber
-1

Jika kode akan melanjutkan untuk melakukan panggilan jika nilainya dapat dipanggil, cukup lakukan panggilan dan tangkap TypeError.

def myfunc(x):
  try:
    x()
  except TypeError:
    raise Exception("Not callable")
Roger Dahl
sumber
4
Ini berbahaya; Anda tidak tahu apa efek sampingnya x.
cwallenpoole
-2

Berikut ini adalah "cara ulang" untuk memeriksanya. Juga bekerja dengan lambda.

def a():pass
type(a) #<class 'function'>
str(type(a))=="<class 'function'>" #True

b = lambda x:x*2
str(type(b))=="<class 'function'>" #True
Vova
sumber
-3

Ini bekerja untuk saya:

str(type(a))=="<class 'function'>"
Rafael De Acha
sumber
1
Dan apa artinya itu kepada kita jika hasilnya adalah string kosong? Untuk fungsi, saya dapatkan "<type 'function'>", untuk integer, saya dapatkan "<type 'int'>", jadi saya tidak melihat cara kerjanya untuk Anda: /
pawamoy
Sekarang hanya berfungsi untuk Python 3 :) Juga tergantung pada maksud asli pertanyaan, itu tidak lengkap: haruskah builtin opendianggap sebagai fungsi? str(type(open))memberi <class 'builtin_function_or_method'>dalam Python 3.
pawamoy