Seite 2 von 3

Verfasst: Freitag 29. Mai 2009, 18:44
von Dill
so genau muß man es ja jetzt eigentlich nicht nehmen, du hast recht am besten erstmal loslegen un schauen was passiert, aber ... :roll:

der handler on_search_button ist nicht teil der logik.
sondern teil des controllers. die logik ist wiederum teil des models.

also vereinfacht in diesem beispiel:

die darstellung der bilder, generierung von events: VIEW

entgegennahme der events (on_search_button) und reaktion (anforderung der bilder) auf diese: CONTROLLER

generierung (logik) und bereithaltung der daten: MODEL


das problem war ja auch nicht, dass er dem controller zuviel aufgaben gegeben hat, sonderm dem model (mit dem zeichnen)

Verfasst: Freitag 29. Mai 2009, 22:14
von str1442
@snafu: Da Python kein statisches Typing kennt, ist das immer so. Kein Objekt kennt wirklich ein anderes - sie interagieren nur zu irgendeinem Zeitpunkt mit anderen Objekten. Selbst wenn du vorher die Klasse als ein Klassenattribut anlegst, weiß die andere Klasse nichts davon, außer das da eben irgendeine Art von Wert drin ist. Der auch None sein kann. Und wenn du von einer Klasse ableitest, muss das nichmal eine Klasse sein, sondern sich nur in etwa wie eine Verhalten. Außerdem übergibst du dann sowieso ein auch nur dem Metaklassenkonstruktor eine Klasse als Argument (in einem Tupel). Du kannst auch sowas machen:

Code: Alles auswählen

>>> class A(type("", (object,), {})):
...  print "x"
... 
x
Sinnlos, aber funktioniert.

Verfasst: Samstag 30. Mai 2009, 09:00
von Dill

Code: Alles auswählen

In [7]: type("", (object,), {})
Out[7]: <class '__main__.'>
bitte wie? was passiert da?

Verfasst: Samstag 30. Mai 2009, 09:09
von Trundle
Dill hat geschrieben:

Code: Alles auswählen

In [7]: type("", (object,), {})
Out[7]: <class '__main__.'>
bitte wie? was passiert da?
Im Prinzip nichts anderes als

Code: Alles auswählen

class Spam(object):
    pass
Nur eben ohne Namen.

Verfasst: Samstag 30. Mai 2009, 09:49
von snafu
str1442 hat geschrieben:Kein Objekt kennt wirklich ein anderes - sie interagieren nur zu irgendeinem Zeitpunkt mit anderen Objekten. Selbst wenn du vorher die Klasse als ein Klassenattribut anlegst, weiß die andere Klasse nichts davon, außer das da eben irgendeine Art von Wert drin ist.
Das ist ja in etwa das, was ich meinte.

Und die von mir angesprochene Vererbung kommt dem Ausdruck "eine Klasse weiß von der anderen" IMHO zumindest etwas näher als wenn man das über Attribute macht. Und @Dill: Damit war ganz sicher nicht gemeint, dass das eine toller sein soll als das andere. ;)

Verfasst: Samstag 30. Mai 2009, 12:41
von mzh
jemand hat ja noch nach einem Pythonbuch zu Entwurfsmustern gefragt.

Ich habe vor kurzem hier mal so was wie ein Openbook dazu gefunden (dritter Link oben).

http://www.mindviewinc.com/Index.php


Das Projekt ist noch nicht fertig, aber es steht schon einiges drin.

Verfasst: Samstag 30. Mai 2009, 16:17
von BlackJack
Vielleicht sollte man bei dem Namen Bruce Eckel ja ehrfürchtig in den Staub fallen, aber ich habe da mal kurz wahllos in Kapitel geklickt und fand so einiges ziemlich grausam. Wenn die Leute nach dem Buch "guten" Python-Stil lernen, dann ist alles in camelCase geschrieben, weil sich "das mehr nach OOP anfühlt", WTF!?, und es wird konsequent alles in Klassen gestopft. Nee danke, dann kann ich auch gleich Java nehmen.

Verfasst: Samstag 30. Mai 2009, 17:46
von str1442
@Dill: [wiki]Metaklassen[/wiki]

@snafu: Naja, das ist aber keine konsequente Sichtweise, denn wie du siehst, ist eine Vererbung auch nur eine Übergabe der einzelnen Klassen im zweiten Parameter des üblichen "Metaklassen-Konstruktionsprotokolls", um es mal so zu nennen. Der neue type() speichert diese in seinem __mro__ Attribut und macht noch ein wenig was damit und das wars dann.

Verfasst: Sonntag 31. Mai 2009, 09:21
von Dill
str1442 hat geschrieben:@Dill: [wiki]Metaklassen[/wiki]
ok, dann muss ich das nicht verstehen.
aber interessant. python scheint hier sogar mächtiger (objektorientierter) zu sein als smalltalk, da ist afair jede klasse ein singleton (ihrer metaklasse). hier gibt es diese einschränkung ja nicht. toll! aber mal im erst, gibt es irgendeine anwendung dafür? (die sich lohnt, bedenkt man, dass der code unverständlich wird). das ist doch eher ein implementierungsdetail...

Verfasst: Sonntag 31. Mai 2009, 09:46
von sma
Dill hat geschrieben:aber interessant. python scheint hier sogar mächtiger (objektorientierter) zu sein als smalltalk, da ist afair jede klasse ein singleton (ihrer metaklasse).
Als alter Smalltalker bezweifle ich das. Nichts ist mächtiger als Smalltalk ;) Aber ernsthaft: In Smalltalk ist alles ein Objekt. Und jedes Objekt ist ein Exemplar einer Klasse. Und da nach Regel 1 Klassen auch Objekte sind, sind sie ebenfalls Exemplare von etwas, das man dann Metaklassen nennt (die auch wieder Objekte sind und Exemplare von sich selbst). Eine Metaklasse kann aber genau wie bei Python mehr als ein Exemplar haben. Die Metaklasse "String class" könnte mehr als eine Klasse "String" gebähren, doch mehr als Verwirrung erreicht man damit selten ;)

Bei Smalltalk könnten sich im Gegensatz zu Python übrigens Klassen ihre methodDictionaries teilen, etwas das Ruby braucht, um Module-Includes zu implementieren. Das geht in Python AFAIK nicht. Daraus schließe ich somit, dass Smalltalk mächtiger ist. QED. Andere Manipulationen erlauben es, auf Sprachebene ohne die VM zu ändern, Traits oder Mehrfachvererbung einzubauen. Eine ganz frühe Version von Smalltalk hatte mal Mehrfachvererbung, doch mal entschied sich, dass die Vorteile den Preis des schwereren Verständnis nicht wert sei. Traits hingegen haben sich als sinnvoll herausgestellt und sind inzwischen ja auch in andere Sprachen (Scala, Fortress) gewandert.

Und mal ehrlich, wer von euch kann den (übrigens aus Dylan stammenden, wo man den generischen Ansatz aus dem CommonLisp Object System vereinfacht hat) C3-Algorithmus für die Serialisierung von Klassen erklären?

Stefan

Verfasst: Sonntag 31. Mai 2009, 10:17
von Dill
sma hat geschrieben:Eine Metaklasse kann aber genau wie bei Python mehr als ein Exemplar haben.
sicher? ich hab das anders gelernt... habe da aber auch nur verstaubtes halbwissen.

sma hat geschrieben: Bei Smalltalk könnten sich im Gegensatz zu Python übrigens Klassen ihre methodDictionaries teilen, etwas das Ruby braucht, um Module-Includes zu implementieren. Das geht in Python AFAIK nicht.
warum solte man denn sowas jetzt wieder brauchen?
(ausser evtl bei der implementierung der sprache)
sorry aber das lasse ich erst als "macht" gelten wenn du mir ein anwendungsbeispiel gibst :)
sma hat geschrieben: Daraus schließe ich somit, dass Smalltalk mächtiger ist. QED. Andere Manipulationen erlauben es, auf Sprachebene ohne die VM zu ändern, Traits oder Mehrfachvererbung einzubauen.
(trait=mixin?)
in py hab ich ja mehrfachvererbung. und kann damit auch einfach ein methodenbündel zu beliebigen klassen mixin-en. dass das hier weniger formal abläuft ist py nicht vorzuwerfen...

Verfasst: Sonntag 31. Mai 2009, 10:53
von sma
Dill hat geschrieben:
sma hat geschrieben:Eine Metaklasse kann aber genau wie bei Python mehr als ein Exemplar haben.
sicher? ich hab das anders gelernt... habe da aber auch nur verstaubtes halbwissen.
Ganz sicher. Ich habe schon mal eine Smalltalk-VM geschrieben.

Module benutzt man bei Ruby auch als Mixins. Und Mixins sind praktisch. So kann man sich in seine Klasse etwa das Modul "Enumerable" hineinmischen und bekommt dadurch 30 oder so praktische Collection-Methoden, wenn man selbst "each" implementiert. Damit ist dieses Modul eigentlich der Theorie nach ein Trait, ein parametrisierbares Set von Methoden. Nur das Ruby das informell per Modul-Kommentar regelt und das System dies nicht überprüft.

Ein import in Python funktioniert anders. Er kopiert Referenzen. Ändere ich zur Laufzeit ein Python-Modul, welches bereits importiert wurde, dann ändert sich an der Importstelle nichts mehr. Bei Ruby hingegen teilen sich alle Klassen, die ein Modul importiert haben, dieses und Änderungen an dem Ruby-Modul wirken sich sofort aus.

Bei Python gibt es auch gar kein Konzept, Methoden nachträglich in Klassen einzufügen, um so das Verhalten der Exemplare zu ändern. Man könnte an __bases__ fummeln, aber das hat einen sehr negativen Beigeschmack.

Mixin-Module braucht man, um Wiederverwendung zu implementieren. Vererbung gibt, das haben viele Jahre Erfahrung mit Smalltalk gezeigt, die leider in vielen Sprachen wie Java noch nicht angekommen sind, eine zu starke Bindung uns sollte möglichst immer vermieden werden.

Da die meisten Sprachen Vererbung und Subtypbildung gleichsetzen, brauchen sie Vererbung zum Aufbau einer Typhierarchie und erkennen nicht, dass dies eigentlich zwei unterschiedliche Konzepte sind. Die "Duck Typing"-Bewegung ist dabei, dass zu erkennen, spricht es aber IMHO nicht deutlich genug aus. Und ja, auch Javas Schnittstellen-Klassen (aka interfaces) sind ein Schritt in diese Richtung, allerdings denkt man erst jetzt darüber nach, dass es ja total toll wäre, wenn man auch strukturgleichen Klassen nachträglich noch Interfaces zuweisen könnte (interface injection als Teil des Davinci-VM-Projekts) - nach 10+ Jahren.

Und ja, man kann grob Traits=Mixins sagen und man kann mit Mehrfachvererbung wiederum beides implementieren. Manchmal ist aber weniger mehr und daher glaube ich, dass traits das überlegere Konzept sind.

Stefan

Verfasst: Sonntag 31. Mai 2009, 10:55
von Leonidas
Dill hat geschrieben:(trait=mixin?)
Je nachdem wie du schaust:

Aus Java-Sicht ist ein Trait wie ein partiell implementertes Interface, aus Python-Sicht ist ein Trait wie ein Mixin, dass bestimmte nicht-implementierte Methoden mit reinzieht (die dann implementiert werden müssen).

Verfasst: Sonntag 31. Mai 2009, 11:05
von Dill
ok bin überzeugt :)

Leonidas hat geschrieben:... aus Python-Sicht ist ein Trait wie ein Mixin, dass bestimmte nicht-implementierte Methoden mit reinzieht (die dann implementiert werden müssen).
was macht das in python für einen sinn nicht implementierte methoden in eine klasse zu ziehen? das ist dann nur ein vertrag, dass diese klasse diese methoden zu implementieren hat oder wie?

Verfasst: Sonntag 31. Mai 2009, 11:08
von Leonidas
Ja, das ist nur ein Vertrag; den Python einfach nicht prüft.

Verfasst: Sonntag 31. Mai 2009, 16:12
von str1442
Bei Smalltalk könnten sich im Gegensatz zu Python übrigens Klassen ihre methodDictionaries teilen, etwas das Ruby braucht, um Module-Includes zu implementieren. Das geht in Python AFAIK nicht.
Man kann __dict__ auf Klassen selbst manipulieren. Will man die Methoden einer Klasse auch schlicht auf eine andere kopieren, kann man sie als Funktionen definieren und dann explizit zuweisen, man kann aber auch alle Funktion über das "im_func" Attribut von Methoden extrahieren und types.MethodType benutzen um sich eine Methode für die eigene Klasse zu bauen.

Code: Alles auswählen

In [1]: from types import MethodType

In [3]: class A(object):
   ...:     def foo(self):
   ...:         print "Hallo!", self
   ...:         
   ...:         

In [4]: class B(object):
   ...:     foo = A.foo.im_func
   ...:     
   ...:     

In [5]: B.bar = A.foo.im_func

In [6]: class C(object):
   ...:     pass
   ...: 

In [7]: c = C()

In [8]: c.foo = MethodType(A.foo.im_func, c, C)

In [9]: A.foo()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/home/str1442/<ipython console> in <module>()

TypeError: unbound method foo() must be called with A instance as first argument (got nothing instead)

In [10]: A().foo()
Hallo! <__main__.A object at 0x9b190cc>

In [11]: B().foo()
Hallo! <__main__.B object at 0x9b190cc>

In [12]: B().bar()
Hallo! <__main__.B object at 0x9b190cc>

In [13]: c.foo()
Hallo! <__main__.C object at 0x9b1922c>
Will man irgendwelche Magie veranstalten, kann man __dict__, isinstance auf MethodType und andere Typen aus dem types Module oder ähnliches benutzen. Man könnte aus __dict__ sogar ein property machen und so die vollkommene Macht darüber bekommen, mag aber sein das man da ein paar Dinge bei beachten muss.
Ein import in Python funktioniert anders. Er kopiert Referenzen. Ändere ich zur Laufzeit ein Python-Modul, welches bereits importiert wurde, dann ändert sich an der Importstelle nichts mehr. Bei Ruby hingegen teilen sich alle Klassen, die ein Modul importiert haben, dieses und Änderungen an dem Ruby-Modul wirken sich sofort aus.
Natürlich ändert sich der Inhalt eines Python Modules überall, wo es benutzt wird. Ein Modul wird in sys.modules (ist ein dict) gespeichert und an sich ist ein Modul nur eine Instanz von types.ModuleType. Nur wenn ein richtiges Modul (also eine .py Datei) geändert wird, ändert sie sich nicht sofort, dann muss man erst reload() benutzen oder das Modul selbsständig aus sys.modules löschen und es neu importieren. Aber Python soll schließlich auch nicht die Dateien auf dem Rechner andauernd überwachen.
Bei Python gibt es auch gar kein Konzept, Methoden nachträglich in Klassen einzufügen, um so das Verhalten der Exemplare zu ändern.
Doch, siehe oben, Klassen händeln das automatisch, und zu speziellen Instanzen kann man sich auch Methoden generieren. Zusätzlich steht einem die ganze Magie von Metaklassen, Klassendekoratoren und "Metafunktionen" (Funktionen, die eine Klasse zurückgeben und "name, bases, dict" als Parameter annehmen, und somit als __metaclass__ spezifiert werden können - im Grunde das gleiche wie Klassendekoratoren, aber übernehmen zusätzlich die Konstruktion) zur Verfügung. An __bases__ rumzubasteln geht auch, ja - man kann sogar die Klasse eines Exemplars ändern:

Code: Alles auswählen

In [19]: class A(object):
   ....:     def foo(self):
   ....:         print self
   ....:         
   ....:         

In [20]: class B(object):
   ....:     def bar(self):
   ....:         print self
   ....:         
   ....:         

In [21]: a = A()

In [22]: print a.__class__, a.foo()
<class '__main__.A'> <__main__.A object at 0x9b63eec>
None

In [23]: a.__class__ = B

In [24]: print a.__class__, a.bar()
<class '__main__.B'> <__main__.B object at 0x9b63eec>
None

Verfasst: Sonntag 31. Mai 2009, 23:53
von sma
str1442 hat geschrieben:Man kann __dict__ auf Klassen selbst manipulieren.
Also mein Python 2.6.2 sagt da: AttributeError: attribute '__dict__' of 'type' objects is not writable

Ich bleibe daher dabei: Zwei Klassen können sich kein method dictionary teilen. Kopien will man ja gerade nicht, denn ansonsten hat man nicht die richtige Semantik.

Noch mal zu dem Unterschied zwischen Python und Ruby. Ein `include Bar` innerhalb einer Klasse Foo fügt konzeptionell alle Methoden aus Bar zu den existierenden Methoden von Foo hinzu. In Python würde man hier ein `from bar import *` innerhalb des Moduls `foo` machen. Auch dieses fügt alles aus bar konzeptionell zu foo hinzu. Bei Python wird hier kopiert. Ändert man später noch mal bar, ändert sich foo nicht. Bei Ruby eben nicht. Hier wird nämlich das dictionaries mit den Methoden von Bar in einer neuen Schattenklasse in die Vererbungshierarchie von Foo eingeklinkt. Ändert man Bar, ändert sich auch die Menge der Methoden, die Foo-Exemplaren aufrufen können.

Stefan

Verfasst: Montag 1. Juni 2009, 08:51
von Darii
sma hat geschrieben:
str1442 hat geschrieben:Man kann __dict__ auf Klassen selbst manipulieren.
Also mein Python 2.6.2 sagt da: AttributeError: attribute '__dict__' of 'type' objects is not writable
Das was du willst, ginge aber mit Metaklassen(__metaclass__).

Verfasst: Montag 1. Juni 2009, 16:42
von str1442
Ein `include Bar` innerhalb einer Klasse Foo fügt konzeptionell alle Methoden aus Bar zu den existierenden Methoden von Foo hinzu. In Python würde man hier ein `from bar import *` innerhalb des Moduls `foo` machen.
Wenn man den Sternchen Import benutzt, wird nichts kopiert - es werden nur neue Referenzen auf Objekte gebildet. "from foobar import spam" ist das gleiche wie "import foobar; spam = foobar.spam; del foobar". Ändert man die Spam Referenz, zeigt sie auf ein anderes Objekt. Ändert man ihren Inhalt, ändert er sich überall. Das ist das normale Verhalten, welches Python überall an den Tag legt. Aber Module samt * Import sind nicht dazu gedacht, "Modulvererbung" irgendwie hinzubekommen. Will man alle Methoden einer anderen Klasse zu einer Klasse hinzufügen, kann man entweder diverse Magie benutzen oder einfach vererben.
Ich bleibe daher dabei: Zwei Klassen können sich kein method dictionary teilen. Kopien will man ja gerade nicht, denn ansonsten hat man nicht die richtige Semantik.
Also um sicher zu gehen: Du willst nur, das zwei Klassen die gleichen Methoden bekommen, dh sie beide die gleiche Funktionen bekommen und daraus eigenständig Methoden bauen? Die obigen Methoden von mir tun genau das. Und da wird auch nichts kopiert; Das im_func Attribut zeigt einfach nur auf eine Funktion und wenn ich es einer anderen Klasse gebe, nutzt die die gleiche Funktion (wrappt aber ein anderes MethodType Objekt darum). Und was spricht gegen soetwas?

Code: Alles auswählen

In [21]: def include(cls):
   ....:     def metafunc(name, bases, d):
   ....:         for attr in dir(cls):
   ....:             if isinstance(getattr(cls, attr), types.MethodType):
   ....:                 d[attr] = getattr(cls, attr).im_func
   ....:         return type(name, bases, d)
   ....:     return metafunc
   ....: 

In [22]: class A(object):
   ....:     def first(self):
   ....:         print 42
   ....:     def second(self):
   ....:         print "xyz"
   ....:         
   ....:         

In [24]: import types

In [25]: class B(object):
    __metaclass__ = include(A)
    def another(self):
        print self
   ....:         
   ....:         

In [29]: b = B()

In [30]: dir(b)
Out[30]: 
['__class__',
 '__delattr__',
 '__dict__',
 '__doc__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__metaclass__',
 '__module__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__str__',
 '__weakref__',
 'another',
 'first',
 'second']

In [31]: b.first()
42

In [32]: b.second()
xyz

In [33]: b.another()
<__main__.B object at 0x876324c>
PS: Mit __dict__ auf Klassen meinte ich eigentlich, zb ein property aus dem __dict__ Attribut im Klassenkörper bei der Klassendefinition zu machen. Bei type gibt es aber sicher auch einen Weg, __dict__ zu beeinflussen.

Verfasst: Dienstag 2. Juni 2009, 11:44
von sma
Mein Punkt war und ist, dass Smalltalk ausdrucksstärker ist als Python, was angezweifelt wurde. Daher musste ich einen (beliebigen) Punkt nennen, der bei Smalltalk (oder Ruby) möglich ist, nicht aber bei Python. Bei Smalltalk können sich zwei Klassen ein Dictionary für Methoden teilen, bei Python habe ich nach wie vor keinen äquivalenten Code gesehen und glaube, es geht nicht, da das dict einer Klasse irgendwie speziell ist (dictproxy) den man nicht selbst setzen kann.

Die include()-Funktion von str1442 kopiert und ist damit kein Beispiel für das gemeinsame Benutzen eines dict.

Hier ist, was gehen muss:

Code: Alles auswählen

class A(object):
    def a(self): return 1
class B(object): pass
class C(object): pass

include(module=A, into=B)
include(module=A, into=C)

print B().a() # 1
print C().a() # 1
A.b = lambda self: 2
print B().b() # 2
del A.a
print C().a() # error
Stefan