问 题

void swap(int *p1, int *p2){
int temp; //临时变量
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int main(){
int a = 66, b = 99;
swap(&a, &b);
printf("a = %d, b = %d\n", a, b);
return 0;
}

如上是C语言的实现,我想用python也做这么一个,要求修改的外部变量是可以用参数传递的

不要这样:

a1 = 80
b1 = 90
def func():
global a1, b1 #若不是用a1, b1就不行了
temp = a1
a1 = b1
b1 = temp
return a1, b1

这样也不行,直接赋值了,如下

str = 'aaa'
def add(str):
str += 'b'
return str
str = add(str) #这步赋值了
print str

希望这个函数是类似C的,可以通过传参数来修改外部变量,不知道怎么写啊,是不是就不可以这样,还是我理解的不够。

忘记说了,参数不要是列表,列表可以在原处修改

解决方案

简而言之,Python是不允许选择值传递还是引用传递的,如果参数是immutable的,那么传递就是“值传递”(复制值),如果是mutable的,那么传递就是“引用传递”。但是哪怕是“引用传递”,引用本身(也就是相当于指针)是“值传递”的,因此你想要的效果应该是无法达到的。

事实上Python是没有值/引用传递的概念的,传递的都是对象本身。代码中的a、b变量也只是储存着对对象的引用。关于Python引用传递可以参见stackoverflow

除了无法实现以外,这样的操作是很不pythonic的,反而我觉得函数操作对象后返回对象本身(你描述的第二种方法)是很不错的,这样可以进行链式编程(例如a.func1().func2().func3())。python有gc,所以不用过于担心内存问题。

要达到类似效果的话有下面两种方法:

由于传入函数的参数是可以进行in-place的变化的,因此你可以把对象封装成引用再传入函数(类似与C#的装箱操作)。具体方法可以使用dict/list/etc.:

data = dict()
data['a']=80
data['b']=90
def func(data):
data['a'], data['b'] = data['b'], data['a']

或者自行写一个wrapper,重载一下__getattr__方便访问。

如果你实在想通过奇淫技巧实现swap的话可以操作python的引用访问,参见这篇blog(极其不推荐)