Probleme mit Pickle

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
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Hi Leute,
habe diese Aufgabe hier gemacht(http://openbookproject.net/pybiblio/pra ... tfolio.php).
Den Code dazu findet ihr hier (http://www.python-forum.de/pastebin.php?mode=view&s=199).

Es funktioniert alles soweit bis auf das Speichern bzw. Laden eines Portfolios.Der Code ist ziemlich lang aber
vielleicht kann sich jemand die main -Funktion ,sowie die Funktionen close,load und save in der Klasse portfolio ansehen
und mir dann sagen warum ich diesen Traceback erhalte:

Traceback (most recent call last):
File "C:\portfolio_tracker.py", line 149, in <module>
main()
File "C:\portfolio_tracker.py", line 143, in main
menu[choice]()
File "C:\portfolio_tracker.py", line 121, in close
self.save()
File "C:\portfolio_tracker.py", line 73, in save
pickle.dump(self,file)
File "C:\Python31\lib\pickle.py", line 1354, in dump
Pickler(file, protocol, fix_imports=fix_imports).dump(obj)
_pickle.PicklingError: Can't pickle <class '__main__.portfolio'>: it's not the same object as __main__.portfolio

Hoffe jemand blickt da durch!
Bis dann derrick
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Code: Alles auswählen

def main():
    global portfolio
    portfolio = portfolio("portfolio1")
Was glaubst du machst du hier?

Ich glaube das ist auch ein guter Moment um auf die Schaedlichkeit von `global` und der Nuetzlichkeit von PEP 8 hinzuweisen.
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Vielleicht noch ein paar erklärende Worte wie ich das fixe?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mach dir erstmal klar _was genau_ du da machst und dann sollten dir die Schuppen von den Augen fallen ;)

Verkuerze deine `main` doch mal auf diese 2 Zeilen, rufe `main` auf und lass dir danach mal ausgeben was dein `portfolio` ist.
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Tag cofi,
wenn ich das mache dann wird eine leere Liste ausgegeben, ich kann aber z.b. auf das name Attribut zugreifen,das sollte heißen ,dass das Objekt gescheit erstellt wurde. Deshalb weis ich nicht wieso jede andere Methode auf dieses "portfolio" zugreifen kann und nur diese load save und close Methoden Probleme haben.
BlackJack

@derrick: *Weisst* Du denn warum da eine leere Liste ausgegeben wird? Was hättest Du da sonst erwartet, und warum? Würdest Du denn hier erwarten das "Hallo" ausgegegen wird?

Code: Alles auswählen

a = 'Hallo'
a = 42
print a
Und was meinst Du damit das jede andere Methode auf dieses (welches von beiden?) `portfolio` zugreifen kann? Auf die Klasse direkt wird ja ausserhalb von `load()` und `save()` nur in Zeile 129 bezug genommen. Und das ist *vor* der Neuzuweisung.

Ich verstehe auch nicht was das ``global`` da überhaupt soll!? Das ist ein übler Hack weil Du die Fehlermeldung ohne das ``global`` vorher nicht verstanden hast. ``global`` ist hier keine vernünftige Lösung! Mach Dir mal klar was Zeile 129 sagt, und warum es vielleicht keine gute Idee ist das so zu schreiben. Was bedeutet der Name `portfolio` *vor* dieser Zeile und was würde er *nach* dieser Zeile bedeuten? An was für ein Objekt wäre der Name jeweils gebunden und wodurch unterscheiden die sich?
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Ja du hast Recht ich hab global tatsächlich nur eingebaut weil ich die hier:
...in main
UnboundLocalError: local variable 'portfolio' referenced before assignment
nicht verstanden habe und auch jetzt nicht verstehe.Was das Problem mit Zeile 129 ist kann ich auch
nicht erkennen wie sonst sollte ich dieses Objekt erzeugen.
BlackJack

@derrick: Welches Objekt? Du hast da *zwei* Objekte aber nur einen Namen. Was bedeutet das `portfolio` links vom ``=`` und was bedeutet es rechts davon? An welches Objekt ist der Name zu welchem Zeitpunkt gebunden?

Kennst Du den Unterschied zwischen globalen und lokalen Namen? Wenn ein Name irgendwo innerhalb einer Funktion an einen neuen Wert gebunden wird, dann sieht Python den als lokalen Namen an. *Ausschliesslich*! Es sei denn man deklariert ihn als ``global``. Dann ist er innerhalb der Funktion global. Und zwar auch wieder *ausschliesslich*. (Wobei ”global” hier immer ”modulweit” oder ”auf Modulebene” meint.)
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Schreibe die Klasse einfach mit einem Großbuchstaben am Anfang (so wie es ja eigentlich auch üblich ist) und dann dürfte sich das Problem der Namensgleichheit erledigt haben.
lordnaikon
User
Beiträge: 58
Registriert: Dienstag 9. Februar 2010, 13:41

snafu hat geschrieben:Schreibe die Klasse einfach mit einem Großbuchstaben am Anfang (so wie es ja eigentlich auch üblich ist) und dann dürfte sich das Problem der Namensgleichheit erledigt haben.
Spielverderber :?
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Danke euch allen für eure Hilfe, snafu dein tipp hat es letztendlich ausgemacht!
BlackJack

@derrick: Soll heissen Du hast verstanden was das Problem war, oder das Problem das Du nicht verstanden hast, tritt nun einfach nicht mehr auf?
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

BlackJack hat geschrieben:Wenn ein Name irgendwo innerhalb einer Funktion an einen neuen Wert gebunden wird, dann sieht Python den als lokalen Namen an.
Wie muss man sich das denn genau vorstellen? Heißt das, der Name, welcher etwas zugewiesen bekommen soll (also links vom `=`), wird bereits im lokalen Namensraum angelegt, *bevor* die Zuweisung ausgewertet wurde? Und dann wird unabhängig davon im nächsten Schritt die Zuweisung ausgewertet, welche "stumpf" sieht, dass der angeforderte Name lokal existiert und daher nicht wissen kann, dass noch gar nichts an den Namen gebunden wurde, weil eben sie selbst das zu Bindende darstellt?

Bringt dieses Verhalten irgendwelche Vorteile? Ich finde es in erster Linie verwirrend. Eine Zuweisung `Foo = Foo()` auf der selben Ebene geht ja durchaus. Also dass der globale bzw jeweils übergeordnete Namensraum gar nicht erst angefasst wird, wenn es schon davor einen Treffer gab, ist soweit klar. Was ich jetzt eher fragwürdig finde, ist der Umstand, dass in bestimmten Situationen (sofern mein vorheriger Absatz denn zutrifft) Namen existieren können, die noch gar keinen Wert haben.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

BlackJack hat geschrieben:@derrick: Soll heissen Du hast verstanden was das Problem war, oder das Problem das Du nicht verstanden hast, tritt nun einfach nicht mehr auf?
Ich denke mal, eher letzteres. Ich finde aber, man kann einem Anfänger manchmal ruhig sagen, dass etwas in einer bestimmten Form nicht funktioniert und dann idealerweise eine Erklärung mitliefern. Grundsätzlich habe ich ja nichts dagegen, die Leute zum Mitdenken und Lesen der Doku zu animieren. Ich glaube aber, in dem Fall wusste der OP nicht wirklich, was ihr eigentlich von ihm wollt, so dass diese Technik der Wissensvermittlung auch nicht sonderlich zielführend war. ;)
deets

snafu hat geschrieben:Heißt das, der Name, welcher etwas zugewiesen bekommen soll (also links vom `=`), wird bereits im lokalen Namensraum angelegt, *bevor* die Zuweisung ausgewertet wurde? Und dann wird unabhängig davon im nächsten Schritt die Zuweisung ausgewertet, welche "stumpf" sieht, dass der angeforderte Name lokal existiert und daher nicht wissen kann, dass noch gar nichts an den Namen gebunden wurde, weil eben sie selbst das zu Bindende darstellt? .
Ja, so in etwa. Das hat verschiedene Gruende: zum einen optimiert Python lokale Namen auf Bytecode-Ebene weg. Das ist natuerlich nicht zwingend, aber so ist es nunmal. Das passiert bereits beim parsen.

Wichtiger und in diesem Fall auch anders nicht zu loesen sind closures: fuer viele of erstmal verwirrend ist folgender code, der fehlschlaegt:

Code: Alles auswählen

def outer():
    x = 10
    def inner():
        a = x**2
        x = a + 3
        return x
    h = inner()
outer()
Denn dabei braucht Python einen Weg zu unterscheiden, welche Namen im inneren Scope eingefuehrt, und welche "nur" referenziert werden vom aeusseren. Da es keine expliziten variablen-deklarationen wie in zB Javascript mit dem "var" gibt, hat man sich eben darauf geeinigt: jeder simple Name auf der linken Seite fuehrt einen Namen lokal ein, und darf dementsprechend davor nicht verwandt werden - auch wenn es im auesseren Scope (und sogar den globalen Variablen) da theoretisch was geben kann.
BlackJack

@snafu: Ich finde schon es wäre zielführend gewesen wenn eine der Fragen die ich gestellt habe mal beantwortet worden wäre. Ich hatte da ja mehrere gestellt, und zwar im Grunde sehr einfache, die einfach nur darauf hinaus laufen ob verstanden wurde, was zu bestimmten Zeitpunkten in der Programmausführung an einen Namen gebunden ist.
Antworten