2010-06-22 79 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})