Python中指针式传递的函数遇到的问题

原创 2015年11月18日 19:39:32

最近在尝试通过 multiprocessing 把原来的计算核心改为通过多进程实现的并行程序,但碰到了一个非常奇怪的问题,经过一些时间的排查,终于找到了问题所在。虽然问题本身很简单,但也许也有一定典型性,尤其是对编程新手而言,因此在这里用最简单的模型重现一下。

首先从下面一段非常简单的程序开始:

def main():
    x = [1, 2, 3, 4, 5]
    foo(x)
    print(x)

def foo(x):
    bar(x)
    # x = bar2(x)
    for i in range(len(x)):
        x[i] = x[i]**2

def bar(x):
    for i in range(len(x)):
        x[i] = x[i] - 1

def bar2(x):
    xx = x.copy()
    for i in range(len(x)):
        xx[i] = x[i] - 1
    return xx


if __name__ == '__main__':
    main()

暂时忽略被注释掉的部分,这段程序实现的功能非常简单,main 中产生一个数组,调用 foo 函数,foo 函数又调用 bar 函数,后者使数组中的每一个元素减一,然后返回 foo 函数中,数组的每个元素再次求平方。

上面两个函数中都没有返回值,因为它接受的是数组,类似于 C 语言中的指针传递,直接操作的是原数组。类似的逻辑应该对很多编程语言都是类似的。

然而,如果要考虑通过多进程来将它并行化(比如用 foo 函数来处理非常大的数组),就需要再多一点考虑了。首先因为 Python 中 GIL 的限制,虽然也可以多线程,但速度甚至不如单线程的版本,要有效地实现纯 Python 的并行,(也许是)最佳也是最简单的方案是用多进程。但多进程中各个进程不能共享内存,也就无法像上面那样用指针传递的方式来建立操作数组的方式。

这种情况下,就需要把函数相应地改成显式地返回新数组的形式,也就是上面的 bar2 函数。然而,改写之后,试运行就可以发现,计算的结果不同了。比如x = [1, 2, 3, 4, 5]的输入,得到的结果应该是[0, 1, 4, 9, 16],但实际并非如此。更奇怪的是,监测 foo 函数,发现在函数内部的结果是正确的。这说明是 foo 函数没有正确地操作原输入数组。

想到这里,问题解决了一半。真正的原因是于x = bar2(x)这一行,等号左侧虽然同样用了 x 的变量名,但由于返回了一个新的数组,也就是说开辟了一块新的内存,使得函数后面操作的跟传入的并不是同一个数组,所以返回值看起来就像没变一样。

找到原因,解决的方法也就简单了,两个办法:

  1. 把所有的指针传递函数都改回显式返回数组的形式。
  2. x = bar2(x)改为x[:] = bar2(x),这样操作的就仍然是原来的数组了。

来源:我的博客

相关文章推荐

python dict 赋值传指针

最近在做一个很大的数据库方面的东东,要用到根据数值来查找,于是想到了python中的字典,平时没用过dict这个东东 用的最多的还是 list 和 tuple (网上查 用法一大堆) 看了一下创建...

【python】传递函数

1. 当对一个变量赋值时,实际是将相同 对象的引用赋值给这个变量。如果对象是函数的话,这个对象所有的别名都是可调用的。 >>> def foo(): ... print 'in foo()' ...

Python 传递函数名

python 把函数名当做参数
  • klov001
  • klov001
  • 2014年04月21日 21:52
  • 1205

Python学习笔记11:Python函数和函数式编程

1、函数vs过程 过程是简单、特殊、没有返回值的函数。Python的过程就是函数,过程默认返回None。2、调用函数 (1)函数操作符(()) (2)关键字参数 让调用者通过函数调用中的参数名...
  • tiana0
  • tiana0
  • 2016年07月14日 21:56
  • 1014

python函数函数指针用法

函数指针,主要用于向函数中传递一个函数名用该函数名(即函数指针)可以进行动态策略执行。 下面是一个python版本的函数指针用法 def minus(a, b): return a - ...

python值传递和引用传递

关于值传递和引用传递,综合目前各种的说法,可以得出这样的结论:可变对象为引用传递,不可变对象为值传递。但是python中一切事物均视为对象,个人觉得值传递和对象传递只不过是对象引用的两种表现。如果是可...

使用python向C语言的链接库传递数组、结构体、指针类型的数据

使用python向C语言的链接库传递数组、结构体、指针类型的数据由于最近的项目频繁使用python调用同事的C语言代码,在调用过程中踩了很多坑,一点一点写出来供大家参考,我们仍然是使用ctypes来调...

python的“函数指针”

C++里面有函数指针,想为python也实现一个函数指针,方便函数调用,参考了五年前的一篇博客里的工作:http://blog.csdn.net/dancing999/article/details/...
  • Waleking
  • Waleking
  • 2012年06月30日 16:46
  • 12136

PYTHON中的函数指针调用的一种方法

class  Test:    EventMethods_Test1 = 1    EventMethods_Test2 = 2    EventMethods_Test3 = 3    def __...

Python函数参数传递:传值还是传引用

引子首先来看一个列子:def change(val): val.append(100) val = ['T', 'Z', 'Y'] nums = [0, 1] change(nums)...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Python中指针式传递的函数遇到的问题
举报原因:
原因补充:

(最多只允许输入30个字)