Umstieg von Java zu Python

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.
deamon
User
Beiträge: 63
Registriert: Mittwoch 8. Oktober 2008, 11:14

BlackJack hat geschrieben:@Leonidas: Javaianer greifen nicht auf Bibliotheken zu, die es nur in C gibt. Sie sind viel schlauer: Sie programmieren das lieber alles noch einmal in Java nach. :-)
Ich weiß schon, wie du es gemeint hast, aber es ist wirklich schlau. C ist keine tolle Sprache und wir haben ihr und C++ etwa die Hälfte aller Sicherheitslücken zu verdanken! In Java kann man keine Pufferüberläufe programmieren (es können höchstens welche in der Laufzeitumgebung vorkommen, die nicht in Java geschrieben ist, aber das ist vergleichsweise selten). Der große Vorteil von Java-Bibliotheken ist, dass man wirklich nur eine JVM als Basis braucht. Ich schätze das sehr.
BlackJack hat geschrieben:Was meinst Du mit "regelmässiger Prüfung zur Laufzeit"? Zur Laufzeit wird regelmässig zumindest der "duck type" geprüft. Ist ja nicht so, dass Python untypisiert wäre.

Ich meinte eine explizite Prüfung im Programm, aber vermutlich war ich da gedanklich falsch, weil ich Ducktyping nicht bedacht hatte.
BlackJack hat geschrieben:Habe mal kurz nachgelesen was DI ist. So im kleinen kann man das Java-Beispiel auf Wikipedia ja problemlos in Python umsetzen. Nach dem Beispiel habe ich mich gefragt wozu man dafür wohl ein Rahmenwerk braucht [...]
In der Tat ist es eigentlich ganz einfach. Aber es gibt dann eben doch viele Details, an die die Macher eines Frameworks schon gedacht haben und die man bestenfalls mit der Zeit nach und nach neu erfinden würde. Bei Spring ist z. B. die Reihenfolge der Deklaration der zu verschaltenden Objekte egal. Oder man kann anhand von Typinformationen optional autoamtisch verschalten lassen, man kann definieren, ob ein Objekt ein Singleton sein soll, oder ob es für jede Anfrage neu erzeugt wird ...

Aber vom Prinzip ist es einfach und man könnte das auch ohne Framework hinbekommen.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Das CommonLisp-Object-System (CLOS) kannte bereits Anfang der 90er :before, :after und :around-Methoden. Wahrscheinlich kannten die Vorgänger Flavors und Loops das auch schon, ich habe das nicht recherchiert.

Diese Methoden und mehr wurden in dem (für Lisp-Fans lesenswerten) Buch "The Art of the Metaobject Protocol" von genau dem Gregor Kiczales beschrieben, der Jahre später dann AspectJ gebaut hat und einem komplexen Formalismus mit Pointcuts, Jointpoints, Advices und Aspekten entwickelt hat. Somit ist das nichts grundsätzlich Neues.

Die Idee eines Aspekts ist naheliegend und kann z.B. durch Mixins (AFAIK eine Erfindung von Flavors) realisiert werden, die dank dynamischer mehrfacher Vererbung in Python trivial ist. Eine ähnliche, modernere Idee sind Traits. Die anderen Methoden lassen sich mit decorators auf einfache Weise realisieren. Decorators systematisch an bestimmte Funktionen (pointcuts) zu hängen, müsste man in Python allerdings mittels Metaprogrammierung realisieren und kann das nicht deklarativ erledigen.

Allgemein ist aber IMHO die Aussage richtig, das Python bereits ausdrucksstark genug ist, um keine spezielle Syntax oder Sprachvariante für AOP zu benötigen. In Lisp wäre es dank besserer Metaprogrammierung (Stichwort Makros) noch einfacher.

Dependency-Injection ist eigentlich nur die Idee, einzelne Klassen mit möglichst wenig gegenseitigen Abhängigkeiten zu entwerfen, um sie so getrennt voneinander möglichst gut testbar zu gestalten. Die Aufgabe, das Objektnetz zusammenzustecken, überlässt man jemand anderem. Statt sich hier jedoch eine komplizierte XML-Syntax (so wie es Spring macht) auszudenken, kann man das Zusammenstecken bei Python auch einfach in Python machen.

Eine Aufteilung in Interfaces und Implementierung ist bei python unnötig. Getter und Setter in der Regel auch.

Schaut man sich ein Beispiel von Fowlers an:

Code: Alles auswählen

<beans>
    <bean id="MovieLister" class="spring.MovieLister">
        <property name="finder">
            <ref local="MovieFinder"/>
        </property>
    </bean>
    <bean id="MovieFinder" class="spring.ColonMovieFinder">
        <property name="filename">
            <value>movies1.txt</value>
        </property>
    </bean>
</beans>
entspricht dies

Code: Alles auswählen

movieLister = MovieLister()
movieFinder = MovieFinder()

movieLister.finder = movieFinder
movieFinder.filename = "movies1.txt"
Um näher am Original zu sein, muss man allerdings ein bisschen tricksen. Allgemein muss man Instantiierung und Initialisierung trennen, sondern kann man keine sich gegenseitig referenzierenden Strukturen bauen. Ich glaube, Spring nutzt hier Proxy-Objekte. Könnte man in Python auch.

Oder vielleicht so:

Code: Alles auswählen

class Ref:
    def __init__(self, name): self.name = name

def bind(dct):
    for o in dct.values():
        for k, v in o.__dict__.items():
            if isinstance(v, Ref):
                setattr(o, k, dct[v.name])

movieLister = MovieLister(Ref('movieFinder'))
movieFinder = MovieFinder("movies1.xt")

bind(locals())
Das vergleiche man mit dem Aufwand, den Spring für den selben Effekt treibt :)

Stefan
deamon
User
Beiträge: 63
Registriert: Mittwoch 8. Oktober 2008, 11:14

Für eine einfache Verschaltung bräuchte man in Java auch kein Framework. Das wäre auch dort ähnlich einfach wie in dem Python-Beispiel möglich.

Code: Alles auswählen

MovieLister movieLister = new MovieLister();
MovieFinder movieFinder = new MovieFinder();

movieLister.setFinder(movieFinder);
movieFinder.setFilename("movies1.txt");
Aber das ist es ja nicht, was ein DI-Framework ausmacht. Ein DI-Framework wie Spring nimmt einem die Auflösung der (auch zyklischen) Abhängigkeiten ab und kann teilweise automatisch Objekte konfigurieren.

Meine Frage ziele aber darauf ab, warum DI im Python-Lager scheinbar nicht so gefragt ist. Welche andere Programmierphilosophie wird verfolgt, dass DI keinen so hohen Stellenwert hat. Meine These ist, dass Abhängigkeiten eher in Kauf genommen werden, weil man ja (fast) immer den Quelltext vorliegen hat und dort bei Bedarf direkt ändern kann.

Das ist vielleicht weniger Elegant als die Objekte an einer Stelle außerhalb exlizit zu konfigurieren, aber ich glaube, dass bei Skriptprogrammierung zu Gunsten der Einfachheit vieles nicht so elegant ist, dafür ist es aber einfacher und das ist ja auch ein Wert für sich.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Also ich finde das ehrlich gesagt eleganter als ein gigantisches XML.
Ich habe oft ein application.py Modul o.ä. was dann die einzelnen Komponenten zu einer Applikation zusammen steckt. Finde ich einfacher und mächtiger als gigantische XML Dateien.
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Das würde ich auch sagen, Python ist elegant genug, dass man keine XML-Datei braucht, damit es nicht noch hässlicher wird(und XML ist imo verdammt hässlich). Ruby ist da ja noch viel extremer als Python, da die Sprache viel flexibler ist.
deamon
User
Beiträge: 63
Registriert: Mittwoch 8. Oktober 2008, 11:14

Darii hat geschrieben:Das würde ich auch sagen, Python ist elegant genug, dass man keine XML-Datei braucht, damit es nicht noch hässlicher wird(und XML ist imo verdammt hässlich).
Es geht nicht darum, ob die Konfiguration von Objekten in XML stattfindet oder nicht. Man kann Spring auch mit Java (oder Groovy) konfigurieren. Es geht darum, dass diese Form der externen Konfiguration von Objekten (mit Hilfe eines Frameworks) in Python scheinbar nicht so beliebt ist.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

deamon hat geschrieben:Es geht darum, dass diese Form der externen Konfiguration von Objekten (mit Hilfe eines Frameworks) in Python scheinbar nicht so beliebt ist.
Und das war meine Vermutung/Meinung warum das so ist.
lunar

Darii hat geschrieben:
deamon hat geschrieben:Es geht darum, dass diese Form der externen Konfiguration von Objekten (mit Hilfe eines Frameworks) in Python scheinbar nicht so beliebt ist.
Und das war meine Vermutung/Meinung warum das so ist.
Warum sollte es das sein?

In Java mit seiner statischen Typisierung ist eine Aufteilung in Schnittstelle und Implementierung erzwungen. Auch ist dynamischer Java-Code viel schwerer zu schreiben, weil man mit Reflection arbeiten muss. Python dagegen hat ein dynamisches Objektmodell, dass Objekte nicht über Typ, sondern Verhalten identifiziert. Außerdem ist Metaprogrammierung in Python straigt-forward, während sie in Java einfach furchtbar ist. Da ist also nichts, für das man groß ein Framework bräuchte, weil Python viel einfacher ist als jedes Framework, das man dafür bauen könnte ...
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

lunar hat geschrieben:Warum sollte es das sein?
Ist die Frage an mich gerichtet? Denn was du da schreibst, ist das was ich meine, nur ausführlicher.
lunar

Darii hat geschrieben:
lunar hat geschrieben:Warum sollte es das sein?
Ist die Frage an mich gerichtet? Denn was du da schreibst, ist das was ich meine, nur ausführlicher.[/quote
Nein, an deinen Vorposter deamon. Hab das falsche Posting zitiert.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

deamon hat geschrieben:Ein DI-Framework wie Spring nimmt einem die Auflösung der (auch zyklischen) Abhängigkeiten ab und kann teilweise automatisch Objekte konfigurieren.
Mein Code-Beispiel mit Ref/bind löst zyklische Abhängigkeiten auf. Automatische Konfiguration hatte ich bei uns für Java überhaupt nicht bewährt, weil man nichts mehr verstanden hat und daher finde ich das ist kein hilfreiches Feature.

Dafür bräuchtest du in Python irgendwelche Typannotationen. Könnte man machen, wäre aber eine freiwillge Angabe, z.B. so:

Code: Alles auswählen

class Foo:
    __types__ = {'foo': Foo, 'bar': str, 'baz': [int]}

def bind(dct):
    for o in dct.values():
    if hasattr(o, '__types__'):
        for n, t in o.__types__:
            setattr(o, n, find(lambda o: isinstance(o, t), dct.values()))
   ...

def find(f, lst):
    for o in lst:
        if f(o): return o
deamon hat geschrieben:Meine These ist, dass Abhängigkeiten eher in Kauf genommen werden, weil man ja (fast) immer den Quelltext vorliegen hat und dort bei Bedarf direkt ändern kann.
Man braucht es nicht. Nichts ist aufwendig kompiliert und jede Datei lässt sich gleich einfach ändern. In Java wählt man den XML-Weg ja nur, weil der Java-Code eben nicht einfach anpassbar ist und nicht so ausdrucksstark ist, wie das XML-Fragment. Mit fehlender Eleganz hat das nichts zu tun, eher im Gegenteil.

In Python könnte ich mir auch einfach dies ausdenken:

Code: Alles auswählen

beans = {}

def Bean(name, **kwargs):
    if name in beans:
        bean = beans[name]
    else:
        bean = beans[name] = locals()[name]()
        bean.__bean = name
    for k, v in kwargs.items():
        setattr(bean, k, Ref(v.__bean) if hasattr(v, '__bean') else v)

Bean('MovieLister', finder=Bean('MovieFinder'))
Bean('MovieFinder', filename="movies.txt")

bind(beans)
Kannst du das in Java ebenfalls in < 20 Zeilen implementieren?

Stefan[/code][/code]
kasaliko
User
Beiträge: 1
Registriert: Mittwoch 18. Februar 2009, 21:29

Hallo!

Ich schreibe gerade eine Hausarbeit zu "Python und Dependency Injection". Ich soll einen DI-Container von Java auf Python übertragen. Da beide Themen in diesem Thread behandelt wurden, hoffe ich, dass mir hier jemand ein paar Tipps geben kann.

Ehrlich gesagt, habe ich keine Ahnung von Python und das umdenken von Java fällt mir schwer. Allerdings habe ich mich ziemlich schnell gefragt, ob ein DI-Container in Python überhaupt sinnvoll ist. Und ob es überhaupt so einfach von Java auf Python zu übertragen ist.

Mein Plan ist jetzt erstmal, so gut es geht (bzw. ich es kann) den DI-Container nachzubauen. Jedoch will ich in der Ausarbeitung näher auf die Besonderheiten von Python eingehen und evtl. auch etwas dazu schreiben, warum Dependeny Injection in Python keine so große Rolle spielt.

Gibt es vllt irgendwelche Bücher oder Artikel, die sich mit diesem Thema auseinandersetzen? Über Google usw. habe ich nichts gescheites gefunden. Allerdings kenne ich mich auch noch nicht so gut in der Pythonwelt aus und weiß nicht wo ich gezielt suchen könnte.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

kasaliko, du hast meine Meinung und ein paar Ad-hoc-Beispiele für DI in diesem Thread gesehen. Hatte ich nicht auch auf Jim Weinrichs Artikel verwiesen? Und das Video von der RubyConf 2008, wo sich Jamis Buck wortreich dafür entschuldigt, 2x ein DI-Rahmenwerk für Ruby schreiben zu wollen? Die sind zwar für Ruby, gelten aber genauso für Python.

Wie bei vielen anderen Entwurfsmustern gilt: Es kommt auf die Programmiersprache an. Für reine DI gibt es in Scriptsprachen wenig Gründe. Will man zusätzlich noch einen Container-Lifecycle wie z.B. bei PicoContainer implementieren, sieht es ein bisschen anders aus.

Mit "keine Ahnung von Python" hast du aber schlechte Voraussetzungen für die Hausarbeit. Und ohne Umdenken wirst du bestenfalls Java mit Python-Syntax schreiben. Aber das kann ja noch werden :)

Weitere Artikel kenne ich keine, aber Google ist dein Freund...

Stefan
Antworten