__call__ или __init__ здесь вызывается? Не понимаю, что и почему - PullRequest
0 голосов
/ 11 ноября 2018

Редактировать : к сожалению, это не ответ в В чем разница между __init__ и __call__ в 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() из примера ниже, как в этот ответ :

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

Ответы [ 3 ]

0 голосов
/ 11 ноября 2018

__init__() вызывается при использовании с классом

__call__() вызывается при использовании с объектом класса

0 голосов
/ 11 ноября 2018

Я считаю, это - это то, что вы ищете.

Поведение вызова объекта в 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)
0 голосов
/ 11 ноября 2018

Я бы сказал, здесь тоже нет .

Часть кода, вызывающая путаницу:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...