构造函数(Python)之外的方法中的实例变量 - 为什么以及如何?

ano*_*oir 6 python constructor class instance-variables

我的问题涉及在类构造函数之外的方法中初始化的实例变量.这适用于Python.

我先说出我的理解:

  1. 类可以定义构造函数,也可以定义其他方法.
  2. 实例变量通常在构造函数中定义/初始化.
  3. 但是实例变量也可以在构造函数之外定义/初始化,例如在同一类的其他方法中.
  4. (2)和(3)的一个例子 - 参见下面的Cat类中的self.meowself.roar:

    class Cat():
    
        def __init__(self):
            self.meow = "Meow!"
        def meow_bigger(self):
            self.roar = "Roar!"
    
    Run Code Online (Sandbox Code Playgroud)

我的问题:

  1. 为什么在构造函数中初始化实例变量是最佳实践?

  2. 如果实例变量在构造函数以外的方法中定期初始化,可能会出现一般/特定的混乱?(例如,在他的编程Python中读过Mark Lutz的Tkinter指南,我认为这很好,我注意到用于保存PhotoImage对象/引用的实例变量在其他方法中初始化,而不是在构造函数中初始化.它似乎没有工作问题,但从长远来看,这种做法是否会引起问题?)

  3. 在哪些情况下,在其他方法中而不是在构造函数中初始化实例变量会更好


  1. 据我所知,实例变量不是在创建类对象时存在,而是实例化类对象之后存在.继续我上面的代码,我证明了这一点:

    >> c = Cat() 
    >> c.meow
    'Meow!'
    >> c.roar
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
    AttributeError: 'Cat' object has no attribute 'roar'
    >>> c.meow_bigger()
    >>> c.roar
    'Roar!'
    
    Run Code Online (Sandbox Code Playgroud)

    原样:

    • 我一开始无法访问实例变量(c.roar).
    • 但是,在我调用实例方法c.meow_bigger()一次后,我突然能够访问实例变量c.roar.
    • 为什么上述行为如此?

感谢您帮助我理解.

Bry*_*ley 18

为什么在构造函数中初始化实例变量是最佳实践?

明晰。

因为它可以很容易地一目了然地看到类的所有属性。如果在多个方法中初始化变量,不阅读每一行代码就很难理解完整的数据结构。

在内部初始化__init__也使文档更容易。对于您的示例,您不能写“Cat 的实例具有roar属性”。相反,您必须添加一段解释 Cat 的实例可能具有“roar”属性的段落,但仅在调用“meow_louder”方法之后。

清晰才是王道。我见过的最聪明的程序员之一曾经告诉我“向我展示你的数据结构,我可以在不看任何代码的情况下告诉你你的代码是如何工作的”。虽然这有点夸张,但绝对有道理。学习代码库的最大障碍之一是理解它操作的数据。

如果在构造函数以外的方法中定期初始化实例变量,会出现什么一般/特定的混乱?

最明显的一点是,一个对象可能没有在程序的所有部分都可用的属性,导致不得不添加大量额外的代码来处理属性未定义的情况。

在什么情况下最好在其他方法中而不是在构造函数中初始化实例变量?

我不认为有。

注意:您不一定必须使用它的最终值来初始化属性。在您的情况下,初始化roarNone. 它已被初始化为某物这一事实表明它是该类维护的一段数据。如果以后值改变就好了。


0x5*_*453 5

请记住,"纯"Python中的类成员只是一个字典.在您运行定义它们的函数之前,成员不会添加到实例的字典中.理想情况下,这是构造函数,因为这样可以保证无论调用函数的顺序如何,所有成员都将存在.

我相信你上面的例子可以翻译成:

class Cat():
    def __init__(self):
        self.__dict__['meow'] = "Meow!"
    def meow_bigger(self):
        self.__dict__['roar'] = "Roar!"

>>> c = Cat()        # c.__dict__ = { 'meow': "Meow!" }
>>> c.meow_bigger()  # c.__dict__ = { 'meow': "Meow!", 'roar': "Roar!" }
Run Code Online (Sandbox Code Playgroud)