【问题标题】:Why isn't __new__ in Python new-style classes a class method?为什么 Python 新式类中的 __new__ 不是类方法?
【发布时间】:2012-02-23 21:52:55
【问题描述】:

Python 2.2 的变更日志(其中引入了新式类)对 __new__ 函数有以下说明:

__new__ 是静态方法,不是类方法。我最初认为它必须是一个类方法,这就是我添加classmethod 原语的原因。不幸的是,对于类方法,向上调用在这种情况下无法正常工作,因此我不得不将其设为静态方法,并以显式类作为其第一个参数。

但是,我想不出为什么类方法不能用于此目的,而且它肯定会更好看。为什么__new__ 最终没有成为类方法?当 Guido 说“在这种情况下向上调用不起作用”时,他指的是什么?

【问题讨论】:

    标签: python new-operator language-design new-style-class


    【解决方案1】:

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

    【讨论】:

    • @Duncan:我故意使用new 而不是__new__。如果不清楚,请发表评论,我会尽力详细说明。
    • 我认为,如果您使用的名称比去掉下划线更清晰一点,它会更清楚,但我现在明白了,谢谢。
    • 不过,这实际上何时会成为问题?如果你想要subcls 的实例,为什么不调用subcls.new()?按照您描述的方式进行操作只会导致无法在 subcls 上运行正确的 __new__ 函数。
    • @Dolda2000:更常见的情况是调用父级__new__ 而不使用super()You need a place to pass cls explicitly in this case.
    • @Searcherer:没有。 new()__new__ 是完全不同的方法。这里的“new”是一个普通的类方法(它可以是任何名称,例如,“new_method_to_illustrate_some_point_in_the_answer”__new__ 是魔术(静态)方法——它必须被称为 __new__
    猜你喜欢
    • 2020-12-05
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 2011-10-21
    • 2015-06-16
    • 1970-01-01
    • 2011-04-16
    相关资源
    最近更新 更多