关于python: __init__(self)的有用性?

Usefulness of def __init__(self)?

我对python还比较陌生,注意到了这些帖子:python初始化和self他们做什么?和不使用def_uu init_uuu(self)的python类

然而,在玩了它之后,我注意到这两个类给出了明显相同的结果。-

1
2
3
4
5
6
class A(object):
    def __init__(self):
        self.x = 'Hello'

    def method_a(self, foo):
        print self.x + ' ' + foo

(从这个问题)

1
2
3
4
class B(object):
    x = 'Hello'
    def method_b(self,foo):
        print self.x + ' ' + foo

这两者有什么区别吗?或者,更一般地说,__init__是否改变了类属性的本质?在文档中提到,创建实例时调用__init__。这是否意味着类B中的x是在实例化之前建立的?


是的,看看这个:

1
2
3
4
5
6
class A(object):
    def __init__(self):
        self.lst = []

class B(object):
    lst = []

现在尝试:

1
2
3
4
5
6
7
8
>>> x = B()
>>> y = B()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1, 2]
>>> x.lst is y.lst
True

而这:

1
2
3
4
5
6
7
8
>>> x = A()
>>> y = A()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1]
>>> x.lst is y.lst
False

Does this mean that x in class B is established before instantiation?

是的,它是一个类属性(在实例之间共享)。在类A中,它是一个实例属性。字符串是不可变的,因此在您的场景中没有真正的区别(除了类B使用较少的内存,因为它只为所有实例定义一个字符串)。但在我的例子中有一个很大的例子。


在第一个示例中,您有类实例的变量。此变量只能通过实例访问(自选)。

1
2
3
4
5
6
class A():
    def __init__(self):
        self.x = 'hello'

print A.x -> AttributeError
print A().x -> 'hello'

在第二个示例中,您有一个静态变量。由于类A的名称,您可以访问这个变量。

1
2
3
4
5
class A():
  x = 'hello'

print A.x -> 'hello'
print A().x -> 'hello'

实际上,可以有一个静态变量和一个同名的实例变量:

1
2
3
4
5
6
7
class A():
    x = 'hello'
    def __init__(self):
        self.x = 'world'

print A.x -> hello
print A().x -> world

静态值在所有实例之间共享

1
2
3
4
5
6
7
8
9
10
11
12
class A():
    x = 'hello'

    @staticmethod
    def talk():
        print A.x

a = A()
print a.talk() -> hello

A.x = 'world'
print a.talk() -> world

这里有一篇好文章:http://linuxwell.com/2011/07/21/static-variables-and-methods-in-python/


正如其他人所说,它是类上的变量和类实例上的变量之间的差异。请参见以下示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> class A:
...     a = []
...
>>> class B:
...     def __init__(self):
...         self.b = []
...
>>> a1 = A()
>>> a1.a.append('hello')
>>> a2 = A()
>>> a2.a
['hello']
>>> b1 = B()
>>> b1.b.append('goodbye')
>>> b2 = B()
>>> b2.b
[]

对于元组、字符串等不可变对象,很难注意到差异,但对于可变对象,它会更改所有内容—应用的更改在该类的所有实例之间共享。

还要注意,关键字参数默认值也会发生同样的行为!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
>>> class A:
...     def __init__(self, a=[]):
...         a.append('hello')
...         print(a)
...
>>> A()
['hello']
>>> A()
['hello', 'hello']
>>> A()
['hello', 'hello', 'hello']

>>> class B:
...     def __init__(self, b=None):
...         if b is None:
...             b = []
...         b.append('goodbye')
...         print(b)
...
>>> B()
['goodbye']
>>> B()
['goodbye']
>>> B()
['goodbye']

这种行为影响了许多新的Python程序员。有利于你尽早发现这些区别!