Bir Python değişkeninin bir işlev olup olmadığını nasıl tespit edebilirim?


687

Bir değişkenim var, x ve bir işleve işaret edip etmediğini bilmek istiyorum.

Şöyle bir şey yapabileceğimi umuyordum:

>>> isinstance(x, function)

Ama bu bana şunu veriyor:

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

Bunu seçmemizin nedeni

>>> type(x)
<type 'function'>

37
Bazı arama özniteliği veya çağrılabilir işlevi arayarak soruna geçici bir çözüm bulmak için üzgünüm ... Temiz bir yol @ryan tarafından önerilen tür (a) == types.functionType hakkında
AsTeR

44
@ ÖRNEK Ördek türü nesnelerin özelliklerini kontrol etmenin uygun yolu, ördek boyutunda bir kaba sığıp uymadıklarını görmemek için onlara quack olup olmadığını sormaktır. "Doğrudan karşılaştırın" yaklaşımı, yerleşikler gibi birçok işlev için yanlış cevap verecektir.
John Feminella

3
@JohnFeminella İlke olarak sana katılıyorum. OP, sadece bir işlevse, çağrılabilir olup olmadığını sormadı. Belki de işlevler ve sınıflar arasında bir ayırım yapılması gerektiğini iddia edebilir mi?
McKay

3
Benim amacım için buraya geldim çünkü insepct.getsourceçeşitli nesnelerde kullanmak istedim ve aslında nesnenin çağrılabilir olup olmadığı değil, 'işlev' verecek bir şey olup olmadığı önemli type(obj). Google beni buraya getirdiğinden, AsTeR'in yorumunun (benim için) en yararlı cevap olduğunu söyleyebilirim. İnsanların keşfetmesi için internette başka yerlerde bol vardır __call__ya callable.
tsbertalan

4
@AsTeR Türler.FunctionType, büyük bir F ile
Ben Mares

Yanıtlar:


892

Bu Python 2.x veya Python 3.2+ içinse de kullanabilirsiniz callable(). Eskiden kullanımdan kaldırıldı, ancak şimdi tanımsız, bu yüzden tekrar kullanabilirsiniz. Tartışmayı buradan okuyabilirsiniz: http://bugs.python.org/issue10518 . Bunu aşağıdakilerle yapabilirsiniz:

callable(obj)

Bu Python 3.x için, ancak 3.2'den önce ise, nesnenin bir __call__niteliği olup olmadığını kontrol edin . Bunu aşağıdakilerle yapabilirsiniz:

hasattr(obj, '__call__')

Önerilen types.FunctionTypesyaklaşım doğru değildir, çünkü yerleşiklerle olduğu gibi muhtemelen geçmesini istediğiniz birçok vakayı kapsamaz:

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

>>> callable(open)
True

Ördek türü nesnelerin özelliklerini kontrol etmenin uygun yolu, ördek şeklinde bir kaba sığıp uymadıklarını görmemek için şakacı olup olmadıklarını sormaktır. types.FunctionTypeBir fonksiyonun ne olduğu hakkında çok özel bir fikriniz yoksa kullanmayın .


73
Bu aynı zamanda bir fonksiyon olup olmadığını size söylemez - sadece çağrılabiliyorsa.
Chris

23
Ayrımın önemli olup olmamasına göre uygulamaya bağlıdır; Bunun asıl soru için uygun olmadığından şüpheliyim, ama bu kesin olmaktan uzak.
Chris

5
Sınıflar, kendisine bir çağrı fonksiyonu ekleyebilir . Dolayısıyla bu kesinlikle ayırt etmek için iyi bir yöntem değildir. Ryan'ın yöntemi daha iyi.
Brian Bruggeman

43
"ördek yazarak" konsepti bunu daha iyi bir cevap haline getirir, örneğin "bir işlev gibi davrandığı sürece ne önemi var?"
jcomeau_ictx

8
Örneğin bir dekoratör yazarken, çağrılabilir ve işlev arasındaki ayrımın çok önemli olduğu kullanımlar vardır (Ryan'ın cevabı hakkındaki yorumuma bakın).
Turion

267

Yerleşik ad alanında yapıcı olmayan yerleşik türler (örn. İşlevler, üreteçler, yöntemler) typesmodülde bulunur. types.FunctionTypeBir isinstanceçağrıda kullanabilirsiniz :

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

Bunun genellikle ihtiyacınız olan şey olmayan çok özel bir "işlev" kavramını kullandığını unutmayın. Örneğin, reddeder zip(teknik olarak bir sınıf):

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

open (yerleşik işlevlerin farklı bir türü vardır):

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

ve random.shuffle(teknik olarak gizli bir random.Randomörneğin yöntemi ):

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

types.FunctionTypeÖrneklere özgü bir şey yapıyorsanız , bayt kodlarını çözme veya kapatma değişkenlerini denetleme types.FunctionTypegibi işlevler kullanıyorsanız , ancak yalnızca bir nesnenin işlev gibi çağrılabilir olması gerekiyorsa, kullanın callable.


5
Soruyu + 1'leme. Bununla birlikte, bir nesnenin bir işlev olup olmadığını tahmin etmeye çalışmak - ya da herhangi bir çağrılabilir nesne olsa bile - genellikle bir hatadır. OP daha fazla bilgi olmadan elbette elden çıkarmak zor, ama yine de ...
bobince

47
Aslında yerleşik işlevler için False, örneğin 'open' gibi döner. Bu nedenle spesifik olmak için isinstance (f, (types.FunctionType, types.BuiltinFunctionType)) kullanmanız gerekecektir. Ve tabii ki kesinlikle sadece fonksiyonlar istiyorsanız, callables veya yöntemler değil.
Lukasz Korzybski

5
@ ŁukaszKorzybski ve daha kesin olmak gerekirse ... ayrıca functools.partial: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial))veya f.funcböyle bir durumda kontrol etmelisiniz .
estani

3
@bobince, bu nasıl USECASE hakkında: Ben bir dekoratör yazmak istiyorum @fooben hem kullanabileceği @foogibi @foo(some_parameter). Daha sonra neyle çağrıldığını kontrol etmelidir, örneğin, dekore etme işlevi (ilk durum) veya parametreyi (başka bir dekoratör döndürmesi gereken ikinci durum).
Turion

types.BuiltinFunctionTypeaynı zamanda , rotaya gitmiyorsanız muhtemelen izin vermek istemediğiniz yerleşik yöntemlerin ("normal") türüdür callable.
user2357112 Monica

92

Python 2.1 beri içe edebilirsiniz isfunctiongelen inspectmodül.

>>> from inspect import isfunction
>>> def f(): pass
>>> isfunction(f)
True
>>> isfunction(lambda x: x)
True

3
Güzel, ama bunun gibi yerleşik işlevleri için yanlış dönmek gibi görünüyor openve hasattr.
Zecc

12
@Zecc isbuiltin bunun içindir.
Paolo

13
inspect.isfunctionÖğretiye bakın : "Nesne kullanıcı tanımlı bir
Mark Mikofski

4
'İsfunction' işlevinin functool.partial işlevlerini tanımadığını unutmayın.
ishmael

74

Kabul edilen cevap, doğru olduğu düşünülen teklif edildi. Anlaşıldığı üzere , Python 3.2'de yer alan bir yedek yokturcallable() : Spesifik olarak, test edilen nesnenin alanını callable()kontrol eder tp_call. Düz bir Python eşdeğeri yoktur. Önerilen testlerin çoğu çoğu zaman doğrudur:

>>> 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

Sınıftan çıkararak buna bir İngiliz anahtarı atabiliriz __call__. Ve sadece işleri daha heyecanlı tutmak __call__için örneğe bir sahte ekleyin !

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

Bunun gerçekten çağrılabilir olmadığına dikkat edin:

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

callable() doğru sonucu döndürür:

>>> callable(can_o_spam)
False

Ama hasattrbir yanlış :

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

can_o_spamsonuçta bu niteliğe sahip; sadece örnek çağrılırken kullanılmaz.

Daha isinstance()da ince, aynı zamanda yanlış yapar:

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

Bu kontrolü daha önce kullandığımız ve daha sonra yöntemi abc.ABCMeta sildiğimiz için sonucu önbelleğe alır. Muhtemelen bu bir hatadır abc.ABCMeta. Yani gerçekten hiçbir olası yolu yoktur, dedi olabilir kullanarak daha sonuç daha doğru bir sonuç üretmek callable()kendisini beri,typeobject->tp_call yuvası yöntemi başka bir şekilde erişilemez.

Sadece kullan callable()


5
hasattr(o, '__call__')Yaklaşım tuzaklarının şaşırtıcı çizimi ve callable()varsa neden daha üstün.
MestreLion

39

Aşağıdakiler bir boole döndürmelidir:

callable(x)

1
Yani çözer onun sorunu ama hâlâ bir sır yarattı: x modülü sınıf 'işlevi' arasında ise yerleşiğini ve yardım (x .__ class__) "Sınıf işlevi", neden görünüşte "fonksiyonu" "tanımlanmamış" olduğunu açıklamaktadır?
Ken

1
"function" bir anahtar kelime veya yerleşik bir tür değildir. İşlev türleri, "türler" modülünde "türler.FunctionType" olarak tanımlanır
Chris


19

callable(x) olacak geçirilen nesne Python çağrılabilir true döndürür, ancak işlev birbirinden ayırt edemez konuşan düzgün Python 3.0 var ve yok:

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)

Sen alırsınız <class 'A'> Trueve <type function> Trueçıktı olarak.

isinstancebir şeyin bir işlev olup olmadığını belirlemek için mükemmel çalışır (deneyin isinstance(b, types.FunctionType)); bir şeyin çağrılıp çağrılmayacağını bilmekle ilgileniyorsanız, bunu kullanabilir hasattr(b, '__call__')veya sadece deneyebilirsiniz.

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

Bu, elbette, çağrılabilir olup olmadığını, ancak TypeErroryürütüldüğünde bir atar veya ilk etapta çağrılamaz olup olmadığını söylemez . Bu senin için önemli olmayabilir.


8
Bunu aramak kötü bir fikir. Ya yan etkileri varsa veya aslında bir şey yapar, ancak gerçekten uzun zaman alırsa?
asmeurer

@asmeurer - Eğer aramıyorsanız, bunun bir işlev olup olmadığını başka neden bilmeniz gerekir?
13'te

1
@detly: hata ayıklama için düzenli olarak bir nesnedeki tüm değişkenleri yazdırmak istiyorum, yöntemler genellikle benim için yararlı değildir, bu yüzden onları yürütmek istemem. Sonunda sadece
çağrılan

2
Çünkü sen ediyoruz buna denir değil anlamına gelmez aramayacağım. Belki sevkiyatı yapıyorsun.
asmeurer

4
Çağrılabilir olup olmadığını bilmek için istisnalar kullanmayla ilgili büyük bir sorun var; ne olursa olduğunu çağrılabilir, ancak arama o aradığınız bir istisna yükseltir? Her iki sessizce bir hata yok sayarız ve bunun çağrılabilir olup olmadığı yanlış tanı. EAFP kullanırken, denemeye çok fazla şey koymaktan kaçınmak istersiniz, ancak bu kullanım durumunda bunu yapmanın bir yolu yoktur.
Ben

15

Sözdizimsel olarak bir işleve benzeyen her şeyi tespit etmek istiyorsanız: bir işlev, yöntem, yerleşik eğlence / meth, lambda ... ancak çağrılabilir nesneleri ( yöntem tanımlı nesneler) hariç tutun __call__, sonra bunu deneyin:

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

Bunu modüldeki is*()kontrol koduyla karşılaştırdım inspectve özellikle de hedefiniz herhangi bir işlevi filtreliyorsa veya bir nesnenin normal özelliklerini tespit ediyorsa, yukarıdaki ifade çok daha eksiksizdir.


Beni typesmodüle yönlendirdiğiniz için teşekkür ederim . make_stemmer()Bazen bir işlevi ve bazen de çağrılabilir bir Stemmerörneği döndürecek bir fabrikayı test ediyordum ve farkı tespit etmem gerekiyordu.
Ocaklar


6

Öğrendiğiniz varsa C++, aşina olmalı function objectya functor, olabilir herhangi bir nesne anlamına gelmektedirbe called as if it is a function .

C ++ ' an ordinary functionda bir işlev nesnesidir ve böylece bir işlev işaretçisi; daha genel olarak, tanımlayan bir sınıfın nesnesi de öyle operator(). C ++ 11 ve daha büyük sürümlerde the lambda expressionde functoröyle.

Benzerlik, Python'da functorsbunların hepsi callable. An ordinary functionçağrılabilir olabilir, çağrılabilir a lambda expressionolabilir, bir functional.partialçağrılabilir olabilir, örnekleri class with a __call__() methodçağrılabilir olabilir.


Tamam, soruya geri dön: I have a variable, x, and I want to know whether it is pointing to a function or not.

Hava durumunu değerlendirmek istiyorsanız, nesne bir işlev gibi davranır, o zaman callableönerilen yöntem@John Feminella tamamdır.

İsterseniz judge whether a object is just an ordinary function or not(çağrılabilir sınıf örneği veya lambda ifadesi değil), xtypes.XXXönerilen @Ryandeğeri daha iyi bir seçimdir.

Sonra bu kodu kullanarak bir deneme yapmak:

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

import functools
import types
import pprint

Bir sınıf ve sıradan bir fonksiyon tanımlayın.

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)

Functorları tanımlayın:

#(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

İşlev listesi listesini ve tür listesini tanımlayın:

## 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]

Functor'ın çağrılabilir olup olmadığına karar verin. Gördüğünüz gibi, hepsi çağrılabilir.

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

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

Functor türünü değerlendirin (tür.XXX). O zaman functor türleri aynı değildir.

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>
"""

Verileri kullanarak çağrılabilir işlev türlerinin bir tablosunu çiziyorum.

resim açıklamasını buraya girin

Daha sonra uygun olan functor tiplerini seçebilirsiniz.

gibi:

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

6

Kabul edilen cevap olarak John Feminella şunları söyledi:

Ördek türü nesnelerin özelliklerini kontrol etmenin uygun yolu, ördek ebatlı bir kaba sığıp uymadıklarını görmemek için, şakacı olup olmadıklarını sormaktır. "Doğrudan karşılaştırın" yaklaşımı, yerleşikler gibi birçok işlev için yanlış cevap verecektir.

İşlevleri kesin olarak ayırt etmek için iki libs olsa da, kapsamlı bir karşılaştırılabilir tablo çiziyorum:

8.9. türleri - Yerleşik türler için dinamik tür oluşturma ve adlar - Python 3.7.0 belgeleri

30.13. inceleme - Canlı nesneleri inceleme - Python 3.7.0 belgeleri

#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',
]

"Ördek tiplemesi" genel amaçlı olarak tercih edilen bir çözümdür:

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

Yerleşik işlevine gelince

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

Yerleşik işlev veya kullanıcı tanımlı işlev olup olmadığını kontrol etmek için bir adım daha gidin

#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

Şunları belirleyin builtin function

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

özet

İstihdam callablebir işlev denetimi ördek türüne,
kullan types.BuiltinFunctionTypedaha fazla belirlemişse talep ediyoruz.


5

Bir fonksiyon sadece bir __call__metodu olan bir sınıftır , böylece

hasattr(obj, '__call__')

Örneğin:

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

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

Bunu yapmanın "en iyi" yoludur, ancak neden çağrılabilir veya not olduğunu bilmeniz gerektiğine bağlı olarak, bunu bir try / execpt bloğuna koyabilirsiniz:

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

Denemek / hariç yapmak Python'y yapmaktan daha fazla ise tartışılabilir if hasattr(x, '__call__'): x().. Yanlış söyleyebilirim hasattrçünkü yanlış TypeError yanlışlıkla yakalamayacaksınız, örneğin:

>>> def x():
...     raise TypeError
... 
>>> hasattr(x, '__call__')
True # Correct
>>> try:
...     x()
... except TypeError:
...     print "x was not callable"
... 
x was not callable # Wrong!

Asla mantıksal akış için değil, kesinlikle Pythonic için değil, yalnızca beklenmedik davranışlara karşı koruma sağlamak için istisna işlemeyi kullanın.
gotgenes

Hasat temelde bir try / hariç bloğunda (C de olsa) bir getattr yapar. blog.jancewicz.net/2007/10/reflection-hasattr.html
dbr

@dbr: Ama hasattr daha estetik.
Nikhil Chelliah

5

İşte birkaç başka yol:

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

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

İkincisini şöyle buldum:

>>> type(lambda x: x);
<type 'function'>
>>> str(type(lambda x: x));
"<type 'function'>"
# Look Maa, function! ... I ACTUALLY told my mom about this!

Bu güzel! Tüm python2.x ve python3.x sürümlerinde çalışmalıdır!
Saurav Kumar

4

Yerine denetlenmesine yönelik '__call__'(işlevlerine münhasır değil), bir kullanıcı tanımlı fonksiyon özelliklerini sahip olup olmadığını kontrol edebilirsiniz func_name, func_docvb Bu yöntemler için çalışmalarını yapmaz.

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

Kontrol etmenin başka bir yolu da isfunction()yöntemi inspectmodülden kullanmaktır.

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

Bir nesnenin yöntem olup olmadığını kontrol etmek için şunu kullanın: inspect.ismethod()


4

Sınıfların da __call__yöntemi olduğu için başka bir çözüm öneririm:

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

1
Cevabınıza katılıyorum, John Feminella'nın cevabı hasattr(obj, '__call__')belirsiz.
GoingMyWay

4

Python sınıflarının da çağrılabilir olduğunu unutmayın.

İşlevleri (ve işlevler ile standart işlevleri ve lambdaları kastediyoruz) kullanmak için şunu kullanın:

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)

2

Herhangi bir işlev bir sınıftır, böylece x örneği örneğinin adını alabilir ve karşılaştırabilirsiniz:


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

2

Bazı cevaplarda kullanılan hasattr(obj, '__call__')ve callable(.)bahsedilen çözümlerin temel bir dezavantajı vardır: hem Truesınıflar için hem de __call__()yöntemli sınıf örnekleri için geri döner . Örneğin.

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

Bir nesnenin kullanıcı tanımlı bir işlev olup olmadığını kontrol etmenin uygun bir yolu (ve bunun dışında hiçbir şey) kullanmaktır isfunction(.):

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

Diğer türleri kontrol etmeniz gerekiyorsa, incelemeye bir göz atın - Canlı nesneleri inceleyin .


2

Tam İşlev Denetleyici

callable çok iyi bir çözümdür. Ancak, bunu John Feminella'nın tersi şekilde ele almak istedim. Bunu şöyle söylemek yerine:

Ördek türü nesnelerin özelliklerini kontrol etmenin uygun yolu, ördek ebatlı bir kaba sığıp uymadıklarını görmemek için, şakacı olup olmadıklarını sormaktır. "Doğrudan karşılaştırın" yaklaşımı, yerleşikler gibi birçok işlev için yanlış cevap verecektir.

Bu şekilde ele alacağız:

Bir şeyin ördek olup olmadığını kontrol etmenin doğru yolu, quack olup olmadığını görmek değil, sadece yüzeyden bir ördek gibi görünüp görünmediğini kontrol etmek yerine, birkaç filtreden gerçekten bir ördek olup olmadığını görmek.

Nasıl Uygularız?

'Türler' modülünün işlevleri tespit etmek için çok sayıda sınıfı vardır, en faydalı olanı Türler faydalısı türlerdir. , ancak yöntem türü, yerleşik tür ve lambda türü gibi birçok başka türü de vardır. Ayrıca bir 'functools.partial' nesnesini bir işlev olarak kabul edeceğiz.

Bir işlev olup olmadığını kontrol etmenin basit yolu, tüm bu türlerde bir isinstance koşulu kullanmaktır. Daha önce, yukarıdakilerin hepsinden miras kalan bir temel sınıf yapmak istedim, ancak Python yukarıdaki sınıflardan bazılarını miras almamıza izin vermediği için bunu yapamıyorum.

Hangi sınıfların hangi işlevleri sınıflandırabileceğine ilişkin bir tablo:

Kinght- 金 fonksiyonlar tablosu Yukarıdaki fonksiyon tablosu kinght- table tarafından

Bunu Yapan Kod

Şimdi, yukarıda tarif ettiğimiz tüm işleri yapan kod budur.

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]

Tek yanlış is_function (kısmi) idi, çünkü bu bir işlev değil, bir sınıftır ve bu tam olarak sınıflar değil, işlevlerdir. İşte bir önizleme kodu denemeniz için .

Sonuç

callable (obj) , mutlak üzerinden ördek yazarak gitmek istiyorsanız, bir nesnenin bir işlev olup olmadığını kontrol etmek için tercih edilen yöntemdir .

Özel is_function (obj) , belki bazı düzenlemelerle, işlev olarak çağrılabilir sınıf örneği saymazsanız, yalnızca yerleşik veya lambda , def ile tanımlanan işlevler yoksa, bir nesnenin bir işlev olup olmadığını kontrol etmek için tercih edilen yöntemdir. veya kısmi .

Ve bence bu her şeyi tamamlıyor. İyi günler!


1

Python3'te , eğer bir fonksiyon olup olmadığı sonucunu type (f) == type (lambda x:x)veren bir ürün buldum . Ama bence tercih ederim , ki bu daha az geçici geliyor. Yapmak istedim , ama bu işe yaramıyor.TruefFalseisinstance (f, types.FunctionType)type (f) is function


0

Önceki yanıtları takiben, ben bunu buldum:

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)

0

Bunu deneyebilirsiniz:

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

hatta daha tuhaf bir şey:

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

-1

Değer çağrılabilir durumdaysa kod arama yapmaya devam ederse, aramayı gerçekleştirin ve yakalayın TypeError.

def myfunc(x):
  try:
    x()
  except TypeError:
    raise Exception("Not callable")

4
Bu tehlikeli; yan etkilerin ne olduğu hakkında hiçbir fikriniz yok x.
cwallenpoole

-2

Aşağıdaki kontrol etmek için bir "repr yolu" dur. Ayrıca lambda ile çalışır.

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

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

-3

Bu benim için çalışıyor:

str(type(a))=="<class 'function'>"

1
Peki bu sonucun boş bir dize olup olmadığını bize ne anlatıyor? Bir fonksiyon için "<type 'function'>", bir tamsayı için, anlıyorum "<type 'int'>", bu yüzden sizin için nasıl çalıştığını görmüyorum: /
pawamoy

Şimdi sadece Python 3 için çalışıyor :) Ayrıca sorunun orijinal amacına bağlı olarak, eksik olurdu: yerleşik openbir işlev olarak mı düşünülmeli? Python 3'te str(type(open))verir <class 'builtin_function_or_method'>.
pawamoy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.