“Çağrılabilir” nedir?


310

Artık bir metasınıfın ne olduğu açık , gerçekte ne anlama geldiğini bilmeden sürekli kullandığım bir kavram var.

Herkesin bir kez parantezle ilgili bir hata yaptığını ve bunun sonucunda "nesne çağrılamaz" istisnasına neden olduğunu düşünüyorum. Dahası, kullanmak __init__ve __new__bu kanlı __call__ne için kullanılabileceğini merak etmeye yol açar .

Sihirli yöntemle ilgili örnekler de dahil olmak üzere bana bazı açıklamalar verebilir misiniz?


Yanıtlar:


308

Çağrılabilir, çağrılabilecek herhangi bir şeydir.

Yerleşik çağrılabilir (objects.c içinde PyCallable_Check) çek argümanı ya ise:

  • __call__yöntemli bir sınıf örneği veya
  • , aksi takdirde callability (işlevler, yöntemler vb. gibi) gösteren boş olmayan bir tp_call (c struct) üyesi olan bir türdür.

Adı verilen yöntem __call__( belgelere göre )

Örnek işlev olarak '' '' çağrıldığında çağrılır

Misal

class Foo:
  def __call__(self):
    print 'called'

foo_instance = Foo()
foo_instance() #this is calling the __call__ method

6
Çağrılabilir yerleşik Python 3.0 arama
Eli Courtwright

13
@Eli: Hmm çok kötü bir hamle gibi geliyor . callableaslında bir şeyin çağrılabilir olup olmadığını söyler, kontrol ederken __call__size hiçbir şey söylemez; Bir nesne ise osağlamaktadır __getattribute__ya __getattr__, hasattr(o, '__call__')return true olabilir, henüz oPython atlar çünkü hala çağrılabilir olmayacak __getattribute__ve __getattr__aramalar için. Bir şeyin çağrılabilir olup olmadığını kontrol etmenin tek gerçek yolu EAFP'dir.
L̲̳̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

49
@ Longpoke: Sadece kayıt için, lütfen Python 3.x'teki belgelerecallable() bakın : " Bu işlev önce Python 3.0'da kaldırıldı ve sonra Python 3.2'de geri getirildi. "
Tadeck

Python 3.8'de sadece varlığı tp_callkontrol edilir. PyCallable_Check uygulamasına bakın , 3 satır.
Michele Piccolini

84

Python'un sources nesnesinden. C :

/* Test whether an object can be called */

int
PyCallable_Check(PyObject *x)
{
    if (x == NULL)
        return 0;
    if (PyInstance_Check(x)) {
        PyObject *call = PyObject_GetAttrString(x, "__call__");
        if (call == NULL) {
            PyErr_Clear();
            return 0;
        }
        /* Could test recursively but don't, for fear of endless
           recursion if some joker sets self.__call__ = self */
        Py_DECREF(call);
        return 1;
    }
    else {
        return x->ob_type->tp_call != NULL;
    }
}

Diyor ki:

  1. Bir nesne bir sınıfın örneğiyse , __call__özniteliği varsa çağrılır .
  2. Başka bir nesne iffx olarak çağrılabilir x->ob_type->tp_call != NULL

Ait Desciption tp_callalanında :

ternaryfunc tp_callNesneyi çağırmayı uygulayan bir işleve yönelik isteğe bağlı bir işaretçi. Nesne çağrılabilir değilse bu NULL olmalıdır. İmza PyObject_Call () ile aynıdır. Bu alan alt türler tarafından miras alınır.

callableVerilen nesnenin çağrılabilir olup olmadığını belirlemek için her zaman yerleşik işlevi kullanabilirsiniz; ya da daha iyisi, sadece ara ve TypeErrorsonra yakala . callablePython 3.0 ve 3.1 kaldırılır, callable = lambda o: hasattr(o, '__call__')veya kullanın isinstance(o, collections.Callable).

Basit bir önbellek uygulaması örneği:

class Cached:
    def __init__(self, function):
        self.function = function
        self.cache = {}

    def __call__(self, *args):
        try: return self.cache[args]
        except KeyError:
            ret = self.cache[args] = self.function(*args)
            return ret    

Kullanımı:

@Cached
def ack(x, y):
    return ack(x-1, ack(x, y-1)) if x*y else (x + y + 1) 

Standart kütüphane, dosya site.py, yerleşik tanımı exit()ve quit()işlevlerinden örnek:

class Quitter(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'Use %s() or %s to exit' % (self.name, eof)
    def __call__(self, code=None):
        # Shells like IDLE catch the SystemExit, but listen when their
        # stdin wrapper is closed.
        try:
            sys.stdin.close()
        except:
            pass
        raise SystemExit(code)
__builtin__.quit = Quitter('quit')
__builtin__.exit = Quitter('exit')

10
Çağrı yönteminin örneğini son derece yanıltıcı buluyorum çünkü önbelleğe alma ve dekoratörler için bir tarifle karıştırıyor, bu da çağrı
Florian Bösch

3
JF Sebastian, aynı zamanda kopyaladığınız ve minimum olmayan başka bir yerden yapıştırdığınız daha fazla örnek kazık yardımcı olmaz.
Florian Bösch

20
@JF Sebastian: BS, daha çok yaşam benzeri örneklerin daha iyi olduğu. Size örnek olarak ağlatan hayat benzeri bir kod gösterebilirim. Basit örnekler de işe yarar ve dikkatini dağıtmadıkları için bir şeyi göstermek için daha iyi çalışırlar.
Florian Bösch

5
Çağrılabilir olanı açıklıyorsunuz, ancak bir dekoratör tanımlamak için çağrılabilir nesnelerin nasıl kullanılacağına dair bir örnek verdiniz. Bunun tipik bir kullanım biliyorum çağrılabilir ama bu sadece çağrılabilir ve nasıl kullanmayı bilmek istiyorum okuyucuların kafasını karıştırabilir çağrılabilir . @Florrian Bösch'ün cevabını tercih ederim.
KFL

2
@Kay: @Florian Bösch'ün cevabını da seviyorum (şimdiki haliyle). btw, dekoratör "çağrılabilir" ifadesinin tipik bir kullanımı değildir . En tipik "callables" gibi işlevleri / yöntemlerdir def f(): ...ve sınıf nesneleri gibi class C: ..., yani f, ''.strip, lenve Cher çağrılabilir. __call__()Sınıflarında bir yöntemi olan örnekler nispeten nadirdir.
jfs

37

Çağrılabilir, yuvarlak parantez () kullanmanıza ve sonunda işlevler gibi bazı parametreleri iletmenize izin veren bir nesnedir.

Her işlev tanımladığınızda python çağrılabilir bir nesne oluşturur. Örnekte, fonksiyon tanımlayabilirsiniz fonk bu yollardan (aynı şey) içinde:

class a(object):
    def __call__(self, *args):
        print 'Hello'

func = a()

# or ... 
def func(*args):
    print 'Hello'

Gibi yöntemler yerine bu yöntemi kullanabilirsiniz. Doit veya run , bence obj () obj.doit () 'den daha açıktır


37

Geriye bakalım:

Bunu düşün...

foo()

... sözdizimsel şeker olarak:

foo.__call__()

fooYanıt veren herhangi bir nesne nerede olabilir?__call__ . Herhangi bir nesne dediğimde, demek istediğim: yerleşik tipler, kendi sınıflarınız ve örnekleri.

Yerleşik tiplerde, yazarken:

int('10')
unicode(10)

Esasen yapıyorsunuz:

int.__call__('10')
unicode.__call__(10)

Bu yüzden foo = new intPython'da bulunmuyorsunuz : sınıf nesnesinin bunun bir örneğini döndürmesini sağlıyorsunuz __call__. Python'un bunu çözme şekli bence çok zarif.


Aslında yapıyorsun type(int).__call__(int, '10')ve type(unicode).__call__(unicode, '10'). Şimşekler her zaman sınıflarında çağrılır, örnek üzerinden değil. Ve asla metasınıftan geçmezler. Çoğu durumda bu sadece bir nitpick, ancak bazen önemlidir.
Mad Physicist

11

Çağrılabilir, __call__yöntemi olan bir nesnedir . Bu, çağrılabilir işlevleri taklit edebileceğiniz veya bir işlevi aldığınız ve onu geliştiren veya bazı parametreleri dolduran bir şey eklediğiniz Kısmi İşlev Uygulaması gibi düzgün şeyler yapabileceğiniz anlamına gelir ve sırayla çağrılabilecek bir şey döndürür ( Currying olarak bilinir) işlevsel programlama çevrelerinde ).

Bazı tipografik hatalar yorumlayıcıda (örneğin) bir dize gibi istemediğiniz bir şeyi çağırmaya çalışır. Bu, yorumlayıcının çağrılabilir olmayan bir uygulama yürütmeye çalıştığı durumlarda hatalara neden olabilir. Bunun gerçekleşmesini aşağıdaki transkript gibi bir şey yaparak bir python yorumlayıcısında görebilirsiniz.

[nigel@k9 ~]$ python
Python 2.5 (r25:51908, Nov  6 2007, 15:55:44) 
[GCC 4.1.2 20070925 (Red Hat 4.1.2-27)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'aaa'()    # <== Here we attempt to call a string.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
>>> 

9

__call__ herhangi bir nesneyi işlev olarak çağrılabilir yapar.

Bu örnek 8 çıktısını verecektir:

class Adder(object):
  def __init__(self, val):
    self.val = val

  def __call__(self, val):
    return self.val + val

func = Adder(5)
print func(3)

7

Oldukça basit bir şekilde, "çağrılabilir" bir yöntem gibi çağrılabilecek bir şeydir. Yerleşik "callable ()" işlevi, bir çağrı özelliğini kontrol ederken olduğu gibi bir şeyin çağrılabilir görünüp görünmediğini size bildirir . Sınıflar gibi fonksiyonlar çağrılabilir, sınıf örnekleri çağrılabilir. Burada ve burada bununla ilgili daha fazla bilgi edinin .


5

Python'da çağrılabilir, türün bir __call__yöntemi olan bir nesnedir :

>>> class Foo:
...  pass
... 
>>> class Bar(object):
...  pass
... 
>>> type(Foo).__call__(Foo)
<__main__.Foo instance at 0x711440>
>>> type(Bar).__call__(Bar)
<__main__.Bar object at 0x712110>
>>> def foo(bar):
...  return bar
... 
>>> type(foo).__call__(foo, 42)
42

Kadar basit :)

Bu elbette aşırı yüklenebilir:

>>> class Foo(object):
...  def __call__(self):
...   return 42
... 
>>> f = Foo()
>>> f()
42

3

Sınıf fonksiyonunun veya metodunun kontrol edilebilir olup olmadığını kontrol etmek, bu fonksiyonu çağırabileceğimiz anlamına gelir.

Class A:
    def __init__(self,val):
        self.val = val
    def bar(self):
        print "bar"

obj = A()      
callable(obj.bar)
True
callable(obj.__init___)
False
def foo(): return "s"
callable(foo)
True
callable(foo())
False

1
callable(obj.__init___)Fazladan alt çizginizin olmadığından emin misiniz (AttributeError'da olduğu gibi)? Değilse, cevabın bunun Trueiçin olmadığından emin misiniz ?
Mad Physicist

2

Sonra "(args)" koyabileceğiniz ve çalışmasını bekleyebileceğiniz bir şey. Çağrılabilir genellikle bir yöntem veya sınıftır. Yöntemler çağrılır, sınıflar somutlaştırılır.


2

callables __call__özel yöntemi uygular, böylece böyle bir yöntemle herhangi bir nesne çağrılabilir.


__call__Sınıf böyle bir yöntem tanımlamazsa , tanımladığınız bir örnek çağrılamaz.
Mad Physicist

2

Callable, yöntem çağrısına sahip bir tür veya "Yerleşik işlev veya Yöntem" sınıfıdır

>>> type(callable)
<class 'builtin_function_or_method'>
>>>

Örnek: print , çağrılabilir bir nesnedir. Yerleşik işleviyle __call__ Yazdırma işlevini çağırdığınızda , Python print türünde bir nesne oluşturur ve varsa parametreleri __call__ yöntemini geçirerek çağırır .

>>> type(print)
<class 'builtin_function_or_method'>
>>> print.__call__(10)
10
>>> print(10)
10
>>>

Teşekkür ederim. Saygılarımızla, Maris


1
Buradaki bilgilerden bazıları yanlış. Örneğin, " printİşlevi çağırdığınızda Python, print türünde bir nesne oluşturur ve yöntemini çağırır __call__". Python bir yazdırma nesnesi oluşturmaz. Sadece eşdeğer bir şey çağırıyor type(print).__call__(print, *args, **kwargs). Ve ilk cümle pek mantıklı değil. Çağrılabilir bir nesneyi karıştırıyor ve işlevi "çağrılabilir" gibi görünüyorsunuz.
Mad Physicist
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.