Если вы звоните __new__
, и вы используете тип как ваш метакласс, то будет вызван __init__
, если результат __new__
является подтипом вашего типа. Иными словами, скажем, у вас есть класс Foo. Если вы вызываете результат PyObject_Type(self)
, это то же самое, что и звонок Foo()
. Это означает, что Foo. __new__
будет вызываться, и если возвращаемое значение является подтипом Foo, то будет вызываться __init__
.
Копаем немного глубже, когда вы вызываете Foo(), это действительно вызывает type_call (в typeobject.c), вот что делает tp_new, за которым следует tp_init. Если вы напрямую предоставляете новую функцию своего объекта (например, Foo_new() вместо PyObject_Type (self)), вы вызываете __new__
без звонка __init__
, и вы можете получить то, что ищете. (Не забудьте указать Foo в качестве аргумента для __new__
).
Итак, чтобы наконец ответить на ваш вопрос, вы можете просто позвонить Foo.__new__(Foo, ...)
. Вот код, который делает то, что вы ищете.
class Foo(object):
def __new__(cls):
return super(Foo, cls).__new__(cls)
def __init__(self):
print "__init__"
def __reduce__(self):
return (Foo.__new__, (Foo,))
print "one"
x = Foo() # prints __init__
print "two"
y = Foo.__new__(Foo) # does not print __init__
print "three"
import pickle
p = pickle.dumps(Foo)
z = pickle.loads(p) # does not print __init__
Как и в сторону, когда я пытался понять все это, я обнаружил, что почти во всех случаях, я мог бы, по сути, реализовать свой код и позволить __init__
называться. Моя ошибка возникла из-за того, что я не отделял материал, который входит в третий аргумент кортежа __reduce__
. Вполне нормально не давать ничего для второго аргумента (при условии, что это __init__
) и просто предоставить кучу вещей в третьем аргументе, который будет напрямую обновлять __dict__
. Если вы просмотрите исходный код cpython в каталоге Modules and Objects, вы увидите ряд реализаций __reduce__
, все из которых работают именно так.
В принципе, '__init__' не следует вызывать, и это предпочтительный способ рассола. См. Раздел '__getinitargs__':« Когда экземпляр маринованного класса не заполнен, его метод '__init __()' обычно * не * вызывается ». Вы внедряете '__getinitargs__'? –
Хорошо, забудьте об этом. Это только для нормальных классов. –