Liste - TypeError: list indices must be integers

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
ramsy
User
Beiträge: 9
Registriert: Donnerstag 10. September 2015, 19:20

Hallo zusammen,

ich habe hier 2 Funktionen. In diesen (python 2.6) will ich eine Liste übergeben und weiter bearbeiten. Vielleicht kann mir jemand sagen was ich falsch mache.
In Funktion1 erstelle ich eine Liste mit random values. Diese nennt sich cs_id . Das befüllen funktioniert. Diese Liste gebe ich mit

Code: Alles auswählen

return cs_id
zurück. Dann übergebe ich die Liste mit:

Code: Alles auswählen

cs_id = func.unzip(InputFile, Instances)
func.changecs(cs_id, LicenseKeys, ConfigFile, ConfigDir, Instances)
an eine andere Funktion.

Dort erhalte ich den Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "warmaker.py", line 33, in <module>
    func.changecs(cs_id, LicenseKeys, ConfigFile, ConfigDir, Instances)
  File "/root/PycharmProjects/warmaker/functions.py", line 71, in changecs
    cspath.append(cs_id + '/conf/contentserver/initial-config.txt')
TypeError: can only concatenate list (not "str") to list
Ich verstehe leider nicht wo das Problem liegt. Hier mal meine Schnippsel:

Übergabe der Liste:

Code: Alles auswählen

cs_id = func.unzip(InputFile, Instances)
func.changecs(cs_id, LicenseKeys, ConfigFile, ConfigDir, Instances)
Funktion 1:

Code: Alles auswählen

def unzip(InputFile, Instances):
    cs_id = []

    for i in xrange(Instances):
        cs_id.append('CS_' + id_generator())
        i += 1

    if os.path.isfile(InputFile):  # check if file exists
        print 'Found ' + InputFile
    else:
        print InputFile + ' not fonund. Try again.'
        sys.exit()
    print 'Building ' + str(Instances) + ' instances... '

    for c in xrange(Instances):
        extract = zipfile.ZipFile(InputFile)
        extract.extractall(cs_id[c])
        extract.close()
        c += 1

    return cs_id
Funktion 2

Code: Alles auswählen

def changecs(cs_id, LicenseKeys, ConfigFile, ConfigDir, Instances):

    g = 0
    cspath = []
    keystore = []

    print "Open initial-config.txt to change values"

    print "Reading keyfile"
    f = open(LicenseKeys, "r")
    for line in LicenseKeys:
        keystore.append(f.readline())
    keystore = map(str.strip, keystore)  # map strip to list, delete \n, create a new list, give it back to keystore
    f.close()

    for g in cs_id:
        cspath.append(cs_id[g] + '/conf/contentserver/initial-config.txt')

        # open path
        f = open(cspath[g], "r")
        csproperties = f.read()
        f.close()

        # change parameters
        result = (csproperties
                  .replace("License Key=", "License Key=" + keystore[g])
                  .replace("Config File=", "Config File=" + ConfigFile)
                  .replace("Config Directory =", "Config Directory=" + ConfigDir))

        # write
        f = open(cspath[g], 'w')
        f.write(result)
        f.close()

        g += 1
    print "Values changed"
ramsy
User
Beiträge: 9
Registriert: Donnerstag 10. September 2015, 19:20

Hat sich erledigt. Wie es oft so ist, kommt die Lösung direkt nachdem man einen neunen thread gestartet hat.

Das Problem war:

Vorher

Code: Alles auswählen

g = 0
for g in cs_id:
        cspath.append(cs_id[g] + '/conf/contentserver/initial-config.txt')
Nachher:

Code: Alles auswählen

for instance in cs_id:
        cspath.append(cs_id[g] + '/conf/contentserver/initial-config.txt')
BlackJack

@ramsy: Das ist alles ein bisschen wirr. Das Thema hat ``TypeError: list indices must be integers`` im Betreff, die tatsächlich auftrentende Ausnahme ist dann aber ``TypeError: can only concatenate list (not "str") to list``. An einer Stelle an der man `os.path.join()` statt ``+`` verwenden sollte.

Wofür steht das `cs` in dem Namen `cs_id`? Und wenn das eine Liste ist, warum ist der Name dann im Singular benannt? Das ist verwirrend. Die Anderen Namen halten sich nicht an den Style Guide for Python Code, was das ganze für Python-Programmierer auch schwerer zu lesbar macht. Und wie kommt man auf den Namen `funcs` für ein Modul oder Package? Das ist supernichtssagend.

Bei `Instances` hingegen könnte man vom Namen her denken es handele sich um einen Containertyp statt um eine Anzahl, also eher `instance_count`.

In der Schleife die `cs_id` füllt wird `i` nicht verwendet und das hochzählen von `i` am Ende der Schleife hat keinen Effekt weil der Wert nirgends verwendet wird. Das gilt auch für die letzte Zeile mit `c` in der anderen ``for``-Schleife.

Statt `InputFile` zu prüfen würde man eher einfach versuchen es zu entpacken und entsprechend auf die Ausnahme reagieren. Eventuell auch gar nicht in dieser Funktion sondern weiter oben in der Aufrufhierarchie. Denn man sollte in solchen Funktionen auch nicht einfach das komplette Programm mit `sys.exit()` abbrechen.

Auch die Ausgabe mit ``print`` gehört da eher nicht hin. Wenn man den Programmablauf protokollieren möchte, gibt es das `logging`-Modul in der Standardbibliothek.

Zusammensetzen von Zeichenketten und Werten mittels ``+`` und `str()` ist eher BASIC denn Python. Python kennt dafür Zeichenkettenformatierung mittels `format()`-Methode oder ``%``-Operator auf Zeichenketten.

Indexvariablen sind in der Regel auch „unpythonisch“, weil man die in der Regel gar nicht braucht. Man kann in Python direkt über die Wert von Sequenzdatentypen iterieren, ohne den Umweg über einen Laufindex.

`extract` ist ein schlechter Name für ein Objekt das ein ZIP-Archiv repräsentiert.

Das definieren von allen Namen ganz am Anfang einer Funktion ist auch eine Angewohnheit aus Sprachen wo man alle Variablen am Anfang deklarieren muss. Namen sollten erst definiert werden wenn man sie braucht. Das macht das Programm leichter lesbar und refaktorisierbar.

Aus dem Namen `LicenseKeys` ahnt man nicht das es sich um einen Dateinamen handelt.

Das einlesen der Datei ist superumständlich. `readline()` verwendet man eigentlich nicht mehr. Dateien sind iterierbare Objekte über die Zeilen. Die fünf Zeilen sind in Python in zwei geschrieben, beziehungsweise bekommt man in zwei Zeilen die sicherere, sieben Zeilen lange Variante hin, die auch wirklich sicherstellt, dass die Datei am Ende geschlossen wird:

Code: Alles auswählen

with open(licence_keys_filename, 'r') as lines:
    licence_keys = [line.strip() for line in lines]
Hier passt dann der Name `licence_keys`.

Deine Lösung ist keine Lösung weil Du immer wieder den gleichen Pfad erstellst und `instance` gar nicht verwendest. Der Indexzugriff an sich ist unsinnig! Vergiss `g`, nimm gleich `instance` beziehungsweise die `itertools.izip()`-Funktion um die IDs mit den Lizenzschlüsseln zu verbinden. Und benenne `instance` irgendwie sinnvoller.
Antworten