我有一个接收一些数据的类对象。基于一个条件,我需要更改该数据,但仅在该条件下。我遇到的问题是,当我调用dict.update()
时,它也会更新原始变量。因此,随后的请求进入,现在可以说,原始变量被“污染”了,并且使用了它不应该具有的覆盖信息。
假设字典是这样的:
my_attributes = {"test": True}
和一些类似这样的逻辑:
class MyClass(object):
def __init__(self, attributes):
if my_condition():
attributes.update({"test": False})
最终结果:
>>> my_attributes
{'test': False}
因此,下次使用MyClass
时,这些根属性仍然会被覆盖。
我似乎已经通过重新定义attributes
绕过了这个问题
class MyClass(object):
def __init__(self, attributes):
if my_condition():
attributes = {}
attributes.update(my_attributes)
attributes.update({"test": False})
这似乎绕过了问题,但我不完全确定这是一个很好的解决方案,甚至是正确的解决方案。
发布于 2019-05-27 04:22:00
如下所示:
class MyClass(object):
@staticmethod
def my_condition():
return True
def __init__(self, attributes):
self.attributes = {**attributes}
if MyClass.my_condition():
self.attributes["test"] = False
my_attributes = {"test": True}
cls_obj = MyClass(my_attributes)
print("my_attributes:", my_attributes, "class.attributes:", cls_obj.attributes)
输出:
my_attributes: {'test': True} class.attributes: {'test': False}
发布于 2019-05-27 05:18:32
将一个(可变的)字典引用传递给一个对象。现在,您有两个引用的所有者:构造函数的调用者(对象的“外部世界”)和对象本身。这两个所有者可以修改字典。下面是一个插图:
>>> d = {}
>>> def ctor(d): return [d] # just build a list with one element
>>> L = ctor(d)
>>> d[1] = 2
>>> L
[{1: 2}]
>>> L[0][3] = 4
>>> d
{1: 2, 3: 4}
你如何防止这种情况发生?两个所有者都想保护自己不受变量的疯狂突变的影响。如果我是外部世界,我希望向dict传递一个不可变的引用,但Python不为dict提供不可变的引用。副本就是我们要走的路:
>>> d = {}
>>> L = ctor(dict(d)) # I don't give you *my* d
>>> d[1] = 2
>>> L
[{}]
如果我是对象,我会在使用它之前复制一个对象:
>>> d = {}
>>> def ctor2(d): return [dict(d)] # to be sure L[0] is *mine*!
>>> L = ctor2(dict(d)) # I don't give you *my* d
但是现在你已经制作了对象的两个副本,因为每个人都害怕看到它的变量被另一个修改了。如果字典包含(可变的)引用,问题仍然存在。
解决方案是详细说明每个人的职责:
class MyClass(object):
"""Usage: MyClass(attributes).do_something() where attributes is a mapping.
The mapping won't be modified"""
...
请注意,这是常见的预期行为:除非指定,否则函数/构造器的参数不会被修改。我们尽可能避免副作用,但情况并不总是这样:参见list.sort()
与sorted(...)
。
因此,我认为您的解决方案很好。但我倾向于避免在构造函数中使用过多的逻辑:
class MyClass(object):
@staticmethod
def create_prod(attributes):
attributes = dict(attributes)
attributes.update({"test": False})
return MyClass(attributes)
@staticmethod
def create_test(attributes):
return MyClass(attributes)
def __init__(self, attributes):
self._attributes = attributes # MyClass won't modify attributes
https://stackoverflow.com/questions/56317027
复制相似问题