PythonOnWheels ( PoW )

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

Hallo Leute,

ich möchte hier gerne die Chance nutzen und mein Projekt kurz vorstellen.

Der Projektname ist : PythonOnWheels (kurz PoW)
Motto: We are only on wheels but it feels like having wings ;)

Es ist ein generatives WebApplication Framework für Python.

HALT: Bitte nicht sofort schreien: " Was die Welt nicht noch mehr braucht sind
amerikanische Anwälte und WebFrameworks für Python."

Ich gebe euch ja irgendwie recht aber bitte schauts euch mal an, da ich
es hier im wesentlichen vorstelle um feedback zu kriegen (positive oder negative Kritik ist willkommen)
Ich bin aber sogar der Meinung das es für PythonOnWheels eine Daseinsberechtigung gibt.
(Neben dem Spass den ich am Entwickeln hatte und habe ;) )

Ich hatte vor Jahren mal einen Screencast über Ruby on Rails gesehen und war davon wirklich begeister.
Dann habe ich sowas natürlich im Python Umfeld gesucht und habe entweder Micro- oder Mega-Frameworks gefunden.
PythonOnWheels positioniert sich hier genau in der Mitte. Die Idee ist den Fokus auf die Applikation zu legen und weniger auf das Framework.

Hier die Features: (English, habe ich von meiner github seite kopiert - DRY und Faulheit )
* Model View Controller
* Uses the well proven Ruby On Rails principles
** convention over configuration
** generate_model, generate_controller, generate_migration
* Scaffolding dabei
** generate_scaffold
* JQuery integration
* AJAX
* Responsive Layout based on Twitter Bootstrap
* Lightweight - simple and easy to use
* Nose Tests
* automatically generate for you. runtest script to run them
* Database Migrations
* web app generation with batteries included:
** Session support
** basic authentication (Beta 2)
* Runs with Apache & mod_wsgi
* includes a ready to run simple_server
* full environment on your laptop, mac or pc

Aktuell kommen noch in die Beta 1
* Observer pattern
* Validation


Hier der Screencast: -- bitte mal ansehen und eure Meinung kundtun --
Weblog mit PythonOnWheels in 10 Minutes
(am besten Vollbild, da man sonst die Commandline schlecht sieht. Ich bin nicht so der Screencast champion )

(dauert insgesamt 14 Minuten, ich erklaere aber auch noch ein bisschen drumherum. Habe nicht versucht so schnell
wie moeglich zu sein.)

Homepage: www.pythononwheels.org

Github:
(wichtig Beta1 branch nehmen - ich strebe die Beta 1 am 31.8.2012 an)

Ich habe auch nicht die Welt neu nachprogrammiert sondern die super basis da draussen genommen:
Deshalb benoetigt ihr (bzw. PoW benoetigt)
---------------------------------------------
python > 2.6 (ich denke < 3.x da ich es damit nocht getestet habe, 2.5 geht leider nicht)
webob (easy_install oder pip)
Mako (easy_install oder pip)
Beaker (easy_install oder pip)
SQLAlchemy (easy_install oder pip)
Nose (easy_install oder pip)


Also vielen Dank schonmal falls ihr das anseht und / oder kommentiert.

Viele Gruesse,
Klaas
Zuletzt geändert von khz am Samstag 1. September 2012, 22:53, insgesamt 2-mal geändert.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Es verdient in jedem Fall Respekt, so ein Projekt auf die Beine zu stellen. Einen Screencast als Einführung zu haben, ist auch immer eine gute Wahl. Ich fand ich gut verständlich (sprachlich & inhaltlich). Allerdings würde ich empfehlen, diese "follow the mouse"-Funktion abzuschalten. Ich wurde da fast seekrank :) Nimm dir lieber einen 1280x800-Ausschnitt deines Bildschirms, bringe vorher alle deine Fenster auf diese Größe, mache die Schrift im Editor und Browser groß genug und komme mit diesem Platz dann aus.

Die Frage, die du beantworten können solltest, ist was deinen Ansatz besonders macht. Das ist jetzt nicht ersichtlich.

Warum brauche ich einen Rails-Clone auf dem Stand von vor 5 Jahren? Oder wie alt ist Rails schon? Juli 2004 - das wären sogar 8 Jahre. Uff.

Du könntest sagen, es ist jetzt Python statt Ruby, aber zumindest ich finde die konkrete Programmiersprache (solange es nicht PHP ist) relativ egal und somit nur ein schwaches Argument. Was kann PoW, das sonst aufwendiger ist oder schlechter funktioniert?

Auch den Vergleich mit Django musst du dir natürlich gefallen lassen. Dieses ist zwar ebenfalls angestaubt (oder ausgereift, je nach Sichtweise), bietet aber im Prinzip das selbe wie PoW. Ich befürchte, dein Blog-Beispiel lässt sich mit Django sogar noch einfacher umsetzen und man bekommt noch ein Endbenutzer-taugliches Admin-UI dazu und könnte auch gleich noch eine Kommentar-Funktion integrieren.

Es ist meine Überzeugung, dass Web-Anwendungen heutzutage anders geschrieben werden sollten als noch vor 8 Jahren. Meteor ist ein gutes Beispiel für einen neuen Ansatz. So etwas für Python wäre cool!

Nutzt man MongoDB als Backing-Store, spart man sich einiges an Komplexität. Der Server stellt dann im wesentlichen die Daten per REST-API zur Verfügung und ein Client-Rahmenwerk kümmert sich um die Darstellung. Das verschiebt die Komplexität vom Server auf den Client. Dafür sollte ersterer auch Web-Sockets unterstützen. Client-seitig kommt man zwangsläufig mit JavaScript in Kontakt. Will man serverseitig eine andere Sprache nutzen, muss es dafür einen guten Grund geben. Oder man muss eine Lösung haben, die Sprache vom Server auch irgendwie auf den Client zu bringen.

Diese Art von Web-Anwendungen zu schreiben ist jedenfalls harte Arbeit und auch wenn sich Backbone als Standard durchzusetzen scheint, ist das nicht unbedingt die beste Wahl und auch noch nicht der klare Sieger. Hier Unterstützung zu haben wäre etwas, das kein anderes Python-Rahmenwerk bietet.

Ab hier wird es OT und ich hatte einfach Spaß daran, mal etwas zu schreiben... Sorry...

So könnte das Blog-Beispiel (ohne HTML) mit einem hypothetischen Web-Framework "wfw" für Node.js aussehen:

Code: Alles auswählen

// app.js
var wfw = require("wfw"), Post = require("./Post");
var app = wfw.app()
  .get("/blog", wfw.find(Post.limit(5).desc('created')), wfw.render("blog"))
  .use(wfw.resource("/blog", Post))
  .listen(3000);
In der ersten Zeile lade ich mein Rahmenwerk und mein Model. Als nächstes erzeuge ich mit "app()" das Web-App-Objekt (implementiert mit "express"). Die Funktion "resource()" bindet die üblichen 7 URLs und weiß, wie sie an die Daten aus dem Modell kommt. Ich überschreibe als nächstes die URL "/blog", welche die ersten fünf Blog-Einträge (den neusten zuerst) mit dem Template "blog" darstellen soll. Dann starte ich die App auf Port 3000.

Habe ich jetzt noch ein Kommandozeilen-Programm für das Scaffolding der Templates und der Modell-Beschreibung (die ich auf mongoose abstütze), bin ich dort, wo auch Rails 1.x mal war.

Code: Alles auswählen

wfw scaffold Post title:String content:String created:Date
Dies würde dann mein Modell erzeugen:

Code: Alles auswählen

// Post.js
var wfw = require("wfw");
var Post = wfw.model("Post", { title: String,  content: String,  created: Date });
Ohne das jetzt ausprobiert zu haben, denke ich, dass "wfw" auch relativ einfach zu implementieren wäre:

Code: Alles auswählen

// wfw.js
var express = require("express"), mongoose = require("mongoose");

exports.model = function model(name, options){
  return mongoose.model(name, new mongoose.Schema(options));
}

exports.app = function app(){
    return express().use(express.bodyParser()).use(express.favicon());
}

exports.resource = function resource(path, model){
  var app = express(), name = path.substring(1) + "_";
  app.get(path, find(model), render(name + "list"));
  app.get(path + "/new", new(model), render(name + "new"));
  app.post(path, create(model), redirect(path));
  app.get(path + "/:id", findOne(model), render(name + "show"));
  app.get(path + "/:id/edit", findOne(model), render(name + "edit"));
  app.put(path + "/:id", update(model), function(...){ ... });
  app.delete(path + "/:id", findOne(model), function(...){ ... });
  return app;
}

exports.find = function find(model){
  return function(req, res, next){
    model.find({}, function(err, objects){
      if (err){ res.send(500); return; }
      req.objects = objects;
      next();
    })
  }
}

exports.findOne = function(model){
  return function(req, res, next){
    model.findOne({_id: req.params.id}, function(err, object){
      if (err){ res.send(500); return; }
      req.object = object;
      next();
    });
  }
}

exports.render = function(name){
  return function(req, res){
    res.render(name, {objects: req.objects, object: req.object});
  }
}

...
Ich nutze dabei jede Menge "middleware"-Funktionen für Express und die Konvention, dass diese mir die Objekte in eine Eigenschaft "objects" bzw. "object" des Request-Objekts einträgt, wo ich das dann in "render" wieder auslese und so dem Template übergebe. Das ist zu simpel, wenn ich Formulare dynamisch generieren wollen würde, aber das kann Rails auch nicht. Die Middleware ist praktisch, weil jeder Zugriff auf die DB asynchron ist und ich ansonsten alle Funktion schachteln müsste. Das ist aber egal hier, entscheidend ist, wie es in "app.js" aussieht.

Stefan
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

Erstmal Danke fuer das Lob und die Kritik.
und ja, irgendwie hast du recht. PoW ist keine Revolution aber vielleicht eine Evolution.
Man kann sehr schnell eine vollwertige MVC+DB App erzeugen.

Meint:
* weniger code schreiben
* kein ändern in irgendwelchen config Files
* egal welche DB (solange SQLAlchemy die unterstützt)

Wo unterscheidet sich PoW:
* generativ ( wenig Schritte zur vollwertigen MVC app -dann "customizen" und eine eigene entwickeln)
* basiert auf python Standards (SQLAlchemy, Webob, Mako ...)
* Scaffolding ( schnell zur eigene App - im Gegensatzu zu deinem Besipiel oder anderen Frageworks )
* im Hintergrund sein. Fokus ist die App nicht das Framework.

Prinzip: eben nicht erst coden sondern PoW machen lassen und dann nur leicht abändern

Bei PoW sind noch mehr Sachen on-board als gezeigt:
+ session management
+ authentication
+ helpers
+ link_to etc
+ pagination
...
Aber hier liegt sicher kein Unterschied, da bieten andere deutlich mehr. Die Idee ist sogar hier
nicht alles reinzupacken, damit es ueberschaubar bleibt.

Du hast recht wenn du sagst, das diese Art WebApps zu entwickeln rel. alt ist.
Aber der ist auch gut und bewaehrt und, wie ich finde, schoen flüssig.

.js auf dem Server und .js auf dem client ist ein neuer Trend aber irgendwie ohne python ...
Meteor muss ich mir nochmal ansehen, hab da bisher nur den intro screencast (kurz) angesehen.

In PoW sind exports.ressource Controller Methoden und exports.find, exports.find_one Model Methoden.
PoW generiert die fuer dich ohne das du eine Zeile code schreibst
.


Dankeschoen und wie gesagt ich freue mich über jedes feedback zu Pow.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

Das mit dem Mouse follow im Screencast ist uebrigens ein guter Tip. Ich nehmen den
nochmal ohne auf.

Allerdings ist das ja schlimmer als im Fernsehstudio. Man braucht ja zig Anläufe
bis man so einen kurzen Screencast mal richtig aufgenommen hat ...
verhaspeln , Ablauf ... puh.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

khz hat geschrieben:Meint:
* weniger code schreiben
* kein ändern in irgendwelchen config Files
* egal welche DB (solange SQLAlchemy die unterstützt)

Wo unterscheidet sich PoW:
* generativ ( wenig Schritte zur vollwertigen MVC app -dann "customizen" und eine eigene entwickeln)
* basiert auf python Standards (SQLAlchemy, Webob, Mako ...)
* Scaffolding ( schnell zur eigene App - im Gegensatzu zu deinem Besipiel oder anderen Frageworks )
* im Hintergrund sein. Fokus ist die App nicht das Framework.
Weniger Code schreiben ist nett, aber da man eher Code liest als schreibt, finde ich auch sehr wichtig, dass möglichst wenig Code entsteht. Somit bin ich nicht der größte Fan von generativen Ansätzen, die viel Code über die Mauer werfen, denn man dann ab sofort selbst pflegen und weiter entwickeln muss. Den Ansatz von Django, Formulare lieber dynamisch zu generieren, finde ich da besser. Dennoch kommen viele Leute mit dem scaffolding-Ansatz von Rails prima klar und er hat den Vorteil, dass nix geheimnisvolles passiert.

Mit SQLAlchemy kannst du wahrscheinlich gegen Djangos eigenen ORM punkten. Ob Mako nun Jinja überlegen ist, ist wahrscheinlich dann eher eine Geschmacksfrage. Aber auch hier ist das "Standard-Argument", das für deinen Ansatz spricht.

Wenn deine Scaffolds auch gleich schon paging enthalten, bist du da besser als Rails.

Ansonsten, noch einmal OT, ich habe den weiter oben skizzieren Code jetzt tatsächlich implementiert, was leider viel länger als ich eigentlich dafür Zeit opfern wollte gedauert hat. 174 Zeilen für das Rahmenwerk und noch einmal 150 Zeilen für den Scaffold-Generator. Mehr als das Beispiel im README geht allerdings auch nicht ;)

Stefan
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

nicht schlecht, Herr Specht ;)

Schöne Leistung !
von der Idee direkt implementiert ... und läuft ;)

Ich habe mir Meteor nochmal angesehen und finde insb. die auto Updates des clients (ohne Relaoad)
interessant.
Wird mit Websockets realisiert (kannte ich gar nicht). Es gibt auch python Implementierungen.

Keine Ahnung ob man das wirklich braucht (und welche Browser das koennen) bzw ein reload soo viel schlechter ist.
Cooler ist der auto-refresh allemal.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

Durch die aktuellen Änderungen auf dem Weg zu Beta1 hatten sich im Beta1 branch Änderungen ergeben, die teilweise dazu gefuehrt haben, dass das Besipiel aus dem webcast nicht 1:1 lief.

Deshalb bleibt der Beta1 branch ab jetzt unveraendert. Ich habe die aktuellen Aenderungen in einen separaten branch verlegt, damit das weblog beispiel definitiv nachvollziehbar / nachprogrammierbar ist. (und bleibt)

Aktuelle arbeiten:
- Authentifizierung als extension ( war schon an Bord aber inline )
- pre_filter, post_filter ( kann man dann transparent jeder action zuordnen.
Sind im Prinzip dynamische wrapper. )
- danach many2many Relations

Ich finde die Filter Sehr praktisch,die Implementierung ist aber aktuell, aufgrund der metaprogrammierung echt zum Haare raufen.

Ich wollte eigentlich __getattribute__ benutzen, das ist aber sehr anfaellig und tricky (rekursionen ...)

Falls jemand nen guten Tip fuer dynamische wrapper hat, gerne mal posten. Man braeucht nen dynamischen dekorator...
http://www.pythononwheels.org
11to1 sparetime development and all pm.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Bei mir kommt, wenn ich das Video anklicke "This video is unavailable. Sorry about that.". Hmm.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

Ich hatte den google account geloescht, da google angemahnt hat
Das python onwheels wohl nicht mein echter Vor- und Nachname ist ;)
Allerdings hatte ich nicht auf sme Schirm, das damit auch der youtube account und alle
Videos geloescht werden. (verdammte weltherrschaft)

Hab die videos neu eingestellt.

Links auf der homepage sind angepasst.
Und der link im Original-post jetzt auch.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

Sieht interessant aus... Was mir nur aufgefallen ist, als ich den Code überflog ist, dass du sehr häufig eval(..) benutzt. Hier ein Beispiel aus BaseController.py (ln. 175-178):

Code: Alles auswählen

def redirect(self, action, **kwargs):
        """ sets the given action and executes it so that all prerequisites are correct """
        self.setCurrentAction(action)
        return eval("self." + action + "(**kwargs)")
Das birgt Sicherheitsrisiken. Besser könnte man es so schreiben:

Code: Alles auswählen

def redirect(self, action, **kwargs):
        """ sets the given action and executes it so that all prerequisites are correct """
        self.setCurrentAction(action)
        return getattr(self, action)(**kwargs)
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

ja, absolut richtig.
Ich muss die evals auf jeden Fall loswerden und durch entsprechende getattr calls ersetzen.

Danke fuer den Hinweis und das Beispiel snippet ;)
Ich habe dazu gleich mal einen Issue bei github erstellt. und werde das jetzt durchackern.
Habe dein Beispiel 1:1 uebernommen. Hoffe das ist i.O.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

kann mir jemand bei folgendem helfen ??

ich moechte irgendwie den Zugriff auf Mehtoden einer Klasse pruefen und
ggf vorab eine check Methode aufrufen.

Da das ganze 'nachtraeglich' eingefuegt werden soll (also nicht als sourcecode)
hatte ich an __getattribute__ gedacht. Ich moechte also eine Klasse A die diese Funktion
gar nicht hat, spaeter erweitern.

damit habe ich aber beim ersten Testen Rekursionsprobleme.

hat jemand damit Erfahrung bzw ein code Beispiel ??

Ziel:
pruefen ob eine aufgerufene Methode in eine Liste self.locker_actions steht (hier die Idee das in
__getattribute__ zu machen). Wenn ja, dann eine Pruefmehtode aufrufen und bei Erfolg/True, die
eigentlich angeforderte Mehtode aufrufen.
Wenn nein, dann eine Error Methode aufrufen.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Kannst du nicht lieber zu einem bestimmten Zeitpunkt alle Methoden geeignet wrappen? Zum Beispiel so:

Code: Alles auswählen

class Foo:
    def __init__(self, x):
        self.x = x
        
    def bar(self, y):
        return self.x + y

def wrap(cls):
    for k, v in cls.__dict__.items():
        if not k.startswith("__") and isinstance(v, type(wrap)):
            print "wrap", k
            setattr(cls, k, mkwrapper(v))

def mkwrapper(f):
    def wrapper(*args, **kwargs):
        print "vor ", f.__name__
        result = f(*args, **kwargs)
        print "nach", f.__name__
        return result
    return wrapper

foo = Foo(3)
wrap(Foo)
print foo.bar(4)
Stefan
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

Hi Stefan,

guter Tip, das muesste eigentlich auch gehen. Ich musste kurz ueberlegen, wie
ich dann einfach dynamisch eine neue methode nach hinzufuegen in der
Liste wrappe.
Statt der liste muss man dann eine lock_action methode nehmen. Das waere
Dann die wrap . In mkwrapper muss ich dann dynamisch
Die pre und post methoden uebergeben und setzen.

Danke schonmal fuer die Idee und den (der hilft ne Masse ;)
Ich versuche mal eine Umsetzung und poste wieder.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

Hi Stefan,

Also, ich habe deinen Code als Basis genommen um den Methodenzugriff
dynamisch mit wrapper Mehtoden zu prüfen.

Allerdings "gübs Probleme", wenn ich die Funktionen wrap
und mkwrapper selbst in eine Protector Klasse verlagere.

Das liegt dann daran, das der Test:
...

Code: Alles auswählen

and isinstance(v, type(wrap))
mit dem du im Beispiel prüfst ob das zu wrappende Objekt eine Funktion ist,
bei Verlagerung der Funktionen wrap/wrapper in eine Klasse,
leider <type 'instancemethod'> mit <type 'function'> vergleicht. Übrigens auch dann, wenn
man dann type(self.wrap) als vergleich nimmt. (siehe Beispiel)
Obwohl das wrappen auf Foo (also Klasse) und nicht auf foo (Instanz) durchgeführt wird.

Hier das konkrete Beispiel:

Code: Alles auswählen

class Foo:
    def __init__(self, x):
        self.x = x
        
    def bar(self, y):
        return self.x + y

    
class Protector(object):
    def __init__(self):
        self.to_protect = {}

    def pre(self): 
        print 'pre'
    
    def post(self): 
        print 'post'
    
    def wrap(self,cls):
        print cls.__dict__.items()
        for k, v in cls.__dict__.items():
            print "key, value:", k,v
            print "type self(wrap):", type(self.wrap)
            print "type(v):", type(v)
            if not k.startswith("__") and isinstance(v, type(self.wrap)):
                print "wrap", k
                setattr(cls, k, mkwrapper(v))
    
    def mkwrapper(f):
        def wrapper(*args, **kwargs):
            print "vor ", f.__name__
            result = f(*args, **kwargs)
            print "nach", f.__name__
            return result
        return wrapper



if __name__ == "__main__":
    
    foo = Foo(3)
    p = Protector()
    p.wrap(Foo)
    print foo.bar(4)
Ich habe die wrap Methode jetzt wie folgt abgeaendert und sollte das gleiche erreichen.

Code: Alles auswählen

def wrap_class(self, cls):
        #print self.__dict__
        #print dir(self.__class__.__dict__)
        print cls.__dict__.items()
        for k, v in cls.__dict__.items():
            print "key, value:", k,v
            if not k.startswith("__"):
                func = getattr(cls, k)
                print "callable",callable(func)
                if callable(func):
                    print "wrap", k
                    setattr(cls, k, mkwrapper(v))
Allerdings wurmt mich noch ein wenig warum ich das mit deinem isinstance nicht hinbekomme. (Bisher ...;)


Naja, bis dahin erstmal und nochmal danke
Zuletzt geändert von khz am Donnerstag 13. September 2012, 21:54, insgesamt 1-mal geändert.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Ich würde entweder mittels

Code: Alles auswählen

hasattr(x, "__call__")
oder mittels

Code: Alles auswählen

isinstance(x, collections.Callable)
testen. Du suchst wahrscheinlich gerade verzweifelt nach letzterem ^^

Sebastian
Das Leben ist wie ein Tennisball.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

Hi EyDu,

jetzt wird es interessant. Metaprogramming ist sowieso spannend, finde ich ..
wenn ich mir die Doku durchlese dann denke ich eigentlich, das

Code: Alles auswählen

func = getattr(instance.function, k)
if callable(func):
    # do something
eigentlich gleichbedeutend sein sollte mit:

Code: Alles auswählen

hasattr(instance.function, "__call__")
laut doku ruft hasattr ja getattr wieder auf. Ist deshalb auch 'sicherer' als callable alleine aber
eben eigentlich nicht als die Kombi wie oben.

(Anm: Damn, kann man eigentlich im Forum statt dem Code button nicht einen python button einfuegen ... :evil: )


Collections.callable klingt wieder sehr interessant. (Hatte ich bisher nicht auf dem Schirm)
Aber da muss ich erst wieder Doku lesen ... ich sage nur ABC (wer das Akronym kennt hat auch schon gelesen ;)

In diesem Rahmen ist auch dieses bugs.pyhton.org ticket interessant.
http://www.pythononwheels.org
11to1 sparetime development and all pm.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Die Zeilen

Code: Alles auswählen

hasattr(instance.function, "__call__")

Code: Alles auswählen

callable(instance.function)
sollten das gleiche Ergebnis liefern. Ich weiß jetzt nicht, was du dem dem k dort vor hast. Wahrscheinlich gibt es da noch kleine Unterschiede, aber ich kann mich gerade weder erinnern, noch habe ich Lust Doku zu lesen :roll:


khz hat geschrieben:(Anm: Damn, kann man eigentlich im Forum statt dem Code button nicht einen python button einfuegen ... :evil: )
Den gibt es, man muss halt nur mal genau hinschauen ;-)

khz hat geschrieben:Aber da muss ich erst wieder Doku lesen ... ich sage nur ABC (wer das Akronym kennt hat auch schon gelesen ;)
ABC = Abstract Base Class, ist eigentlich eine übliche Abkürzung
Das Leben ist wie ein Tennisball.
khz
User
Beiträge: 38
Registriert: Freitag 3. August 2012, 22:47
Kontaktdaten:

man, man, man ....
python-Taste gefunden. Manchmal ist man betriebsblind ;) - Danke

k bezog sich auf die snippets der vorposts:

Code: Alles auswählen

def wrap_class(self, cls):
        #print self.__dict__
        #print dir(self.__class__.__dict__)
        print cls.__dict__.items()
        for k, v in cls.__dict__.items():
            print "key, value:", k,v
            if not k.startswith("__"):
                func = getattr(cls, k)
                print "callable",callable(func)
                if callable(func):
                    print "wrap", k
                    setattr(cls, k, mkwrapper(v))
Ich denke das callable alleine != hasattr

Collections.callable scheint einen gute Option aber ich denke wir
reden hier auch ueber %0,0000001 der Faelle in denen das nicht semantisch
gleichbedeutend ist....Ich starte erstmal wie gezeigt oder schwenke später ...
ist sowieso als plugin geplant, sodass sich die Leute spaeter leicht eine
Alternative Implementierung ziehen (oder entwickeln) können.

Fuer mich ist im Moment wichtig wie ich all die verschiedenen Moeglichkeiten einordnen (und dann entscheiden) kann
damit ich weiterkomme. Ich moechte mich eben auch nicht X Tage mit theoretischen Unterschieden befassen
sondern meine Authentifizierung hinbekommen ;)
Aber die soll nicht 'gestickt/gefrickelt' sondern schon so sein, das es den Empfehlungen der community
entspricht.

Bin parallel gerade in der PyPi Paketerstellung fuer Pow...
ist auch ein bindendes Thema....
Deshalb schonmal sorry falls ich erst verspaetet antworte ....

P.S.:ABC = Abstract Base Class, ist eigentlich eine übliche Abkürzung
danke fuer das Salz in der Wunde ;)
http://www.pythononwheels.org
11to1 sparetime development and all pm.
BlackJack

@khz: Willst Du eigentlich wirklich alles wrappen was aufrufbar ist, oder nur Methoden? Kennst Du das `inspect`-Modul?

Code: Alles auswählen

In [70]: inspect.getmembers(B, inspect.ismethod)
Out[70]: [('a', <unbound method B.a>), ('b', <unbound method B.b>)]
'a' ist von einer Klasse `A` geerbt — hast Du auch an so etwas gedacht, damit Du geerbte Methoden nicht mehrfach wrappst?
Antworten