def __init__(self)的用处是什么?
我刚开始学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 个回答
正如其他人所说的,这里讲的是类中的变量和类的实例中的变量之间的区别。看看下面的例子。
>>> 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的新手感到困惑。你能早早发现这些区别,真是太好了!
在第一个例子中,你有一个类的实例变量。这个变量只能通过实例来访问,也就是需要用到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/
好的,看看这个:
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使用的内存更少,因为它只为所有实例定义了一个字符串)。但是在我的例子中,区别就很大了。