关于python:__call__ ,__init__ ?

__call__ or __init__ called here? Don't undestand which and why

编辑:很遗憾,这个问题没有得到回答,在python中,init_uuuu和call_uuuu之间的区别是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class OAuth2Bearer(requests.auth.AuthBase):

    def __init__(self, api_key, access_token):
        self._api_key = api_key
        self._access_token = access_token

    def __call__(self, r):
        r.headers['Api-Key'] = self._api_key
        r.headers['Authorization'] ="Bearer {}".format(self._access_token)
        return r

#############

class AllegroAuthHandler(object):
    def apply_auth(self):
        return OAuth2Bearer(self._api_key, self.access_token)   # what will happen here?

我读到了关于__init____call__的文章,但我仍然不理解这段代码中发生了什么。

我不明白:

1)将调用哪个方法,__init____call__

2)如果__init__,那么__init__不返回任何内容。

3)如果__call__不能用两个参数调用__call__

我认为应该叫__init__,因为我们有X(),而不是下面的例子中的X(),如这个答案所示:

1
2
x = X() # __init__ (constructor)
x() # __call__


我相信这就是你要找的。

在python中调用对象的行为由其类型的__call__控制,因此:

1
OAuth2Bearer(args)

实际上是这样吗?

1
type(OAuth2Bearer).__call__(OAuth2Bearer, args)

什么是OAuth2Bearer的类型,也被称为"元类"?如果不是默认的type,则是type的一个子类(这是由python严格执行的)。从上面的链接:

If we ignore error checking for a minute, then for regular class instantiation this is roughly equivalent to:

1
2
3
4
5
def __call__(obj_type, *args, **kwargs):
    obj = obj_type.__new__(*args, **kwargs)
    if obj is not None and issubclass(obj, obj_type):
        obj.__init__(*args, **kwargs)
    return obj

因此,调用的结果是传递给object.__init__之后的object.__new__的结果。object.__new__基本上只是为一个新的对象分配空间,这是唯一的一种方法。要调用OAuth2Bearer.__call__,您必须调用该实例:

1
OAuth2Bearer(init_args)(call_args)


与类一起使用时调用__init__()

与类对象一起使用时调用__call__()


我想说它不在这里。

导致混淆的代码部分是

1
OAuth2Bearer(self._api_key, self.access_token)

你需要知道一件事:虽然OAuth2Bearer是一个类的名称,但它也是type类(一个内置类)的对象。所以当你写上面这一行的时候,实际上叫做

1
type.__call__()

如果您尝试以下代码,则可以轻松验证:

1
print(repr(OAuth2Bearer.__call__))

它将返回如下内容:

1
<method-wrapper '__call__' of type object at 0x12345678>

type.__call__做什么和返回什么在其他问题中有很好的讨论:它调用OAuth2Bearer.__new__()来创建一个对象,然后用obj.__init__()初始化该对象,并返回该对象。

您可以这样想OAuth2Bearer(self._api_key, self.access_token)的内容(用于说明的伪代码)

1
2
3
4
OAuth2Bearer(self._api_key, self.access_token):
    obj = OAuth2Bearer.__new__(OAuth2Bearer, self._api_key, self.access_token)
    obj.__init__()
    return obj