什么是Python中的“可调用”?
既然已经清楚元类是什么 ,那么我总是会使用一个相关的概念,而不知道它的真正含义。
我想每个人都用括号犯了一个错误,导致一个“对象不可调用”的例外。 更重要的是,使用__init__
和__new__
会导致想知道这个血腥的__call__
可以用于什么。
你能给我一些解释,包括用魔法的例子吗?
可调用是可以调用的任何东西。
内置的可调用 (objects.c中的PyCallable_Check)检查参数是否为:
- 具有__call__方法或类的类的实例
- 是一个具有非空tp_call (c结构)成员的类型,否则指示可调用性(例如在函数,方法等中)
名为__call__的方法是( 根据文档 )
当实例被调用为函数时调用
例
class Foo: def __call__(self): print 'called' foo_instance = Foo() foo_instance() #this is calling the __call__ method
从Python的源代码object.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; } }
它说:
- 如果一个对象是一个类的实例,那么它是可调用的, 如果它有
__call__
属性。 - 否则对象
x
可调用iffx->ob_type->tp_call != NULL
描述tp_call
字段 :
ternaryfunc tp_call
指向实现调用对象的函数的可选指针。 如果对象不可调用,这应该是NULL。 签名与PyObject_Call()相同。 该字段由子类型继承。
您始终可以使用内置的callable
函数来确定给定的对象是否可以调用; 或者更好,然后调用它,稍后再捕获TypeError
。 callable
在Python 3.0和3.1中被移除,使用callable = lambda o: hasattr(o, '__call__')
或isinstance(o, collections.Callable)
。
例如,一个简单的缓存实现:
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
用法:
@Cached def ack(x, y): return ack(x-1, ack(x, y-1)) if x*y else (x + y + 1)
来自标准库的例子,文件site.py
,内置的exit()
和quit()
函数的定义:
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')
可调用对象允许使用圆括号(),并最终传递一些参数,就像函数一样。
每次你定义一个函数时,python会创建一个可调用的对象。 在例子中,你可以用这些方法定义函数func (它是一样的):
class a(object): def __call__(self, *args): print 'Hello' func = a() # or ... def func(*args): print 'Hello'
你可以使用这个方法而不是像doit或run这样的方法,我认为obj()比obj.doit()更清晰。
让我解释一下:
考虑这个…
foo()
…作为语法糖用于:
foo.__call__()
foo
可以是任何响应__call__
对象。 当我说任何对象,我的意思是:内置类型,你自己的类和它们的实例。
在内置类型的情况下,当你写:
int('10') unicode(10)
你基本上在做:
int.__call__('10') unicode.__call__(10)
这也是为什么你在Python中没有foo = new int
的原因:你只需要让__call__
类的对象返回它的一个实例。 Python解决这个问题的方式在我看来非常优雅。
Callable是具有__call__
方法的对象。 这意味着你可以伪造可调用的函数,或者做一些整洁的事情,比如部分函数应用 ,你可以在其中添加一些增强或填充某些参数的东西,然后返回一些可以依次调用的东西(在函数式编程循环中称为Currying )。
某些印刷错误会导致解释器试图调用你不想要的东西,比如(例如)一个字符串。 如果解释器试图执行不可调用的应用程序,这可能会产生错误。 您可以通过执行下面的脚本来看到这发生在python解释器中。
[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 >>>
很简单,“可调用”是可以被称为方法的东西。 内置函数“callable()”会告诉你是否有东西看起来是可调用的,就象检查一个调用属性一样。 函数可以像类一样调用,类实例可以被调用。 在这里和这里查看更多信息。
__call__
使得任何对象都可以作为函数被调用。
这个例子会输出8:
class Adder(object): def __init__(self, val): self.val = val def __call__(self, val): return self.val + val func = Adder(5) print func(3)
在Python中,一个可调用对象的类型有一个__call__
方法:
>>> 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
就如此容易 :)
这当然可以超载:
>>> class Foo(object): ... def __call__(self): ... return 42 ... >>> f = Foo() >>> f() 42
要检查类的功能或方法是否可以调用,这意味着我们可以调用该函数。
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
这是你可以把“(args)”之后,并期望它的工作。 可调用通常是一种方法或一个类。 方法被调用,类被实例化。
这里很好的例子。
可调用实现__call__
特殊方法,因此具有这种方法的任何对象都可以调用。
可调用是一种类型或类的“内置函数或方法”与方法调用
>>> type(callable) <class 'builtin_function_or_method'> >>>
例如: print是一个可调用的对象。 使用内建函数__call__当您调用打印函数时,Python将创建一个print类型的对象并调用其方法__call__传递参数(如果有的话)。
>>> type(print) <class 'builtin_function_or_method'> >>> print.__call__(10) 10 >>> print(10) 10 >>>
谢谢。 问候,Maris
找出一个对象是可调用的或不试试这个
x=234 for i in dir(x): if i.startswith("__call__"): print i
这里没有输出。
def add(x,y): return x+y for i in dir(add): if i.startswith("__call__"): print i >>>__call__