【问题标题】:What is the difference writing code in a class and in def __init__(self) in Python? [duplicate]在 Python 中的类和 def __init__(self) 中编写代码有什么区别? [复制]
【发布时间】:2012-12-11 20:17:05
【问题描述】:

可能重复:
Variables inside and outside of a class __init__() function

我知道当一个类被调用时,它会先运行__init__ 中的代码。我还是看不出那和直接在类下写代码的区别。

例如:

class main():
  x = 1

  def disp(self):
    print self.x
class main():
  def __init__(self):
    self.x = 1

  def disp(self):
    print self.x

对我来说,两者都具有相同的功能。 (也许我遗漏了一些东西。)我想知道哪个更(咳咳)pythonic 以及为什么。

【问题讨论】:

标签: python class init


【解决方案1】:

如前所述,类属性(在类级别分配)和实例属性(例如在__init__ 中分配为自身属性)是不同的。

另一方面,在您的第一个类中,您定义了两个不同的属性(类x 和实例x)共存,但它们会相互干扰。下面的代码尝试显示如果以这种方式定义类可能会遇到的问题。

In [32]: class main():
   ....:     x = 1
   ....:     def disp(self):
   ....:         print(self.x)
   ....:

# I create 2 instances
In [33]: jim = main()
In [34]: jane = main()

# as expected...:
In [35]: main.x
Out[35]: 1

In [36]: jim.x
Out[36]: 1

In [37]: jane.x
Out[37]: 1

# now, I assign to jim attribute x
In [38]: jim.x = 5

# main class preserves its attribute value as well as jane instance  
In [39]: main.x
Out[39]: 1

In [40]: jane.x
Out[40]: 1

# But what happens if I change the class attribute ?
In [41]: main.x = 10

# nothing to jim (I overwrote before jim.x)
In [42]: jim.x
Out[42]: 5

# but jane did see the change 
In [43]: jane.x
Out[43]: 10

【讨论】:

    【解决方案2】:

    这里有几个关键区别,__init__ 和在课堂上写的,以及你写的内容。

    使用x = 1

    首先,你是对的——这两条代码有效地为你的目的做同样的事情(特别是因为我们在这里使用 int 对象,这对于可变对象会有所不同):

    请注意,他们实际上并没有做同样的事情-请参阅此答案中的 cmets 以进行澄清。

    class main(object):
        x = 1
    

    class main(object):
        def __init__(self):
            self.x = 1
    

    这就是为什么许多非标准 Python 库,如 mongoenginedjango 模型,都有一个标准,您可以在不使用 __init__ 语句的情况下创建类,以免覆盖内置的,但仍然允许您创建类属性,例如 Django 示例:

    class mymodel(models.model):
        name = models.CharField(max_length=20)
        url = models.UrlField()
    

    但是,正如另一张海报指出的那样,两者之间的区别在于,当 x=1__init__ 函数之外时,即使未初始化,它也是类本身的一部分——参见 Zagoulkin Dmitry 的回答了解更多详情。不过,在大多数情况下,这种区别与您无关。

    其他注意事项

    除了设置变量之外,__init__ 还有更多用途。最重要的一项是在初始化期间接受参数的能力。 据我所知,没有__init__ 函数就没有办法做到这一点。我会在这个例子中告诉你我的意思。

    假设我们正在创建一个Person 类,当我们创建一个Person 时,我们会提供他们的年龄,然后自动为我们计算他们的出生年份。

    import datetime
    class Person(object):
        def __init__(self, age):
            self.age = age
            self.birth_year = (datetime.date.today() - datetime.timedelta(days=age*365)).year
    

    使用中:

    >>>joe = Person(23)
    >>>joe.age
    23
    >>>joe.birth_year
    1990
    

    如果没有__init__,这将是不可能的,因为否则我们无法将初始化传递给age 参数。

    【讨论】:

    • “这两项代码有效地做同样的事情”。并不真地。第一个是类属性,第二个产生每个实例的属性。在OP给出的示例中,x(即main.x)和self.x是共存的不同变量,因此可以独立修改(分配给实例时除外)。
    • 这是一个公平的观点,我已经更新了我的答案来参考你。
    • 所有答案都可以说是好的。但我之所以选择这个,是因为在初始化示例期间接受参数的示例。这很有帮助。
    【解决方案3】:

    不一样。 在第一个示例中,您有 x 没有初始化。

    >>> class main():
    ...     def __init__(self):
    ...             self.x =1
    ...
    >>> test2 = main()
    >>> dir(test2)
    ['__doc__', '__init__', '__module__', 'x']
    >>> class main1():
    ...     x =1
    ...     def disp(self):
    ...             print self.x
    ...
    >>> dir(main1)
    ['__doc__', '__module__', 'disp', 'x']
    >>> dir(main)
    ['__doc__', '__init__', '__module__']
    >>>
    

    【讨论】:

    • 这是一个明显的例子。但这是一个重复的问题。我该怎么办>.
    【解决方案4】:

    让我们考虑以下类定义:

    class Main:
            x = 1
    
            def __init__(self):
                self.y = 5
    

    在这种情况下,我们可以直接引用 x:Main.x 即它是一个类属性,它属于这个类的每个对象。

    >>>Main.x
    1
    

    但是,属性y 是特定于每个对象的。我们不能这样直接引用它:

    >>> Main.y
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: class Main has no attribute 'y'
    

    你需要实例化一个Main类的对象来引用y:

    >>> obj = Main()
    >>> obj.y
    5
    

    这类似于 C++ 和 Java 中的 static 变量。

    【讨论】:

    • 很好的例子,但请注意,OP 代码有隐藏的惊喜,因为它声明了具有相同名称的类和实例变量x
    【解决方案5】:

    是的,正如其他各种问题中所述,类主体中定义的变量是类的属性,而def __init__(self) 块中定义的变量是类实例的属性。

    Difference between defining a member in init to defining it in the class body in Python?

    【讨论】:

      猜你喜欢
      • 2016-10-08
      • 2022-12-08
      • 2012-11-01
      • 1970-01-01
      • 2015-08-29
      • 2015-11-04
      • 1970-01-01
      • 2015-07-24
      • 2016-02-24
      相关资源
      最近更新 更多