Dynamisch Funktionsargumente bestimmen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

Liebes Forum
Ein Beispiel: ich habe eine Funktion mit drei Argumenten: y=f(x1, x2, x3). Wenn ich zwei Argumente, x_i und x_j, als Parameter a und b annehme, dann kann ich y gegen das dritte Argument x_k in 2D plotten.
Ich möchte also über eine Liste von möglichen x_k Werten die Funktion ausrechnen:

Code: Alles auswählen

X_k = [x_k1, x_k2, ..., x_kN]
for x_k in X_k:
    f(a, b, x_k)
Hier ist allerdings ein Problem, nämlich dass ich annehme, a priori zu wissen, dass x_k das letzte Argument ist, und deshalb f(a, b, x_k) schreiben kann. Wenn ich allerdings, x_i und x_k als Parameter a und c auffasse, dann müsste ich ja einen weiteren Funktionsaufruf einbauen:

Code: Alles auswählen

if type(X_i) == list:
    for x_i in X_i:
        f(x_i, b, c)
if type(X_j) == list:
    for x_j in X_j:
        f(a, x_j, c)
if type(X_k) == list:
    for x_k in X_k:
        f(a, b, x_k)
Der Ursprung dieser Frage liegt darin, dass die Funktion über ein Webinterface zugänglich gemacht wird, in dem die Parameter gesetzt werden können und in dem definiert wird, welches Argument als Variable funktionieren soll. Hoffe, dass man einigermassen verstehen kann, worum es mir geht.
Kann man das nicht besser lösen? Danke für Hinweise.
[url=http://www.proandkon.com]proandkon.com[/url]
BlackJack

Ungetestet:

Code: Alles auswählen

a, b, c = X_i, X_j, X_k
variable_argument = None
for argument, values in zip('abc', [X_i, X_j, X_k]):
    if isinstance(values, list):
        variable_argument = argument
        break

if variable_argument is None:
    raise TypeError('no variable list given')

arguments = dict(a=a, b=b, c=c)
for value in values:
    arguments[variable_argument] = value
    f(**arguments)
LivingOn
User
Beiträge: 33
Registriert: Montag 11. August 2008, 07:53

Hier eine weitere Alternative. Um es einfach zu halten, habe ich mal andere Variablenamen verwendet:

Code: Alles auswählen

def show(a,b,c):
    print(a,b,c)

def doit(*args):
    variable = (v for v in "bc")
    arguments = {}
    for i in args:
        if isinstance(i, list):
            arguments['a'] = i
        else:
            arguments[variable.next()] = i
    show(**arguments)

doit([1,2,3],2,3)    
doit(1,[1,2,3],3)    
doit(1,2,[1,2,3])    

>>> ([1, 2, 3], 2, 3)
>>> ([1, 2, 3], 1, 3)
>>> ([1, 2, 3], 1, 2)
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

@ BlackJack: Danke für den Hinweis.

Ich versuche mein Minimalbeispiel besser an der realen Aufgabe anzupassen.
Eine HTML Form ist gegeben:

Code: Alles auswählen

<form action="thermo.cgi">
<!--n-->
<input type="text" name="particles">
<input type="radio" name="thermo" value="particles">

<!--T-->
<input type="text" name="temperature">
<input type="radio" name="thermo" value="temperature">

<!--V-->
<input type="text" name="volume">
<input type="radio" name="thermo" value="volume">

<input type="submit">
</form>
Das CGI Skript plottet also in der leicht umgestellten idealen Gasgleichung, p(n, V, T) = 1/V*nRT, den Druck p gegen entweder V, n oder T.

Das CGI Skript könnte jetzt ungefähr so aussehen:

Code: Alles auswählen

# The independent variable, its value and +/- 20% are obtained.
x_lbl = form['thermo'].value
x_val = form[x_lbl].value
x_rng = get_x_range_around(x_val)

# Get the values for the parameters
n = form['particles'].value
temperature = form['temperature'].value
volume = form['volume'].value

# Now, depending on x_lbl, a different function has to be called.
if x_lbl == 'particles':
    for x in x_rng:
        print x, ideal_gas(x, temperature, volume)

if x_lbl == 'temperature':
    for x in x_rng:
        print x, ideal_gas(n, x, volume)

if x_lbl == 'volume':
    for x in x_rng:
        print x, ideal_gas(n, temperature, x)
Die willkürliche Definition der ideal_gas Funktion

Code: Alles auswählen

def ideal_gas(n, t, v):
    return 1.0/v*n*R*t
[url=http://www.proandkon.com]proandkon.com[/url]
BlackJack

@LivingOn: ``variable = (v for v in "bc")`` hätte ich ja als ``variable = iter('bc')`` geschrieben. :-)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@mzh: Den unteren Teil könnte man so ein wenig kompakter schreiben:

Code: Alles auswählen

for x in x_rng:
    if x_lbl == 'particles':
        print x, ideal_gas(x, temperature, volume)
    elif x_lbl == 'temperature':
        print x, ideal_gas(n, x, volume)
    elif x_lbl == 'volume':
        print x, ideal_gas(n, temperature, x)
Da Deine innere `for x`-Schleife ja in jeder Bedingung vorkommt, kann man die doch nach außen stellen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

@hyperion, ja sicher, trotzdem, frage mich wie ich die 3-ssig if's umgehen kann.
[url=http://www.proandkon.com]proandkon.com[/url]
Antworten