Pass by value erzwingen?

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.
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Hallo zusammen,

da in Python alles via Referenz auf ein Objekt übergeben wird, scheint es mir etwas problematisch von "pass-by-value" und "pass-by-reference" zu sprechen. Was ich möchte ist aber folgendes: Ich möchte in einer best. Funktion *immer* die Referenz auf eine Kopie des Ursprungsobjektes erhalten.

Momentan prüfe ich, ob ein Objekt bereits in einer Liste von Objekten ist und erstelle in diesem fall mit copy.deepcopy() eine Kopie davon. Das erscheint mir aber etwas unsauber - gibt es da kein Hausmittel?

lG

Daniel
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Wenn du immer eine Kopie haben willst, warum musst du dann erst in irgendwelchen Liste suchen? Das ist etwas anders als *immer*. Am besten du postet mal einen Beispielcode oder beschreibst besser was du möchtest.
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

der sinn eines call by value ist ja meist nicht, dass die funktion eine kopie erhält die sie behalten und damit jeglichen unsinn anstellen darf, ohne dass der ursprungswert verändert wird. es geht dabei meist um performanacevorteile. in python könnte man die eh nicht erreichen, daher macht cbv hier kein sinn.

ich tippe daher mal, dass es keine andere möglichkeit gibt als eine manuelle kopie zu erstellen.
Zuletzt geändert von Dill am Mittwoch 13. Mai 2009, 08:42, insgesamt 1-mal geändert.
http://www.kinderpornos.info
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Viele Leute beklagen sich, dass Python "call by value" so "schwer" macht -- und stellen dann fest, dass man diese Semantik eigentlich nie braucht.

Möglicherweise lässt sich dein Problem also auch auf eine viel einfachere Art und Weise lösen...
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Hallo,

danke schonmal für eure Antworten. Anscheinend muss ich das wirklich mit deepcopy() machen.
Wer dennoch interessiertist, kann sich gerne die ausführliche Beschreibung antun (Achtung, ich muss da etwas auf dem Unterschied zwischen "dem gleichen" - und "dem selben" rumreiten ;).

Es sollen Lieder aus den Charts ausgelesen und zu meiner Wiedergabeliste hinzugefügt werden. In Pseudocode

Code: Alles auswählen

charts = get_charts_list()
tracks = get_track_objects_from_list(charts)

for track_id in charts:
    for track in tracks:
        if track_id == track.id:
            add_track_to_playlist(track)
Soweit so klar: Auf Grund einer Designentscheidung werden immer nur IDs von Liedern gespeichert. Die dazugehörigen Track-Objekte, die ich benötige, werden nach einem db-query erstellt. Diese sind aber erstmal nicht in der Reihenfolge der Liste (was bei Charts doof ist), also wird mit den verschränkten Schleifen nachsortiert.
Wenn nun aber in der Liste charts das gleiche Lied (also die gleiche ID) mehrfach auftaucht, wird immer die selbe Objektreferenz an die Playliste übergeben. Hier sitzt das eigentliche Problem: Dadurch, dass in den Charts das *gleiche* Lied mehrfach auftaucht, wird immer das *selbe* Objekt an die Playlist übergeben.
Hier kann ich aber nicht nachbessern, da ich diesen Vorgang soweit recht intuitiv finde und mir die Plugin-Schnittstelle nicht verhunzen will.

Da es nun durchaus passieren kann, dass ein Lied mehrfach in die Playlist gepackt wird, wird zusätzlich zur ID (die unterschiedliche Lieder voneinander unterscheidet), eine UID generiert (die auch für gleiche Lieder unterschiedlich ist) und als Attribut im Track-Objekt gespeichert.
Über diese UID erkennt mein Programm, welches Lied gerade abgespielt wird und welches z.B. das nächste ist.

Dumm natürlich, wenn zwei *gleiche* Lieder durch die *selbe* Objektreferenz repräsentiert werden: Dann haben automatisch alle gleichen Lieder die selbe UID und mein Programm kommt völlig durcheinander, wenn es darum geht, die Position des fraglichen Liedes in der Playlist zu bestimmen.

Meine Lösung also: Wenn ein Track-Objekt zur Playlist hinzugefügt wird, teste ich, ob das *selbe* Objekt bereits in der Liste ist und erstelle ggf. eine Kopie davon. Natürlich könnte ich auch einfach jedes Objekt kopieren, aber da die Kopie in der add_track_to_playlist() Funktion angefertigt wird, kann man ja auch gleich nachschauen, ob eine Kopie überhaupt nötig ist.

lG

brb
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Um in einer Liste zu erkennen, was der nächste Eintrag ist, würden mir jetzt irgendwie noch andere Wege einfallen. Ich verstehe das Konzept leider noch nicht ganz.
BlackJack

Ich finde es auch ein wenig komisch. Ich würde eher erwarten, dass sich die Playlist die aktuelle Position merkt, dann könnte da auch 100 mal das selbe Objekt drin stehen. Die Notwendigkeit Objekte zu "klonen" ist IMHO (bei Python) ein "design smell".
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Naja, da mögt ihr recht haben, aber das Programm ist ja nicht - wie hier beschrieben - 10 Zeilen lang sondern 15.000.
Im konkreten Fall fand ich es sinnvoll, dass jedes Lied in der Playlist auch durch ein eigenes Lied-Objekt repräsentiert wird - und nicht durch zwei Referenzen auf das selbe Objekt. Egal, ich diskutiere hier gerade am PC ganze Zeit mit mir selbst die Vor- und Nachteile meines Aufbaus, bin mir der Probleme bewusst und glaube doch, dass das Design doch nicht völlig verhunzt ist.

Eigentlich hat sich die Frage auch erübrigt: Ich kann mir nicht vorstellen, dass es eine Möglichkeit gibt, im Kopf einer Methode festzulegen, dass ein bestimmter Parameter bitte die Referenz auf eine Kopie des via Referenz übergebenen Objektes sein solle - das wäre doch etwas weit her geholt.

Danke für eure Mühe, insbesondere für die Kritik ;).

Daniel
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dill hat geschrieben:der sinn eines call by value ist ja meist nicht, dass die funktion eine kopie erhält die sie behalten und damit jeglichen unsinn anstellen darf, ohne dass der ursprungswert verändert wird. es geht dabei meist um performanacevorteile.
Was sollte denn Call-by-value für Performancevorteile haben? Letztendlich muss dazu bei jedem Aufruf der Funktion der Parameter kopiert werden, bei Call-by-reference muss man nur eine sowieso schon existierende Referenz an die Funktion weitergeben.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

der vorteil ist, dass bei cbv der funktion die variable auf den stack gelegt wird.
http://www.kinderpornos.info
BlackJack

In wie weit ist das jetzt ein Vorteil?
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Hier muss ein Missverständnis vorliegen. Python benutzt ausschließlich "call-by-value". Die Werte sind allerdings Referenzen (aka Zeiger) auf Objekte. Oder anders ausgedrückt, die Objektdaten selbst werden nicht dupliziert für einen Funktionsaufruf. Dies ist das normale Verhalten. C und C++ verhalten sich hier ungewöhnlich, indem sie implizit Strukturen kopieren.

"call-by-reference" ist AFAIK so definiert:

Code: Alles auswählen

def a(x): x = 1
y = 0
a(y)
assert y == 1
Dies gilt NICHT in Python. Als dritten im Bunde gibt es übrigens noch "call-by-name", den kann Python auch nicht. Ruby oder Smalltalk haben auch nur CbV. Eine Sprache, die alles kann wäre z.B. Algol-68. Pascal und C# fallen mir für CbR und CbV ein. Scala hat CbV und CbN.

Stefan
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

sma hat geschrieben:Hier muss ein Missverständnis vorliegen. Python benutzt ausschließlich "call-by-value". Die Werte sind allerdings Referenzen (aka Zeiger) auf Objekte. Oder anders ausgedrückt, die Objektdaten selbst werden nicht dupliziert für einen Funktionsaufruf. Dies ist das normale Verhalten. C und C++ verhalten sich hier ungewöhnlich, indem sie implizit Strukturen kopieren.

"call-by-reference" ist AFAIK so definiert:

Code: Alles auswählen

def a(x): x = 1
y = 0
a(y)
assert y == 1
Dies gilt NICHT in Python. Als dritten im Bunde gibt es übrigens noch "call-by-name", den kann Python auch nicht. Ruby oder Smalltalk haben auch nur CbV. Eine Sprache, die alles kann wäre z.B. Algol-68. Pascal und C# fallen mir für CbR und CbV ein. Scala hat CbV und CbN.

Stefan

Code: Alles auswählen

>>> def f(x): x.append("foo")
...
>>> y = []
>>> f(y)
>>> f(y)
>>> y
['foo', 'foo']
>>> f(y)
>>> f(y)
>>> y
['foo', 'foo', 'foo', 'foo']
=DD

...Nun denn, unrecht hat Stefan trotzdem nicht. Finde eh, dass man eher nebeneffektsfreie Funktionen schreiben sollte, wenn es geht.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

BlackVivi, dein Beispiel zeigt etwas GANZ ANDERES. Die entscheidende Zeile für CvR ist ``y = 0``. Du weist in deinem Beispiel `y` in der Funktion niemals etwas anderes zu. `y` hält vor und nach dem Funktionsauf das SELBE Objekt. Die Variable hat sich NICHT verändert, nur das Objekt, aber das ist EGAL. Das R von CvR bezieht sich darauf, dass eine REFERENZ auf die Variable übergeben wird.

Stefan
BlackJack

Au ja, schon wieder *die* Diskussion. Call-by-value ist es in Python nicht, weil die Referenzen keine Werte sind. Es gibt nicht den Datentyp "Referenz" in Python. Die Bezeichnung bei Python ist call-by-sharing oder call-by-object.
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

sma hat geschrieben:BlackVivi, dein Beispiel zeigt etwas GANZ ANDERES.
Gaaaanz ruhig... Das war nur'n Scherz von meiner Seite, um dich'n bissel anzustacheln. Mehr nicht. Hab ja danach geschrieben, dass ich auf deiner Seite steh oO' Und die Smilies dazu... Ich weiß, dass es was anderes ist'ne Methode von einem Objekt aufzurufen als'ne Zuweisung an einer Referenz zu machen.

(Die Bezeichnung Call-by-Object find ich übrigens arg passend)
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

BlackVivi hat geschrieben:Gaaaanz ruhig...
Ich LESE offenbar in letzter Zeit zu viele Beiträge eines Netizen namens Zornhau der es LIEBT, wichtige Wörter GROSS zu schreiben :)

Stefan
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

BlackVivi hat geschrieben:(Die Bezeichnung Call-by-Object find ich übrigens arg passend)
Ich finds albern, selbst die Java-Jungs nennen es bei sich call-by-value, obwohl sie ihre Pointer Referenzen nennen. In der Python-Doku steht übrigens auch call-by-value. Aber wenn man sich dann besser fühlt, kann man sich natürlich auch neue Namen dafür ausdenken (so wie man in Java Zeiger Referenzen nennt), auch wenn dann keiner mehr versteht, was man eigentlich meint.

Ich würde ja call-by-implicit-pointer-to-an-object-that-is-passed-by-value vorschlagen ;)
BlackJack

@Darii: Wo steht denn das in der Python-Doku?

Es ist nicht albern, weil man sowohl bei call-by-value als auch bei call-by-reference Erwartungen weckt, die man dann erst wieder ausräumen muss.

Wenn die Java-Jungs (und Mädels) sagen würden, es wären Pointer, aber eben doch wieder nicht so wie das ein C- oder Pascal-Programmierer erwarten würde, bringt das keinen wirklichen Vorteil. Auch wenn sie nicht call-by-sharing oder call-by-object als Begriff sagen würden, müssten sie trotzdem erklären was es ist.

Und call-by-sharing ist kein neuer Begriff, es sei denn 1974 ist für Dich schon zu neu. ;-)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dill hat geschrieben:der vorteil ist, dass bei cbv der funktion die variable auf den stack gelegt wird.
Und der Performancevorteil ist jetzt wo? Der Wert muss trotzdem kopiert werden und wenn die Funktion die den Wert bekommt auch noch weitere Funktionen aufruft ist das Objekt letztendlich mehrfach im Stack vorhanden. Ich sehe da also dann zwei Nachteile: mehr Speicherverbrauch und mehr Zeitverbrauch. Natürlich hat es auch einen Vorteil, aber es ist nicht die Performance (oder wir sprechen von negativen Performancevorteilen).
Darii hat geschrieben:
BlackVivi hat geschrieben:(Die Bezeichnung Call-by-Object find ich übrigens arg passend)
Ich finds albern, selbst die Java-Jungs nennen es bei sich call-by-value, obwohl sie ihre Pointer Referenzen nennen. In der Python-Doku steht übrigens auch call-by-value. Aber wenn man sich dann besser fühlt, kann man sich natürlich auch neue Namen dafür ausdenken (so wie man in Java Zeiger Referenzen nennt), auch wenn dann keiner mehr versteht, was man eigentlich meint.
Java hat genausowenig wie Python Zeiger. Es sind Referenzen, aber Referenzen sind keine Pointer. Les dir doch mal die ganzen Threads durch, wo die Leute eine Liste an eine Funktion übergeben, diese verändern und dann das gleiche mit einer Zahl machen und sich wundern, warum sich die zahl außerhalb der Funktion nicht auch geändert hat.

Ich habe anfangs auch den Unterschied zwischen Call-by-Reference und Call-by-Object nicht verstanden, und den Begriff für Überflüssig gehalten, aber wenn man genauer nachdenkt sind es durchaus zwei verschiedene Dinge (ich empfehle in C einen Pointer-to-int zu übergeben und die innerhalb der Funktion zu modifizieren und dann in Python eine Zahl übergeben und das zu modifizieren um sich die Unterschiede klar zu machen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten