我最近遇到一个Python的bug。那是一个新手犯的愚蠢错误,但它让我开始思考Python的机制(我是一名长期从事C++编程,但对Python还比较陌生)。我会呈现出有问题的代码,并解释我如何修复它,然后我有几个问题...
场景:我有一个叫做A的类,它有一个字典数据成员,以下是其代码(当然这只是简化过的):
class A:
dict1={}
def add_stuff_to_1(self, k, v):
self.dict1[k]=v
def print_stuff(self):
print(self.dict1)
使用这段代码的类是B类:
class B:
def do_something_with_a1(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('a', 1)
a_instance.add_stuff_to_1('b', 2)
a_instance.print_stuff()
def do_something_with_a2(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('c', 1)
a_instance.add_stuff_to_1('d', 2)
a_instance.print_stuff()
def do_something_with_a3(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('e', 1)
a_instance.add_stuff_to_1('f', 2)
a_instance.print_stuff()
def __init__(self):
self.do_something_with_a1()
print("---")
self.do_something_with_a2()
print("---")
self.do_something_with_a3()
请注意,每次调用do_something_with_aX()
都会初始化一个新的“干净”的A类实例,并在添加之前和之后打印字典。
错误(如果你还没有发现):
>>> b_instance = B()
{}
{'a': 1, 'b': 2}
---
{'a': 1, 'b': 2}
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
---
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
{'a': 1, 'c': 1, 'b': 2, 'e': 1, 'd': 2, 'f': 2}
在 class A 的第二次初始化中,字典不是空的,而是以上一次初始化的内容开头,以此类推。我期望它们应该是"新鲜的"。解决这个“bug”的方法显然是添加:
self.dict1 = {}
在A类的__init__
构造函数中,然而这让我想到:
- "dict1 = {}"在dict1声明时的初始化的意义是什么?它没有意义吗?
- 导致从最后一个初始化复制引用的实例化机制是什么?
- 如果我在构造函数(或任何其他数据成员)中添加"self.dict1 = {}",它如何不影响先前初始化实例的字典成员?
编辑:在阅读了答案后,我现在明白了,通过声明一个数据成员并在__init__
或其他地方不引用它作为self.dict1,实际上定义了C++/Java中所称的静态数据成员。通过将其称为self.dict1,我使其"绑定"到实例。
__init__()
。你是有意为之,让它等同于一个空的def __init__(self): pass
,因此当然它没有数据成员吗?如果不是,请修复你的代码。 - smci