Seiteneffekt?

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
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Hallo Leute,

ich war gerade dabei eine (einfache) Liste an die Funktion zu übergeben. In diesem Zusammenhang ging ich dann wie folgt vor:

Code: Alles auswählen

>>> def func(list):
...     print list

>>> foo_list = [0,1,1,2,3,5,8]
>>> func(foo_list)


Und dabei stieß ich auf den Begriff "Seiteneffekt". Ich las auf einigen Seiten, dass dies ein schlechter Programmierstil sei, und man dies so nicht handhaben sollte. Und soweit ich es auch verstanden habe, wird hierbei nicht die Liste als solches übergeben, sondern nur der Verweis auf die Liste. Das heißt, in Wirklichkeit wurde die Liste gar nicht an die Funktion übergeben, sondern nur der Verweis wo die Liste sich befindet. Viel mehr wurde dafür plädiert, dass man die Liste als eine Kopie an die Funktion übergeben solle. Etwa so:

Code: Alles auswählen

>>> def func(list):
...     print list
... 
>>> foo_list = [0,1,1,2,3,5,8]
>>> func(foo_list[:])
Mit dieser sogenannten Slicing-Funktion [:] wird ja eine Kopie erstellt, und diese an die Funktion übergeben.

Soweit so gut, aber irgendwie habe ich das Gefühl, diesen Sachverhalt noch nicht ganz verinnerlicht zu haben. Was ist nun so "schlecht" an einem Seiteneffekt? Wieso sollte man den sogenannten "Seiteneffekt" verhindern? Welche Nachteile erkaufe ich mir? Und wieso sollte man eine Kopie an die Funktion übergeben? Wieso nicht den Verweis?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: Seiteneffekte sind die Nebenwirkungen der Medikamente. Man will sie im Normalfall nicht haben. Wenn eine Funktion dafür da ist, den Inhalt einer Liste zu ändern (sort_list) dann ist das kein Seiteneffekt, sondern gewollt. Hingegen eine Funktion, die von außen nicht den Anschein hat, den Inhalt zu ändern, sollte das auch nicht tun. Aber wo hast Du gelesen, dass man immer eine Kopie der Liste erstellen soll? Das ist nämlich genau der falsche Weg. Derjenige, der die Funktion schreibt, muß darauf achten, dass sie seiteneffektfrei ist, nicht derjenige der sie aufruft. Im Umkehrschluß, Funktionen, die Listen verändern müssen das gewollt und dokumentiert tun.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Hallo Siriu3,

ich habe dies hier gelesen. Im Abschnit "Seiteneffekt".
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Sophus: Wir wissen aus mittlerweile vielen Threads daß du ziemlich beratungsresistent bist. Da ich von unterwegs mit dem Smartfone schreibe, nutze ich nicht die SuFu, um zu gucken ob wir Dir nicht schon einmal etwas zu diesem Kurs gesagt haben. Ich bin mir aber fast sicher - und falls nein, so ist dir das als Stammleser aber bereits sicherlich schon einmal über den Weg gelaufen, *was* wir hier empfehlen und was *nicht*.

Du hast jetzt gehört, wie es sich mit solchen pauschalen Aussagen verhält. Darüber hinaus gibt es ganz allgemein einige richtig gute Tutorials. Den Schluss daraus überlasse ich jetzt dir!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wenn eine Funktion etwas neben seiner Dokumentation und erst recht mit den Argumenten tut, sollte man das vermeiden.
Den verlinkten Absatz kann man aber schlicht nicht generell unterschreiben. Manchmal _will_ man diese Effekte, beispielsweise bei einer Funktion die sein Argument _in-place_ sortiert.

Man sollte sich einfach an das Principle of least Surprise halten.

Nebenbei: Es heisst Nebeneffekt, Seiteneffekt ist eine falsche Uebersetzung von "side effect".
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

eine netter Nebeneffekt des Beispiels im 1. Post ist, dass es mit `list` einen äußerst schlechten Variablennamen benutzt, weil `list` in Buildin Funktion ist.

Code: Alles auswählen

>>> def func(list):
...     print(list)
...     list('abc')
... 
>>> a = [1, 2, 3]
>>> func(a)
[1, 2, 3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in func
TypeError: 'list' object is not callable
>>> >>> list('abc')
['a', 'b', 'c']
Ansonsten hatte ich beim Programmieren noch nie das Bedürfnis `func(foo_list[:])` zu schreiben. Weil: siehe Post von sirius3 :-)

Gruß, noisefloor
Antworten