OOP

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.
r74
User
Beiträge: 14
Registriert: Montag 15. Dezember 2008, 21:34

Hallo Forum

Seit kurzem beschäftige ich mich mit Objektorientiertem Programmieren.

Mich irritiert in Python folgendes:

Die Länge einer Liste list kann ich wie folgt erfragen:

Code: Alles auswählen

len(list)
(nach meinem Verständnis: len ist eine Funktion, sie nimmt als Argument eine Liste)

Währenddem ich der Liste ein Element wie folgt anhänge:

Code: Alles auswählen

list.append(...)
(nach meinem Verständnis: append ist eine Methode, sie wird auf das Objekt Liste angewendet)

Warum können nicht konsequent Methoden auf Objekte angewendet werden (wie z.B. in Java), also

Code: Alles auswählen

list.len()
list.append()
Vielen Dank für viele klärende Hilfen.
Benutzeravatar
Masaru
User
Beiträge: 425
Registriert: Mittwoch 4. August 2004, 22:17

Vielleicht weil Python (im Gegensatz zu Java) dem Entwickler nicht aufzwingt ausschließlich objektorientiert zu programmieren, sondern auch den prozeduralen Weg offen lässt?
r74
User
Beiträge: 14
Registriert: Montag 15. Dezember 2008, 21:34

@Masaru:
Die Möglichkeit

Code: Alles auswählen

list.len()
existiert ja gar nicht.
Ich muss dafür die "prozedurale" Version

Code: Alles auswählen

len(list)
verwenden.

Warum existieren nicht beide Möglichkeiten?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du könntest

Code: Alles auswählen

list.__length__()
benutzen. Die len-Funktion ist einfach nur eine Kurzfrom dieses Aufrufs.
Das Leben ist wie ein Tennisball.
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

r74 hat geschrieben:@Masaru:
Die Möglichkeit

Code: Alles auswählen

list.len()
existiert ja gar nicht.
Ich muss dafür die "prozedurale" Version

Code: Alles auswählen

len(list)
verwenden.

Warum existieren nicht beide Möglichkeiten?
Dafür, wiederum, gibt es eine Antwort. Im Zen um genau zu sein:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

EyDu hat geschrieben:Du könntest

Code: Alles auswählen

list.__length__()
benutzen. Die len-Funktion ist einfach nur eine Kurzfrom dieses Aufrufs.
Heißt die Methode nicht ``__len__``?
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ja tut sie :oops:
Das Leben ist wie ein Tennisball.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

r74 hat geschrieben:Ich muss dafür die "prozedurale" Version

Code: Alles auswählen

len(list)
verwenden.
Das ist schlicht falsch, `len` ruft obj.__len__() auf, und arbeitet in dem Sinne wie ein ganz normaler Operator. `iter` arbeitet vergleichbar.
Da in "prozedural" und "objektorientiert" zu denken macht keinen sinn.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Also, r74, ich kann deine Anfragen gut nachvollziehen, auch wenn einige, die mehr von Python verstehen als ich, das hier wegbügeln.

Ich empfinde hier auch Inkonsistenzen. Beispiel für eine Liste a:
Es heißt a.sort() und nicht sort(a), stattdessen gibt es z.B. sorted(a).
Andererseits aber len(a) und nicht a.len(). Der Verweis auf die magic methods ist doch Augenwischerei.
IMHO wäre es konsistenter gewesen, wenn man allen Sequenztypen eine anständige len()-Methode mitgegeben hätte.
BlackJack

@r74: Auch ein Grund war wohl, dass die Entwickler gerne *einen* Namen haben wollten und nicht jeder seine eigenen Namen dafür erfindet. In Java ist das nämlich gar nicht so einheitlich: `length()` bei Zeichenketten, bei Arrays `length` (Feld statt Methode), und bei den Containerklassen in der Standardbibliothek `size()`. Und wenn die Leute anfangen selbst Containerklassen zu schreiben, habe ich auch schon `getLength()` und `getSize()` gesehen.

Und da `len` ja auch ein Objekt ist, ist das auch alles objektorientiert. Und funktional. ;-)
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

r74 hat geschrieben:Warum können nicht konsequent Methoden auf Objekte angewendet werden (wie z.B. in Java), also

Code: Alles auswählen

list.len()
list.append()
Kurzfassung: Weils halt so ist. ;) Ist denke ich mal hauptsächlich historisch gewachsen. Andererseits, tut es weh len(object) statt object.len() zu schreiben?

Das Konzept von len(dass nach einer Methode __len__ bei dem Objekt gesucht wird) findest du in Python aber auch an anderen Stellen, z.B. bei "foo in bar" sucht Python nach einer Methode namens __contains__ von bar. Oder bei for(__getitem__ und __iter__ sind hier heiße Kandidaten).

Das findet sich übrigens auch in dem so „konsequenten“ Java in der Form foreach(da werden Methoden des Iterator-Protokolls aufgerufen) wieder.
numerix hat geschrieben:Ich empfinde hier auch Inkonsistenzen. Beispiel für eine Liste a:
Es heißt a.sort() und nicht sort(a), stattdessen gibt es z.B. sorted(a).
Das sind aber auch zwei verschiedene Funktionen. sort arbeitet in-place, sorted gibt eine neue Liste zurück und akzeptiert außerdem ein beliebiges iterable.
BlackJack

Nochmal zum Sortieren: Das ist in Java auch als Funktion gelöst über `Arrays.sort(…)` bzw. `Collections.sort(…)`.
r74
User
Beiträge: 14
Registriert: Montag 15. Dezember 2008, 21:34

Vielen Dank für die lehrreichen Antworten. Aber irgendwie blicke ich bei dieser "Vermischung" von Punktsyntax und funktionaler Syntax nicht durch.

Warum kann das Löschen eines Elementes aus einer Liste durch oder

Code: Alles auswählen

.remove()
erfolgen?

Ich weiss, dass ich mit del ein Element mit einem bestimmten Index löschen kann, durch remove() das Element mit einem bestimmten Wert.

Aber warum verwendet man einmal die Punktsyntax, das andere mal nicht?
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

Schau dir am besten nochmal an, was del und pop denn genau machen und wo der Unterschied liegt. remove hat damit noch weniger zu tun.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

r74 hat geschrieben:Vielen Dank für die lehrreichen Antworten. Aber irgendwie blicke ich bei dieser "Vermischung" von Punktsyntax und funktionaler Syntax nicht durch.
Da gibt es ja auch nichts zu durchblicken. Im Gegensatz von Java gibt es in Python Funktionen und dementsprechend werden sie auch benutzt. In Java gibt es stattdessen statische Methoden(was aber auch nichts anderes als eine Funktion ist), s. BlackJacks Post.
Aber warum verwendet man einmal die Punktsyntax, das andere mal nicht?
Kurz: Weils halt so ist(irgendwie wiederhole ich mich). del funktioniert genau wie for etc. del sucht nach bestimmten Methoden des Objekts und führt sie aus. del ist übrigens keine Funktion sondern eine Anweisung(statement) mit funktional hat das nichts zu tun. Ums nochmal deutlich zu sagen: Weils halt so ist. Da gibt es kein Geheimnis hinter, die Sprache wurde nunmal so entworfen.

@SchneiderWeisse: Jetzt wirfst du aber auch Sachen durcheinander die nichts miteinander zu tun haben.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Darii hat geschrieben:Das sind aber auch zwei verschiedene Funktionen. sort arbeitet in-place, sorted gibt eine neue Liste zurück und akzeptiert außerdem ein beliebiges iterable.
Das weiß ich wohl, tangiert aber nicht das, worum es eigentlich ging.
(Hätte ich nicht auf die Existenz von sorted() hingewiesen, hätte spätestens im übernächsten Post gestanden, dass es doch sorted() gibt ...)

Deine Kurzfassung "Weil's halt so ist" trifft die Sache IMHO am besten. Es war offenbar eine Design-Entscheidung und jetzt ist es eben so.
lunar

Ich finde, das man den Unterschied zwischen "len()" und ".append()" eigentlich auch gut begründen kann, nämlich mit dem Unterschied zwischen in sich generischen Operationen und typspezifischen Operationen.

Jeder beliebige Container hat eine Länge bzw. eine gewisse Anzahl darin enthaltener Objekte. Dementsprechend ist "len()" eine sehr generische Operation und nicht an einen Typen gebunden. Der Typ muss nur wissen, wie er seine Länge bestimmen kann, und somit "__len__()" implementieren. Aber dieses "Wissen" ist ein Implementierungsdetail, dementsprechend ist "__len__()" auch eine spezielle, "versteckte" Methode. Das Anhängen mit ".append()" dagegen ist keine generische Operation. Anhängen kann man nur an Container, die eine Ordnung und damit auch ein definiertes Ende haben (e.g. Listen). Dementsprechend ist ".append()" eine Listen-Methode.

Ähnliches gilt für "sorted" und "sort". Sortieren kann man nur Container, die eine Ordnung haben. Somit ist die "in-place"-Sortierung eine der Liste vorbehaltene Operationen, und daher als Methode implementiert. Dagegen kann man jeden beliebigen, iterierbaren Container in eine geordnete Liste überführen. "sorted()" ist also ähnlich generisch wie "len()". Der Container muss wiederum nur wissen, wie er über seine Elemente iteriert, und "__iter__()" implementieren. Das aber ist ja schon wieder ein Implementierungsdetail …

Ich persönlich finde die Unterscheidung zwischen generischen Funktionen wie "len()" und speziellen Operationen wie ".sort()" oder ".append()" eigentlich sehr logisch und konsistent. Aber vielleicht bin ich durch Python und C++ auch nur zu sehr an generische Funktionen gewöhnt …
Zuletzt geändert von lunar am Dienstag 23. Februar 2010, 10:57, insgesamt 1-mal geändert.
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

@SchneiderWeisse: Jetzt wirfst du aber auch Sachen durcheinander die nichts miteinander zu tun haben.
Ach, hatte die Frage falsch verstanden... dachte er fragt, warum es zweimal das gleiche tut...
r74
User
Beiträge: 14
Registriert: Montag 15. Dezember 2008, 21:34

@lunar:
Deine Antwort muss ich als Programmierlaie noch etwas verdauen. Klingt aber jedenfalls viel befriedigender als "Weils halt so ist".

@Darii:
"Weils halt so ist" geht immer (meistens) als Antwort. Aber ich glaube nicht, dass die Python-Entwickler ohne wirklichen Grund es einfach so gemacht haben, wie es im Moment ist.
Da gibt es ja auch nichts zu durchblicken.
Ich denke, es gibt was zu durchblicken.
Dackel
User
Beiträge: 11
Registriert: Mittwoch 4. März 2009, 20:44

Python ist ja auch keine reine OO-Sprache. Ohne die Entwicklungsgeschichte zu kennen kann ich mir gut vorstellen, dass len, sorted, etc. in ihrer Form aus der funktionalen Ecke kommen.
Ist aber ebenfalls nur Spekulation.
Antworten