【发布时间】:2010-09-11 19:01:41
【问题描述】:
现在很清楚what a metaclass is,有一个相关的概念,我一直在使用,但不知道它的真正含义。
我想每个人都犯了一次括号错误,导致“对象不可调用”异常。更何况,使用__init__ 和__new__ 会让人想知道这个该死的__call__ 可以用来做什么。
你能给我一些解释,包括魔术方法的例子吗?
【问题讨论】:
现在很清楚what a metaclass is,有一个相关的概念,我一直在使用,但不知道它的真正含义。
我想每个人都犯了一次括号错误,导致“对象不可调用”异常。更何况,使用__init__ 和__new__ 会让人想知道这个该死的__call__ 可以用来做什么。
你能给我一些解释,包括魔术方法的例子吗?
【问题讨论】:
可调用对象是可以调用的任何东西。
built-in callable (PyCallable_Check in objects.c) 检查参数是否为:
__call__ 方法的类的实例或名为__call__的方法是(according to the documentation)
当实例作为函数被“调用”时调用
class Foo:
def __call__(self):
print 'called'
foo_instance = Foo()
foo_instance() #this is calling the __call__ method
【讨论】:
callable 实际上会告诉您某些内容是否可调用,而检查 __call__ 不会告诉您任何内容;如果对象o 提供__getattribute__ 或__getattr__,hasattr(o, '__call__') 可能会返回True,但o 仍然无法调用,因为Python 跳过__getattribute__ 和__getattr__ 进行调用。因此,检查某些东西是否可调用的唯一真正方法是 EAFP。
callable() in Python 3.x:“此函数首先在 Python 3.0 中被删除,然后在 Python 3.2 中被带回。”。跨度>
tp_call 的存在。请参阅PyCallable_Check 的实现,它是 3 行。
__call__ 方法的对象也总是有 tp_call 设置。我不确定“所有可调用对象都具有tp_call”何时实施,但PyCallable_Check 更改发生在 2006 年 8 月:github.com/python/cpython/commit/…
来自 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 field的描述:
ternaryfunc tp_call可选 指向实现的函数的指针 调用对象。这应该是 如果对象不可调用,则为 NULL。 签名与 for 相同 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')
【讨论】:
def f(): ... 之类的函数/方法,以及诸如class C: ... 即f、''.strip、len 和C 之类的类对象都是可调用的。在其类中具有__call__() 方法的实例相对较少。
可调用对象是一个允许您使用圆括号 ( ) 并最终传递一些参数的对象,就像函数一样。
每次定义函数时,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 解决这个问题的方式非常优雅。
【讨论】:
type(int).__call__(int, '10') 和type(unicode).__call__(unicode, '10')。 Dunders 总是在他们的类上被调用,而不是通过实例。他们也从不通过元类。在大多数情况下,这只是一个挑剔,但有时它很重要。
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 "<stdin>", line 1, in <module>
TypeError: 'str' object is not 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
【讨论】:
你可以在后面加上“(args)”并期望它起作用。可调用对象通常是方法或类。方法被调用,类被实例化。
【讨论】:
检查类的函数或方法是否可调用,这意味着我们可以调用该函数。
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
【讨论】:
callable(obj.__init___) 没有额外的下划线(如在 AttributeError 中)?如果不是,你确定那个答案不是True 吗?
callables 实现了__call__ 特殊方法,因此任何具有这种方法的对象都是可调用的。
【讨论】:
__call__ 的实例将无法调用。
Callable 是带有方法的“内置函数或方法”的类型或类 打电话
>>> type(callable)
<class 'builtin_function_or_method'>
>>>
示例: print 是一个可调用对象。使用内置函数 call 当您调用 print 函数时,Python 会创建一个 print 类型的对象 并调用其方法 call 传递参数如果有的话。
>>> type(print)
<class 'builtin_function_or_method'>
>>> print.__call__(10)
10
>>> print(10)
10
>>>
【讨论】:
print 函数时,Python 会创建一个 print 类型的对象并调用它的方法 __call__”。 Python 不会创建打印对象。它只是调用相当于type(print).__call__(print, *args, **kwargs) 的东西。而且第一句话没有多大意义。您似乎混淆了可调用对象和“可调用”函数。