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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20661448/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 20:58:52  来源:igfitidea点击:

Should all member variables be initialized in __init__

pythonoopinstance-variables

提问by user1893354

Maybe this is more of a style question than a technical one but I have a class with several member variables and I want to have it work so that some of the member variables are initialized when the user first creates an instance of the class (i.e. in the __init__function) and I want the other member variables to be defined from arguments of member functions that will be called later on. So my question is should I initialize all member variables in the __init__function (and set the ones that will be defined later on to dummy values) or initialize some in the __init__function and some in later functions. I realize this might be difficult to understand so here are a couple of examples.

也许这更像是一个风格问题而不是技术问题,但我有一个包含多个成员变量的类,我想让它工作,以便在用户第一次创建类的实例时初始化一些成员变量(即在该__init__功能),我想其他的成员变量从成员函数参数,将稍后被称为定义。所以我的问题是我应该初始化函数中的所有成员变量__init__(并将稍后定义的成员变量设置为虚拟值)还是在__init__函数中初始化一些,在以后的函数中初始化一些。我意识到这可能很难理解,所以这里有几个例子。

This example has var3set to 0 initially in the __init__function, then set to the desired value later on in the my_funct function.

此示例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

and in this example, var3is not defined at all in the __init__function

在这个例子中,var3__init__函数中根本没有定义

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

  def my_funct(self,var3):
       self.var3=var3

I don't think either way would make a big difference (maybe a slight difference in memory usage). But I was wondering if one of these is preferred over the other for some reason.

我不认为任何一种方式都会产生很大的不同(可能内存使用量略有不同)。但我想知道出于某种原因,其中一个是否比另一个更受欢迎。

采纳答案by Simeon Visser

In object-oriented programming it's up to the developer to ensure an object is always in a consistent state after instantiation and after a method finishes. Other than that you're free to develop the class as you wish (keeping in mind certain principles with subclassing / overriding and so on).

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

A tool such as Pylintwill warn when you're setting instance variables outside __init__. It can be argued that setting all instance variables in the __init__is cleaner but it's not a rule that must be abided by at all times.

当您在外部设置实例变量时,诸如Pylint 之类的工具会发出警告__init__。可以说,在 中设置所有实例变量__init__更干净,但这并不是必须始终遵守的规则。

回答by Derek Litz

I would actually discourage initializing variables you don't always need in __init__to an arbitrary default value.

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

I do question your use of OO if this is the case, but I'm sure there is a valid and understandable case where __init__will not do everything, and the class will want to further modify itself by adding additional attributes with other methods.

如果是这种情况,我确实质疑您对 OO 的使用,但我确信存在一个有效且可理解的情况,其中__init__不会执行所有操作,并且该类将希望通过使用其他方法添加附加属性来进一步修改自身。

The proper way in my opinion to test if a variable was set while running a method that may want to use it would be to use hasattr. This is in the case that this is a valid way to use the method and the test just switches behavior in a sensible way.

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

Another way would be to try and use it and handle the exception and provide some user friendly information about what the user of your class is doing wrong. This is in the case the method needs the attribute to be set before running.

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

i.e. Hey man, you did initialize the class, but you need to make sure the zattribute exists by calling the z_initmethod before running the z_runmethod.

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

Another, arguably the more pythonic way, would be to just document how to use the method in the docstring and then let the exception fly when it is used improperly. This is good enough for the first implementation of something and you can then focus on the next task. This is in the same situation as above, the method needs the attribute to be set.

另一种可以说是更 Pythonic 的方法是只记录如何在文档字符串中使用该方法,然后在使用不当时让异常飞起来。这对于第一次实施某事已经足够了,然后您可以专注于下一个任务。这和上面的情况一样,方法需要设置属性。

The reason I do not like the idea of initializing variables to arbitrary defaults is this can be confusing (because it is arbitrary) and is line noise.

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

If the value is notarbitrary and simply a default value that can be changed you should be using a default value in the __init__method that can be overridden. It can also actually be a valid initial state, which is also notarbitrary and you should set it in the __init__method.

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

So the real answer is it depends, and you should probably avoid it and question your use of OO if you are doing this either by adding attributes in other methods or initializing attributes to arbitrary values.

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

While Simeon Visser is saying to keep your object in a consistent state, he has no basis for what consistency is based on your abstract example. While Pylint warns on this kind of thing, warnings from lint programs are simply so a high level reviewer can be alerted of things that usuallyindicate code smell. I say high level reviewer because a real reviewer should be reading and understanding all of your code, and thus not really need Pylint.

虽然 Simeon Visser 说要使您的对象保持一致状态,但他没有根据您的抽象示例确定什么是一致性。虽然 Pylint 对这类事情发出警告,但来自 lint 程序的警告只是为了提醒高级审阅者注意通常表明代码异味的事情。我说高级审阅者是因为真正的审阅者应该阅读并理解您的所有代码,因此并不真正需要 Pylint。

An example that breaks the rule of thumb:

一个打破经验法则的例子:

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

回答by Cody Aldaz

Here is an excerpt from sololearn.com (a free site to learn python)

这是 sololearn.com(一个免费的学习 Python 的网站)的摘录

"Properties provide a way of customizing access to instance attributes. They are created by putting the property decorator above a method, which means when the instance attribute with the same name as the method is accessed, the method will be called instead.

“属性提供了一种自定义访问实例属性的方法。它们是通过将属性装饰器放在方法之上来创建的,这意味着当访问与方法同名的实例属性时,将改为调用该方法。

One common use of a property is to make an attribute read-only."

属性的一种常见用途是将属性设为只读。”

Example (also from sololearn.com):

示例(也来自 sololearn.com):

class Pizza:
    def __init__(self, toppings):
    self.toppings = toppings

    @property
    def pineapple_allowed(self):
       return False

   pizza = Pizza(["cheese", "tomato"])
   print(pizza.pineapple_allowed)
   pizza.pineapple_allowed = True

Result:

结果:

  >>>
 False
 AttributeError: can't set attribute
 >>>

If var3 depends on var1 and var2 you could do

如果 var3 取决于 var1 和 var2 你可以做

class myClass:
    def __init__(self,var1,var2):
        self.var1=var1
        self.var2=var2
    @property
    def var3(self):
        return(self.var1+self.var2)  #var3 depends on var1 and var2
 m1=myClass(1,2)
 print(m1.var3)   # var3 is 3

var3 can also be set to whatever you want using a setter function. Note that you can avoid setting var3 to an arbitrary value by using None.

var3 也可以使用 setter 函数设置为您想要的任何值。请注意,您可以通过使用 None 来避免将 var3 设置为任意值。

class myClass2(object):
    def __init__(self,var1,var2):
        self.var1=var1
        self.var2=var2
        self._var3=None     # None or an initial value that makes sense
        @property
        def var3(self):
            return(self._var3)
        @var3.setter
        def var3(self,value):
            self._var3=value
   m2=myClass(1,2)
   print(m2.var3)        # var3 is none
   print(m2.var3(10))    # var3 is set to 10