【问题标题】:Using decorators vs iteration to set values?使用装饰器与迭代来设置值?
【发布时间】:2013-05-30 22:21:06
【问题描述】:

所以我必须遍历一个对象列表,使用它们的一些值进行计算,然后为它们分配新值。

因为列表中的许多项目都将被分配相同的新值,所以我使用字典来保存需要相同值的项目列表。例如:

item_dict = {}

for item in list:
    value = item.value
    if value not in item_dict:
        item_dict[value] = [item]
    else:
        item_dict[value].append(item)

# do some calculations base on values

new_data # some dictionary created by computation
# new data is stored new_data[value] = new_value

for value, new_value in new_data.items():
    items = item_dict[value]
    for item in items:
        item.value = new_value

我正在考虑使用装饰器删除 items 循环中的 for 项目,因为该列表的所有 new_value(s) 都是相同的。例如:

def dec(item):
    def wrap(value):
        item.value = value
    return wrap

def rec(item, func):
    def wrap(value):
        item.value = value
        func(value)
    return wrap

item_dict = {}

for item in list:
    value = item.value
    if value not in item_dict:
        item_dict[value] = dec(item)
    else:
        item_dict[value] = rec(item, item_dict[value])

# do some calculations base on values

new_data # some dictionary created by computation
# new data is stored new_data[value] = new_value

for value, new_value in new_data.items():
    items = item_dict[value]
    items(new_value)

装饰时尚会更有效率吗?它会对记忆产生多大的影响?有没有更好的方法来做到这一点?

【问题讨论】:

  • rec 函数,乍一看,就像一个无操作。它的目的是什么?
  • 哎呀,让我来解决这个问题
  • 您需要items_dict 进行计算吗?如果您只需要根据new_data 更新所有项目值,我认为只需遍历您的列表一次,每次都查找新值会更清楚。字典查找速度很快。
  • @PeterDeGlopper 我实际上是从项目中存储通用对象的 id 值以执行像 GenericModel.objects.filter(id__in=values) 这样的查询,所以我需要遍历所有项目以获取首先是所有 id,以便我可以执行查询。所以 new_data 将是 new_data[content_type] = [list of queried content objects]
  • 你的意思是item_dict而不是new_data吗?对于每种内容类型,您的原始代码在 new_data 中只有一个值。我仍然认为构建item_dict 是不必要的 - 您至少为每个项目插入一个字典,以便以后可以减少字典查找的数量,但是直接迭代您的项目列表只会进行一次字典查找每个项目。

标签: python


【解决方案1】:

一个 defaultdict 在这里工作得很好:

from collections import defaultdict

item_dict = defaultdict(list)

for item in value_list:
    item_dict[item.value].append(item)

# do some calculations base on values

new_data # some dictionary created by computation
# new data is stored new_data[value] = new_value

for value, new_value in new_data.items():
    for item in item_dict[value]:
        item.value = new_value

我很难想出装饰器版本可以更好的方法 - 一方面,您必须担心递归限制。

【讨论】:

  • 你能解释一下为什么它比装饰器方法更好,即性能提升多少以及为什么?谢谢
  • @Derek:装饰器方法显然需要更多内存,因为您正在创建一个每个循环都带有闭包的新函数对象。我的回答在性能上与您的迭代解决方案并没有真正的不同——它只是一种更简洁的表达方式。
【解决方案2】:

get 方法在第一种情况下效果很好。

item_dict = {}

for item in list:
    item_dict[item.value] = item_dict.get(item.value, []) + [item]

完成这项工作的关键是使用列表添加而不是追加,因为追加返回 None。

【讨论】:

  • 如果你打算这样做,set_default 可能会更好。 item_dict.set_default(item.value, []).append(item)
  • 您能详细说明一下吗?你的方法更有效吗?每次我们看到 item.value 时,您不会设置默认值吗?
  • 你是对的,更多信息见this question
猜你喜欢
  • 1970-01-01
  • 2016-11-18
  • 2014-03-24
  • 1970-01-01
  • 2015-12-12
  • 1970-01-01
  • 1970-01-01
  • 2012-06-20
  • 2021-01-07
相关资源
最近更新 更多