2013-05-09 14 views
5

Kann ich mit Python eine Referenz auf eine Referenz speichern, sodass ich ändern kann, worauf diese Referenz in einem anderen Kontext verweist? Zum Beispiel nehme ich die folgende Klasse haben:Einen Verweis auf eine Referenz in Python speichern?

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

würde Ich mag etwas analog zu folgendem erzeugen:

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 

Derart, dass der folgende Code

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

würde dazu führen, f.standalone entspricht 7 und f.lst entspricht [4, 9, 6].

Im Wesentlichen wäre dies ein Analog zu einem Zeiger auf Zeiger.

+0

Ich denke, der ganze Sinn von Referenzen ist, dass Sie nicht in der Lage sein sollten, nur zu tun . –

+0

Wie beabsichtigen Sie dies zu nutzen? – FogleBird

+2

Wenn Sie C++ wollen, wissen Sie, wo Sie es finden können ... – pydsigner

Antwort

5

Kurz gesagt, es ist nicht möglich. Überhaupt. Die nächstgelegene Entsprechung ist das Speichern eines Verweises auf das Objekt, dessen Element/Element neu zugewiesen werden soll, sowie der Attributname/index/key, und verwenden Sie dann setattr/setitem. Allerdings ergibt sich ganz andere Syntax, und Sie haben zwischen den beiden zu unterscheiden:

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) 

Ich habe tatsächlich verwendet, um etwas sehr ähnlich, aber die gültigen Anwendungsfälle sind dünn gesät. Für Globals/Modulmitglieder können Sie entweder das Modulobjekt oder globals() verwenden, je nachdem, ob Sie sich innerhalb oder außerhalb des Moduls befinden. Es gibt keine Entsprechung für lokale Variablen überhaupt - das Ergebnis locals() kann nicht verwendet werden Änderung Ortsansässige zuverlässig, es ist nur nützlich für Inspektion.

Ich habe tatsächlich etwas sehr ähnliches verwendet, aber die gültigen Anwendungsfälle sind selten.

2

Einfache Antwort: Sie können nicht.
Komplizierte Antwort: Sie können Lambdas verwenden. Irgendwie.

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

Warum '__setitem__' und nicht nur direkten Zugriff auf Elemente mit' [] '? – Eric

+1

Duh, denn das wäre kein Lambda – Eric

+2

Wie Eric anscheinend realisiert hat :), 'f.lst [1] = value' ist kein Ausdruck, sondern' f.lst .__ setitem __ (1, value) 'ist . – chepner

0

Dies würde für den Inhalt von Containerobjekten funktionieren. Wenn Sie nichts dagegen haben ein Dereferenzierungsebene auf Ihre Variablen Zugabe (die man sowieso in der C-Zeiger-to-Zeiger Fall bräuchten), könnten Sie:

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

Und Sie würden nicht wirklich die Notwendigkeit Objekt überhaupt neu zuordnen.

Class Reassigner(object): 

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

Wenn Sie Zuweisungen verschieben müssen; Sie könnten functools.partial (oder nur lambda) verwenden:

from functools import partial 

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

Wenn reassign der einzige Betrieb ist; Sie brauchen keine neue Klasse. Funktionen sind erstklassige Bürger in Python: Sie können sie einer Variablen zuweisen, in einer Liste speichern, als Argumente übergeben usw.

+0

'operator.setitem' macht die Groß-/Kleinschreibung symmetrisch zum Attribut case und sieht besser aus. – delnan

+0

@delnan: Ich habe darüber nachgedacht, aber ich wollte zeigen, dass 'partially' auch auf Methoden (nicht nur auf Funktionen) funktioniert und es gibt auch spezielle Methoden in Python. Andernfalls ist 'operator.setitem' möglicherweise vorzuziehen, da es das Nachschlagen von'__setitem__ 'verzögert (Ausnahmen befinden sich am Standort des Aufrufers). – jfs

Verwandte Themen