2010-06-22 81 views
3

是否有方法将variable number of arguments传递给函数,并使用(*args, **keywords)参数传递样式更改这些参数?我试了几件事情,但无论是看不出有任何变更,或由编译器产生错误:Python:具有可变参数列表的对象分配

def foo(*args): 
    args[0] = 4 

这让我TypeError: object does not support assignment(他们的元组。)或者

def foo(*args): 
    plusOne = [ item+1 for item in args ] 
    args = plusOne 
它没有

效果如此如此。如果没有机制也不能解决问题,我可以承认失败。

编辑:

解释,为什么我试图走这条路线,这里考虑的情况:

class bar(object): 
    def __init__(self,obj): 
     self.obj = obj 

def foo(input): 
    input.obj = "something else" 

如果我通过我的bar对象到富,我得到了状态的变化。要创建一个装饰器来执行重置所有这种状态的deepcopy,我目前正在为它定义N个参数。我想创建一个接受任意数量参数的函数。因此,这个问题。

+0

相关:http://stackoverflow.com/questions/575196/in -python-why-can-a-function-modify-some-arguments-as-perceived-by-the-caller-b – SilentGhost 2010-06-22 13:51:13

+0

感谢您的链接。 – wheaties 2010-06-22 15:50:21

回答

4

否 - Python使用call by object-sharing,也称为按值调用。

若要澄清术语:您没有收到对象的深层副本,但对象的副本参考。注意:这与call-by-reference不一样!您可以将其视为按值调用,并且这些值是对对象的引用。

所以要回答你的问题,你会收到参数副本(对象引用)。您不能修改对象引用,就好像它们通过引用传递一样。如果你愿意,你可以做一个新的修改副本,但从你的例子来看,这不是你想要的。调用范围将不会看到您的更改。

如果您改为变异您收到的对象,客户端可以看到这些变化。

+0

这就是我害怕听到的。谢谢,不过。 – wheaties 2010-06-22 13:14:01

+0

你链接到的内容说:*然而,由于函数可以访问与调用者相同的对象(不做任何复制),调用者可以看到函数中这些对象的突变* – SilentGhost 2010-06-22 13:46:02

+0

@Silent Ghost:无副本的对象被创建,但创建了对象引用的副本。 – 2010-06-22 13:57:02

3

原因

args[0] = 4 

不起作用是因为,错误消息说,args一个元组,这是不可改变的。所以,你需要它,它转换为可变对象第一次,例如像这样:

>>> def foo(*args): 
    print(args) 
    args = list(args) 
    args[0] = 42 
    print(args) 


>>> foo(23) 
(23,) 
[42] 

如果你提供更多的信息,将有可能提供更多的Python的解决方案,因为你在做什么,似乎奇怪。此外,第二个代码似乎工作得很好。

例如,下面的工作只是正常和改变呼叫范围变量:

>>> def spam(*a): 
    a[0][0] = 42 


>>> l = [23, 32] 
>>> spam(l) 
>>> l 
[42, 32] 

的原因是完全一样的:l对象的可变性。您的示例中可以显示相同内容:

>>> def foo(*input): 
    input[0].obj = "something else" 


>>> b = bar('abc') 
>>> foo(b) 
>>> b.obj 
'something else' 
+1

这不会更改调用范围中的相应变量,我认为这是OP所需的。 – 2010-06-22 13:15:49

+0

@Dave:虽然我没有看到与问题相关的情况如何,但调用范围中的任何内容是否会被更改取决于对象的属性。看我的编辑。 – SilentGhost 2010-06-22 13:21:51

+0

那么我不能只做一个深层次的拷贝和重新分配。如果它包含一个'__dict__',那么我需要重新分配对象的__dict__'。 – wheaties 2010-06-22 13:29:09

1

如果你想改变传递给函数的参数,这样你就可以做这样的事情:

>>> x, y = (10, 17) 
>>> foo(x, y) 
>>> print (x, y) 
(11, 18) 

你的运气了,在马克的回答说明的原因。

然而,如果你传递可变对象到你的功能,你可以改变这些对象和看到的结果调用foo后:

def foo(*args): 
    for arg in args: 
     arg['value'] += 1 

>>> d1 = {'value': 1} 
>>> d2 = {'value': 2} 
>>> foo(d1, d2) 
>>> print (d1, d2) 
({'value': 2}, {'value': 3})