0

Edit: this is unfortunately not answered in 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?

I read about __init__ and __call__, but I still don't undestand what is going on in this code

I don't understand:

1.) Which method will be called, __init__ or __call__

2.) If __init__, then __init__ doesn't return anything

3.) If __call__, then __call__ can't be called with two parameters

I think __init__ should be called, because we have X(), not x() from example below as in this answer:

x = X() # __init__ (constructor)
x() # __call__
Karol Zlot
  • 2,887
  • 2
  • 20
  • 37
  • Nice explanation here: https://stackoverflow.com/a/9663601/259889 – Sid Nov 11 '18 at 05:12
  • Possible duplicate of [What is the difference between \_\_init\_\_ and \_\_call\_\_ in Python?](https://stackoverflow.com/questions/9663562/what-is-the-difference-between-init-and-call-in-python) – Severin Pappadeux Nov 11 '18 at 05:12
  • @SeverinPappadeux Unfortunately this is not explaining questions 2 and 3 :-( – Karol Zlot Nov 11 '18 at 05:18
  • @Sid Unfortunately this is not explaining questions 2 and 3 :-( – Karol Zlot Nov 11 '18 at 05:18
  • You're right that `__init__` doesn't return anything, but it's *called* on the new object, which is what gets returned when you call the class. So you could sort of imagine a `return self` and you'd have more or less the right idea. – Blckknght Nov 11 '18 at 05:19
  • @Blckknght Thank you! I couldn't undestand this. Now it is much clearer! – Karol Zlot Nov 11 '18 at 05:22
  • @qewghbjhb Object of type `OAuth2Bearer` will be constructed, thus __init__ will be called, then handle to this object will be returned. __call__ is not called . Does it answer your question? – Severin Pappadeux Nov 11 '18 at 05:23

3 Answers3

3

I believe this is what you're looking for.

The behaviour of calling an object in Python is governed by its type's __call__, so this:

OAuth2Bearer(args)

Is actually this:

type(OAuth2Bearer).__call__(OAuth2Bearer, args)

What is the type of OAuth2Bearer, also called its "metaclass"? If not type, the default, then a subclass of type (this is strictly enforced by Python). From the link above:

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

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

So the result of the call is the result of object.__new__ after passed to object.__init__. object.__new__ basically just allocates space for a new object and is the only way of doing so AFAIK. To call OAuth2Bearer.__call__, you would have to call the instance:

OAuth2Bearer(init_args)(call_args)
roeen30
  • 759
  • 3
  • 13
0

I'd say it's neither here.

The part of code that's causing confusion is

OAuth2Bearer(self._api_key, self.access_token)

You need to know one thing: While OAuth2Bearer is the name of a class, it's also an object of class type (a built-in class). So when you write the above line, what's actually called is

type.__call__()

This can be easily verified if you try this code:

print(repr(OAuth2Bearer.__call__))

it will return something like this:

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

What type.__call__ does and returns is well covered in other questions: It calls OAuth2Bearer.__new__() to create an object, and then initialize that object with obj.__init__(), and returns that object.

You can think of the content of OAuth2Bearer(self._api_key, self.access_token) like this (pseudo-code for illustration purposes)

OAuth2Bearer(self._api_key, self.access_token):
    obj = OAuth2Bearer.__new__(OAuth2Bearer, self._api_key, self.access_token)
    obj.__init__()
    return obj
iBug
  • 35,554
  • 7
  • 89
  • 134
  • Do I undestand correctly that `return OAuth2Bearer(init_args)` would be `return new OAuth2Bearer(init_args)` in C# ? – Karol Zlot Nov 12 '18 at 11:33
  • @qewghbjhb I don't know C# but it appears like you're right (I read Java and they're similar so this is a guess). – iBug Nov 12 '18 at 15:05
0

__init__() is called when used with Class

__call__() is called when used with object of Class

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
rajamohan reddy
  • 101
  • 1
  • 4