既然现在清楚了元类是什么,那么有一个相关的概念我经常使用,但不知道它真正的含义。
我想每个人都曾经因为括号的错误而导致"对象不可调用"的异常。更重要的是,使用__init__
和__new__
会让人想知道这该死的__call__
可以用来做什么。
您能给我一些解释吗?包括使用魔术方法的示例。
可调用对象是任何可以被调用的东西。
内置的callable(对象中的PyCallable_Check)检查参数是否为:
__call__
方法的类的实例或名为__call__
的方法是(根据文档)
在将实例“调用”为函数时调用
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,但是因为Python在调用时跳过__getattribute__
和__getattr__
,所以o
仍然无法被调用。因此,检查某个东西是否可调用的唯一真正方法是EAFP。 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳__call__
方法的对象总是也设置了 tp_call
。我不确定“所有可调用项都有 tp_call
”是何时实现的,但 PyCallable_Check
的更改发生在 2006 年 8 月:https://github.com/python/cpython/commit/50e9fb9e2d6b4b12524116ab775ac6543e4a5332#diff-ba56d44ce0dd731d979970b966fde9d8dd15d12a82f727a052a8ad48d4a49363 - mtraceur__call__
属性,它被定义为表示该函数的method-wrapper
实例。对于def x(): pass
,我们有一个不变式,即x.__call__.__self__ is x
。 - undefined以下内容来自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->ob_type->tp_call != NULL
时,对象x
是可调用的。tp_call
字段的说明如下:
您始终可以使用内置的
ternaryfunc tp_call
是一个可选的指向实现调用对象的函数的指针。如果对象不可调用,则此项应为NULL。签名与PyObject_Call()相同。该字段被子类型继承。
callable
函数来确定给定对象是否可调用;或者更好地,只需调用它,并稍后捕获TypeError
。在Python 3.0和3.1中,callable
已被删除,请使用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 __()
方法的实例相对较少。 - jfs可调用对象是一个允许您使用圆括号()并最终传递一些参数的对象,就像函数一样。
每当您定义一个函数时,Python都会创建一个可调用对象。例如,您可以以以下方式定义函数 func (它们是相同的):
class a(object):
def __call__(self, *args):
print 'Hello'
func = a()
# or ...
def func(*args):
print 'Hello'
我认为使用obj()比使用doit()或run()等方法更加清晰易懂。
让我倒过来解释:
考虑这个...
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')
。Dunder方法总是在它们的类上调用,而不是通过实例调用。它们也从不经过元类。对于大多数情况来说这只是一个小问题,但有时候确实很重要。 - Mad PhysicistMyClass()
试图调用该类,通过查找MyClass
's class上的__call__
方法来完成,即它跳过在MyClass
内进行属性查找(否则它可能会找到一个为实例设计的用户定义的__call__
!)并找到type.__call__
-然后通过通常的机制评估为MyClass
上的绑定方法,然后进行调用。 - Karl Knechtel可调用对象是拥有__call__
方法的对象。这意味着您可以模拟可调用函数,或者执行一些聪明的事情,例如偏函数应用,其中您获取一个函数并添加增强它或填充某些参数的东西,返回可以在其上调用的某些内容(在函数式编程圈子中称为柯里化)。
某些排版错误会导致解释器试图调用您不打算调用的内容,例如字符串。这可能会导致解释器尝试执行非可调用应用程序而出现错误。您可以通过以下交互式 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)
type
。这个对象是独一无二的,它是自己的类型,也是自己的实例。它定义了一个 __call__
方法,以便类可以被调用;这就是在实际分配内存时调用实现特定魔法的地方,同时还可以使用类的 __new__
钩子,然后在生成的对象上调用 __init__
。 - Karl Knechtel__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
callable(obj.__init___)
没有多一个下划线(例如 AttributeError)吗?如果没有,你确定答案不是 True
吗? - Mad Physicist