【问题标题】:Is a constructor __init__ necessary for a class in Python?Python中的类是否需要构造函数__init__?
【发布时间】:2016-07-09 09:52:07
【问题描述】:

我读到构造函数就像传递给类的第一个参数,这对我来说很有意义,因为参数似乎是通过__init__ 方法传递给类的。例如,

class NewsStory(object):
    def __init__(self, guid, title, subject, summary, link):
        self.guid = guid
        self.title = title
        self.subject = subject
        self.summary = summary
        self.link = link

    def get_guid(self):
        return self.guid

    def get_title(self):
        return self.title

    def get_subject(self):
        return self.subject

    def get_summary(self):
        return self.summary

    def get_link(self):
        return self.link
firstStory = NewsStory('Globally Unique Identifier', \
    'first_title','first_subject','This is an example \
    sumary','example_link@something.com')

print firstStory.get_guid() # prints Globally Unique Identifier

所以当我“调用”类时,我将__init__ 方法的参数传递给它?我是新手,我读到的所有东西都很难理解和困惑。谢谢!

编辑 1

我发现这个问题有助于解释一些事情,比如 newinit 之间的区别,抱歉,我不知道如何添加链接,得删掉并粘贴:What can `__init__` do that `__new__` cannot?

【问题讨论】:

  • 你真的试过不使用它吗?

标签: python class oop constructor initialization


【解决方案1】:

我在这里看到了构造函数之间的误解——构造对象和初始化对象:

Python's use of __new__ and __init__?

当您需要控制新实例的创建时,请使用__new__。当您需要控制新实例的初始化时,请使用__init__

所以我们在这里必须小心。

我读到构造函数就像传递给类的第一个参数,这对我来说很有意义,因为参数似乎是通过__init__ 方法传递给类的。

构造函数不会传递给类,确切地说构造函数的结果(__new__)将是类或其子类中每个实例方法的第一个参数(注意:__new__ 仅适用对于新式类):

class A:
    def __new__(self):
            return 'xyz'

查看调用类(创建对象)时会发生什么:

>>> A()
'xyz'
>>> type(A())
<class 'str'>

调用类不再返回A类型的实例,因为我们改变了构造函数__new__的机制。实际上,这样做不仅会改变类的整体含义,而且很难破译。在特定对象的创建期间,您不太可能切换对象的类型。我希望这句话有意义,如果没有,它在你的代码中如何有意义!

class A:
    def __new__(self):
            return 'xyz'

    def type_check(self):
            print(type(self))

看看当我们尝试调用type_check方法时会发生什么:

>>> a = A()
>>> a
'xyz'
>>> a.type_check()
AttributeError: 'str' object has no attribute 'type_check'

a 不是A 类的对象,所以基本上你不能再访问A 类了。

__init__ 用于初始化对象的状态。 __init__ 不是在创建对象后调用将初始化对象成员的方法,而是通过在创建时初始化对象的成员来解决此问题,因此,如果您在类中有一个名为 name 的成员并且如果你想在创建类时初始化name,而不是调用额外的方法init_name('name'),你肯定会为此使用__init__

所以当我“调用”类时,我将__init__ 方法中的参数传递给它?

当你调用类时,你将参数传递给__init__方法?

无论您向类传递什么参数,所有参数都将传递给__init__,并自动为您添加一个附加参数,即通常称为self(实例本身)的隐含对象,它将始终作为最左边的参数由 Python 自动生成:

class A:
    def __init__(self, a, b):
        self.a = a
        self.b = b 

        A(  34,  35) 
 self.a = 34 |    |  
             |    | 
             |    | self.b = 35  
  init(self, a,   b)
        |
        |
        | 
       The instance that you created by calling the class A() 

注意:__init__classic classes and new style classes 都有效。而__new__仅适用于新式类。

【讨论】:

  • 当我调用 a = A() 我得到 <__main__.a instance at> 当我在我的文本编辑器中调用方法类型检查 [a = A(), a.type_check() ] 我得到 。也许我们有不同版本的 Python?
  • 我编辑了我的答案并添加了一个小注释。是的,如果您使用的是 Python 2.X,则有两种类型的类,经典类和新型类。请注意,__new__ 仅适用于新型类,即继承自预定义类 object 的类。所以你需要添加类object作为类A的超类,class A(object)仅在2.X中。所以再次__new__ 仅适用于新样式类。 What is the difference between old style and new style classes in Python?
  • 虽然__new__ 是非常高级的功能,但您不会经常在代码中遇到它。我只是想说明__init____new__ 之间的区别。 __init__ 不是构造函数,它是在创建该对象期间(调用类时)用于初始化对象成员(例如姓名、地址、电话...)的方法。因此,您不应该将我为__new__ 方法提供的示例视为有效或广泛使用的代码。恰恰相反,我只是想说明两者之间的区别(__init____new__)。
【解决方案2】:

理解 Python 类构造函数并不太难,但肯定有点棘手,尤其是如果我们已经从其他支持 OOP 的语言(如 C++ 或 Java)中听到了一些面向对象的编程术语。

类构造函数的主要目的是创建具有针对特定初始状态定制的实例的对象。在 Python 中理解这一点非常重要,因为不需要声明数据属性(成员变量),并且它们在首次分配时立即存在。因此,对实例的所有数据属性进行分组的好地方是构造函数。

在类的所有函数之外分配的任何数据属性都由该类的所有实例共享。在这里,Python 变得更加棘手,因为它具有可变数据类型和不可变数据类型。

例如看下面的代码sn-p:

我的班级: 我 = 3 arr = [] x = 我的班级() x.i = 4 x.arr.append('x') y = MyClass() y.i = 5 y.arr.append('y') MyClass.arr.append('m') 打印 "{}, {}, {}".format(x.i, y.i, MyClass.i) 打印 "{}, {}, {}".format(x.arr, y.arr, MyClass.arr)

输出将是:

4、5、3 ['x', 'y', 'm'], ['x', 'y', 'm'], ['x', 'y', 'm']

由于整数在 Python 中是不可变的数据类型,每次赋值都会创建整数对象的新副本,这可能会误导一些程序员,因为看起来每个实例都有自己的成员变量私有副本。列表数据类型是可变的,所以上面的代码 sn-p 从所有实例中修改相同的列表副本。

因此,如果所有成员都由类的所有实例共享,则不需要为 Python 类编写构造函数,否则编写构造函数并将所有私有数据成员分组在其中是一种好习惯。

在上面的代码 sn-p 中,如果程序员真的想要一个私有数据成员,i 用于类实例,那么与其依赖不可变属性,不如编写一个构造函数并初始化变量。

修改代码以使用构造函数:

我的班级: arr = [] def __init__(self, i): 自我.i = 我 x = MyClass(4) y = MyClass(5) 打印 "{}, {}".format(x.i, y.i)

输出将是:

4, 5

希望在此线程上其他人已经分享的有用知识的基础上有所帮助。祝你好运。

【讨论】:

    【解决方案3】:

    你在正确的轨道上。 __init__() 的参数是实例化类的参数。这类似于其他语言中的 构造函数,但是 __new__()(您几乎不需要实际使用)是实际创建对象的对象。

    如果我创建这个类:

    class TestClass(object):
        def __init__(self, paramA, paramB):
            self.paramA = paramA
            self.paramB = paramB
    

    我会像这样实例化这个类:

    tc = TestClass(1, 2)
    

    如果我打印:

    print tc.paramA
    print tc.paramB
    

    我明白了:

    1
    2
    

    但是,构造函数除了传递参数之外还有其他用途。它们运行创建对象时需要运行的任何代码,例如,这里:

    class AnotherTestClass(object):
        def __init__(self):
            self.name = "testing"
    
    atc = AnotherTestClass()
    print atc.name
    

    会显示:

    testing
    

    如果您不需要向类传递任何参数来创建它的对象,并且不需要进行任何初始化或初始设置,则不需要__init__() 方法:

    class SimpleTestClass(object):
        def output(self, text):
            print text
    
    stc = SimpleTestClass()
    stc.output("hi!")
    

    输出:

    hi!
    

    请注意,以上是 Python 2.7 语法,因为原始问题是使用 Python 2.x。

    【讨论】:

    • __init__ 不是传统意义上的构造函数。对象已经存在。 __new__ 将是构造函数,在 python 中你很少需要接触它。
    • @MaxNoe,您在技术上是正确的,但是来自其他语言,构造函数是最好的比较,因为这是您将初始化参数传递给对象的地方。我在编辑中更改了措辞以澄清这一点。以 PHP 为例,__construct() 仍然可以引用$self,但没有什么可以与__new__() 媲美。
    • OP 在他的问题中使用了 Python 2 语法!查看他对print 语句的使用。这太荒谬了。
    【解决方案4】:

    不,构造函数只是被调用来构造对象的方法。它没有在任何地方通过。而是将对象 itself 自动传递给类的所有方法。

    如果你没有要构造的东西,则不需要构造函数,但通常你一开始就有事情要做。

    【讨论】:

      【解决方案5】:

      Python 类的工作方式与其他语言中的类略有不同。 例如,python 中没有私有属性。只是命名约定暗示方法或成员变量不适合公共使用(前导_)。

      虽然每个类都必须具有属性__new____init__,它们共同构建了其他语言可能称为构造函数的东西,但python 基类实现了这些方法。如果不需要,您不必覆盖它们。

      这很好:

      class A:
         def hello(self):
              print('Hello, World')
      
      a = A()
      a.hello()
      

      在python中__new__(cls, ...)首先用于创建请求的cls的类实例。然后将新创建的实例作为self 传递给__init__(self, ...)

      __new____init__ 方法都接收您传递给 构造表达式 的参数。这就是python调用m = MyClas(1, 2, 3)的方式。

      class A:
          def __new__(cls, *args, **kwargs):
              print('In __new__')
              print(args)
              print(kwargs)
              return object.__new__(cls) # create a new object of type cls
      
          def __init__(self, *args, **kwargs):
              print('In __init__')
              print(args)
              print(kwargs)
      
      
      a = A(1, 2, c=3)
      

      结果:

      In __new__
      (1, 2)
      {'c': 3}
      In __init__
      (1, 2)
      {'c': 3}
      

      【讨论】:

      • OP 使用的是 Python 2,而不是 Python 3。
      【解决方案6】:

      没有必要,因为它是在调用类时定义默认值的对象构造函数,但开发人员通常建议使用 init 函数作为约定。 init 在普通函数必须返回值的情况下返回“none”。

      【讨论】:

        猜你喜欢
        • 2014-04-23
        • 2013-10-25
        • 2021-05-25
        • 1970-01-01
        • 1970-01-01
        • 2012-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多