2016-06-06 12 views
1

Ich muss meine Bibliothek monkey-patch, um eine Instanz eines Symbols zu ersetzen, und es wird durch einige Funktion Schließungen referenziert. Ich muss diese Funktionen kopieren (da ich auch Zugriff auf die ursprüngliche ungepatchte Version der Funktion benötigen), aber __closure__ ist unveränderlich, und ich kann nicht copy.copy es, also wie kann ich neue Schließzellenobjekte in Python 2.7 erstellen?Wie erstellt man neue Schließzellobjekte?

ich zum Beispiel angesichts dieser Funktion

def f(): 
    def incorrectfunction(): 
     return 0 
    def g(): 
     return incorrectfunction() 
    return g 

def correctfunction(): 
    return 42 

func = f() 
patched_func = patchit(f) # replace "incorrectfunction" 
print func(), patched_func() 

Und ich will

0, 42 
+0

Ist 'functools.partial (f, 2)()' gut genug? –

+0

Nein, weil ich es für Affe-Patching verwende. IE, ich muss "Patchit" -Funktion über alle Symbole ausführen, um das alte Symbol in Schließungen mit dem Affen-Patch-Symbol –

+0

ersetzt Entschuldigung ich war nicht klar, ersetzt mein Spielzeug Beispiel mit einer realistischeren Version –

Antwort

4

Der einfache Weg, um zu sehen, um eine Schließung Zelle machen würde, um eine Schließung zu machen:

def make_cell(val=None): 
    x = val 
    def closure(): 
     return x 
    return closure.__closure__[0] 

Wenn Sie den Inhalt einer Zelle neu zuweisen möchten, müssen Sie einen C API Anruf:

import ctypes 
PyCell_Set = ctypes.pythonapi.PyCell_Set 

# ctypes.pythonapi functions need to have argtypes and restype set manually 
PyCell_Set.argtypes = (ctypes.py_object, ctypes.py_object) 

# restype actually defaults to c_int here, but we might as well be explicit 
PyCell_Set.restype = ctypes.c_int 

PyCell_Set(cell, new_value) 

CPython natürlich nur.

+1

@ YaroslavBulatov: Wenn Sie müssen nur eine Verschlusszelle kopieren, das ist einfach, indem Sie eine Schließung machen. – user2357112

0

Wenn Sie eine leere Zelle (das ist, was ich diese Frage gefunden) (Ein wo Referenzierung eine NameError: free variable '...' referenced before assignment in enclosing scope wirft und den Zugriff auf sie ist cell.cell_contents wirft eine ValueError: Cell is empty), können Sie einen Wert eine lokale Variable, aber es nie vergeben werden lassen:

def make_empty_cell(): 
    if False: 
     # Any action that makes `value` local to `make_empty_cell` 
     del value 
    return (lambda: value).__closure__[0] 

Sie können sie wie folgt zusammenfassen:

_SENTINEL = object() 

def make_cell(value=_SENTINEL): 
    if value is not _SENTINEL: 
     x = value 
    return (lambda: x).__closure__[0] 

Also ohne Argumente Aufruf gibt eine leere Zelle, und mit einem beliebigen Wert, eine Zelle mit diesem Wert.

Wenn Sie leere Zellen sich nicht, können Sie tun:

def make_cell(value): 
    return (lambda: value).__closure__[0] 

Beachten Sie, dass es func_closure bei älteren Python 2, statt __closure__ ist.

Verwandte Themen