TypeError: can only concatenate list (not "int") to list

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
andi_wand
User
Beiträge: 37
Registriert: Samstag 3. Dezember 2011, 17:04

Moin,
noch eine Frage zu meinem Labyrinth:
Ich habe folgenden Code:

Code: Alles auswählen

def suggest(pos,env,arrivalpos):
           print env[pos[0]+1][pos[1]]
env ist ein 2d-Array (Liste von Listen), pos ist eine Liste mit zwei Variablen. Wenn ich das ausführe, kommt folgender Fehler:
TypeError: can only concatenate list (not "int") to list

Was ist da bei mir das Problem?
BlackJack

Das steht doch da ziemlich deutlich: Du kannst an Listen mit ``+`` keine Zahlen (`int`) anhängen sondern nur andere Listen:

Code: Alles auswählen

In [423]: [23] + 42
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/home/bj/<ipython console> in <module>()

TypeError: can only concatenate list (not "int") to list
andi_wand
User
Beiträge: 37
Registriert: Samstag 3. Dezember 2011, 17:04

pos[0] ist doch eine Int-Zahl, oder hab ich da was missverstanden?
andi_wand
User
Beiträge: 37
Registriert: Samstag 3. Dezember 2011, 17:04

Interessanterweise funktioniert das ganze ein paar mal, erst nach dem dritten/vierten Durchlauf hab ich dann ein Problem...
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Dann lass dir doch einfach mal pos[0] ausgeben.
Das Leben ist wie ein Tennisball.
andi_wand
User
Beiträge: 37
Registriert: Samstag 3. Dezember 2011, 17:04

Anfangs ist es ein int, dann wird es zu einer Liste... :shock:
andi_wand
User
Beiträge: 37
Registriert: Samstag 3. Dezember 2011, 17:04

Die betroffenen Funktionen sind:

Code: Alles auswählen

def suggest(pos,env,arrivalpos):
    suggest_dir=[] 
    
    env[arrivalpos[0]][arrivalpos[1]]="."
    
    print env[pos[0]][pos[1]]
    if(env[pos[0]+1][pos[1]]=="F"):
        print "Finished"
        return [42]
    if(env[pos[0]-1][pos[1]]=="F"):
        print "Finished"
        return [42]
    if(env[pos[0]][pos[1]+1]=="F"):
        print "Finished"
        return [42]
    if(env[pos[0]][pos[1]-1]=="F"):
        print "Finished"
        return [42]
    if (env[pos[0]+1][pos[1]]==" "): 
       # & ((pos[0]+1!=arrivalpos[0]) & (pos[1]!=arrivalpos[1]))):
        #print "Rechts geht es"
        suggest_dir.append(True)
    else:
        #if((env[pos[0]+1][pos[1]]=="#") | ((pos[0]+1==arrivalpos[0]) & (pos[1]==arrivalpos[1]))):
            suggest_dir.append(False)
            #print "Rechts geht es nicht"
    if (env[pos[0]-1][pos[1]]==" "):# & ((pos[0]-1!=arrivalpos[0]) & (pos[1]!=arrivalpos[1]))):
        suggest_dir.append(True)
        #print "Links geht es"
    else:
        #if((env[pos[0]-1][pos[1]]=="#") | ((pos[0]-1==arrivalpos[0]) & (pos[1]==arrivalpos[1]))):
            suggest_dir.append(False)
            #print "Links gehts nicht"
    if (env[pos[0]][pos[1]-1]==" "):# & ((pos[0]!=arrivalpos[0]) & ((pos[1]-1)!=arrivalpos[1]))):
        suggest_dir.append(True)
        #print "Oben geht es"
    else:
        #if((env[pos[0]][pos[1]-1]=="#") | ((pos[0]==arrivalpos[0]) & (pos[1]-1==arrivalpos[1]))):
            suggest_dir.append(False)
            #print "Oben geht es nicht"
    if (env[pos[0]][pos[1]+1]==" "):# & ((pos[0]!=arrivalpos[0]) & (pos[1]+1!=arrivalpos[1]))):
        suggest_dir.append(True)
        #print "Unten geht es"
    else:
        #if((env[pos[0]][pos[1]+1]=="#") | ((pos[0]==arrivalpos[0]) & (pos[1]+1==arrivalpos[1]))):
            suggest_dir.append(False)
            #print "Unten geht es auch nicht..."
    #print suggest_dir
    return suggest_dir
und

Code: Alles auswählen

def solve_maze(self):
        Start=self.getStart()
        Pos_x_last_working=Start[0]
        Pos_y_last_working=Start[1]
        Pos_x_last=Start[0]
        Pos_y_last=Start[1]
        Pos_x=Start[0]
        Pos_y=Start[1]
        Stop=self.getFinish()
        maze=self.maze_Rows
        counter=0
        suggested_dir=[]
        'Markierung des Startpunkts'
        self.maze_Rows[Start[0]][Start[1]]='.'
        'Bewegung'
        i = 0
        print "Startet die Bewegung"
        while((Pos_x !=Stop[0] or Pos_y !=Stop[1]) or suggested_dir!=42):
            if i >=10:
                return -1
                break
            i=i+1
            Pos=[]
            Pos_arr=[]
            Pos_arr.append(Pos_x_last)
            Pos_arr.append(Pos_y_last)
            Pos.append(Pos_x)
            Pos.append(Pos_y)
            suggested_dir=suggest(Pos,self.maze_Rows,Pos_arr)
            #print "Bin am Punkt:"
            #print Pos
            #print suggested_dir
            #print Pos_arr
            counter=0
            for i in xrange(len(suggested_dir)):
                if(suggested_dir[i]==True):
                    counter=counter+1
            time.sleep(1)
            print counter
            print Pos_x,Pos_y
            print Pos_x_last_working,Pos_y_last_working
            print "Kurze Pause"
            time.sleep(1)
            if(counter>1):
                Pos_x_last_working=Pos
            if(counter==0):
                Pos_x_last=Pos_x
                Pos_y_last=Pos_y
                Pos_x=Pos_x_last_working
                Pos_y=Pos_y_last_working
            if suggested_dir[0] == 42:
                print "Finished"
                return 0
            #time.sleep(1)
            '''Ab hier muss noch gearbeitet werden!'''
            if(suggested_dir[0]==True):
                Pos_x_last=Pos_x
                Pos_y_last=Pos_y
                Pos_x=Pos_x+1
                Pos_y=Pos_y
                print "Nach rechts bewegt"
            else:
                if(suggested_dir[1]==True):
                    Pos_x_last=Pos_x
                    Pos_y_last=Pos_y
                    Pos_x=Pos_x-1
                    Pos_y=Pos_y
                    print "Nach links bewegt"
                else:
                    if(suggested_dir[2]==True):
                        Pos_x_last=Pos_x
                        Pos_y_last=Pos_y
                        Pos_x=Pos_x
                        Pos_y=Pos_y-1
                        print "Nach oben bewegt"
                    else:
                        if(suggested_dir[3]==True):
                            Pos_x_last=Pos_x
                            Pos_y_last=Pos_y
                            Pos_x=Pos_x
                            Pos_y=Pos_y+1
                            print "Nach unten bewegt"
            print Pos
                                            
        print self.maze_Rows
        print "Finished"
Woran liegt das, dass auf einmal eine Liste auftaucht?
Vielen Dank schon mal für die Hilfe
EDIT: Fehler gefunden, danke
BlackJack

@andi_wand: Das sieht alles recht umständlich und nach Programmieren mittels Kopieren und Einfügen aus. Und nicht wirklich nach Python. Die auskommentierten Teile wo ``|`` und ``&`` für logische Operationen missbraucht werden, diese ganzen Indexzugriffe mit ``0`` und ``1`` als Index, die unnötigen Klammern um die Bedingungen, Zeichenketten als Kommentare, … — das sind alles Sachen die Du überarbeiten solltest.

Es gibt logische Verknüpfungen und ``elif``. Ausserdem ist da viel zu viel hart kodiert, was man durch Datenstrukturen viel einfacher gestalten könnte. Die einzelnen Zweige unterscheiden sich oft nur geringfügig. Diese Unterschiede sollte man als Daten heraus ziehen und eine Schleife über die Daten mit nur *einer* "Wiederholung" des Quelltextes schreiben.

Funktionen sollten nicht so grundverschiedene Ergebnistypen zurück geben. `suggest()` gibt eine Liste mit einer 42 drin zurück, oder eine mit vier Wahrheitswerten für die verschiedenen Richtungen. Wenn man will das nur der „finishing move“ gemacht wird, dann könnte man auch eine Liste mit vier Wahrheitswerten zurück geben, wo nur der zum "F" auf Wahr steht. Dann muss der Aufrufer sich nicht mit so komischen, unsinnigen Sachen wie ``[42]`` herum schlagen. Solche "Sonderfälle" sollte man vermeiden. Den ganzen Quelltextwust könnte man durch eine Schleife über die relativen Koordinaten deutlich verkürzen. Ich würde sogar eine Liste mit den möglichen relativen Koordinaten als Ergebnis zurück geben. Denn die benutzt Du in `suggest()` zum Testen und lieferst Wahrheitswerte, und beim Aufrufer werden diese Wahrheitswerte wieder in relative Koordinaten umgesetzt. Den Zwischenschritt könnte man sich sparen.

Der Rückgabewert von `solve_maze()` ist auch unsinnig. Je nach Programmverlauf wird -1, 0, oder `None` zurück gegeben. Sinn machen würde vielleicht `True` und `False`, je nachdem ob das Labyrinth gelöst werden konnte oder nicht.

Diese ganzen verschiedenen `Pos_*`-Variablen erscheinen mir zu viel. Das lässt sich sicher mit weniger lösen. Das `Pos_*`-Präfix ist auch etwas überflüssig, denn wenn man die zum Beispiel `x`, `y`, `last_x`, `last_y`, usw. nennt, sollte aus dem Kontext eigentlich auch so klar werden, dass es sich um Positionsangaben handelt.

In Python muss man keine Variablen „deklarieren“; es macht also wenig Sinn Namen, die man erst später im Quelltext benötigt, weiter vorne an Werte zu binden, welche nie verwendet werden. Das betrifft zum Beispiel `counter` und `suggested_dir`. Letzteres wird zwar in der ``while``-Bedingung verwendet, aber das ist unsinnig, weil `suggested_dir` den Wert, auf den dort getestet wird, niemals annimmt.

`Pos` und `Pos_arr` werden äusserst umständlich erzeugt. Wenn Du eine Liste mit zwei Elementen haben möchtest, dann schreibe doch auch eine literale Liste mit zwei Elementen in den Quelltext und nicht eine leere Liste gefolgt von zwei `append()`-Aufrufen auf der Liste. Da die beiden Namen nur für den Funktionsaufruf verwendet werden, könnte man beide Listen auch in den Aufruf schreiben, ohne ihnen Namen zu geben.

Das typische Anti-Pattern-Beispiel in Python ist ``for i in xrange(len(obj))`` um dann mittels `i` per Indexzugriff auf die Elemente von `obj` zuzugreifen. Solche Objekte sind in aller Regel „iterable“, dass heisst man kann *direkt* über die Elemente des Objekts iterieren, ohne den Umweg über einen Index.

Man kann sich in dieser Schleife auch zunutze machen, dass Wahrheitswerte in Python ein Untertyp von ganzen Zahlen sind und `True` und `False` sich wie die Zahlen 1 und 0 verhalten. Dann liessen sich die vier Zeilen zu ``counter = sum(suggested_dir)`` abkürzen.

Grundsätzlich wird das so nicht funktionieren. Zumindest nicht für allgemeine Labyrinthe, denn da muss man mehr als nur einen Schritt zurück gehen können, wenn man in eine Sackgasse gelaufen ist.

Wahrheitswerte sollte man nicht mit ``== True`` testen. Da kommt bloss wieder ein Wahrheitswert heraus und den hatte man ohne den Vergleich ja schon. Wenn man auf das Gegenteil des vorhandenen Wahrheitswertes testen will, gibt es ``not``. Also statt ``if spam == True:`` oder ``if spam != False:`` einfach ``if spam:``. Und statt ``if spam != True:`` oder ``if spam == False:`` besser ``if not spam:``.
BlackJack

Nachtrag: So ungefähr könnte etwas aufgeräumterer und „pythonischerer“ Quelltext für die beiden Funktionen aussehen:

Code: Alles auswählen

DIRECTIONS = RIGHT, LEFT, UP, DOWN = [(1, 0), (-1, 0), (0, -1), (0, 1)]

DIRECTION_TO_STR = { RIGHT: 'rechts', LEFT: 'links', UP: 'oben', DOWN: 'unten' }

FINISH_FIELD = 'F'
FREE_FIELD = ' '
VISITED_FIELD = '.'


def suggest_directions(pos, maze):
    x, y = pos
    result = list()
    for direction in DIRECTIONS:
        x_delta, y_delta = direction
        field = maze[x + x_delta, y + y_delta]
        if field == FINISH_FIELD:
            return [direction]
        if field == FREE_FIELD:
            result.append(direction)
    return result


class Maze(object):
    
    def solve_maze(self):
        last_x, last_y = x, y = self.start
        print 'Startet die Bewegung'
        for i in xrange(10):
            if (x, y) == self.finish:
                print self.maze_Rows
                print 'Finished'
                return True
            self[x, y] = VISITED_FIELD
            suggested_directions = suggest_directions((x, y), self)
            time.sleep(1)
            print len(suggested_directions)
            print x, y
            print 'Kurze Pause'
            time.sleep(1)
            if suggested_directions:
                x_delta, y_delta = direction = suggested_directions[0]
                last_x, x = x, x + x_delta
                last_y, y = y, y + y_delta
                print 'Nach', DIRECTION_TO_STR[direction], 'bewegt.'
            else:
                # 
                # Hier kommt der Code hin für den Fall, dass man keine
                # Bewegungsmöglichkeit mehr hat.
                # 
                pass
        
        return False
andi_wand
User
Beiträge: 37
Registriert: Samstag 3. Dezember 2011, 17:04

Danke für den Code, aber ich brauche ihn leider nciht mehr ("An der Aufgabe vorbeigeschossen").
Ich vermisse immer noch cpp und dessen Möglichkeiten...
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

andi_wand hat geschrieben:Ich vermisse immer noch cpp und dessen Möglichkeiten...
Und welche Möglichkeiten sollen das sein?
Das Leben ist wie ein Tennisball.
andi_wand
User
Beiträge: 37
Registriert: Samstag 3. Dezember 2011, 17:04

z.B. die switch-Funktion, damit kann man sich viele if-elses sparen
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das bekommt man in Python viel schöner mit Dictionaries und Funktionen hin.
Das Leben ist wie ein Tennisball.
andi_wand
User
Beiträge: 37
Registriert: Samstag 3. Dezember 2011, 17:04

Wie geht denn das?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Code: Alles auswählen

>>> def foo(): print "foo"
... 
>>> def bar(): print "bar"
... 
>>> switch = {"f":foo, "b":bar}
>>> switch["f"]()
foo                                                                                                       
>>> switch["b"]()                                                                                        
bar
Das Leben ist wie ein Tennisball.
andi_wand
User
Beiträge: 37
Registriert: Samstag 3. Dezember 2011, 17:04

Ok, danke, wird gleich mal ausprobiert
BlackJack

@andi_wand: Ich hatte doch auch Quelltext gepostet. Das ist im Grunde die ganze Funktionalität die Du gezeigt hast, ohne dass man so viele ``if``\s braucht. Es nutzt die Daten um Entscheidungen einzusparen.
Antworten