现在很清楚元类是什么,有一个相关的概念,我一直在使用,而不知道它的真正含义.
我想每个人都用括号做错了,导致"对象不可调用"异常.更重要的是,使用__init__
并__new__
导致想知道这种血腥__call__
可以用于什么.
你能给我一些解释,包括魔术方法的例子吗?
可调用是可以调用的任何东西.
所述内置的可调用(PyCallable_Check在objects.c)检查该参数可以是:
带有__call__方法或类的类的实例
是一种具有非null tp_call(c struct)成员的类型,否则表示可调用性(例如在函数,方法等中)
名为__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
可以调用iff x->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)
这也是你foo = new int
在Python中没有的原因:你只需让类对象返回它的实例__call__
.在我看来,Python解决这个问题的方式非常优雅.
Callable是具有该__call__
方法的对象.这意味着你可以伪造可调用的函数或做一些像Partial Function Application这样的整洁的东西,你可以在这里使用函数并添加一些增强它或填充一些参数的东西,返回可以依次调用的东西(在函数式编程圈子中称为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 "", line 1, in 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中,callable是一个类型有一个__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