This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Move handling of one-argument call of type() from type.__new__() to type.__call__()
Type: Stage: resolved
Components: Interpreter Core Versions: Python 3.9
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: gvanrossum, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2020-03-08 14:43 by serhiy.storchaka, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 18852 merged serhiy.storchaka, 2020-03-08 14:44
Messages (2)
msg363664 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-03-08 14:43
The builtin type() serves two functions:

1. When called with a single positional argument it returns the type of the argument.

>>> type(1)
<class 'int'>

2. Otherwise it acts as any class when called -- creates an instance of this class (a type). It includes calling corresponding __new__ and __init__ methods.

>>> type('A', (str,), {'foo': lambda self: len(self)})
<class '__main__.A'>

type is a class, and it can be subclassed. Subclasses of type serve only the latter function (the former was forbidden in issue27157).

>>> class T(type): pass
... 
>>> T(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type.__new__() takes exactly 3 arguments (1 given)
>>> T('A', (str,), {'foo': lambda self: len(self)})
<class '__main__.A'>

But surprisingly you can use the __new__ method for getting the type of the object.

>>> type.__new__(type, 1)
<class 'int'>
>>> T.__new__(T, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type.__new__() takes exactly 3 arguments (1 given)

The proposed PR moves handling the special case of one-argument type() from type.__new__ to type.__call__.

It does not fix any real bug, it does not add significant performance boost, it does not remove a lot of code, it just makes the code slightly more straightforward. It changes the behavior of type.__new__(type, obj) which is very unlikely called directly in real code.

>>> type(1)
<class 'int'>
>>> type.__new__(type, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type.__new__() takes exactly 3 arguments (1 given)
msg363757 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-03-09 17:59
New changeset 413f01352a8268fb62bb47bde965462d7b82a06a by Serhiy Storchaka in branch 'master':
bpo-39904: Move handling of one-argument call of type() from type.__new__() to type.__call__(). (GH-18852)
https://github.com/python/cpython/commit/413f01352a8268fb62bb47bde965462d7b82a06a
History
Date User Action Args
2022-04-11 14:59:27adminsetgithub: 84085
2020-03-09 18:29:44serhiy.storchakasetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2020-03-09 17:59:09serhiy.storchakasetmessages: + msg363757
2020-03-08 14:44:13serhiy.storchakasetkeywords: + patch
stage: patch review
pull_requests: + pull_request18209
2020-03-08 14:43:01serhiy.storchakacreate