关于类:Python中的__ new__和__init__

__new__ and __init__ in Python

我正在学习python,到目前为止,我可以告诉你以下关于__new____init__的事情:

  • __new__用于对象创建
  • __init__用于对象初始化
  • __new____init__之前被调用,因为__new__返回一个新实例,__init__随后被调用以初始化内部状态。
  • __new__适用于不可变对象,因为一旦分配,它们就不能更改。所以我们可以返回具有新状态的新实例。
  • 我们可以用__new____init__来表示两个可变对象,因为它的内部状态是可以改变的。
  • 但我现在还有一个问题。

  • 当我创建一个新实例,如a = MyClass("hello","world")时,这些参数是如何传递的?我的意思是,我应该如何使用__init____new__构造类,因为它们不同,并且除了默认第一个参数外,都接受任意参数。
  • self关键字是在名称方面可以改成别的什么吗?但我想知道,cls是不是在名称方面会发生变化,因为它只是一个参数名?
  • 我做了如下的一些实验:

    1
    2
    3
    >>> class MyClass(tuple):
        def __new__(tuple):
            return [1,2,3]

    我做了以下的事情:

    1
    2
    3
    >>> a = MyClass()
    >>> a
    [1, 2, 3]

    虽然我说我要返回tuple,但这个代码工作正常,返回了我[1,2,3]。我知道,调用__new__函数后,我们将第一个参数作为希望接收的类型进行传递。我们说的是New函数,对吗?除了绑定类型,我不知道其他语言返回类型?

    我也做了另一件事:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> issubclass(MyClass,list)
    False
    >>> issubclass(MyClass,tuple)
    True
    >>> isinstance(a,MyClass)
    False
    >>> isinstance(a,tuple)
    False
    >>> isinstance(a,list)
    True

    我没有做更多的实验,因为更远的地方不亮,我决定停在那里,然后决定问StackOverflow。

    我读到的SO帖子:

  • 创建python对象
  • python使用了uuu new_uuuu和uuu init_uuuuu?

  • how I should structure the class using __init__ and __new__ as they are different and both accepts arbitrary arguments besides default first argument.

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

    self keyword is in terms of name can be changed to something else? But I am wondering cls is in terms of name is subject to change to something else as it is just a parameter name?

    两者都只是参数名,在语言中没有特殊意义。但是他们的使用在Python社区中是一个非常强的约定;在这些上下文中,大多数pythonistas将永远不会更改名称selfcls,并且在其他人更改时会混淆。

    注意,使用def __new__(tuple)会在构造函数函数内部重新绑定名称tuple。当实际实现__new__时,您将希望这样做

    1
    2
    3
    def __new__(cls, *args, **kwargs):
        # do allocation to get an object, say, obj
        return obj

    Albeit I said I want to return tuple, this code works fine and returned me [1,2,3].

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

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

    作为参考,请查看python语言参考中对__new__的要求。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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

    记住,有更好的方法来完成这个行为。