【问题标题】:Can't give back manager.list in Python multiprocessing from subprocess comes from array.tolist()无法在 Python 多处理中从子进程返回 manager.list 来自 array.tolist()
【发布时间】:2020-06-19 16:34:19
【问题描述】:

我想通过 array(a).tolist() 更改多处理子进程中的 manager.list。在子流程中添加列表有效,但使用该方法更改无效。

任何提示什么是错的?非常感谢。

from multiprocessing import Process, Manager
import numpy as np

def f(lst, lst1):
    lst.append([2])
    a = np.array([[8],[9]])
    lst1 = np.array(a).tolist()
    print('lst1: ', lst1)

if __name__ == '__main__':

    manager = Manager()

    lst = manager.list()
    lst.append([1])
    print('lst main before: ', lst)

    lst1 = manager.list()
    lst1.append([7])
    print('lst1 main before: ', lst1)

    p = Process(target=f, args=(lst,lst1))
    p.start()
    p.join()

    print('lst main after: ', lst)
    print('lst1 main after: ', lst1)

输出:

lst main before:  [[1]]
lst1 main before:  [[7]]
lst1:  [[8], [9]]
lst main after:  [[1], [2]]
lst1 main after:  [[7]]

【问题讨论】:

  • np.ndarray.tolist 创建一个 list,而不是 manager.list 我不太确定你在这里期待什么
  • 因为 lst1 在 main 中被定义为 manager.list 我希望函数 def f 中 lst1 的变化会改变 main 中的 lst1。它与 lst 中的 append 一起使用。显然不是...有没有办法可以将进程中的数组或列表返回给 main?
  • lst1 = np.array(a).tolist() 永远不会更改托管列表。变量赋值不是 Python 中的数据副本。您刚刚更改了 lst1 局部变量所指的对象。

标签: python arrays multiprocessing tolist


【解决方案1】:

函数参数本身是函数的局部变量。

因此,在def f(lst, lst1): 中,您定义了两个名为lstlst1 的新变量,它们被分配了您调用函数时使用的值。将变量命名为与您传入的变量相同的名称不会影响这一点。事实上,像 PyCharm 这样优秀的 Python 编辑器会在您执行此操作时发出警告,因为您正在“遮蔽”全局。

如果您要修改分配给lst1 的列表,这将更改全局指向的列表(它是同一个列表),但是如果您将新的东西分配给lst1,它将不再指向那个列表,你不会看到全局变量的变化。

例如:

def change_and_assign(xs):
    # adds 'b' to the list pointed to by local xs, but also global; it's the same list
    xs.append('b')
    # assigns a new list to the local, but doesn't modify global xs
    xs = ['c']

xs = ['a']
change_and_assign(xs)
print(xs)

这将打印['a', 'b'],而不是['c']

您应该返回您所追求的值,或者将其分配给没有被遮蔽的全局变量(但我建议使用之前的值):

def change_and_return_new(xs):
    # same as before
    xs.append('b')
    # function will return the value and return value can be assigned
    return ['c']

xs = ['a']
# assign return value to ys
ys = change_and_return_new(xs)
print(xs, ys)

def change_and_assign_global(xs):
    # declare that zs should be a global
    global zs
    # same as before
    xs.append('b')
    # assign a new list to the global zs
    zs = ['c']

xs = ['a']
# this will modify xs, but also create a global zs
change_and_assign_global(xs)
print(xs, zs)

如果您不明白发生了什么,请重新阅读并查看是否理解,或者查找有关全局和局部变量和范围的其他信息 - 如果您想自己编写 Python 代码而不难追踪错误。

【讨论】:

  • 谢谢,变量已更改。仍然不起作用。问题是我认为使用 lst1 = np.array(a).tolist() 创建了一个新列表(就像之前写的那样),但我想访问 main 中的现有列表,什么适用于 append...
  • 是的,这就是我要说的——你误读了,或者我可能不够清楚,变量的命名在这里并不重要。如果您想在函数内部使用新值,则必须返回该值或将其分配给已声明为全局的全局 - 前者比后者更可取。
  • 据我所知,不建议使用 global 并且 return 确实(并且没有)与多处理一起使用,因此建议改为使用共享变量。但是对象概念并不完全清楚(也许仍然不是......) - 追加更改现有对象,lst1= 在 def 中生成一个新对象。谢谢 Grismar,现在更清楚了。
【解决方案2】:

我找到了一个解决方案,答案已经在代码中,非常简单,抱歉问:

a = np.array([[8],[9]])
lst2 = np.array(a).tolist()
L1.append(lst2)

代替:

a = np.array([[8],[9]])
lst1 = np.array(a).tolist()

【讨论】:

  • 问题不是您实际上没有返回值吗?
  • 不,抱歉,之前不清楚,我的问题是子进程列表中的更改没有影响 - 正如我所认为的一样 - 主进程中的列表。但正如我现在所理解的那样,'lst1=' 会生成一个新对象,而 'appending' 会更改现有对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-27
  • 2019-12-12
  • 2017-08-22
  • 2022-07-23
  • 1970-01-01
相关资源
最近更新 更多