dynamisches erzeugen von Variablen durch Strings

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
TomTomTom
User
Beiträge: 3
Registriert: Sonntag 24. August 2014, 14:30

Hallo,

ich habe folgendes Problem. Meiner Meinung nach benötige ich im Code generierte Variablen um mein Problem lösen zu können. Auf meiner Suche nach ähnlichen Problemen wurde ich immer auf Dictionarys hingewiesen, wüsste jedoch nicht, wie ich damit mein Problem lösen kann.

Problemstellung:

var0 = function()
var1 = function2(var0)
var2 = function2(var1)
...
var99 = function2(var98)

Auf die Funktionen function und function2 habe ich keinen Einfluss.
Ich habe derzeit im Code Strings erzeugt die 'var0', 'var1',...,'var99' heißen.
Was könnte ich machen, damit soetwas funktioniert.
variable( 'var1') = function2(variable('var0'))

Vielen Dank für eure Vorschläge.

TomTomTom
BlackJack

@TomTomTom: Ich verweie hier mal auf Dictionaries. ``variable( 'var1') = irgendwas`` ist ja schon mal keine gültige Syntax. Aber das Beispiel ist *so* nahe an `variable` als Dictionary dran, dass ich nicht so ganz verstehe wie Du Dictionaries nicht als Lösung sehen kannst!?

Edit: Und falls die Variable tatsächlich von 0 an durchnummeriert wird, dann willst Du kein Wörterbuch sondern ganz einfach eine Liste.

Edit2:

Code: Alles auswählen

var = [function()]
for _ in xrange(99):
    var.append(function2(var[-1]))
TomTomTom
User
Beiträge: 3
Registriert: Sonntag 24. August 2014, 14:30

Danke, du hast mir sehr geholfen. Konnte mir nicht vorstellen, dass ganze Funktionen in einem Dictionary stehen können.
BlackJack

@TomTomTom: Mal davon abgesehen das man auch Funktionen in Datenstrukturen stecken kann, weil das letztendlich Objekte, also Werte, sind wie andere auch, ist das hier doch überhaupt nicht der Fall (solange `function()` und/oder `function2()` keine Funktionen als Rückgabewerte haben).
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@TomTomTom: Falls du deine Funktionen wie angedeutet in dieser Weise aufrufst:

Code: Alles auswählen

v0 = ...
v1 = f1(v0)
v2 = f2(v1)
v3 = f3(v2)
v4 = f4(v3)
v5 = f5(v4)
v6 = f6(v5)
...
also so, dass jede Funktion einfach nur einen Wert in einen anderen transformiert, und dieser dann lediglich als Basis für die nächste Transformation dient und nicht anderweitig benutzt wird, dann möchtest du vielleicht Funktionskomposition:

Code: Alles auswählen

def compose(*fs):
    def composed(x):
        for f in fs:
            x = f(x)
        return x
    return composed

def add3(v):
    return v + 3

def mul2(v):
    return v * 2

new_func = compose(add3, mul2, str, mul2, int, add3)

result = new_func(7)
print result
Ergebnis: Das Programm oben ist äquivalent zu diesem hier:

Code: Alles auswählen

v0 = 7
v1 = add3(v0)
v2 = mul2(v1)
v3 = str(v2)
v4 = mul2(v3)
v5 = int(v4)
v6 = add3(v5)
result = v6
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
pixewakb
User
Beiträge: 1411
Registriert: Sonntag 24. April 2011, 19:43

@pillmuncher: Ich glaube auf Basis der Art seiner Frage und wie er dort mit Python operiert, dass deine Lösung für ihn nicht praktisch nutzbar ist. Da schwirrt mir gerade selbst der Kopf und ich habe aktuell keine freie Zeit mich da einzuarbeiten. Wird so etwas praktisch irgendwo programmiert (Kontext, Aufgaben) oder ist das ein esoterisches Sprachkonstrukt???
BlackJack

@pixewakb: Funktionskomposition und so eine `compose()`-Funktion gehört in der oder ähnlicher Form in den Werkzeugkasten jeder funktionalen Programmiersprache. Dazu muss man eigentlich nur Closures verstanden haben, die auf jeden Fall zu den Grundlagen funktionaler Programmiersprachen gehören. Und falls das jetzt zu esoterisch klingen sollte: so eine Programmiersprache ist JavaScript. Also eine ziemlich verbreitete und praktisch eingesetzte Sprache.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@pixewakb: Ja, manchmal benutze ich sowas. Ich bemühe mich, es nicht zu übertreiben mit dem funktionalen Stil. Sonst kann ich gleich in Scheme oder Haskell programmieren. Im Fall von TomTomTom, sofern ich ihn richtig verstanden habe, bietet sich Funktionskomposition allerdings an.

Man könnte es auch so programmieren, vielleicht wird es dann deutlicher, wie es funktioniert:

Code: Alles auswählen

>>> value = 7
>>> for func in add3, mul2, str, mul2, int, add3:
...     value = func(value)
...
>>> print value
2023
Zum Vergleich:

Code: Alles auswählen

>>> add3(7)
10
>>> mul2(10)
20
>>> str(20)
'20'
>>> mul2('20')
'2020'
>>> int('2020')
2020
>>> add3(2020)
2023
Andererseits hat compose() einige nützliche Eigenschaften. Nehmen wir an, wir haben folgende Definitionen:

Code: Alles auswählen

def compose_two(f, g):
    def composed_two(x):
        y = f(x)
        z = g(y)
        return z
    return composed_two

def identity(x):
    return x
Damit haben wir bereits die Menge der einstelligen Python-Funktionen zum Monoid gemacht. Monoide kennt jeder, der in der Schule Mathematik hatte. Allerdings wurde es nicht Monoid genannt. Es wurde einfach als ein paar anscheinend unzusammenhängende Gesetze gelehrt. Hier das Assoziativgesetz für die Addition und die Multiplikation:

Code: Alles auswählen

a + (b + c) == (a + b) + c
a * (b * c) == (a * b) * c
Wenn man statt der Zeichen + und * die add() und mul() Funktionen aus dem operator Modul verwendet, dann sieht es so aus:

Code: Alles auswählen

from operator import add, mul
add(a, add(b, c)) == add(add(a, b), c)
mul(a, mul(b, c)) == mul(mul(a, b), c)
Und hier zum Vergleich für einstellige Funktionen f, g, h:

Code: Alles auswählen

compose_two(f, compose_two(g, h)) == compose_two(compose_two(f, g), h)
Und in der Pythonshell kann man es ausprobieren:

Code: Alles auswählen

>>> def mul2(v):
...     return v * 2
...
>>> def add3(v):
...     return v + 3
...
>>> def sub5(v):
...     return v - 5
...
>>> func1 = compose_two(compose_two(mul2, add3), sub5)
>>> func2 = compose_two(mul2, compose_two(add3, sub5))
>>> func1(12)
22
>>> func2(12)
22
>>> sub5(add3(mul2(12)))  # zum Vergleich
22
Aus der Mathematik kennt man auch neutrale Elemente. Für die Addition ist das die 0 und für die Multiplikation die 1. Dabei gelten diese Gesetze:

Code: Alles auswählen

a + 0 == 0 + a == a
a * 1 == 1 * a == a
Oder in funktionaler Schreibweise:

Code: Alles auswählen

add(a, 0) == add(0, a) == a
mul(a, 1) == mul(1, a) == a
Und für unsere einstelligen Funktionen gibt es sowas ebenso, da ist das neutrale Element identity():

Code: Alles auswählen

compose_two(f, identity) == compose_two(identity, f) == f
In der Pythonshell:

Code: Alles auswählen

>>> f1 = compose_two(add3, identity)
>>> f2 = compose_two(identity, add3)
>>> f1(12)
15
>>> f2(12)
15
>>> add3(12)
15
Blöd ist jetzt nur, dass man mit compose_two() nur zwei Funktionen komponieren kann. Für drei Funktionen könnte man sich definieren:

Code: Alles auswählen

 def compose_three(f, g, h):
    def composed_three(x):
        y = f(x)
        z = g(y)
        u = h(z)
        return u
    return composed_three
Und für vier, fünf, ... Funktionen kann man sich ebenfalls compose-Funktionen schreiben. Nun gibt es aber in Python die Möglichkeit, beliebig viele Argumente an eine Funktion zu übergeben:

Code: Alles auswählen

>>> def foo(*args):
...     for a in args:
...         print(a)
...
>>> foo(1, 2, 3)
1
2
3
>>> foo('hallo', 'huhu')
hallo
huhu
Solche Funktionen nennt man variadisch. Damit kann man nun eine allgemeine compose() Funktion schreiben:

Code: Alles auswählen

def compose(*fs):
    def composed(x):
        for f in fs:
            x = f(x)
        return x
    return composed
Womit wir wieder am Anfang wären.

Ich schrieb, dass diese Funktion einige nützliche Eigenschaften hat. Man kann damit zB. compose_xxx() und die Identitätsfunktion definieren:

Code: Alles auswählen

>>> def compose_two(f, g):
...     return compose(f, g)
...
>>> def compose_three(f, g, h):
...     return compose(f, g, h)
...
>>> func = compose_three(mul2, add3, sub5)
>>> func(12)
22
>>> identity = compose()
>>> identity(12)
12
>>> identity('hallo')
'hallo'
In specifications, Murphy's Law supersedes Ohm's.
bb1898
User
Beiträge: 200
Registriert: Mittwoch 12. Juli 2006, 14:28

Moment mal. In der ursprünglichen Frage ging es nicht um Komposition verschiedener Funktionen, sondern schlicht um die wiederholte Anwendung ein und derselben Funktion; nur für den Anfangswert wird eine andere Funktion benutzt.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

bb1898 hat geschrieben:Moment mal. In der ursprünglichen Frage ging es nicht um Komposition verschiedener Funktionen, sondern schlicht um die wiederholte Anwendung ein und derselben Funktion;
Das hatte ich tatsächlich überlesen. Dann ist die Antwort an TomTomTom natürlich: Wenn du die Zwischenwerte nicht brauchst, dann nimm eine Schleife.

Code: Alles auswählen

value = function()
for _ in range(99):
    value = function2(value)
Und falls die Zwischenwerte doch gebraucht werden, erzeuge eine Liste, wie von BlackJack gezeigt.
In specifications, Murphy's Law supersedes Ohm's.
TomTomTom
User
Beiträge: 3
Registriert: Sonntag 24. August 2014, 14:30

Vielen Dank für eure vielen Antworten.
Zur Klärung meines Beispiels, es ging um die Erstellung von mehreren Gui Elementen, die immer als einen Parameter ein Grundelement erwarteten auf dem das Neue aufgebaut werden sollte. Ich konnte es inzwischen mittels des Dictionaries lösen.

Gruß TomTomTom
Antworten