分数模块中__new__

Ric*_*ard 5 python metaprogramming

我一直在努力理解__new__和元编程.所以我看看官方的python源代码.

http://hg.python.org/cpython/file/2.7/Lib/fractions.py

它们__new__对Fractions 的功能如下:

class Fraction(Rational):

    def __new__(cls, numerator=0, denominator=None):
        """Constructs a Fraction. ...        """

        self = super(Fraction, cls).__new__(cls)
        ...

        if isinstance(numerator, float):
                # Exact conversion from float
                value = Fraction.from_float(numerator)
                self._numerator = value._numerator
                self._denominator = value._denominator
                return self

    @classmethod
    def from_float(cls, f):
        """Converts a finite float to a rational number, exactly. ..."""
        # ...
        return cls(*f.as_integer_ratio())
Run Code Online (Sandbox Code Playgroud)

为什么他们return self,而不是

return Fraction.from_float(numerator)
Run Code Online (Sandbox Code Playgroud)

我以为我明白了,但现在我很困惑.

(编辑)

为了支持子类化,改变它会有什么不同

return cls.from_float(numerator)
Run Code Online (Sandbox Code Playgroud)

Ray*_*ger 4

分数中的代码是一个复杂的起点.最好逐步建立一个理解.

1)object .__ new__是创建新式类实例的根工具:

o = object()
Run Code Online (Sandbox Code Playgroud)

2)定义__new__的类通常调用object .__ new__来完成它的工作:

class A(object):
    def __new__(cls):
        return object.__new__(cls)

a = A()
Run Code Online (Sandbox Code Playgroud)

3)classmethod通常依赖于类的__new__来完成它的工作:

class A(object):

    def __new__(cls):
        return object.__new__(cls)

    @classmethod
    def from_something(cls):
        return cls.__new__()
Run Code Online (Sandbox Code Playgroud)

有了这种理解,您可以看到分数模块正在做什么:

1)from_float()调用cls(numerator, denominator)将实例创建委托给Fraction .__ new __()方法.

2)Fraction .__ new __()方法使用super()来调用object .__ new __()来进行实际的实例创建.

附加物

@Blckknght想要知道为什么value不直接返回(在它被创建之后,它的分子和Demoninator selfvalue被扔掉之前被复制到了.答案是Fraction.from_float创建一个Fraction的实例而不是cls.换句话说,代码正在为子类化提供支持:

>>> from fractions import Fraction
>>> class MyFraction(Fraction):
        pass

>>> f = MyFraction(2, 3)
>>> f
Fraction(2, 3)
>>> f.__class__               # this MUST be MyFraction, not a Fraction
<class '__main__.MyFraction'>
Run Code Online (Sandbox Code Playgroud)

编辑

@richard想知道"为什么不使用:return cls.from_float(numerator)"?

它被称为开放封闭原则.子类格式应该能够覆盖from_float()而不会无意中破坏__init __():

>>> class MyFraction(Fraction):
        def from_float(cls, *args):
        raise NotImplemented


>>> f = MyFraction(5.75)
>>> f
Fraction(23, 4)
Run Code Online (Sandbox Code Playgroud)

  • 虽然我同意这似乎有点迟钝,并且在对这些事情不熟悉时并不是很容易理解("__new__"本身并不过分困难,但仍然可能是一个心理障碍 - 尤其是当来自其他语言时),我怀疑来自这样一个权威来源的替代答案将是可用的:) (2认同)