Auf Variablen zugreifen

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
Raphael_15
User
Beiträge: 3
Registriert: Samstag 30. Januar 2021, 23:38

Hallo,
für ein Projekt müsste ich wissen, wie ich denn Variablen globalisieren kann. Hier ein Beispiel.

def test():
number1 = 1

def ausführen():
print(number1)

ausführen()

Jetzt kommt als Fehlermeldung, das number1 not defined ist, wie kann ich es denn machen, das alle Variablen aus test von ausführen ausgeführt und benutzt werden können? Klar könnte ich hier jetzt number1 einfach ohne eine Funktion schreiben, aber bei meinem Programm müssen alle Variablen eben aufrufbar sein, also in ein Funktion, da es einen Restart Butten gibt und die Variablen logischerweise wieder "erkannt" werde müssen.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Für GUIs muss man Klassen definieren, so dass man den Zustand auch nach Ende der Funktion speichern kann.

Code: Alles auswählen

class Programm: 
    def __init__(self):
        self.nummer = 1

    def ausführen(self):
        print(self.nummer)

def main():
    programm = Programm()
    programm.ausführen()

if __name__ == "__main__":
    main()
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Du möchtest in deinem Projekt keine globalen Variablen haben, dein Wunsch danach basiert auf fehlendem Wissen.

Daher lies dich mal hier ein: https://betterprogramming.pub/alternati ... b2a7d5411b

oder hier: https://stackoverflow.com/questions/593 ... -variables

Und allgemein hier: https://towardsdatascience.com/18-commo ... d983805f0f
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@ThomasL: der erste Link ist Schrott. Benutzt durchweg globale Variablen und hält sich zudem nicht an Konventionen. Wer glaubt, daraus was zu lernen bekommt das Gegenteil.
Der Stackoverflow-Artikel ist ganz gut.
Und der letzte Link ist wenig hilfreich was man statt globaler Variablen nehmen soll.
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Raphael_15,

dass auf number1 nur innerhalb der Funktion test() zugegriffen werden kann, hat gute Gründe. Denn wenn das von jeder Stelle aus dem Programm möglich wäre, würde der Code schnell unübersichtlich werden.
Die Funktion test() kann aber kontrolliert Zugriff auf number1 gewähren, indem der entsprechende Wert aus der Funktion zurückgegeben wird:

Code: Alles auswählen

def test():
    number1 = 1
    return number1
Dieser Rückgabewert kann außerhalb der Funktion entgegengenommen werden:

Code: Alles auswählen

ergebnis = test()
ergebnis enthält jetzt den Wert 1.

den kann man ausgeben:

Code: Alles auswählen

print(ergebnis)
bzw. etwas kompakter:

Code: Alles auswählen

print(test())
Oder dein Code angepasst:

Code: Alles auswählen

def test():
    number1 = 1
    return number1

def ausführen():
    ergebnis = test()
    print(ergebnis)

ausführen()
Die Daten sollten also nicht global zur Verfügung stehen, sondern quasi als Ein- / Ausgangsparameter durch die einzelnen Funktionen "wandern".

Und:
print() ist auch eine Funktion, die zwar Eingangsparameter, aber keine Ausgangsparameter hat.
Raphael_15
User
Beiträge: 3
Registriert: Samstag 30. Januar 2021, 23:38

Ok, danke für eure Antworten, ich denke die beste Möglichkeit wäre es eine allgemeine Game Loop einzubauen, hier mal ein Beispiel, wie mein Programm ungefähr aufgebaut ist.

import pygame
from pygame import mixer
import sys
import random

pygame.font.init()
# Bool
run = True
start = True
pause_game = False
draw_menu = False
shoot = True
lost = False
restart = False
# Display
width = 500
height = 500
screen = pygame.display.set_mode([width, height])

# Lists
lasers = []
enemies = []

class laser:
def __init__(self, x, y, speed):
pass

class ship:

def __init__(self) -> None:
pass
def main():
COOLDOWN = 0
FPS = 60
background = pygame.image.load('background.png')
background2 = pygame.image.load('background.png')
clock = pygame.time.Clock()
clock.tick(FPS)
lost_count = 0
shuttle = ship(width / 2 - 10, height - 100)

# Back sound
pygame.init()
while True:
pass



Das Prgramm ergibt natürlich überhaupt keinen Sinn, ich möchte damit nur verdeutlichen, wie das Programm aufgebaut ist. Wie gesagt habe ich eben diese Variablen oben, wie start, run oder draw_menu, die ich irgendwie öfters ausführen können muss, da ich das Programm ja sonst nicht gerestartet werden kann. Wenn ich das dann aber mit einer allgemeinen Klasse mache die dann beispielsweise Game Loop heißt, was mache ich dann mit den ganzen anderen Klassen wie ship()? Löse ich die auf, oder mache ich dann eine Klasse in einer Klasse? Ich denke mal das ich dann ganz oben eine init function hätte aber wie bereits gesagt, was mache ich dann mit den Klassen? Ich denke nicht das es gut ist eine Klasse in einer Klasse zu machen, aber wenn ja, wie ruft man diese dann auf? Und was mache ich dann mit Parametern, wie oben als Beispiel bei laser, es wird dann ja vermutlich nur eine init geben, also wo soll ich dann die Parameter definieren? Vielen Dank schon mal im vorraus!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Man definiert nicht irgendwelche Variablen auf Vorrat, sondern erst, wenn man sie auch wirklich braucht. Ein Code-Beispiel, das keinen Sinn macht, hilft auch nicht, zu verstehen, was Dein Problem ist. Es gilt halt generell, dass es keine globalen Variablen geben darf, sondern das alles, was eine Funktion braucht über ihre Argumente übergeben werden muß.
Und alles was eine Klasse braucht, muß an __init__ übergeben werden.
Konstanten stehen am Anfang der Datei und nicht in irgendwelchen Funktionen.
Klassen schreibt man mit großem Anfangsbuchstaben. `sys` wird hoffentlich nicht gebraucht, weil das Programm natürlich endet, wenn `main` per `return` verlassen wird.

Code: Alles auswählen

import random
import pygame
from pygame import mixer

FPS = 60
WIDTH = 500
HEIGHT = 500

class Laser:
    def __init__(self, x, y, speed):
        pass

class Ship:
    def __init__(self, x, y):
        pass

def main():
    pygame.init()
    pygame.font.init()
    screen = pygame.display.set_mode([WIDTH, HEIGHT])

    lasers = []
    enemies = []

    background = pygame.image.load('background.png')
    background2 = pygame.image.load('background.png')
    clock = pygame.time.Clock()
    lost_count = 0
    shuttle = Ship(WIDTH / 2 - 10, HEIGHT - 100)

    while True:
        clock.tick(FPS)
Raphael_15
User
Beiträge: 3
Registriert: Samstag 30. Januar 2021, 23:38

Ok, vielen Dank, wenn ich jetzt mal das Codebeispiel nehme, das du unten angehängt hast, wenn du jetzt dem Nutzer eine Restarzmöglichkeit geben möchtest und du WIDTH und HEIGHT in der Klasse Ship benötigst, und das jetzt nicht nur in der Klasse ship sondern durch das ganze Programm benötigst, wie würdest du das machen?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Raphael_15: `WIDTH` und `HEIGHT` sind ja Konstanten, da ist es okay wenn die überall verwendet werden. Auch wenn es natürlich flexibler ist, nicht so viel als Konstanten fest zu machen und auch solche Werte eventuell als Argumente zu übergeben.

Wobei sich beispielsweise auch die Frage stellt warum `Ship` diese Werte braucht. Das wird dann ja üblichweise eine `draw()`-Methode haben, die ein `Surface` übergeben bekommt, auf dem sich das `Ship` dann darstellt, und dieses `Surface` hat ja Breite und Höhe die man abfragen und benutzen kann.

Die Neustartmöglichkeit würde man üblicherweise durch eine Funktion lösen, die den Teil abarbeitet der neustartbar sein soll, die man dann einfach beendet und erneut aufruft. Also statt das so zu lösen das für einen neustart extra Code geschrieben wird, der alle möglichen Daten(strukturen) leert/wieder in einen Anfangszustand versetzt. Wichtig: Beenden und neu aufrufen, und nicht einfach rekursiv aufrufen!
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten