Python:带有变量参数列表的对象赋值

时间:2010-06-22 13:07:18

标签: python arguments variadic-functions

是否有方法将variable number of arguments传递给函数并让它使用( *args, **keywords )参数传递方式更改这些参数?我尝试了一些事情,但要么看到没有变化,要么编译器引发错误:

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对象传递给foo,我会改变状态。要创建一个执行deepcopy的装饰器,它会重置所有这样的状态,我现在正在为N个参数自定义它。我想创建一个接受任意数量的参数。因此,问题。

3 个答案:

答案 0 :(得分:4)

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

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

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

如果您 mutate 您收到的对象,客户可以看到这些更改。

答案 1 :(得分:3)

原因

args[0] = 4

不起作用是因为,正如错误消息所说,args一个元组,它是不可变的。因此,您首先需要将其转换为可变对象,例如:

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


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

如果您提供更多信息,可以提供更多的pythonic解决方案,因为您所做的事情似乎很奇怪。此外,第二个代码似乎工作正常。

例如,以下工作正常并更改调用范围变量:

>>> 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'

答案 2 :(得分:1)

如果要更改传递给函数的参数,以便可以执行以下操作:

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

你运气不好,原因是Mark的答案。

但是,如果您将可变对象传递给函数,则可以在调用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})