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.
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.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Dackel hat geschrieben:funktionalen Ecke
Das ist was ganz anderes: http://de.wikipedia.org/wiki/Funktional ... iersprache
Dackel
User
Beiträge: 11
Registriert: Mittwoch 4. März 2009, 20:44

Ich glaube, Du missverstehst mich.

Nicht alle, die an der Entwicklung von Python beteiligt waren, waren OO-Fetischisten. Wenn man von einer rein funktionalen Sprache kommt, wird man eher eine Funktionsapplikation à la

Code: Alles auswählen

len x
gewöhnt sein. Insofern können insbesondere zur Behandlung von Listentypen einiges schlicht aus der Gewohnheit von alten ML- oder Haskellprogrammierern gewachsen sein.
Aber da tiefer drüber zu diskutieren ist IMO sinnlos, es sei denn jemand, der direkt an der Entwicklung zu der Zeit beteiligt war, beantwortet es uns.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

r74 hat geschrieben:Aber ich glaube nicht, dass die Python-Entwickler ohne wirklichen Grund es einfach so gemacht haben, wie es im Moment ist.
Ja natürlich nicht, aber das war auch nicht deine Frage. Auf deine Frage ist die Antwort nunmal „Ist so“. Auch wenn es unbefriedigend ist. Aber es gibt einfach keinen zwingenden Grund warum man eine len()-Funktion nehmen musste.
BlackJack

@Darii: Vielleicht gab es doch zwingende Gründe. Zum Beispiel Zeichenketten. Ich glaube die waren nicht immer vollwertige Objekte. Deswegen auch die redundanten Funktionen im `string`-Modul, bevor die meisten Funktionen da drin zu Methoden auf `str` wurden. Die Länge von Zeichenketten zu ermitteln ist sicher wichtig, und wenn die keine Methode dafür haben können, braucht man halt mehr oder weniger zwingend eine Funktion. Man hätte natürlich auch ein Schlüsselwort oder einen Operator verwenden können. ;-)
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Darii hat geschrieben: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).
Genauer gesagt wird bei der jeweiligen Klasse des Objekts gesucht, nicht bei der Instanz selbst.
Darii hat geschrieben:
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.
Ja, das ist typischerweise der Unterschied: Funktionen mutieren das übergebene Objekt nicht sondern geben ein neues zurück, Methoden mutieren das Objekt und geben None zurück. (Das ist keineswegs zwingend, aber oft so.)
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

bords0 hat geschrieben:Genauer gesagt wird bei der jeweiligen Klasse des Objekts gesucht, nicht bei der Instanz selbst.
Bis auf Descriptoren wird immer die normale Suchreihenfolge für die Attribute eingehalten, d.h. erst Instanz dann Klasse.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Blackjacks Erklärung zu `len` ist die richtige. Ein Uniformitätsprinzip ("Special cases aren't special enough to break the rules.") hätte ausgehend von einem objektorientierten Ansatz natürlich erfordert, dass alles dem "Object-Action"-Prinzip folgt und daher wäre etwas wie `foo.count()` konsequenter gewesen. Aber zu dem Zeitpunkt, wo immer mehr von Python objektorientiert wurde, war es offenbar schon zu spät und Rückwärtskompatibilität wurde noch höher bewertet als Uniformität.

Stefan

PS: Das __-Methoden nicht in Exemplaren gesucht werden sondern das man damit erst in der Klasse beginnt war auch mal eine Entscheidung in Python, die AFAIK hauptsächlich mit der Effizienz der Methodensuche zu tun hat.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

sma hat geschrieben:Aber zu dem Zeitpunkt, wo immer mehr von Python objektorientiert wurde, war es offenbar schon zu spät und Rückwärtskompatibilität wurde noch höher bewertet als Uniformität.
Vielleicht ja 2017 in Python 4. ;P Wobei es sich wohl empfehlen würde, bei ".len()" zu bleiben, da ".count()" schon existiert.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Jetzt machst du schon wieder den Fehler, kompatibel bleiben zu wollen :) Wenn schon, denn schon. Ein dict (oder allgemein Collections ohne weitere Eigenschaft) hat streng genommen keine Länge. Smalltalk wählte damals `size`, Objective-C etwas später `count` und ich finde, das ist der beste Kompromiss.

Stefan
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Darii hat geschrieben:
bords0 hat geschrieben:Genauer gesagt wird bei der jeweiligen Klasse des Objekts gesucht, nicht bei der Instanz selbst.
Bis auf Descriptoren wird immer die normale Suchreihenfolge für die Attribute eingehalten, d.h. erst Instanz dann Klasse.
Der Witz ist, dass bei "special syntax" (und len etc.) die Suche gleich bei der Klasse anfängt und nicht bei der Instanz. Die Attribute selbst kann man ganz normal nachschlagen.

Code: Alles auswählen

>>> list.__len__
<slot wrapper '__len__' of 'list' objects>
>>> len(list)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
TypeError: object of type 'type' has no len()
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

bords0 hat geschrieben:Der Witz ist, dass bei "special syntax" (und len etc.) die Suche gleich bei der Klasse anfängt und nicht bei der Instanz.
Jein. Tatsachlich hast du Recht, das gilt aber nur für new-Style-Klassen. Naja, „Special cases aren't special enough to break the rules.“ hatten wir ja gerade...

Code: Alles auswählen

>>> list.__len__
<slot wrapper '__len__' of 'list' objects>
>>> len(list)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
TypeError: object of type 'type' has no len()
Was willst du jetzt damit zeigen? Das kann sowieso gar nicht funktionieren, da list.__len__ keine Klassenmethode ist.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

Code: Alles auswählen

>>> list.__len__
<slot wrapper '__len__' of 'list' objects>
>>> len(list)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
TypeError: object of type 'type' has no len()
Was willst du jetzt damit zeigen? Das kann sowieso gar nicht funktionieren, da list.__len__ keine Klassenmethode ist.[/quote]

Dass bei len nicht bei der Instanz (hier: list) nach dem Attribut __len__ gesucht wird.

Was Klassenmethoden damit zu tun haben, verstehe ich nicht :?:
len braucht doch keine Klassenmethoden (classmethod)?
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

bords0 hat geschrieben:Dass bei len nicht bei der Instanz (hier: list) nach dem Attribut __len__ gesucht wird.

Was Klassenmethoden damit zu tun haben, verstehe ich nicht :?:
len braucht doch keine Klassenmethoden (classmethod)?
Ganz einfach, da __len__ keine Klassenmethode ist, könne list.__len__() gar nicht funktionieren, wenn dort danach gesucht würde. Ich hab mir halt die Fehlermeldung nicht durchgelesen.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

bords0 hat geschrieben:Der Witz ist, dass bei "special syntax" (und len etc.) die Suche gleich bei der Klasse anfängt und nicht bei der Instanz. Die Attribute selbst kann man ganz normal nachschlagen.
Irgendwo muss man Kompromisse eingehen damit die Ausführungsgeschwindigkeit nicht völlig in den Keller geht.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Der Dict-Lookup mehr oder weniger bringt einen bei Python jetzt auch nicht um. ;) Sowas zu optimieren ist dann Aufgabe der VM und nicht der Sprache. Aber so ist das einfach nur inkonsistent.
Antworten