【问题标题】:python class attribute reference side effect?python类属性引用副作用?
【发布时间】:2020-09-01 13:59:23
【问题描述】:

我对代码中的错误感到困惑:

给定以下类,方法为distribute_tags

class ConsulData:
    def __init__(self, logger, marshalled_data, prom_numbering, prom_count):
        self.logger = logger
        self.current = marshalled_data
        self.to_update= {}
        self.payloads = []
        self.prom_count = prom_count
        self.prom_numbering = prom_numbering

    def distribute_tags(self):
        cpt = 0
        cp_current = copy.deepcopy(self.current)
        for keys, values in cp_current.items():
            num = (cpt % self.prom_count) + self.prom_numbering
            prometheus_tag = "prometheus-{}".format(num)
            if not prometheus_tag in values['Tags']:
                self.to_update[keys] = values
                data = []
                [data.append(v) for v in values['Tags'] if not v.startswith("prometheus")]
                data.append(prometheus_tag)
                self.to_update[keys]['Tags'] = data
            cpt += 1
    {...}

没有deepcopy,循环执行后,print(self.current == self.to_update)返回True

print(id(self.current) == id(self.to_update)) 返回 False。

deepcopy 的使用修复了我意想不到的错误,因为 distribute_tags 内部所做的事情或多或少与做的事情相同:

In [2]: d1 = {'key1':'value1', 'key2':'value2'}
In [3]: d2 = {}

In [4]: for k, v in d1.items():
   ...:     d2[k] = v

In [6]: d2['key1'] = 'lol'

In [8]: d1
Out[8]: {'key1': 'value1', 'key2': 'value2'}

In [9]: d2
Out[9]: {'key1': 'lol', 'key2': 'value2'}

其中 d1 数据不受 d2 修改的影响,因为它们是对不同对象的 2 个不同引用。

传递给 init 函数的 marshalled_data 如下所示:

payload = {
    'service1': {
        'ID': 'service1',
        'Service': 'service1', 
        'Tags': ['sre-metrics', 'prometheus-2'], 
        'Meta': {
            'env': 'dev', 
            'namespace': 'test', 
            'path': '/path1', 
            'svc': 'svc1', 
            'team': 'testing'},
        'Port': 80, 
        'Address': 'test1.testing.org', 
        'Weights': {'Passing': 1, 'Warning': 1}, 
        'EnableTagOverride': False
    }, 
...

【问题讨论】:

  • self.to_update[keys] = values 不会复制values。因此,当您使用 self.to_update[keys]['Tags'] = data 时,如果您不使用 deepcopy(),那么您也在修改原始字典
  • 谢谢@Barmar 我把它当作答案

标签: python class dictionary reference


【解决方案1】:

如果你不做深拷贝,

self.to_update[keys] = values

分配对同一 values 字典的引用。当你以后做

self.to_update[keys]['Tags'] = data

您正在修改该字典,因此两个值仍然相等。

【讨论】:

    猜你喜欢
    • 2012-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-04
    • 2019-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多