2013-05-09 22 views
5

使用Python,是否有任何方法來存儲對引用的引用,以便我可以更改該引用在另一個上下文中引用的內容?例如,假設我有下面的類:在Python中存儲對引用的引用?

class Foo: 
    def __init__(self): 
     self.standalone = 3 
     self.lst = [4, 5, 6] 

我想創造一些類似以下內容:

class Reassigner: 
    def __init__(self, target): 
     self.target = target 
    def reassign(self, value): 
     # not sure what to do here, but reassigns the reference given by target to value 

使得下面的代碼

f = Foo() 
rStandalone = Reassigner(f.standalone) # presumably this syntax might change 
rIndex = Reassigner(f.lst[1]) 
rStandalone.reassign(7) 
rIndex.reassign(9) 

會導致f.standalone等於7f.lst等於[4, 9, 6]

本質上,這將是一個模擬的指針到指針。

+0

我認爲引用的重點在於您不應該能夠這樣做。 – 2013-05-09 20:16:52

+0

你打算如何使用它? – FogleBird 2013-05-09 20:19:44

+2

如果你想要C++,你知道在哪裏可以找到它... – pydsigner 2013-05-09 20:23:05

回答

5

總之,這是不可能的。完全一樣。最接近的等價物是存儲對要重新分配其成員/項目的對象的引用,加上屬性名稱/索引/鍵,然後使用setattr/setitem。然而,這會產生完全不同的語法,你必須在兩者之間進行區分:

class AttributeReassigner: 
    def __init__(self, obj, attr): 
     # use your imagination 
    def reassign(self, val): 
     setattr(self.obj, self.attr, val) 

class ItemReassigner: 
    def __init__(self, obj, key): 
     # use your imagination 
    def reassign(self, val): 
     self.obj[self.key] = val 

f = Foo() 
rStandalone = AttributeReassigner(f, 'standalone') 
rIndex = ItemReassigner(f.lst, 1) 
rStandalone.reassign(7) 
rIndex.reassign(9) 

其實我已經使用了非常相似的東西,但有效的使用情況是少之又少。 對於全局變量/模塊成員,您可以使用模塊對象或globals(),這取決於您是在模塊內部還是外部。沒有相應的局部變量在所有 - 的locals()結果不能當地人可靠地使用變化,它只是爲檢查有用。

其實我已經使用了非常相似的東西,但有效的使用情況是少之又少。

2

答案很簡單:你不能。
複雜的答案:你可以使用lambdas。有點。

class Reassigner: 
    def __init__(self, target): 
     self.reassign = target 

f = Foo() 
rIndex = Reassigner(lambda value: f.lst.__setitem__(1, value)) 
rStandalone = Reassigner(lambda value: setattr(f, 'strandalone', value)) 
rF = Reassigner(lambda value: locals().__setitem__('f', value) 
+0

爲什麼'__setitem__'不只是用'[]'指示項目訪問? – Eric 2013-05-09 20:23:06

+1

Duh,因爲那不會是lambda – Eric 2013-05-09 20:23:43

+2

正如Eric似乎已經意識到:),f.lst [1] = value不是表達式,而是'f.lst .__ setitem __(1,value)'是。 – chepner 2013-05-09 20:37:12

0

這將適用於容器對象的內容。如果你不介意加入一個間接層到您的變量(你需要在C指針到指針的情況下是這樣),你可以:

class Container(object): 

    def __init__(self, val): 
     self.val = val 

class Foo(object): 

    def __init__(self, target): 
     self.standalone = Container(3) 
     self.lst = [Container(4), Container(5), Container(6)] 

而且你不真正需要的重新設置對象。

Class Reassigner(object): 

    def __init__(self, target): 
     self.target = target 
    def reassign(self, value): 
     self.target.val = value 
1

如果您需要推遲分配;你可以使用functools.partial(或只是lambda):

from functools import partial 

set_standalone = partial(setattr, f, "standalone") 
set_item = partial(f.lst.__setitem__, 1) 
set_standalone(7) 
set_item(9) 

如果reassign是唯一的操作;你不需要一個新班級。 函數是Python中的一等公民:您可以將它們分配給變量,存儲在列表中,作爲參數傳遞等。

+0

'operator.setitem'使項目案例與屬性大小寫對稱,看起來更好。 – delnan 2013-05-09 22:12:37

+0

@delnan:我想過,但我想證明「partial」也適用於方法(不僅是函數),Python中也有特殊的方法。否則'operator.setitem'可能會更好,因爲它推遲'__setitem__'查找(異常在調用者站點)。 – jfs 2013-05-10 00:49:13