为什么Python新风格类中的__new__不是类方法?

45 投票
1 回答
4549 浏览
提问于 2025-04-17 12:06

Python 2.2的更新日志提到,__new__这个函数是一个静态方法,而不是类方法。最开始我以为它应该是个类方法,所以我加上了classmethod这个东西。但不幸的是,在这种情况下,类方法的调用方式不太对劲,所以我不得不把它做成一个静态方法,并且把类作为第一个参数。

不过,我想不出为什么类方法在这里不适用,而且用类方法看起来肯定更好。那么,为什么最后__new__没有成为一个类方法呢?当Guido说“在这种情况下,上层调用不太对劲”时,他指的是什么呢?

1 个回答

31

__new__ 是一个静态方法,这样做的好处是你可以在里面创建子类的实例:

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

如果 new 是一个类方法,那么上面的代码就会写成:

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

但这样就没有地方可以放 subcls 了。

不过,我其实不太明白什么时候使用 __new__ 是合适的。也许我没看明白,但我觉得这似乎是个不太正常的用法(而且要说的是,如果你真的想这么做,可以通过 object.__new__.__func__ 来访问)。至少,我很难想象这会是 Guido 改变 __new__ 从类方法变成静态方法的原因。

更常见的情况是调用父类的 __new__,而不使用 super()。在这种情况下,你需要一个地方来明确传递 cls

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())

撰写回答