MAX-Value aus "variablen" Variablen

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
bernie70
User
Beiträge: 7
Registriert: Samstag 1. Mai 2010, 17:20

Hallo,

ich habe verschiedene Variablen gesetzt. In Wirklichkeit sind es wesentlich mehr Variablen, ich habe den Code hier nur zur Demonstration reduziert.

Ich möchte jeweils den MAX-Value dieser Variablen erhalten, wobei die Variablennamen "variabel" sind (so wie ich es bis jetzt gemacht habe).

Beim "print" bekomme ich allerdings nicht den erwarteten Wert (3 bzw. 3.3), sondern "a_1_03" bzw. "b_1_03".

Was habe ich falsch gemacht bzw. kann man das anders lösen?

LG,
bernie70

[code]
a_1_01 = 1
a_1_02 = 2
a_1_03 = 3

b_1_01 = 1.1
b_1_02 = 2.2
b_1_03 = 3.3

for param in ['a', 'b']:
globals()[f'{param}_1_0103'] = max(param + "_1_01", param + "_1_02", param + "_1_03")

print(a_1_0103)
print(b_1_0103)
[/code]
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das sieht schwer danach aus, dass was du eigentlich brauchst, die richtigen Datenstrukturen sind. Man baut keine solchen durchnummerierten Konglomerate von Variablennamen. Und vor allem legt man nicht auch noch selbst globale Variablen an!

Richtig saehe das zb so aus:

Code: Alles auswählen

the_as = {
   1: 1,
   2: 2,
   3: 3,
}
the_bees = {
   1: 1.1,
...
}

parameters = {}
for name, things in [("a", the_as), ("b", the_bees)]:
    parameters[name] = max(things.values()
Niemals in meinen >20 Jahren Python habe ich das globals()-Woerterbuch in so einer Art gebraucht. Das ist kein sinnvolles vorgehen.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Das ist sehr fragil und fehlerträchtig, was du da machst und ein Beispiel, wie man in Python nicht vorgehen sollte. Besser ist es die Werte für a und b, denn die scheinen gruppiert zusammenzugehören, z.B. in Listen zu speichern. Dann reicht ein einfacher Aufruf von max():

Code: Alles auswählen

a = [1, 2, 3]
max(a)
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei das die im Grunde die gleiche Antwort ist, die bernie70 for 13 Jahren schon mal gegeben wurde: Variable aus Variable erstellen. Aber ich vermute, dem Inhalt des letzten Beitrags nach, dass damals schon die ”Lösung” mit `globals()` gefunden wurde. ☹️
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
bernie70
User
Beiträge: 7
Registriert: Samstag 1. Mai 2010, 17:20

Vielen Dank für Eure Antworten.
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

bernie70 hat geschrieben: Mittwoch 7. Juni 2023, 11:23
Was habe ich falsch gemacht
Du nimmst nur das "Maximum" von Strings. Also dann in deinem (lokalen) Konstrukt..

Code: Alles auswählen

a_1_01 = 1
a_1_02 = 2
a_1_03 = 3

b_1_01 = 1.1
b_1_02 = 2.2
b_1_03 = 3.3

for param in ['a', 'b']:
    locals()[f'{param}_1_0103'] = max(locals()[param + "_1_01"], locals()[param + "_1_02"], locals()[param + "_1_03"])

print(a_1_0103)
print(b_1_0103)
3
3.3
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und immer gibts wen, der das Seil zum selber erhängen anreicht…
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei `locals()` hier objektiv falsch ist, weil das nur funktioniert sofern `locals()` das *selbe* Ergebnis wie `globals()` liefert, denn tatsächlich lokale Namensräume kann man mindestens mal in CPython nicht um neue Namen erweitern. Das ist auch explizit dokumentiert.

Mein Beitrag zum Horrorkabinett wäre:

Code: Alles auswählen

global_variables = globals()
global_variables.update(
    (
        f"{param}_1_0103",
        max(global_variables[f"{param}_1_0{i}"] for i in range(1, 4)),
    )
    for param in ["a", "b"]
)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@__blackjack__: das macht es aber sehr schwierig, das Programm anzupassen, wenn man mal von mehr als drei Variablen das Maximum ermitteln möchte:

Code: Alles auswählen

MIN_VARIABLE_INDEX = 1
MAX_VARIABLE_INDEX = 3

global_variables = globals()
global_variables.update(
    (
        f"{param}_1_0{MIN_VARIABLE_INDEX}0{MAX_VARIABLE_INDEX}",
        max(global_variables[f"{param}_1_0{i}"] for i in range(MIN_VARIABLE_INDEX, MAX_VARIABLE_INDEX + 1)),
    )
    for param in ["a", "b"]
)
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

__blackjack__ hat geschrieben: Donnerstag 8. Juni 2023, 07:52 Wobei `locals()` hier objektiv falsch ist, weil das nur funktioniert sofern `locals()` das *selbe* Ergebnis wie `globals()` liefert, denn tatsächlich lokale Namensräume kann man mindestens mal in CPython nicht um neue Namen erweitern. Das ist auch explizit dokumentiert.
Ganz so kann man das wohl nicht sagen:
Locals und Globals sind identisch auf Modulebene, ansonsten bekommt jeder Kontext eine eigene (leere) Locals aber mit Scope auf Globals.
Änderungen in Locals sind dann eben auch nur im jeweiligen (lokalen) Kontext sichtbar.
Allerdings hast du Recht damit, dass man mit expliziten Änderungen von Locals i.a. vorsichtig sein sollte..
Note The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

Code: Alles auswählen

def test_locals():
    a_1_01 = 1
    a_1_02 = 2
    a_1_03 = 3

    b_1_01 = 1.1
    b_1_02 = 2.2
    b_1_03 = 3.3

    for param in ['a', 'b']:
        locals()[f'{param}_1_0103'] = max(locals()[param + "_1_01"], locals()[param + "_1_02"], locals()[param + "_1_03"])

    print(locals()['a_1_0103'])
    print(locals()['b_1_0103'])
    print(a_1_0103) # NameError

test_locals()
3
3.3
Traceback (most recent call last):
..
print(a_1_0103) # NameError
^^^^^^^^
NameError: name 'a_1_0103' is not defined. Did you mean: 'a_1_01'?
Natürlich ist das aber alles Gefrickel und sollte vermieden werden. Es gibt m.E. auch keinen wirklichen Grund für "Variablenstrings".
Zuletzt geändert von Qubit am Donnerstag 8. Juni 2023, 12:43, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Qubit: wie soll man denn sonst dazu sagen, wenn ein Code der `locals` benutzt, nicht funktioniert?
Und "sollte nicht verändert werden" ist auch etwas anderes als "vorsichtig sein".

Führt man Deinen Code in einer Funktion aus, bekommt man den Fehler:

Code: Alles auswählen

NameError: name 'a_1_0103' is not defined
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

Sirius3 hat geschrieben: Donnerstag 8. Juni 2023, 12:42 @Qubit: wie soll man denn sonst dazu sagen, wenn ein Code der `locals` benutzt, nicht funktioniert?
Und "sollte nicht verändert werden" ist auch etwas anderes als "vorsichtig sein".

Führt man Deinen Code in einer Funktion aus, bekommt man den Fehler:

Code: Alles auswählen

NameError: name 'a_1_0103' is not defined
Ich habe mal meinen letzten Beitrag um das Beispiel erweitert, wie es mit "Vorsicht" bei Locals funktioniert..
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Qubit: Mit ”funktioniert” meinte ich, dass das wirklich generell funktioniert, und nicht nur zufällig. Denn es mag ja so sein das `locals()` auf Modulebene das gleiche wie `globals()` liefert, aber das muss es nicht. Die Anmerkung in der Dokumentation ist da deutlich. In anderen Implementierungen als CPython kann das anders aussehen und auch in CPython können die Entwickler sich entscheiden bei `locals()` auf Moduleben etwas anderes zurück zu geben. Auf der anderen Seite könnte das ändern auch in Funktionen ”funktionieren”. Sind halt Implementierungsdetails.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Qubit
User
Beiträge: 128
Registriert: Dienstag 7. Oktober 2008, 09:07

__blackjack__ hat geschrieben: Donnerstag 8. Juni 2023, 12:55 @Qubit: Mit ”funktioniert” meinte ich, dass das wirklich generell funktioniert, und nicht nur zufällig. Denn es mag ja so sein das `locals()` auf Modulebene das gleiche wie `globals()` liefert, aber das muss es nicht. Die Anmerkung in der Dokumentation ist da deutlich. In anderen Implementierungen als CPython kann das anders aussehen und auch in CPython können die Entwickler sich entscheiden bei `locals()` auf Moduleben etwas anderes zurück zu geben. Auf der anderen Seite könnte das ändern auch in Funktionen ”funktionieren”. Sind halt Implementierungsdetails.
Ja, da hast du völlig Recht!

Letzte Bemerkung von mir dazu..
wenn man tatsächlich solche "Stringvariablen" benutzen und davon welche im weiteren Kontext verwenden will (wie diese Max-Variablen), dann würde ich im jeweiligen Kontext ein Dict definieren (ggfs. auf Modulebene so ein "string_vars" definieren)..

Code: Alles auswählen

string_vars = {}

def test_locals():
    a_1_01 = 1
    a_1_02 = 2
    a_1_03 = 3

    b_1_01 = 1.1
    b_1_02 = 2.2
    b_1_03 = 3.3

    for param in ['a', 'b']:
        string_vars[f'{param}_1_0103'] = max(vars()[param + '_1_01'], vars()[param + '_1_02'], vars()[param + '_1_03'])

test_locals()

print(string_vars)

#...string_vars
{'a_1_0103': 3, 'b_1_0103': 3.3}
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Qubit: jetzt fängst Du auch noch an, mit globalen Variablen zu arbeiten!
Und warum jetzt vars() statt locals()? Macht es nicht besser.
Antworten