【问题标题】:Python constructors and __init__Python 构造函数和 __init__
【发布时间】:2012-02-17 15:20:18
【问题描述】:

为什么构造函数确实被称为“构造函数”?它们的目的是什么?它们与类中的方法有何不同?

另外,一个班级可以有更多的__init__ 吗?我尝试了以下方法,有人可以解释一下结果吗?

>>> class test:
    def __init__(self):
        print "init 1"
    def __init__(self):
        print "init 2"

>>> s=test()
init 2

最后,__init__ 是运算符重载器吗?

【问题讨论】:

  • 从技术上讲,__init__ 是一个初始化程序。 python 构造函数是__new__。 Python 使用自动两阶段初始化 - __new__ 返回一个有效但(通常)未填充的对象(参见 bool 的反例),然后自动调用 __init__。这避免了像 C++ 这样的语言对部分构造对象的问题——在 Python 中你永远不会有一个(尽管它可能是部分初始化的)。您几乎不需要在一个类上同时覆盖 __new__ 和 __init__。
  • @TimDelaney:我不确定你对 C++ 中部分构造的对象的意思。
  • @phresnel 在 C++ 中,对象的类型是基类(而不是子类),而在基类构造函数中。您不能在基类构造函数中调用虚方法并让子类提供实现。在 Java 中,您可以在基类构造函数中调用子类方法,但子类成员变量将在 基类构造函数(和方法调用)之后自动初始化。在像 Python 这样具有两阶段初始化的语言中,您可以愉快地调用基类初始化程序中的方法并让子类提供(或覆盖)行为。
  • @TimDelaney:啊,谢谢你的澄清。
  • @TimDelaney。我认为您的评论应该取代接受的答案。

标签: python


【解决方案1】:

为什么构造函数确实被称为“构造函数”?

构造函数(名为__new__)创建并返回该类的新实例。所以C.__new__ 类方法是类C 的构造函数。

C.__init__ 实例方法在特定实例上调用,在创建之后,在将其传递回调用者之前对其进行初始化。所以该方法是 C 的新实例的 initialiser。

它们与类中的方法有何不同?

如official documentation 中所述,__init__ 在实例创建后调用。其他方法不接受这种处理。

他们的目的是什么?

构造函数C.__new__ 的目的是在构造新的C 实例期间定义自定义行为。

初始化程序C.__init__ 的目的是在创建C 的每个实例后定义其自定义初始化。

例如 Python 允许你这样做:

class Test(object):
    pass

t = Test()

t.x = 10   # here you're building your object t
print t.x

但如果您希望Test 的每个 实例的x 属性等于10,则可以将该代码放入__init__:

class Test(object):
    def __init__(self):
        self.x = 10

t = Test()
print t.x

每个实例方法(在类的特定实例上调用的方法)都接收实例作为其第一个参数。该参数通常被命名为self。

类方法,例如构造函数__new__,接收类作为它们的第一个参数。

现在,如果您想要 x 属性的自定义值,您只需将该值作为参数传递给 __init__:

class Test(object):
    def __init__(self, x):
        self.x = x

t = Test(10)
print t.x
z = Test(20)
print t.x

我希望这可以帮助您消除一些疑问,并且由于您已经收到其他问题的好答案,所以我将在此停止:)

【讨论】:

    【解决方案2】:

    Python 中没有函数重载,这意味着您不能拥有多个同名但参数不同的函数。

    在您的代码示例中,您没有重载 __init__()。发生的情况是,第二个定义重新绑定名称 __init__ 到新方法,导致第一个方法无法访问。

    关于构造函数的一般问题,Wikipedia 是一个很好的起点。对于 Python 特定的东西,我强烈推荐Python docs。

    【讨论】:

    • 这是否也意味着源文件被依次解析(解释?)?我可以确定我以后定义的任何函数都会覆盖之前定义的同名函数吗? :( 我的 Q 听起来很傻……应该知道它
    • @0xc0de:在 Python 中,函数定义实际上是可执行语句,并且从上到下运行,所以是的。
    • @0xc0de 实际发生的是类的主体在它自己的命名空间中执行,然后将该命名空间传递给元类(连同名称和基类)。然后,函数定义只是创建一个具有指定主体的函数并将其分配给它的名称。 __init__ 的最后一个作业将是课堂上的最终作业。
    【解决方案3】:

    Python 中没有方法重载的概念。但是你可以通过指定可选参数和关键字参数来达到类似的效果

    【讨论】:

      【解决方案4】:

      类只是用来创建对象的蓝图。构造函数是每次创建对象时运行的一些代码。因此,拥有两个构造函数是没有意义的。发生的情况是第二个覆盖了第一个。

      您通常使用它们为该对象创建变量,如下所示:

      >>> class testing:
      ...     def __init__(self, init_value):
      ...         self.some_value = init_value
      

      那么你可以做的是从这个类中创建一个对象,如下所示:

      >>> testobject = testing(5)
      

      然后测试对象将有一个名为 some_value 的对象,在此示例中为 5。

      >>> testobject.some_value
      5
      

      但是您不需要像我在示例中那样为每个对象设置一个值。你也可以这样做:

      >>> class testing:
      ...     def __init__(self):
      ...         self.some_value = 5
      

      那么 some_value 的值为 5 并且您不必在创建对象时设置它。

      >>> testobject = testing()
      >>> testobject.some_value
      5
      

      >>> 和 ... 在我的示例中不是你写的。这就是它在 pyshell 中的样子...

      【讨论】:

      • 没问题,很高兴它帮助了你:)
      【解决方案5】:

      创建新对象时会自动调用构造函数,从而“构造”对象。您可以拥有多个 init 的原因是因为名称只是 python 中的引用,您可以随时更改每个变量引用的内容(因此是动态类型)

      def func(): #now func refers to an empty funcion
          pass
      ...
      func=5      #now func refers to the number 5
      def func():
          print "something"    #now func refers to a different function
      

      在你的类定义中,它只保留后一个

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-19
        • 1970-01-01
        • 2021-01-17
        • 1970-01-01
        • 1970-01-01
        • 2014-06-13
        相关资源
        最近更新 更多