2012-02-01 5 views
31

Changelog для Python 2.2 (где были введены классы нового стиля) говорит следующее о функции __new__:Почему не __new__ в классах нового стиля Python метод класса?

__new__ статический метод, а не метод класса. Первоначально я думал, что это должен быть метод класса, и именно поэтому я добавил примитив classmethod. К сожалению, с помощью методов класса, upcalls не работают правильно в этом случае, поэтому я должен был сделать его статическим методом с явным классом в качестве его первого аргумента.

Однако я не могу придумать, почему методы класса не будут работать для этой цели, и это, безусловно, будет выглядеть лучше. Почему в конце концов метод __new__ оказался в качестве метода класса? О чем говорит Гвидо, когда он говорит, что «восстания в этом случае не работают»?

ответ

17

__new__ будет статический методом позволяет потребительный случай, когда вы создаете экземпляр подкласса в нем:

return super(<currentclass>, cls).__new__(subcls, *args, **kwargs) 

Если new является метод класса, то выше написано как:

return super(<currentclass>, cls).new(*args, **kwargs) 

и нет места для размещения subcls.

Я действительно не вижу, когда это было бы правильным использованием __new__. Может быть, я этого не вижу, но мне кажется, что это полностью патологическое его использование (и нужно сказать, что если вы все еще этого хотите, тогда вы можете получить доступ к нему с помощью object.__new__.__func__). По крайней мере, мне очень трудно представить, что это было бы причиной того, что Гвидо изменит __new__ как метод класса на статический метод.

Более распространенным случаем является вызов родителя __new__ без использования super(). You need a place to pass cls explicitly in this case:

class Base(object): 
    @classmethod 
    def new(cls): 
     print("Base.new(%r)" % (cls,)) 
     return cls() 

class UseSuper(Base): 
    @classmethod 
    def new(cls): 
     print("UseSuper.new(%r)" % (cls,)) 
     return super(UseSuper, cls).new() # passes cls as the first arg 

class NoSuper(Base): 
    @classmethod 
    def new(cls): 
     print("NoSuper.new(%r)" % (cls,)) 
     return Base.new() # passes Base as the first arg 

class UseFunc(Base): 
    @classmethod 
    def new(cls): 
     print("UseFunc.new(%r)" % (cls,)) 
     return Base.new.im_func(cls) # or `.__func__(cls)`. # passes cls as the first arg 

print(UseSuper.new()) 
print('-'*60) 
print(NoSuper.new()) 
print('-'*60) 
print(UseFunc.new()) 
+0

@ Duncan: Я намеренно использовал 'new', а не' __new__'. Если неясно, оставьте комментарий, я попытаюсь уточнить. – jfs

+0

Я думаю, если бы вы использовали имя, которое было немного более отчетливым, чем просто отбрасывание подчеркиваний, это было бы яснее, но теперь я понимаю, спасибо. – Duncan

+0

Когда это будет действительно проблема? Если вам нужен экземпляр 'subcls', почему бы вам не назвать' subcls.new() '? Выполнение этого так, как вы описываете, имеет эффект не запускать правильные '__new__' функции на' subcls'. – Dolda2000

Смежные вопросы