TypeError: 'NoneType' object is not subscriptable

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
NilsV
User
Beiträge: 30
Registriert: Dienstag 17. August 2010, 12:35

eigentlich habe ich gehofft, das mir dieser Code das 1 mal 7 berechnet (Kopfrechnen ist halt zu anstrengend :wink: ):

Code: Alles auswählen

def berechnung(zahl):
    ergebnis = [zahl,]
    for zahlen in range(10): 
        zahl = ergebnis[0] + ergebnis[-1]
        ergebnis = ergebnis.append(zahl)
    return ergebnis

zahl = 7
ergebnis = berechnung(zahl)
print(ergebnis)
Aber leider bekomme ich nur diesen Fehler (Hab die Dateipfade rauseditiert):

Code: Alles auswählen

Traceback (most recent call last):
  File "problem.py", line 9, in <module>
    ergebnis = berechnung(zahl)
  File "problem.py", line 4, in berechnung
    zahl = ergebnis[0] + ergebnis[-1]
TypeError: 'NoneType' object is not subscriptable
Ich verstehe leider nicht was mir Python damit sagen möchte, was habe ich falsch gemacht? Ich verwende übrigends Python 3.1.2
Zuletzt geändert von NilsV am Dienstag 24. August 2010, 00:18, insgesamt 1-mal geändert.
pudeldestodes
User
Beiträge: 65
Registriert: Samstag 9. Juni 2007, 23:45

Die append-Methode verändert deine ergebnis-Liste in-place - und gibt das None-Objekt zurück, das du im 0-ten Durchlauf an ergebnis bindest. Im 1-ten Durchlauf der Schleife versuchst du dann eben mit [] nicht mehr auf ein Element einer Liste zuzugreifen, sondern auf ein Element des None-Objekt. Und das geht nicht, da None kein sequence type ist:

Code: Alles auswählen

>>> test = [1]
>>> test.append(2)
>>> test
[1, 2]
>>> return_value = test.append(3)
>>> return_value
>>> type(return_value)
<class 'NoneType'>
>>> return_value[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not subscriptable
>>> test
[1, 2, 3]

Kurz: ersetze

Code: Alles auswählen

ergebnis = ergebnis.append(zahl)
durch

Code: Alles auswählen

ergebnis.append(zahl)
NilsV
User
Beiträge: 30
Registriert: Dienstag 17. August 2010, 12:35

Vielen Dank für Deine Hilfe. Ich erinnere mich das ich das Problem mit dem Rückgabewert von append schon mal hatte. Muss mir unbedingt merken das append nicht zusätzlich zugewiesen werden darf.
BlackJack

@NilsV: Noch eine kleine Kritik am Quelltext: Er ist zu kompliziert. Das 1-mal `n` geht auch ganz einfach so:

Code: Alles auswählen

def calculate(n):
    return [i * n for i in xrange(1, 11)]
Auf jeden Fall würde ich bei Deinem Quelltext innerhalb der Funktion `zahl` nicht neu binden und anstelle von ``ergebnis[0]`` schreiben. Das ist eine unnötige Indirektion, wo sich der Leser erst klar darüber werden muss, dass da immer der gleiche Wert steht und welcher das ist.
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Oder:

Code: Alles auswählen

def calculate(n):
    return range(n,n*11,n)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wobei das bei Python3 nur einen Generator zurueckgibt. In BlackJack's Beispiel muss man dann auch `xrange` durch `range` ersetzen.

Zumindest hoffe ich, dass der OP Python3 benutzt, da er sonst das arme `print` missbraucht.
NilsV
User
Beiträge: 30
Registriert: Dienstag 17. August 2010, 12:35

Zumindest hoffe ich, dass der OP Python3 benutzt, da er sonst das arme `print` missbraucht.
Python 3.1.2, also keine Missbrauchs Gefahr für print :wink: (vermutlich im Gegensatz zum Rest von Python, allerdings ohne Vorsatz :oops: )
@NilsV: Noch eine kleine Kritik am Quelltext: Er ist zu kompliziert.
Aus der Perspektive eines erfahrenen Python Programmierers mag das so sein, für mich als Anfänger ist es Quelltext den ich verstehe. Dein Beispiel (mit range anstelle von xrange) liefert zwar das selbe Ergebnis mit wesentlich weniger Quelltext, aber ich verstehe leider nicht was da steht:

Das i zum Beispiel, ich schreibe da bisher immer etwas hin das mir beim Lesen verständlich macht was die For Schleife tut, in meinem Beispiel so als währe das Wort Zahlen nichts weiter als eine art Kommentar. i wurde, nach meinem mangelnden Wissenstand, nirgendwo definiert, wie und wieso kann man damit Rechnen? Was ist i? Eine Art lokale Zuweisung die nach dem Schleifenende wieder Verschwindet (Begrenzte Haltbarkeit)? Was kann man i zuweisen?

Das einzige was für mich an dem Konkreten Beispiel Sinn ergeben würde(nachdem ich es 10 Minuten angestarrt habe) ist das i eine Art Platzhalter für die einzelnen Zahlen ist die Range liefert (wird wohl auch so sein), ich verstehe aber nicht die Logik im Syntax. Ich könnte das jetzt einfach abschreiben (und vermutlich auch auf andere Situationen übertragen) aber das wäre nur abschreiben, weil ich nicht verstehe was das geschriebene bedeutet (oder die Bedeutung nur erahnen/raten kann). Was es für mich am nächsten Tag schwierig macht zu verstehen, was ich da geschrieben habe.

Für eine Erklärung was es wirklich damit auf sich hat, wäre ich natürlich sehr dankbar.
BlackJack

@NilsV: Das `i` ist die Schleifenvariable. Das kann man fast wörtlich lesen wie es da steht: `i` mal `n` für (jedes) `i` aus dem Bereich (range) von 1 bis 11 (exklusive). Das ``for``...``in`` steht halt nach dem Ausdruck der das einzelne Listenelement beschreibt, statt wie bei einer normalen ``for``-Schleife davor.

Ohne die "list comprehension" (LC) bräuchte man einen zusätzlichen Namen an den man die Ergebnisliste bindet. Das sähe dann so aus:

Code: Alles auswählen

def calculate(n):
    result = list()
    for i in xrange(1, 11):
        result.append(i * n)
    return result
Bei der LC braucht man den Namen für die Liste nicht mehr um ein einzelnes Element anzuhängen und der Ausdruck aus dem `append()` wandert an die erste Stelle in der LC.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

`i` ist nicht magisch, das Konstrukt nennt sich `List Comprehension` und i wird nach der "Benutzung" zugewiesen naemlich durch `for i in range(1,11)`.

Vielleicht kommt dir die mathematische Mengenschreibweise (Zermelo-Fraenkel) da bekannt vor: {i ∈ N : i ungerade}
Kann man in Python (mit Generator Expressions, dasselbe in gruen, allerdings noetig weil das eine "unendliche" Anzahl ist) mit

Code: Alles auswählen

(i for i in itertools.count(0) if i % 2 == 1)
schreiben. Und wie gesagt kann das `i` auch `zahl` heissen. Fuer Programmierer ist `i` nur eben _die_ Zaehlvariable.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

NilsV hat geschrieben:Für eine Erklärung was es wirklich damit auf sich hat, wäre ich natürlich sehr dankbar.
Man kann den Code fast auf Deutsch übersetzen:

[i * n for i in xrange(1, 11)]
Eine Liste mit den Werten i*n für alle i im Bereich von 1 (inklusive) bis 11 (exklusive)
Antworten