Python:在没有构造函数的情况下将对象重新分配给 Class 不会覆盖字典字段
Python: Reassigning Object to Class with No Constructor Does Not Overwrite Dictionary Field
我正在使用 Python 3.9.1
,但对 Python 的默认构造函数的工作方式感到困惑。
我下面的 class 有一个 Dictionary
字段,没有构造函数。
当我填充它的 Dictionary
然后将我的对象重新分配给一个新实例时,字典保留其现有值(这也发生在 List
字段):
from typing import Dict
class MyClass:
records: Dict[str, str] = {}
if __name__ == '__main__':
my_class = MyClass()
print(my_class.records) # prints `{}`.
my_class.records['1'] = 'one'
print(my_class.records) # prints `{'1': 'one'}`.
# This does not overwrite `my_class` with a new instance.
# `records` still contains the above element.
my_class = MyClass()
print(my_class.records) # prints `{'1': 'one'}`.
但是,当我添加构造函数时,它按预期工作:
from typing import Dict
class MyClass:
records: Dict[str, str] = {}
def __init__(self) -> None:
self.records = {}
if __name__ == '__main__':
my_class = MyClass()
print(my_class.records) # prints `{}`.
my_class.records['1'] = 'one'
print(my_class.records) # prints `{'1': 'one'}`.
# `my_class` is now overwritten and `records` has been set to `{}`.
my_class = MyClass()
print(my_class.records) # prints `{}`
我的印象是 Python 的默认构造函数会使用我在 class 中声明的字段(在本例中为 records: Dict[str, str] = {}
)来覆盖现有对象。
让我更加困惑的是,当我使用常规字段时(string
在下面的情况下,但它也适用于自定义 classes),我不需要构造函数覆盖字段:
class MyClass:
field: str = ''
if __name__ == '__main__':
my_class = MyClass()
print(my_class.field) # prints nothing.
my_class.field = 'some value'
print(my_class.field) # prints `some value`.
# `field` has been reset to '' even though `MyClass` has no constructor.
my_class = MyClass()
print(my_class.field) # prints nothing.
谁能解释一下 Python 在做什么?
Specifically, why is the dictionary field's state being changed instead of it being overwritten?
因为您没有分配给记录。你只是在读它。这个
my_class.records['1'] = 'one'
相当于这个
d = my_class.records
d['1'] = 'one'
此外,这就是添加该构造函数使代码“有效”的原因。因为在其中,您要重新分配 records
.
self.records = {}
这是一个很好的话题,在 python 中开始学习基本数据类型时经常遇到它。 你知道嗡嗡声 - 一切都是对象
现在解决方案:
您遇到的问题有两个原因。
- 可变性
- Class变量
让我们一起探索吧。
在您演示的第一个代码中...让我向您展示(修剪后的代码)
class MyClass:
records: Dict[str, str] = {}
my_class = MyClass()
print(my_class.records) # prints `{}`.
这里发生了两件事,首先在 class space 中创建了一个名为 'record' 的变量,其数据类型为 Dict
。其次它是一个可变数据类型。
在第二个示例中显示 str
数据类型,它是不可变的。
而且,这就是技巧发生的地方。
python 的工作方式有时会让您感到困惑。首先,这些是不可变和可变类型,它们将分别为您提供相同的行为:
不可变对象: int, float, long, complex, string tuple, bool
Mutable Object: list, dict, set, byte array, user-defined classes
↓ 与其搞得一团糟。考虑这个↓
a = [1, 2, 3]
b = a
a[0] = 111
# Now?
b
>>> [111, 2, 3]
#But
a = (1, 2, 3)
b = a
a = (111, 2, 3)
b
>>> (1, 2, 3)
我想这是众所周知的,但幕后的这个确切原则正在发生在你的案例中。
在这里您还可以检查不可变对象中的 id 是否会更改,但在可变对象中则不会。
如果我们不注意简单的事情,那么 python 有很多事情可以愚弄我们。
阅读更多内容 Amazing article focusing just on this
我正在使用 Python 3.9.1
,但对 Python 的默认构造函数的工作方式感到困惑。
我下面的 class 有一个 Dictionary
字段,没有构造函数。
当我填充它的 Dictionary
然后将我的对象重新分配给一个新实例时,字典保留其现有值(这也发生在 List
字段):
from typing import Dict
class MyClass:
records: Dict[str, str] = {}
if __name__ == '__main__':
my_class = MyClass()
print(my_class.records) # prints `{}`.
my_class.records['1'] = 'one'
print(my_class.records) # prints `{'1': 'one'}`.
# This does not overwrite `my_class` with a new instance.
# `records` still contains the above element.
my_class = MyClass()
print(my_class.records) # prints `{'1': 'one'}`.
但是,当我添加构造函数时,它按预期工作:
from typing import Dict
class MyClass:
records: Dict[str, str] = {}
def __init__(self) -> None:
self.records = {}
if __name__ == '__main__':
my_class = MyClass()
print(my_class.records) # prints `{}`.
my_class.records['1'] = 'one'
print(my_class.records) # prints `{'1': 'one'}`.
# `my_class` is now overwritten and `records` has been set to `{}`.
my_class = MyClass()
print(my_class.records) # prints `{}`
我的印象是 Python 的默认构造函数会使用我在 class 中声明的字段(在本例中为 records: Dict[str, str] = {}
)来覆盖现有对象。
让我更加困惑的是,当我使用常规字段时(string
在下面的情况下,但它也适用于自定义 classes),我不需要构造函数覆盖字段:
class MyClass:
field: str = ''
if __name__ == '__main__':
my_class = MyClass()
print(my_class.field) # prints nothing.
my_class.field = 'some value'
print(my_class.field) # prints `some value`.
# `field` has been reset to '' even though `MyClass` has no constructor.
my_class = MyClass()
print(my_class.field) # prints nothing.
谁能解释一下 Python 在做什么?
Specifically, why is the dictionary field's state being changed instead of it being overwritten?
因为您没有分配给记录。你只是在读它。这个
my_class.records['1'] = 'one'
相当于这个
d = my_class.records
d['1'] = 'one'
此外,这就是添加该构造函数使代码“有效”的原因。因为在其中,您要重新分配 records
.
self.records = {}
这是一个很好的话题,在 python 中开始学习基本数据类型时经常遇到它。 你知道嗡嗡声 - 一切都是对象
现在解决方案:
您遇到的问题有两个原因。
- 可变性
- Class变量
让我们一起探索吧。 在您演示的第一个代码中...让我向您展示(修剪后的代码)
class MyClass:
records: Dict[str, str] = {}
my_class = MyClass()
print(my_class.records) # prints `{}`.
这里发生了两件事,首先在 class space 中创建了一个名为 'record' 的变量,其数据类型为 Dict
。其次它是一个可变数据类型。
在第二个示例中显示 str
数据类型,它是不可变的。
而且,这就是技巧发生的地方。
python 的工作方式有时会让您感到困惑。首先,这些是不可变和可变类型,它们将分别为您提供相同的行为:
不可变对象: int, float, long, complex, string tuple, bool
Mutable Object: list, dict, set, byte array, user-defined classes
↓ 与其搞得一团糟。考虑这个↓
a = [1, 2, 3]
b = a
a[0] = 111
# Now?
b
>>> [111, 2, 3]
#But
a = (1, 2, 3)
b = a
a = (111, 2, 3)
b
>>> (1, 2, 3)
我想这是众所周知的,但幕后的这个确切原则正在发生在你的案例中。
在这里您还可以检查不可变对象中的 id 是否会更改,但在可变对象中则不会。
如果我们不注意简单的事情,那么 python 有很多事情可以愚弄我们。 阅读更多内容 Amazing article focusing just on this