【问题标题】:Python: Why would float.__new__(cls) work when cls isn't float?Python:当 cls 不浮动时,为什么 float.__new__(cls) 会起作用?
【发布时间】:2012-11-12 03:15:59
【问题描述】:

python 文档here 中的以下示例让我有些困惑。

>>> class inch(float):
...     "Convert from inch to meter"
...     def __new__(cls, arg=0.0):
...         return float.__new__(cls, arg*0.0254)
...
>>> print inch(12)
0.3048
>>> 

据推测,float 是在 Python 深处定义的实际浮点类。当我们调用float.__new__(cls, argument) 时,我们偷偷地调用了为给定参数返回float 实例的函数,但是我们传递给它的是inch 类而不是float 类。既然英寸类并没有真正做任何事情,为什么这会起作用?

【问题讨论】:

    标签: python


    【解决方案1】:

    因为inch 是float 的子类,所以它满足float.__new__() 实例工厂的所有要求。 __new__(cls) static method 的工作是创建第一个参数的实例,而不是它的“自己的”类。

    请注意那里的“静态方法”一词。 __new__ 工厂实际上只是一个与类相关的专业函数,仅出于继承原因。换句话说,它是一个在面向对象层次结构中运行良好的函数。您应该通过super() 找到它,或者直接调用它(如此处所做)。以下实际上会更 Pythonic:

    def __new__(cls, arg=0.0):
        return super(inch, cls).__new__(cls, arg*0.0254)
    

    因为如果要在多重继承层次结构中使用inch,那将调用“正确的”__new__ 函数;在这个简单的例子中,它最终会调用float.__new__

    因此,__new__(cls, ...) 应该创建一个 cls 类型的实例。为什么然后将它绑定到一个类而不是让它成为一个更通用的函数呢?因为在float.__new__(cls, value) 的情况下,它不仅创建了一个cls 类型的新实例,还将它的初始值设置为value。为了使它起作用,float.__new__(...) 需要对float 类的外观有深入的了解。因为inch()float() 的子类,所以它也具有与float() 完全相同的必要位,因此当float.__new__() 工厂创建一个新的inch 实例时,所有这些位都可以生成它是一个inch() 实例。

    【讨论】:

    • 太棒了!现在这更有意义了。所以,为了确保我现在理解 - new 是一种静态方法,也就是说它对“自我”没有兴趣(也没有论据)。当我为这个特定的类覆盖它时,它可能保持静态(因为几乎不可能有一个需要实例的 new 方法)。没有任何装饰器,python 怎么知道这样做?
    • 因为__new__ 很特别。它自动成为静态方法,请参阅我在答案中链接的文档。
    • __new__ 是双重特殊的。这可能是一种课堂方法。在传递cls(例如,float.__new__(cls, ..))时调用父级__new__ 而不使用super() 的能力可能是why __new__ is not a classmethod 的原因。
    • 啊哈——就在第一行:“一个静态方法(特殊情况,所以你不需要这样声明它)”。谢谢大家!
    【解决方案2】:

    回答这个问题需要一点背景知识:

    1. 只有object.__new__()可以创建一个新的instances类型的对象,这个 kind 对象不能被子类化。
    2. 一个实例有一个type,可以在传递类型名的时候赋值 cls__new__(cls) 作为第一个参数。 class 关键字创建 另一种对象:类(又名类型)和这些对象 可以被子类化。

    现在,回到你的例子,什么

    float.__new__(cls, argument)
    

    本质上是使用object.__new__(cls)创建一个新实例(float.__base__object), 将类型cls(在本例中为inch)分配给它,并且还对float.__new__ 中定义的argument 执行某些操作。

    所以当cls 不是float 而是inch 时它会起作用也就不足为奇了:类/类型已经由class inch(float) 创建,您只是将此类型分配给一个新实例.

    【讨论】:

      猜你喜欢
      • 2023-03-13
      • 2010-09-28
      • 1970-01-01
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多