2013-05-09 11 views
5

Używając języka Python, czy istnieje sposób przechowywania odniesienia do pliku referencyjnego, aby można było zmienić to, do czego odnosi się odwołanie w innym kontekście? Na przykład załóżmy, że mam następujące klasy:Przechowywanie odniesienia do odwołania w Pythonie?

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

chciałbym stworzyć coś analogicznego do następującego:

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 

taka, że ​​następujący kod

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

spowodowałoby f.standalone równe 7 i f.lst równe [4, 9, 6].

Zasadniczo byłby to wskaźnik analogiczny do wskaźnika do wskaźnika.

+0

Myślę, że cały ten punkt odniesienia polega na tym, że nie można tego po prostu zrobić . –

+0

Jak masz zamiar tego użyć? – FogleBird

+2

Jeśli chcesz C++, wiesz, gdzie go znaleźć ... – pydsigner

Odpowiedz

5

Krótko mówiąc, nie jest to możliwe. W ogóle. Najbliższym odpowiednikiem jest przechowywanie odwołania do obiektu, którego element/element chcesz ponownie przypisać, oraz nazwa atrybutu/indeks/klucz, a następnie użyj setattr/setitem. Jednak ta daje zupełnie inną składnię, i trzeba rozróżniać między nimi:

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) 

ja rzeczywiście używany coś bardzo podobnego, ale ważne przypadki użycia są bardzo nieliczne. W przypadku globałów/elementów modułów można użyć obiektu modułu lub globals(), w zależności od tego, czy znajdujesz się w module, czy poza nim. Nie ma żadnego odpowiednika dla zmiennych lokalnych - wynik locals() nie może być użyty do zmiany locals niezawodnie, jest to przydatne tylko dla kontroli.

Używam czegoś bardzo podobnego, ale ważne przypadki użycia są bardzo nieliczne.

2

Prosta odpowiedź: Nie możesz.
Skomplikowana odpowiedź: Możesz użyć lambdas. Raczej.

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

Dlaczego '__setitem__', a nie tylko bezpośredni dostęp do elementu z' [] '? – Eric

+1

Duh, ponieważ to nie będzie lambda – Eric

+2

Jak Eric zdaje się zrealizować :), 'f.lst [1] = wartość' nie jest wyrażeniem, ale' f.lst .__ setitem __ (1, wartość) 'jest . – chepner

0

To działałoby dla zawartości obiektów kontenerowych. Jeśli nie przeszkadza dodanie jednego poziomu zadnie do zmiennych (które należałoby w przypadku C wskaźnik do wskaźnika w każdym razie), można:

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)] 

I nie byłoby naprawdę potrzebne ponownie przypisać obiekt.

Class Reassigner(object): 

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

Jeśli chcesz odłożyć przydziały; można użyć functools.partial (lub tylko lambda):

from functools import partial 

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

Jeśli reassign jest jedyną operacją; nie potrzebujesz nowej klasy. Funkcje są obywatelami pierwszej klasy w Pythonie: można je przypisać do zmiennej, przechowywać na liście, przekazywać jako argumenty itp.

+0

'operator.setitem' powoduje, że wielkość elementu jest symetryczna do wielkości atrybutu i wygląda lepiej. – delnan

+0

@delnan: Zastanowiłem się nad tym, ale chciałem zademonstrować, że 'partial' działa również na metodach (nie tylko funkcjach) i istnieją również specjalne metody w Pythonie. W przeciwnym razie 'operator.setitem' może być lepszym rozwiązaniem, ponieważ odkłada wyszukiwanie' __setitem__' (wyjątki znajdują się w witrynie wywołującej). – jfs