Python 类成员初始化 [英] Python Class Members Initialization
问题描述
我最近刚与 Python 中的一个错误作斗争.这是那些愚蠢的新手错误之一,但它让我想到了 Python 的机制(我是 C++ 的长期程序员,Python 新手).我将列出有问题的代码并解释我做了什么来修复它,然后我有几个问题......
场景:我有一个叫做A的类,它有一个字典数据成员,下面是它的代码(当然这是简化了):
A 类:dict1={}def add_stuff_to_1(self, k, v):self.dict1[k]=vdef print_stuff(self):打印(self.dict1)
使用这个代码的类是B类:
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()打印(" - -")self.do_something_with_a2()打印(" - -")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}在A类的第二次初始化中,字典不是空的,而是从上次初始化的内容开始,以此类推.我希望他们开始新鲜".
解决这个错误"的显然是添加:
self.dict1 = {}
在 A 类的 __init__
构造函数中.然而,这让我感到奇怪:
- 在 dict1 的声明点(A 类中的第一行)初始化dict1 = {}"是什么意思?毫无意义?
- 导致从上次初始化复制引用的实例化机制是什么?
- 如果我在构造函数(或任何其他数据成员)中添加self.dict1 = {}",它如何不影响先前初始化实例的字典成员?
<小时>
按照答案,我现在明白通过声明一个数据成员而不是在 __init__
或其他地方作为 self.dict1 引用它,我实际上是在定义 C++/Java 一个静态数据成员.通过将其称为 self.dict1,我将其设置为实例绑定".
你一直提到的 bug 是 已记录,Python 类的标准行为.
像最初那样在 __init__
之外声明一个 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 with self
in __init__
; its as simple as that.
这篇关于Python 类成员初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!