Python - 应该在__init__中初始化所有成员变量

use*_*354 40 python oop instance-variables

也许这更像是一个样式问题,而不是技术问题,但我有一个带有几个成员变量的python类,我想让它工作,以便在用户首次创建类的实例时初始化一些成员变量(即在__init__函数中)我希望从稍后将调用的成员函数的参数定义其他成员变量.所以我的问题是我应该初始化函数中的所有成员变量__init__(并将稍后定义的变量设置为虚拟值)或者在__init__函数中初始化一些变量,在稍后的函数中初始化一些变量.我意识到这可能很难理解,所以这里有几个例子.

此示例var3最初在__init__函数中设置为0 ,然后在my_funct函数中设置为所需的值.

class myClass(object):
   def __init__(self,var1,var2):
        self.var1=var1
        self.var2=var2
        self.var3=0

  def my_funct(self,var3):
       self.var3=var3
Run Code Online (Sandbox Code Playgroud)

并且在此示例中,var3没有在所限定的所有__init__功能

class myClass(object):
   def __init__(self,var1,var2):
        self.var1=var1
        self.var2=var2

  def my_funct(self,var3):
       self.var3=var3
Run Code Online (Sandbox Code Playgroud)

我认为任何一种方式都不会产生很大的不同(可能是内存使用量略有不同).但我想知道其中一个是否因为某些原因而优先于另一个.

Sim*_*ser 29

在面向对象的编程中,开发人员应确保在实例化之后和方法完成之后对象始终处于一致状态.除此之外,您可以根据自己的意愿自由开发课程(请记住子类化/覆盖等的某些原则).

当您在外部设置实例变量时,Pylint等工具会发出警告__init__.可以说,设置所有实例变量__init__更清晰,但这不是必须始终遵守的规则.

  • @ user1893354你可以在实例化之后添加变量但是不可能创建一个对象,调用一个或多个方法并最终得到一个混乱的对象.方法的行为及其返回值应始终保持一致.例如,我们不能有一个报告"破损"和"正常运行"的"汽车"类. (3认同)
  • 是的,但是对象的状态通常由多个变量组成.例如,如果你正在创建一个视频游戏,`Car`可能有变量,如:`self.wheel_damage`,`self.exterior_damage`,`self.engine_damage`(等).在这种情况下,不应该有100%健康的汽车,但也有75%的车轮损坏. (3认同)
  • 同意.一致性是关键 - 您不希望外人使用您的API或类处于无效状态. (2认同)
  • 您能否简要定义一下“一致状态”的含义?这是否意味着实例化后不应添加新的成员变量? (2认同)

Der*_*itz 6

我实际上不鼓励将并非总是需要的变量初始化__init__为任意默认值。

我确实质疑您是否使用OO,但是我确信有一个有效且可以理解的情况,它__init__不会做任何事情,并且该类将希望通过使用其他方法添加其他属性来进一步修改自身。

我认为,在运行可能要使用的方法时测试是否设置了变量的正确方法是use hasattr。在这种情况下,这是使用该方法的有效方法,而测试只是以合理的方式切换行为。

另一种方法是尝试使用它并处理异常,并提供有关您的类用户做错了什么的一些用户友好信息。这是在方法需要在运行之前设置属性的情况下。

例如,嘿,您确实初始化了该类,但是在运行该方法之前,需要z通过调用该z_init方法来确保该属性存在z_run

另一个可以说是更Python化的方法是,仅在文档字符串中记录如何使用该方法,然后在异常使用不当时让异常运行。这对于某些东西的第一次实现就足够了,然后您可以专注于下一个任务。在与上述相同的情况下,该方法需要设置属性。

我不喜欢将变量初始化为任意默认值的想法的原因是,这可能会造成混淆(因为它是任意的)并且是线路噪声。

如果该值不是任意值,而只是可以更改的默认值,则应在__init__可以覆盖的方法中使用默认值。实际上,它也可以是有效的初始状态,这也不是任意的,您应该在__init__方法中进行设置。

因此,真正的答案取决于它,您可能应该避免使用它,并通过添加其他方法中的属性或将属性初始化为任意值来质疑您对OO的使用。

Simeon Visser在说要使您的对象保持一致状态时,他没有依据抽象示例得出什么一致性的依据。虽然Pylint对此类事情发出警告,但皮棉程序发出的警告只是为了使高级检查人员可以警惕通常指示代码气味的事情。我说高级审阅者,是因为真正的审阅者应该阅读并理解您的所有代码,因此并不需要Pylint。

违反经验法则的示例:

class Mutant(object):
    """A mutant!"""

    def __init__(self):
        """A mutant is born with only 1 eye and 1 mouth"""

        self.eyes = 1
        self.mouth = 1
        self.location = 'Montana'

    def roll_to(self, location):
        """If they have limbs, running is less dangerous"""

        if hasattr(self, 'limbs'):
             print 'Your mutant broke its limbs off!!'
             del self.limbs

        self.location = location

    def run_to(self, location):
        """If they don't have limbs, running is not effective"""

        if not hasattr(self, 'limbs'):
             print 'Your mutant tries to run but he has no limbs.'
        else:
             self.location = location

    def grow_limbs(self, number_of_limbs):
         """Ah, evolution!"""

         assert number_of_limbs > 0, 'Cannot grow 0 or less limbs...'

         if hasattr(self, 'limbs'):
             self.limbs += number_of_limbs
         else:
             self.limbs = number_of_limbs
Run Code Online (Sandbox Code Playgroud)

  • 就我个人而言,我更喜欢将肢体设置为“无”,而不是删除它 (2认同)