【问题标题】:__call__ or __init__ called here? Don't undestand which and why__call__ 或 __init__ 在这里调用?不明白哪个和为什么
【发布时间】:2018-11-11 05:10:19
【问题描述】:

编辑:很遗憾,What is the difference between __init__ and __call__ in Python? 没有回答这个问题

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(),如this answer

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

【问题讨论】:

标签: python class constructor call init


【解决方案1】:

我相信this 就是您要找的。​​p>

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

OAuth2Bearer(args)

其实是这样的:

type(OAuth2Bearer).__call__(OAuth2Bearer, args)

OAuth2Bearer 的类型是什么,也称为“元类”?如果不是type(默认值),则为type 的子类(Python 严格执行此操作)。从上面的链接:

如果我们暂时忽略错误检查,那么对于常规类实例化,这大致相当于:

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.__new__传递给object.__init__后的结果。 object.__new__ 基本上只是为新对象分配空间,这是 AFAIK 这样做的唯一方法。要调用OAuth2Bearer.__call__,您必须调用实例:

OAuth2Bearer(init_args)(call_args)

【讨论】:

  • 如果您满意,请将其标记为答案:)
  • 很好的答案!很有帮助。
【解决方案2】:

我会说都不在这里。

导致混淆的部分代码是

OAuth2Bearer(self._api_key, self.access_token)

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

type.__call__()

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

print(repr(OAuth2Bearer.__call__))

它会返回如下内容:

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

type.__call__ 的作用和返回在其他问题中得到了很好的说明:它调用 OAuth2Bearer.__new__() 创建一个对象,然后用 obj.__init__() 初始化该对象,并返回 该对象

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

OAuth2Bearer(self._api_key, self.access_token):
    obj = OAuth2Bearer.__new__(OAuth2Bearer, self._api_key, self.access_token)
    obj.__init__()
    return obj

【讨论】:

  • 我是否正确理解 return OAuth2Bearer(init_args) 在 C# 中将是 return new OAuth2Bearer(init_args)
  • @qewghbjhb 我不懂 C#,但看起来你是对的(我读过 Java,它们很相似,所以这是一个猜测)。
【解决方案3】:

__init__() 与 Class 一起使用时被调用

__call__() 与 Class 的对象一起使用时被调用

【讨论】:

    猜你喜欢
    • 2012-03-28
    • 2021-06-04
    • 2021-04-28
    • 1970-01-01
    • 2022-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-23
    相关资源
    最近更新 更多