Подтвердить что ты не робот

Объекты Python из существующих объектов с использованием __new__

Изучая модель данных Python, я играю с созданием объектов из существующих объектов с помощью метода __new__. Вот несколько примеров, которые создают новые объекты разных типов:

x = 2;     print type(x).__new__(x.__class__)
x = {};    print type(x).__new__(x.__class__)
x = [1,2]; print type(x).__new__(x.__class__)
x = 2.34;  print type(x).__new__(x.__class__)
x = '13';  print type(x).__new__(x.__class__)
x = 1.0j;  print type(x).__new__(x.__class__)
x = True;  print type(x).__new__(x.__class__)
x = (1,2); print type(x).__new__(x.__class__)

Однако следующие три эксперимента дают мне ошибки:

x = None;           print type(x).__new__(x.__class__)
x = lambda z: z**2; print type(x).__new__(x.__class__)
x = object;         print type(x).__new__(x.__class__)

Ошибки (соответственно):

TypeError: object.__new__(NoneType) is not safe, use NoneType.__new__()
TypeError: Required argument 'code' (pos 1) not found
TypeError: type() takes 1 or 3 arguments

Почему эти три примера не работают? (Примечание: для примера lambda кажется, что я должен передать фрагмент кода при вызове метода __new__, но я не знаю, как это сделать.) Я использую Python 2.6.

Обратите внимание, что я понимаю, что это не обязательно так, как вы хотели бы создавать новые объекты в реальном коде, но моя цель непрактична, скорее, это понять, как работают методы объекта низкого уровня.

4b9b3361

Ответ 1

Это ничего особенного, просто для некоторых типов существует "пустой" объект по умолчанию этого типа, а для других - нет. Ваши рабочие примеры в основном эквивалентны:

int()
dict()
list()
float()
str()
complex()
tuple()

., все из которых работают. Ваши последние три примера в основном пытаются создать новые экземпляры NoneType, function и type.

  • NoneType завершается с ошибкой по уникальной причине, потому что None - это singleton. Тип NoneType может иметь только один экземпляр, а именно объект None. (Особое сообщение об ошибке, которое вы получаете, немного странно, но если вы сделаете types.NoneType(), вы получите более прямое сообщение с сообщением "Невозможно создать экземпляры NoneType".)
  • function не работает, потому что, как вы видели, для этого требуется аргумент, и вы его не предоставляете. Вам понадобится объект кода, который вы можете получить из существующей функции или из функции compile. (Для этого также требуется аргумент globals, который может быть просто dict.)
  • type терпит неудачу, потому что вы не дали достаточно аргументов. Вы можете либо сделать type(foo), чтобы получить тип foo, либо type(name, bases, dict), чтобы создать новый тип (т.е. Класс).

Обратите внимание, что в последнем примере вы берете тип object, который сам по себе является типом. Если вместо этого вы сделаете x = object() (сделав x отдельным объектом, а не типом объекта), то он будет работать и создать "пустой" объект.

Следует помнить, что вызов __new__ на самом деле не волшебный. Именно это происходит, когда вы пытаетесь создать экземпляр типа, делая someType(). Если этот тип требует аргументов, вызов __new__ завершится неудачно, как и любой другой вызов функции, если вы не дадите ему правильные аргументы, потому что type(x).__new__ - это просто функция, как любая другая функция. Вы можете увидеть это с помощью определяемого пользователем класса:

>>> class Foo(object):
...     pass
>>> x = Foo();           print type(x).__new__(x.__class__)
<__main__.Foo object at 0x00EB0370>
>>> class Foo(object):
...     def __init__(self, someArg):
...         pass
>>> class Foo(object):
...     def __new__(cls, someArg):
...         return super(Foo, cls).__new__(cls)
>>> x = Foo(2);           print type(x).__new__(x.__class__)
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    x = Foo(2);           print type(x).__new__(x.__class__)
TypeError: __new__() takes exactly 2 arguments (1 given)

Это удалось в первом случае, потому что мой класс не требовал аргументов; он не прошел во втором классе, потому что второй класс требует аргументов.

__new__ не подлежит какой-либо секретной причине; он просто терпит неудачу, потому что тип, который вы пытаетесь создать, требует аргументов, чтобы построить экземпляр. (Случай None является единственным, который здесь различен, потому что он не работает по особой причине, потому что None является специальным объектом в Python.)