Is type(1) the equivalent of type.__call__(1)?

Viewed 344

I run codes in Jupyter console(Python's version is 2.7.14),

type(1)
Out[71]: int

type.__call__(1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-72-0ed097e2c413> in <module>()
----> 1 type.__call__(1)

TypeError: descriptor '__call__' requires a 'type' object but received a 'int'

I've guessed type(...) is a equivalent of type.__call__(...) but it seems no. So I wonder:

  1. What have been done by the python interpreter when I call type(1) or type(name, base, dict)?
  2. When the type.__call__(...) will be invoked?

Thanks.

4 Answers

Short version: There are two reasonable things type.__call__ could resolve to: a bound method representing the method used for calling type itself, or an unbound method representing the method used for calling instances of type. You're expecting the first result, but what you actually get is the second.


Long version:

some_callable(thing) is normally equivalent to some_callable.__call__(thing). For example, print(1) is equivalent to print.__call__(1) (as long as you have from __future__ import print_function turned on):

>>> print(1)
1
>>> print.__call__(1)
1

type is a callable, and type(thing) would be equivalent to type.__call__(thing), except that attribute lookup runs into a complication.

During the type.__call__ attribute lookup, Python searches type and its superclasses (just object) for a __dict__ entry with key '__call__'. Python also searches type's type and type's type's superclasses for such a __dict__ entry. (You can see the code responsible for invoking these searches in type_getattro, the C function that handles attribute lookup for types.) Since type is its own type, both of these searches find type.__dict__['__call__'].

One of these searches takes priority. The way the choice is made, and the reason the choice even matters, is the descriptor protocol. If the first search wins, then the descriptor protocol is applied as normal for finding a class attribute (descriptor.__get__(None, cls)); if the second search wins, the descriptor protocol is applied as normal for finding an instance attribute (descriptor.__get__(instance, cls)). The second search needs to win for type.__call__(thing) to behave like type(thing), but it would only win if type.__dict__['__call__'] was a data descriptor, and it's not.

The first search wins. The descriptor protocol is applied as normal for finding a class attribute, and the result of looking up type.__call__ is an unbound method. It represents the general __call__ method of instances of type, rather than the __call__ instance method of type-as-an-instance-of-type. It would need to be called as

type.__call__(type, 1)

to be equivalent to type(1).


After all that, you might be wondering how type(thing) works without running into all those complications. In terms of language semantics, Python only performs the second search when looking up type's __call__ method to call it, so the first search can't win because it doesn't even happen. In terms of actual implementation, CPython doesn't actually look up the __call__ method at all; it looks up type's type, goes to the C-level slot on type's type corresponding to __call__, and calls the function it finds. For a __call__ method implemented in Python, the C slot would contain a function that looks up and calls the Python method, but for a __call__ implemented in C, the C slot contains the __call__ implementation directly.

Because type is a class, you need its __new__ method:

>>> type.__new__(type, 1)
<type 'int'>

Usually, cls(*args, **kwargs) is equivalent to cls.__new__(cls, *args, **kwargs) followed by calling .__init__(*args, **kwargs) on the returned object.

Here's one possible implementation of this behavior of type():

class MyType(object):
    def __new__(cls, obj):
        return obj.__class__

    def __init__(self, hahaha):
        pass

See blhsing's answer for question 2.

The reason, as @user2357112 said, is that type acts as both a built-in function (which also doubles as a metaclass but that's not important here) and a class.

type(1), in accordance with Built-in Functions — Python 2.7.15 documentation, acts as a regular function that returns the type of an object or creates a new custom type object.

In [13]: type?
Docstring:
type(object) -> the object's type
type(name, bases, dict) -> a new type
Type:      type

type.__call__, on the other hand, is an implementation of the call for objects of the class type -- i.e. types -- which, as you know, creates an instance of that type. I.e. an unbound method:

In [14]: type.__call__?
Type:        wrapper_descriptor
String form: <slot wrapper '__call__' of 'type' objects>
Namespace:   Python builtin
Docstring:   x.__call__(...) <==> x(...)

The reason for the difference in execution paths is that attribute lookup is not done in the first case:

In [16]: dis.dis(compile("type(1)","<stdin>","eval"))
  1           0 LOAD_NAME                0 (type)
              3 LOAD_CONST               0 (1)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE

In [17]: dis.dis(compile("type.__call__(1)","<stdin>","eval"))
  1           0 LOAD_NAME                0 (type)
              3 LOAD_ATTR                1 (__call__)
              6 LOAD_CONST               0 (1)
              9 CALL_FUNCTION            1
             12 RETURN_VALUE

And when calling an object like a function, tp_call takes priority.

To answer the second half of your question, since @iBug already answered the first half, type.__call__ is a method of type, so instead of type.__call__(1), you should call it as a bound method:

self = type(1)
self.__call__(1)

or:

type.__call__(type(1), 1)

both of which returns:

type(1).__new__(type(1), 1)

which is really int(1) since type(1) returns int.

Related