Python类成员初始化 [英] Python Class Members Initialization
问题描述
我刚刚在Python中打过一个错误。它是那些蠢的新手bug之一,但它让我思考Python的机制(我是一个长期的C ++程序员,Python的新手)。我将展示buggy代码,并解释我做了什么来解决它,然后我有几个问题...
场景:我有一个类A,它有一个字典数据成员,以下是它的代码(这是当然是简化):
A类:
dict1 = {}
def add_stuff_to_1(self,k,v):
self.dict1 [k] = v
def print_stuff
print(self.dict1)
使用此代码的类是B类: p>
class B:
类A的构造函数。但是,这使我很奇怪:
def do_something_with_a1(self):
a_instance = A $ b 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 ',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()$ b $注意,每次调用do_something_with_aX()
都会初始化一个新的clean类A的实例,并在添加之前和之后打印字典。
错误(如果你还没有想到它) p>
>>> 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}
在类A的第二个初始化中,字典不为空,但是从最后一次初始化的内容开始,等等。我希望他们开始新鲜。
解决这个bug显然是添加了:
self.dict1 = {}
> __ init __
- dict1 = {}在dict1声明的点初始化(类A中的第一行)?
- 导致从最后一次初始化复制引用的实例化机制是什么?
- 如果在构造函数(或任何其他数据成员)中添加self.dict1 = {},它如何影响先前初始化实例的字典成员?
编辑:根据答案,我现在明白,通过声明一个数据成员而不是引用它
__ init __
或其他地方作为self.dict1,我实际上定义了在C ++ / Java中调用的静态数据成员。通过调用它self.dict1我把它实例绑定。解决方案是文档,Python类的标准行为。
正如你最初所做的那样声明一个
__ init __
外部的dict声明一个类级别的变量。它只创建一次,只要创建新对象,它将重用这个相同的dict。要创建实例变量,请在__ init __
中使用self
声明它们;它很简单。I have just recently battled a bug in Python. It was one of those silly newbie bugs, but it got me thinking about the mechanisms of Python (I'm a long time C++ programmer, new to Python). I will lay out the buggy code and explain what I did to fix it, and then I have a couple of questions...
The scenario: I have a class called A, that has a dictionary data member, following is its code (this is simplification of course):
class A: dict1={} def add_stuff_to_1(self, k, v): self.dict1[k]=v def print_stuff(self): print(self.dict1)
The class using this code is class 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()
Notice that every call to
do_something_with_aX()
initializes a new "clean" instance of class A, and prints the dictionary before and after the addition.The bug (in case you haven't figured it out yet):
>>> 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}
In the second initialization of class A, the dictionaries are not empty, but start with the contents of the last initialization, and so forth. I expected them to start "fresh".
What solves this "bug" is obviously adding:
self.dict1 = {}
In the
__init__
constructor of class A. However, that made me wonder:
- What is the meaning of the "dict1 = {}" initialization at the point of dict1's declaration (first line in class A)? It is meaningless?
- What's the mechanism of instantiation that causes copying the reference from the last initialization?
- If I add "self.dict1 = {}" in the constructor (or any other data member), how does it not affect the dictionary member of previously initialized instances?
EDIT: Following the answers I now understand that by declaring a data member and not referring to it in the
__init__
or somewhere else as self.dict1, I'm practically defining what's called in C++/Java a static data member. By calling it self.dict1 I'm making it "instance-bound".解决方案What you keep referring to as a bug is the documented, standard behavior of Python classes.
Declaring a dict outside of
__init__
as you initially did is declaring a class-level variable. It is only created once at first, whenever you create new objects it will reuse this same dict. To create instance variables, you declare them withself
in__init__
; its as simple as that.这篇关于Python类成员初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!