Python中的__new__和__init__

Tar*_*rik 51 python class

我正在学习Python和到目前为止,我可以告诉低于约的事情__new____init__:

  1. __new__ 用于创建对象
  2. __init__ 用于对象初始化
  3. __new__被调用之前__init____new__返回一个新的实例,并__init__随后调用初始化内部状态.
  4. __new__对于不可变对象是有益的,因为它们一旦被分配就无法更改.所以我们可以返回具有新状态的新实例.
  5. 我们可以使用__new____init__为两个可变对象,因为它的内部状态可以改变.

但我现在还有另外一个问题.

  1. 当我创建一个新实例时a = MyClass("hello","world"),如何传递这些参数?我的意思是我应该如何构造类__init__,__new__因为它们是不同的,并且除了默认的第一个参数之外都接受任意参数.
  2. self关键字在名称方面可以改为别的吗?但我想知道cls在名称方面可能会改变其他东西,因为它只是一个参数名称?

我做了一些实验,如下:

>>> class MyClass(tuple):
    def __new__(tuple):
        return [1,2,3]
Run Code Online (Sandbox Code Playgroud)

我在下面做了:

>>> a = MyClass()
>>> a
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

虽然我说我想回来tuple,但这段代码运行正常并且还给了我[1,2,3].我知道在__new__调用函数后,我们将第一个参数作为我们想要接收的类型传递.我们说的是New功能对吗?我不知道除绑定类型以外的其他语言返回类型?

我也做了其他事情:

>>> issubclass(MyClass,list)
False
>>> issubclass(MyClass,tuple)
True
>>> isinstance(a,MyClass)
False
>>> isinstance(a,tuple)
False
>>> isinstance(a,list)
True
Run Code Online (Sandbox Code Playgroud)

我没有做更多的实验,因为进一步不明亮我决定停在那里并决定问StackOverflow.

我读过的SO帖子:

  1. Python对象创建
  2. Python使用__new__和__init__?

Fre*_*Foo 49

我应该如何构造类__init__,__new__因为它们是不同的,并且除了默认的第一个参数之外都接受任意参数.

你很少需要担心__new__.通常,您只需定义__init__并让默认值__new__将构造函数参数传递给它.

self关键字在名称方面可以改为别的吗?但我想知道cls在名称方面可能会改变其他东西,因为它只是一个参数名称?

两者都只是参数名称,在语言中没有特殊含义.但它们的使用在Python社区中是一个非常强大的惯例; 大多数Pythonistas 永远不会更改名称selfcls在这些上下文中,并会在其他人做的时候混淆.

请注意,您使用def __new__(tuple)重新绑定tuple构造函数内的名称.实际实施时__new__,你会想要这样做

def __new__(cls, *args, **kwargs):
    # do allocation to get an object, say, obj
    return obj
Run Code Online (Sandbox Code Playgroud)

虽然我说我想回来tuple,但这段代码运行正常并且还给了我[1,2,3].

MyClass()将具有__new__返回的值.Python中没有隐式类型检查; 程序员有责任返回正确的类型("我们都同意成年人 ").能够返回不同于请求的类型对于实现工厂非常有用:您可以返回所请求类型的子类.

这也解释了你观察到的issubclass/ isinstance行为:你使用的子类关系class MyClass(tuple),isinstance反映了你从中返回"错误"类型__new__.

作为参考,检查出的要求__new__的Python语言参考.

编辑:好的,这是一个可能有用的例子__new__.该类Eel跟踪过程中有多少鳗鱼活着,如果超过某个最大值则拒绝分配.

class Eel(object):
    MAX_EELS = 20
    n_eels = 0

    def __new__(cls, *args, **kwargs):
        if cls.n_eels == cls.MAX_EELS:
            raise HovercraftFull()

        obj = super(Eel, cls).__new__(cls)
        cls.n_eels += 1
        return obj

    def __init__(self, voltage):
        self.voltage = voltage

    def __del__(self):
        type(self).n_eels -= 1

    def electric(self):
        """Is this an electric eel?"""
        return self.voltage > 0
Run Code Online (Sandbox Code Playgroud)

请注意,有更聪明的方法可以实现这种行为.

  • 你不应该从`__new__`调用`__init__`,如果你返回一个类型为`cls`的实例,Python会自己做. (4认同)
  • 我想补充一点,能够从"__new__"返回一些看似奇怪的行为(至少在理论上)可以是有用的.我可以想象类似于"BalancedBinaryTree"类的东西,它可以从列表中初始化.它有`LeafNode`和`EmptyTree`的子类,如果输入列表有0或1个元素,`__new__`返回其中一个.从本质上讲,它意味着您可以在不看似的情况下实现工厂,因此您可以更改您的类是使用工厂还是直接实例化而不必破坏您的界面. (4认同)
  • 在我提到你的鳗鱼例子之前,我给了你 +1。希望我能再给一次“提高 HovercraftFull” (4认同)