Python中的__new__和__init__

时间:2011-11-12 19:16:35

标签: python class

我正在学习Python,到目前为止,我可以告诉以下关于__new____init__的内容:

  1. __new__用于创建对象
  2. __init__用于对象初始化
  3. __new____init__之前被调用,因为__new__返回一个新实例,之后调用__init__来初始化内部状态。
  4. __new__适用于不可变对象,因为它们在分配后无法更改。所以我们可以返回具有新状态的新实例。
  5. 我们可以将__new____init__用于两个可变对象,因为它的内部状态可以更改。
  6. 但我现在还有另外一个问题。

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

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

      我在下面做了:

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

      虽然我说我想要返回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
      

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

      我读过的SO帖子:

      1. Python object creation
      2. Python's use of __new__ and __init__?

1 个答案:

答案 0 :(得分:48)

  

我应该如何使用__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
  

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

MyClass()将具有__new__返回的值。 Python中没有隐式类型检查;程序员有责任返回正确的类型(“我们这里都是consenting adults”)。能够返回不同于请求的类型对于实现工厂非常有用:您可以返回所请求类型的子类。

这也解释了您观察到的issubclass / isinstance行为:子类关系来自您使用class MyClass(tuple)isinstance反映您返回“错误”从__new__输入。

供参考,请查看 Python语言参考中的requirements for __new__

修改:好的,这是__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

请注意,有smarter ways来完成此行为。