2012-03-27 8 views
0

Grundsätzlich habe ich eine API, die eine Klasse Foo() mit einer Methode Foo.bar (arg1, name) bereitstellt.Partielle Anwendung von Funktionen innerhalb eines Kontextmanagers ("mit ..")

Gibt es eine Möglichkeit, ein functools.partial Objekt Foo.bar in einem Kontext-Manager, also wie folgt anzuwenden:

x=Foo() 
with my_argument(name="Something") as e: 
    x.bar(arg1=5) # == x.bar(arg1=5, name="Something") in this context 

Ich fragte mich, ob es eine elegantere Art und Weise für dieses andere ist als Affe Patchen Foo.bar?

Edit: Der Punkt ist, habe ich Code wie folgt:

model.addConstr(a, name="constraint_1") 
model.addConstr(b, name="constraint_2") 

Und ohne zusätzliche Textvorschlag der folgende Code sollte die gleichen Anrufe nachgeben 'Modell':

with Arguments(name="constraint"): 
    model.addConstr(a) 
    model.addConstr(b) 
+2

Sie meinen teilweise Anwendung. Teilbewertung ist eine (meist statische, teilweise weil sie ziemlich teuer ist) [Programmtransformation] (http://morepypy.blogspot.com/2012/01/comparting-partial-evaluation-and.html). Und wenn das möglich wäre, würdest du es wirklich nicht tun wollen, außer * vielleicht * beschränkt auf Methoden des Objekts, das den Kontextmanager lieferte. – delnan

+0

Nicht so, aber ja. –

Antwort

1

Nicht so, nein. Wie soll Ihre my_argument Klasse wissen, dass es mit x.bar arbeiten soll, ohne dass Sie das weitergeben? Was genau werden die __enter__() und __exit__() Methoden von my_argument in dieser Situation tun?

Ich sehe nicht, warum Sie nicht gerade ein functools.partial Objekt für x.bar machen und das verwenden.

2

Ich glaube nicht unbedingt Sie den Kontext-Manager benötigen, können Sie stattdessen teilweise von functools verwenden:

from functools import partial 
x=Foo() 
_xbar = partial(x.bar, name="something") 
_xbar(arg1=5) 

Wenn Sie auf "Switch Kontext" wollen, nur redifine _xbar:

_xbar = partial(x.bar, name="some other thing") 
2
class Argumentor(object): 
    def __init__(self, *args, **kwargs): 
    self.args = args 
    self.kwargs = kwargs 

    def __enter__(self): 
    return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
    pass 

    def __call__(self, func, *args, **kwargs): 
    newargs = args + self.args 
    newkwargs = kwargs.copy() 
    newkwargs.update(self.kwargs) 
    return func(*newargs, **newkwargs) 

def foo(num, name): 
    print num, name 

with Argumentor(name='bar') as f: 
    f(foo, 42) 
+0

Schön gemacht! Hätte nicht so gedacht. – brice

+0

Wäre es nicht schöner, wenn dies entweder die Funktion als Argument für die Manager-Init übernimmt oder der Manager selbst eine teilweise angewandte Callable zurückgibt? – Marcin

+0

@Marcin: Was, wenn Sie es auf mehrere Funktionen anwenden möchten? –

Verwandte Themen