Verständnisproblem bei Listen/Variablen und Referenz/Kopie

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.
sepplx123
User
Beiträge: 13
Registriert: Montag 14. Dezember 2015, 04:13

Hallo,

leider komme ich gerade bei folgendem Problem nicht weiter.

folgendes Beispiel:
Ich habe die Variablen a,b,c die alle eine Zahl sein sollen.
Dann gibt es eine Liste d, die diese Variablen beinhaltet.

Wenn ich nun mit der Listenfunktion auf einen Index zugreife, so möchte ich eigentlich auf das verlinkte Objekt zugreifen und nicht den Wert ändern.
Im nachfolgendem Beispiel hätte ich gerne wenn ich d[0]=5 zuweise, sich die Variable a ebenfalls ändert.

Was wäre hierbei die richtige Lösung?

Code: Alles auswählen

>>> a=1
>>> b=2
>>> c=3
>>> d =[a,b,c]
>>> d
[1, 2, 3]
>>> d[0]=5
>>> d
[5, 2, 3]
>>> a
1
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

sepplx123 hat geschrieben:Wenn ich nun mit der Listenfunktion auf einen Index zugreife, so möchte ich eigentlich auf das verlinkte Objekt zugreifen und nicht den Wert ändern.
Abgesehen davon, dass hier der Begriff Listenfunktion völlig verkehrt verwendet wird - warum glaubst du, dass du so ein Verhalten möchtest?
In specifications, Murphy's Law supersedes Ohm's.
sepplx123
User
Beiträge: 13
Registriert: Montag 14. Dezember 2015, 04:13

Ich habe viele Variablen denen ich neue Werte zuweisen möchte.
Um es mir nun einfach zu machen, dachte ich mir, ich reihe diese Variablen in eine Liste ein und wollte dann mit dem Listenindex einfach der Reihe nach allen Variablen neue Werte zuweisen. Danach sollte wieder mit dem ursprünglichen Variablennamen weitergearbeitet werden.

Es wird aber sobald ich einem Listenindex einen neuen Wert gebe eine neue ID dafür vergeben und somit handelt es sich nicht mehr um die ursprüngliche Variable.

Was ich suche ist eine Möglichkeit, einen Zeiger auf eine Integer Variable zu erstellen.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Es gibt weder Variablen noch Zeiger in Python, du kannst allerdings diese Zahlen in einer Klasse Kapseln und dann die Objekte der Klasse anpassen.

Aber erzaehl doch mal was ueber das eigentliche Problem, vielleicht ist deine Loesung nicht sonderlich geeignet.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@sepplx123: Es gibt Iterable Unpacking, vielleicht hilft dir das:

Code: Alles auswählen

In [1]: a = 1

In [2]: b = 2

In [3]: c = 3

In [4]: a, b, c = 4, 5, 6

In [5]: a
Out[5]: 4

In [6]: b
Out[6]: 5

In [7]: c
Out[7]: 6

In [8]: xs = [7, 8, 9]

In [9]: a, b, c = xs

In [10]: a
Out[10]: 7

In [11]: b
Out[11]: 8

In [12]: c
Out[12]: 9
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

sepplx123 hat geschrieben:Ich habe viele Variablen denen ich neue Werte zuweisen möchte.
Um es mir nun einfach zu machen, dachte ich mir, ich reihe diese Variablen in eine Liste ein und wollte dann mit dem Listenindex einfach der Reihe nach allen Variablen neue Werte zuweisen. Danach sollte wieder mit dem ursprünglichen Variablennamen weitergearbeitet werden.
Das geht mit `locals()`. Ausgabe aus der Python-Shell:

Code: Alles auswählen

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> locals()['x'] = 3
>>> x
3
>>> locals()['x'] = 5
>>> x
5
>>> x = 7
>>> locals()['x']
7
Und zum Ändern mehrerer Werte:

Code: Alles auswählen

>>> for varname in ('x', 'y', 'z'):
...     locals()[varname] = 42
...
>>> x
42
>>> y
42
>>> z
42
BlackJack

@snafu: *Was* geht mit `locals()`? Eine Zuweisung viel komplizierter schreiben? Nicht einmal das geht wirklich:

Code: Alles auswählen

In [10]: def f():
   ....:     locals()['x'] = 42
   ....:     print x
   ....: 

In [11]: f()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-11-0ec059b9bfe1> in <module>()
----> 1 f()

<ipython-input-10-502d84fe37ff> in f()
      1 def f():
      2     locals()['x'] = 42
----> 3     print x
      4 

NameError: global name 'x' is not defined
Das geht nur zufällig auf Modulebene. Dann kann man aber auch `globals()` nehmen. Und wenn man globale Variablen auch noch auf diese Weise setzt, kann man sich auch gleich in den Fuss schiessen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@sepplx123:
Was Du beschreibst, klingt verdächtig nach **-Konstrukten in C/C++ (Zeiger-Zeiger). IdR will / braucht man sowas nicht in Python bzw. hängt zu sehr am Stil von Zeigersprachen fest. Nachbilden kann man solches Verhalten trotzdem mittels eines Proxyobjektes, welches die "verbiegbare" Referenz vorhält:

Code: Alles auswählen

class Reference(object):
    def __init__(self, value):
        self.value = value
    
a = Reference(5)
b = a
b.value = 8
print a.value
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Alternativ geht auch `setattr()`. Eigentlich ist `setattr()` sogar üblicher.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@snafu: was geht auch mit setattr?
@jerch: genau so ein Konstrukt will auch niemand haben. Genauso fangen Leute an, einelementige Listen an Funktionen zu übergeben, weil sie Call-By-Reference wollen.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Sirius3: Das Setzen bzw Verändern von Variablen für einen bestimmten Namensraum.

@BlackJack: Das Setzen bzw Verändern von Variablen. Allerdings mit gewissen Einschränkungen, die du ja bereits demonstriert hast.

Was soll eigentlich diese rhetorische Fragerei? Die Nutzung von `locals()` ist mit einigen Fallstricken verbunden, aber sie ist möglich. Ich persönlich habe `locals()` noch nie in "richtigem" Programmcode eingesetzt, weil ich noch nicht in der Situation war, dies machen zu müssen. Wahrscheinlich würde ich hier eher ein Dictionary nehmen und dort die benötigten Werte ablegen. Aber das muss jeder für sich selbst entscheiden.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Sirius3 hat geschrieben:@jerch: genau so ein Konstrukt will auch niemand haben.
Nicht ganz, ctypes z.B. braucht dies sehr wohl, um die Zeigersemantik zumindest teilweise noch abbilden zu können. Ohne dem wäre ctypes unbenutzbar, wobei typisierte Zeigerarithmetik IMHO nicht implementiert ist, also nur ein Teil abgebildet wird.
BlackJack

@jerch: `ctypes` als Gegenbeispiel zu bringen wenn es darum geht das man so etwas nicht haben will weil das zu C-ähnlich ist, passt irgendwie nicht. ;-)

@snafu: Die rhetorischen Fragen sind nicht rhetorisch, denn ich habe immer noch den Eindruck Du ”löst” da andere Probleme als im Ausgangsbeitrag gefragt sind. Und bei `locals()` gibt's es keine Fallstricke, das funktioniert schlicht nicht so wie Du das anwendest. In Funktionen geht es nicht und auf Modulebene ist es semantisch die falsche Funktion. Und mit `setattr()` geht es noch weniger, oder wie setzt Du damit lokale Variablen in einer Funktion neu? Das ginge höchstens bei Modulen und da ist dann wieder das Problem dass man das nicht machen sollte, weil globale Variablen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@BlackJack:
Es lassen sich andere Bsp. finden, wo man das nutzt, z.B. settings-Objekte für Module, Applikationen, world-Objekte in Spielen etc.

Die von Sirius benannte einelementige Liste das Extrembsp. mit einem Standardcontainer. Was IMHO nicht richtig ist, ist die Aussage, dass man sowas nicht möchte. Eigentlich ist das Gegenteil der Fall - man aggregiert allzu häufig Daten per Referenzsammlungen, um dann was damit zu machen. Z.B. das häufig auftretende Problem, dass Pythonanfänger Variablen nummerieren wollen, ist mit "Referenzcontainern" viel besser lösbar. Was man dagegen idR nicht in Python braucht, ist eine "Einzelreferenz", da eine Variable diese schon darstellt (in Zeigerlogik ein dereferenzierter Zeiger ist). IMHO ist auch unter C ein einelementiges ** ein code smell, da man Referenzpointer ausser bei Arrays nicht zwingend braucht und mit unnötigen Zeiger-Zeigern die Lesbarkeit aufgrund überflüssiger Indirektionen erschwert.
BlackJack

@jerch: Aber genau um diese Einzelreferenz ging es dem OP und das möchte man eigentlich nicht.

Einelementige Zeiger auf Zeiger kann man in C schnell haben wenn man API hat oder schreibt bei denen der Rückgabewert der Funktion ein Fehlercode ist und das eigentliche Ergebnis deshalb über ein solches Zeigerelement zurückgegeben/gesetzt wird. Das wäre IMHO dann kein „code smell“. Programmiersprachen ohne Ausnahmebehandlung sind halt einfach ein wenig doof in dieser Hinsicht.
sepplx123
User
Beiträge: 13
Registriert: Montag 14. Dezember 2015, 04:13

Hallo zusammen und vielen Dank für die vielen Antworten.

Im Speziellen habe ich das Problem beim Erstellen eines Scoreboards für mein Spiel Snake.
Ich hänge jetzt einfach mal die gesamte Klasse hier rein um das eigentliche Problem verständlicher darzustellen.

Code: Alles auswählen

class Scoreboard():
    """ Create a scroeboard and saves the values in a txt-file.
        It also shows actual score information in the game window.
            points for  actions:
            level_solved = 10000
            eat_apple    = 1000
            command_sent = 100
            speed_index  = (slow=100, medium=250, fast=500, ultra=1000)
            time passed in s = 1 x speed_index
    """
    def __init__(self,spielfeld,snake,canvas,scrollbox,player_name):
        self.spielfeld = spielfeld
        self.snake = snake
        self.canvas = canvas
        self.scrollbox = scrollbox

        # total data for player saved in the db
        self.levels_solved = 0
        self.apples_eaten = 0
        self.commands_sent = 0
        self.total_time_passed = 0
        self.total_points = 0

        # data for actual level shown in the game window
        self.player_name = player_name
        self.act_level = 0
        self.time_passed = 0
        self.act_points = 0

        # other variables
        self.time_level_start = 0
        self.time_level_end = 0

        
        # database
        self.point_db = { 'level_solved': 10000, 
                          'eat_apple': 1000, 
                          'command_sent' : 100, 
                          'speed_index_slow' : 100,
                          'speed_index_medium' : 250,
                          'speed_index_fast' : 500,
                          'speed_index_ultra' : 1000,
                         }
        
        self.scoreboard_db = { self.player_name : [self.levels_solved, self.apples_eaten, self.commands_sent,
                                                  self.total_time_passed, self.total_points]
                              }

        self.load_db_file()

        #for item in self.scoreboard_db:
        #    print('scoreboard_db:','player:',item,'stats:',self.scoreboard_db[item] )
        #print('init class Scoreboard done')
        

    def load_db_file(self):
        try:
            scoreboard_file = open("snake_scoreboard.txt", "r")
            liste = scoreboard_file.read().splitlines()
            scoreboard_file.close()
            if liste:
                #print('liste:', liste)
                for item in liste:
                    temp = item.split(" ")
                    #print('temp =',temp)
                    self.scoreboard_db[temp[0]] = [temp[1],temp[2],temp[3],temp[4],temp[5]]
            else:
                self.create_db_file()

        except:
            print('===> no scoreboard file found. It will be created now!')
            self.create_db_file()


    def create_db_file(self):
        try:
            scoreboard_file = open("snake_scoreboard.txt", "w")
            print('----------------------------')
            for line in self.scoreboard_db:
                if line: # dont create empty name entrys in scoreboard_file
                    temp = self.scoreboard_db[line]
                    out_line = "{0:s} {1:d} {2:d} {3:d} {4:d} {5:d}\n".format(line,temp[0],temp[1],temp[2],temp[3],temp[4])
                    print("{0:s} {1:d} {2:d} {3:d} {4:d} {5:d}".format(line,temp[0],temp[1],temp[2],temp[3],temp[4]))
                    #print(out_line)
                    scoreboard_file.write(out_line)
            print('----------------------------')
            scoreboard_file.close()
        except:        
            print('===> scoreboard file could not be created!')

    def save_player(self):
        try:
            scoreboard_file = open("snake_scoreboard.txt", "a")
            print('----------------------------')
            out_line = "{0:s} {1:d} {2:d} {3:d} {4:.3f} {5:d}\n".format(self.player_name,self.levels_solved,self.apples_eaten,self.commands_sent,self.total_time_passed,self.total_points)
            print("{0:s} {1:d} {2:d} {3:d} {4:.3f} {5:d}".format(self.player_name,self.levels_solved,self.apples_eaten,self.commands_sent,self.total_time_passed,self.total_points))
            scoreboard_file.write(out_line)
            print('----------------------------')
            scoreboard_file.close()            
        except:        
            print('===> saving player data to scoreboard_file could not be done!')

    def new_game(self):
        # total data for player saved in the db
        self.levels_solved = 0
        self.apples_eaten = 0
        self.commands_sent = 0
        self.total_time_passed = 0
        self.total_points = 0
        # data for actual level shown in the game window
        self.act_level = 1
        self.time_passed = 0
        self.act_points = 0
        # other variables
        self.time_level_start = 0
        self.time_level_end = 0

    def next_level(self):
        # data for actual level shown in the game window
        self.act_level += 1
        self.time_passed = 0
        self.act_points = 0
        # other variables
        self.time_level_start = 0
        self.time_level_end = 0


    def level_summary(self):
        print('_____level summary------------------------------')
        if self.act_level != self.levels_solved:
            print('_____actual level:',self.act_level,'===>>> failed !!!' )
        else:   
            print('_____levels solved:',self.levels_solved )
        print('_____total apples eaten:', self.apples_eaten)   
        print('_____total commands sent:', self.commands_sent)    
        print('_____time played this level:', self.time_passed)
        print('_____total time:', self.total_time_passed)
        print('_____points gained this level:', self.act_points)
        print('_____total points:', self.total_points)
        print('------------------------------------------------')


    def calc_time_passed(self,start,end): 
        """ calculates time in s between a start and an end point """
        self.time_passed = ((end.hour - start.hour)*3600*1000 +
                            (end.minute - start.minute)*60*1000 +
                            (end.second - start.second)*1000 +
                            (end.microsecond - start.microsecond)/1000)/1000
        return self.time_passed


    def output_level_time(self):
         """ calculates the time spent in this level """
         self.calc_time_passed(self.time_level_start, self.time_level_end)


    def calc_act_points(self,reason):
        """ possible reasons: level_solved, eat_apple, command_sent """
        new_value = self.point_db[reason]           # get the new value from the dict
        self.act_points += new_value                # update actual points
        self.total_points += new_value              # update total points
        
        if reason == "level_solved":
            self.levels_solved += 1
        if reason == "eat_apple":
            self.apples_eaten += 1       
        if reason == "command_sent":
            self.commands_sent += 1
        
    def calc_total_points(self,speed_index):
        """ calculates total points until game over
        'speed_index_slow' : 1
        'speed_index_medium' : 2
        'speed_index_fast' : 5
        'speed_index_ultra' : 10 """
        new_value = int((self.time_passed * self.point_db[speed_index.get()])) # adds spent time * time_multiplier
        self.act_points += new_value                                      # update actual points
        self.total_points += new_value                                    # update total points
        self.total_time_passed += self.time_passed                        # update total time passed
        

    def reset(self):
        # total data for player saved in the db
        self.levels_solved = 0
        self.apples_eaten = 0
        self.commands_sent = 0
        self.total_time_passed = 0
        self.total_points = 0

        # data for actual level shown in the game window
        #self.player_name = 0
        self.act_level = 0
        self.time_passed = 0
        self.act_points = 0

        # other variables
        self.time_level_start = 0
        self.time_level_end = 0
        
        print("reset scoreboard done")
Wie man sieht gibt es Variablen für die gesamt Punkte und welche für das aktuelle Level:

Code: Alles auswählen

# total data for player saved in the db
        self.levels_solved = 0
        self.apples_eaten = 0
        self.commands_sent = 0
        self.total_time_passed = 0
        self.total_points = 0

        # data for actual level shown in the game window
        self.player_name = player_name
        self.act_level = 0
        self.time_passed = 0
        self.act_points = 0
Die gesamten Punkte sowie der Name sollen dann in einer Datenbank (Dictionary) abgelegt werden und für jeden Spielernamen ein extra Eintrag erstellt werden.

Code: Alles auswählen

self.scoreboard_db = { self.player_name : [self.levels_solved, self.apples_eaten, self.commands_sent,
                                                  self.total_time_passed, self.total_points]
                              }
Weiterhin gibt es für verschiedene Spiel-Events Punkte die man dann sowohl zu den gesamt Punkten und zu den Level-Punkte addiert.
Diese Punkte stehen ebenfalls in einem Dictionary:

Code: Alles auswählen

# database
        self.point_db = { 'level_solved': 10000, 
                          'eat_apple': 1000, 
                          'command_sent' : 100, 
                          'speed_index_slow' : 100,
                          'speed_index_medium' : 250,
                          'speed_index_fast' : 500,
                          'speed_index_ultra' : 1000,
                         }
Wenn jetzt ein Event stattfindet und die Punkte neu berechnet werden sollen, wird folgende Methode aufgerufen:

Code: Alles auswählen

def calc_act_points(self,reason):
        """ possible reasons: level_solved, eat_apple, command_sent """
        new_value = self.point_db[reason]           # get the new value from the dict
        self.act_points += new_value                # update actual points
        self.total_points += new_value              # update total points
        
        if reason == "level_solved":
            self.levels_solved += 1
        if reason == "eat_apple":
            self.apples_eaten += 1       
        if reason == "command_sent":
            self.commands_sent += 1
Und hier ist nun mein Problem, dass ich das event als "reason" der Methode zuführe und aus dem Dictionary "point_db[reason]" die zugehörigen raussuche. Das passt auch soweit nur müssen diese Punkte zu den zugehörigen Punkten addiert werden. Und das mache ich zur Zeit von Hand und filtere mittels if-Abfrage aus und jeweils von Hand zu. Da es hier ja nur 3 Abfragen sind geht es ja noch. Aber schöner wäre es, wenn ich die Punkte Varariablen (self.levels_solved, self.apples_eaten, self.commands_sent ) auch in das Dictionary für die Punkte "self.point_db " anhänge und dann in einem Rutsch alles erledige.
Also quasi so:

Code: Alles auswählen

# database
        self.point_db = { 'level_solved': [10000, self.levels_solved],
                          'eat_apple': [1000, self.apples_eaten],
                          'command_sent' : 100,  self.commands_sent],
                          'speed_index_slow' : 100,
                          'speed_index_medium' : 250,
                          'speed_index_fast' : 500,
                          'speed_index_ultra' : 1000,
                         }

    def calc_act_points(self,reason):
        """ possible reasons: level_solved, eat_apple, command_sent """
        new_value = self.point_db[reason]           # get the new value from the dict

        self.act_points += new_value[0]                  # update actual points
        self.total_points += new_value[0]               # update total points
        new_value[1] += 1                                     # update level_events_counter(apples,levels_solved,commands_sent)
Wenn ich nun am Ende eines Levels die Punkte anzeigen will mittels der Methode:

Code: Alles auswählen

def calc_total_points(self,speed_index):
        """ calculates total points until game over
        'speed_index_slow' : 1
        'speed_index_medium' : 2
        'speed_index_fast' : 5
        'speed_index_ultra' : 10 """
        new_value = int((self.time_passed * self.point_db[speed_index.get()])) # adds spent time * time_multiplier
        self.act_points += new_value                                      # update actual points
        self.total_points += new_value                                    # update total points
        self.total_time_passed += self.time_passed                        # update total time passed


    def level_summary(self):
        print('_____level summary------------------------------')
        if self.act_level != self.levels_solved:
            print('_____actual level:',self.act_level,'===>>> failed !!!' )
        else:   
            print('_____levels solved:',self.levels_solved )
        print('_____total apples eaten:', self.apples_eaten)   
        print('_____total commands sent:', self.commands_sent)    
        print('_____time played this level:', self.time_passed)
        print('_____total time:', self.total_time_passed)
        print('_____points gained this level:', self.act_points)
        print('_____total points:', self.total_points)
        print('------------------------------------------------')
Dann sind die Werte in der geänderten "self.point_db" (self.levels_solved, self.apples_eaten,self.commands_sent) nicht identisch mit denen die bei "level_summary(self)" abgefragt werden.

So da ich nun noch eine Nacht drüber geschlafen habe, ist es eigentlich logisch das es so ist. Es sind ja 2 verschiedene Speicherbereiche die belegt werden wenn ich der Variable die nun zufällig den gleichen Namen hat, aber ein Element einer Liste ist einen neuen Wert zuweise.

Ich muss also "level_summary(self)" folgendermaßen ändern:

Code: Alles auswählen

def level_summary(self):

       temp, self.levels_solved = self.point_db['level_solved']
       temp, self.apples_eaten = self.point_db['eat_apple']
       temp, self.commands_sent = self.point_db['command_sent']

        print('_____level summary------------------------------')
        if self.act_level != self.levels_solved:
            print('_____actual level:',self.act_level,'===>>> failed !!!' )
        else:   
            print('_____levels solved:',self.levels_solved )
        print('_____total apples eaten:', self.apples_eaten)   
        print('_____total commands sent:', self.commands_sent)    
        print('_____time played this level:', self.time_passed)
        print('_____total time:', self.total_time_passed)
        print('_____points gained this level:', self.act_points)
        print('_____total points:', self.total_points)
        print('------------------------------------------------')
Und ein weiteres Problem das ich aktuell habe ist ebenfalls sichtbar:

Code: Alles auswählen

def load_db_file(self):
        try:
            scoreboard_file = open("snake_scoreboard.txt", "r")
            liste = scoreboard_file.read().splitlines()
            scoreboard_file.close()
            if liste:
                #print('liste:', liste)
                for item in liste:
                    temp = item.split(" ")
                    #print('temp =',temp)
                    self.scoreboard_db[temp[0]] = [temp[1],temp[2],temp[3],temp[4],temp[5]]
            else:
                self.create_db_file()
Ist es möglich in einer verschachtelten Liste auf die inneren Elemente direkt zuzugreifen und sich den Umweg über meine "temp" Variable zu sparen und "self.scoreboard_db[temp[0]] = [temp[1],temp[2],temp[3],temp[4],temp[5]]" einfacher zu erhalten?

Also wie bei folgendem Beispiel:

Code: Alles auswählen

>>> a=1
>>> b=2
>>> c=3
>>> d=4
>>> e=5
>>> f=6
>>> liste=[[a,b,c],[d,e,f],2,3,4,5,6]
>>> x=liste[0]
>>> x[0]
1
>>>
Ich möchte in der Liste "liste" auf das Element "a" zugreifen. Aber ich möchte nicht er das Objekt "x" erstellen nur um dann "x[0]" schreiben zu können. Geht das einfacher?

Ich weiß, viel Text und und etwas kaotisch.... Aber ich hoffe weiterhin auf Hilfe bei Verbesserung und mögliche TIpps zur Optimierung und besseren Strukturierung.
Danke!
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@sepplx123: aus meiner Sicht Dein größtes Problem ist, dass die Aufgabe von Scoreboard nicht klar ist. Soll das jetzt die Punkte eines Spielers verwalten? Oder die aller Spieler? Werden die Punkte jetzt in Attributen, Listen oder Dictionaries gespeichert? Es gibt Methoden zum Zählen, Speichern, Anzeigen, Zurücksetzen, die immer auf einem anderen Subensemble der Daten operieren. Irgendwie von allem ein bißchen, aber nie konsequent. Aus der Datei geladene Stände wandern nie in die Attribute, und haben auch noch den falschen Datentyp.

Im Grunde ist alles so verquer, dass es am besten wäre nochmal sauber von vorne zu beginnen. Es gibt eine Klasse Spielstand für einen Spieler und eine Klasse, die die Spielstände aller Spieler verwaltet.

Und da Du mit Klassen arbeitest, ist das ursprüngliche Problem auch einfach mit setattr zu lösen:

Code: Alles auswählen

REASON2ATTRIBUTE = {
    'level_solved': 'levels_solved',
    'eat_apple': 'apples_eaten',
    'commands_sent': 'command_sent',
}
def add_points(self, reason):
    amount = POINTS['reason']
    self. act_points += amount
    attr_name = REASON2ATTRIBUTE[reason]
    setattr(self, attr_name, getattr(self, attr_name) + amount)
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@BlackJack
Stimmt. Mit `locals()` war ich auf dem falschen Dampfer. Wie gesagt: Ich habe das selbst noch nie ernsthaft eingesetzt und hatte gedacht, hier einen Anwendungsfall gefunden zu haben.

Deinen Einwand bezüglich `setattr()` verstehe ich nicht wirklich. Anhand dessen, was der OP mit seinem Quelltext gezeigt hat, sieht man hier doch fast schon den perfekten Anwendungsfall für `setattr()`. Und hier ist mir schleierhaft, was daran so verkehrt sein soll. Wie würdest du es denn lösen?
BlackJack

@snafu: Mein Einwand zu `setattr()` bezog sich auf das was der OP vor dieser Klasse gesagt hat und das war ”Variablen” setzen und im Beispiel waren reine Namen und keine Attribute. Das er eigentlich was anderes wollte bei dem `setattr()` Sinn macht, konnte man da IMHO nicht rauslesen.
sepplx123
User
Beiträge: 13
Registriert: Montag 14. Dezember 2015, 04:13

Vielen Dank für die ganzen Tipps!

Mein Problem wurde mit setattr() und getattr() gelöst. Das war genau das was ich suchte! Danke @Sirius3 für das Codebeispiel.

Könnte sich nochmals jemand den zweiten Teil meines Posts anschauen und mir evtl. auch hier eine Hilfestellung geben?
sepplx123 hat geschrieben: Und ein weiteres Problem das ich aktuell habe ist ebenfalls sichtbar:

Code: Alles auswählen

def load_db_file(self):
        try:
            scoreboard_file = open("snake_scoreboard.txt", "r")
            liste = scoreboard_file.read().splitlines()
            scoreboard_file.close()
            if liste:
                #print('liste:', liste)
                for item in liste:
                    temp = item.split(" ")
                    #print('temp =',temp)
                    self.scoreboard_db[temp[0]] = [temp[1],temp[2],temp[3],temp[4],temp[5]]
            else:
                self.create_db_file()
Ist es möglich in einer verschachtelten Liste auf die inneren Elemente direkt zuzugreifen und sich den Umweg über meine "temp" Variable zu sparen und "self.scoreboard_db[temp[0]] = [temp[1],temp[2],temp[3],temp[4],temp[5]]" einfacher zu schreiben?

Also wie bei folgendem Beispiel:

Code: Alles auswählen

>>> a=1
>>> b=2
>>> c=3
>>> d=4
>>> e=5
>>> f=6
>>> liste=[[a,b,c],[d,e,f],2,3,4,5,6]
>>> x=liste[0]
>>> x[0]
1
>>>
Ich möchte in der Liste "liste" auf das Element "a" zugreifen. Aber ich möchte nicht erst das Objekt "x" erstellen nur um dann "x[0]" schreiben zu können. Geht das vielleicht auch einfacher?
Danke!
Antworten