【问题标题】:Python: Replace a list in place from where it is referenced, not create a new reference/listPython:从引用的位置替换列表,而不是创建新的引用/列表
【发布时间】:2019-06-15 18:16:36
【问题描述】:

我正在使用 Python 中的大量值(内存占用为 5GB)。

有时,我需要按键访问值,有时我需要循环值。出于性能原因,我在启动时将 Dict 转换为 List,因此我可以:

  • 在我想按键访问值的情况下使用 Dict
  • 在我想要循环值的情况下使用列表
my_big_dict_of_values
my_big_values_list = list(my_big_dict_of_values.values())

为了清楚起见,以下是性能比较:

>some_dict = dict(zip(range(1000000), reversed(range(1000000))))
>some_list = list(some_dict.values())
>%timeit for t in some_dict.values(): t 
21.1 ms ± 483 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
>%timeit for t in some_list: t 
16.1 ms ± 1.31 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

当我需要根据用户输入从字典中删除键时,我的问题就出现了。 首先,我从字典中删除条目:

for key in keys_to_remove:
    del(my_big_dict_of_values[key])

这个操作之后,我还想更新my_big_values_list。我可以这样做:

解决方案 A(慢)

indexes_to_remove = list()
for idx, value in enumerate(my_big_values_list):
    if value.key in keys_to_remove:
        indexes_to_remove.append(idx)
for index in sorted(indexes_to_remove, reverse=True):
    del my_big_values_list[index]

但是,这真的很慢而且很麻烦。

理想情况下,我想再次从字典中创建列表:

解决方案 B(快速参考问题)

my_big_values_list = list(my_big_dict_of_values.values())

这很快,但似乎创建了一个新的引用。我需要替换传递给其他类/函数的my_big_values_list 的所有引用,这看起来很奇怪,例如来说明。

my_big_dict_of_values
my_big_values_list = list(
    my_big_dict_of_values.values())

handle_process = handle_process_class(
    my_big_dict_of_values, my_big_values_list)

userinput = userinput(handle_process)

handle_process.calculate()

def userinput_class():
    def __init__(handle_process):
        self.handle_process = handle_process
    def user_del_key(key):
        del(self.handle_process.my_big_dict_of_values[key])
        # Update list here too:
        # Solution A works
        # Solution B throws error in
        # handle_process.calculate() because
        # handle_process still has old list

def handle_process_class():
    def __init__(my_big_dict_of_values, my_big_values_list):
        self.my_big_dict_of_values = my_big_dict_of_values
        self.my_big_values_list = my_big_values_list
    def calculate(self):
        return len(self.my_big_values_list)

有没有办法在原地修改my_big_values_list,但只需用新列表替换(例如 list(my_big_dict_of_values.values()))。

我已经阅读了 Python 如何将引用传递给值,并且我想我了解其中的大部分内容。这就是为什么我想出了解决方案A,但我不知道如何使用解决方案B来修改引用列表。也许有人可以解释这里发生了什么?

【问题讨论】:

  • 确定你需要这个列表吗???循环值就像for val in yourdict.values(): 一样简单,或者 - 如果您使用的是 Python 2.7 并且想要节省 RAM - for val in yourdict.iter_values():
  • 在大多数情况下我会同意,但迭代列表 is faster 而不是迭代 dict.values(),这在我的 dict() 中的值的数量上很明显
  • 注意:我编辑了原始答案并添加了性能比较
  • 它本身可能更快,但维护列表的开销也会增加一些开销,因此取决于您的具体用例,净收益可能或不那么重要(说不出来,真的)。此外,这也可能不是您代码中的主要瓶颈,因此如果您想正确优化代码,您真的想先对其进行分析。 (注:并不是说当前的优化没有用或没有意义——只是我们人类在猜测任何非平凡代码中真正的瓶颈在哪里方面非常糟糕)。
  • 完全同意:我可能需要对我的代码进行适当的性能测试。更多背景知识:my_big_dict_of_values 是我的程序的核心,我在它的所有代码部分中运行了数百万次迭代。

标签: python performance reference pass-by-value


【解决方案1】:

要就地修改列表,请分配给它的切片:

my_big_values_list[:] = list(my_big_dict_of_values.values())

例子:

>>> my_big_dict_of_values = {"a": 1, "b": 2, "c": 3}
>>> my_big_values_list = list(my_big_dict_of_values.values())
>>> another_list_reference = my_big_values_list

>>> print(my_big_values_list, another_list_reference)
[1, 2, 3] [1, 2, 3]

>>> del(my_big_dict_of_values["b"])
>>> my_big_values_list[:] = list(my_big_dict_of_values.values())

>>> print(my_big_values_list, another_list_reference)
[1, 3] [1, 3]

但是在性能和​​内存使用方面,您应该考虑是否真的需要一个单独的大列表,因为您可以直接循环 dictionary.values()

【讨论】:

  • 哇,如此简单且解释清楚!非常感谢,这绝对有助于我的全部 Python 知识。
猜你喜欢
  • 2018-10-28
  • 2019-05-12
  • 2018-11-24
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
  • 2017-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多