def __init__(self)的用处是什么?

42 投票
3 回答
23116 浏览
提问于 2025-04-18 04:17

我刚开始学Python,看到了一些帖子:Python中的__init__和self到底是什么?不使用def __init__(self)的Python类

不过我试了一下,发现这两个类的结果看起来是一样的-

class A(object):
    def __init__(self):
        self.x = 'Hello'

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

(来自这个问题

还有

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

这两者之间真的有区别吗?或者更一般来说,__init__对类的属性有什么根本性的影响吗?在文档中提到,__init__是在实例被创建时调用的。这是否意味着在创建实例之前,类B中的x就已经建立了?

3 个回答

5

正如其他人所说的,这里讲的是类中的变量和类的实例中的变量之间的区别。看看下面的例子。

>>> 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
[]

对于像元组、字符串这样的不可变对象,可能不太容易发现这个区别,但对于可变对象来说,这个区别就非常重要了——因为对可变对象的修改会在该类的所有实例之间共享。

另外,关键字参数的默认值也会出现同样的情况哦!

>>> 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的新手感到困惑。你能早早发现这些区别,真是太好了!

9

在第一个例子中,你有一个类的实例变量。这个变量只能通过实例来访问,也就是需要用到self。

class A():
    def __init__(self):
        self.x = 'hello'

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

在第二个例子中,你有一个静态变量。你可以通过类的名字A来访问这个变量。

class A():
  x = 'hello'

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

实际上,你可以有一个静态变量和一个实例变量,它们的名字是一样的:

class A():
    x = 'hello'
    def __init__(self):
        self.x = 'world'

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

静态变量在所有实例之间是共享的。

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/

49

好的,看看这个:

class A(object):
    def __init__(self):
        self.lst = []

class B(object):
    lst = []

现在试试这个:

>>> x = B()
>>> y = B()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1, 2]
>>> x.lst is y.lst
True

还有这个:

>>> x = A()
>>> y = A()
>>> x.lst.append(1)
>>> y.lst.append(2)
>>> x.lst
[1]
>>> x.lst is y.lst
False

这是不是意味着在类B中,x是在实例化之前就已经建立了?

是的,x是一个类属性(它在所有实例之间是共享的)。而在类A中,x是一个实例属性。恰好字符串是不可变的,所以在你的例子中没有什么实质性的区别(除了类B使用的内存更少,因为它只为所有实例定义了一个字符串)。但是在我的例子中,区别就很大了。

撰写回答