Applicazioni server-side in Python Sebastiano Viviani sebastiano.viviani@system5.it
Cenni storici Progettato e creato da Guido van Rossum viene pubblicato nel 1991 Nel 1994 raggiunge la versione 1.0 (CWI istituto nazionale olandese per la ricerca nelle scienze informatiche e matematiche) Dal 1995 al 2001 viene sviluppato presso il CNRI (organizzazione no-profit di ricerca con sede in Virginia) salvo una piccola parentesi in BeOpen.com Dal 2001 ad oggi è proprietà della Python Software Foundation (organizzazione no-profit)
Caratteristiche tecnologiche Linguaggio di scripting Object oriented (con ereditarietà multipla) Gestione delle eccezioni Dynamic typing / strong typing Elementi di programmazione funzionale Utilizzo di una VM con relativo bytecode Definizione dei blocchi di codice attraverso l'indentazione
Implementazioni esistenti Cpython (implementazione di riferimento con relativi sorgenti) disponibile per Linux/Windows/OSX Porting esistenti per Solaris/AIX/iSeries(AS400)/zOS(MVS) Windows CE Jython (VM su JVM) interprete e con traduzione in Java Byte Code IronPython (VM in ambiente.net) PyPy (Python on Python)
Performance Da Computer Language Benchmarks Game http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=all Rapporto 1,00 1,50 17,00 21,00 23,00 48,00 linguaggio C gcc Java 6 -server Python Perl PHP Ruby
Come valutare le performances Java -> Pure Java Python -> Librerie native (C) Estensibilità: C nativo, SWIG, PyREX
Batterie incluse Estesa libreria fornita assieme al base system Package per gestione email, parser xml, internazionalizzazione, embedded db su sql-lite Client per i più diffusi protocolli internet: IMAP, POP3, SMTP, HTTP, XML-RPC, FTP, TELNET, NNTP Oggetti server: HTTP, SMTP, XML-RPC Sistema di logging, Profiler API per accesso SQL (DB-API) Documentazione relativa a librerie, API, tutorial
Tipi di dati (1) Gestisce nativamente tipi scalari (booleani, caratteri, interi, float, complessi) Iteratori Sequenze (stringhe, stringhe unicode, liste, t- uple) Insiemi Dizionari Files I metodi possono restituire qualunque di questi dati
Tipi di dati (2) Classi e metodi sono tipi nativi Prevede l'introspezione Prevede la serializzazione Thread Meccanismi di sincronizzazione
Qualche esempio from datetime import datetime from xml.etree import ElementTree def date_adder(doc): tree = ElementTree.XML(doc) pags = [float(a.text) for a in tree.findall("./pag")] return (datetime.now(), sum(pags)) print date_adder("""<?xml version="1.0" encoding="utf-8"?> <document> <pag>10.0</pag> <pag>12.0</pag> <pag>9.5</pag> </document>""") >>> (datetime.datetime(2007, 11, 19, 18, 41, 56, 796911), 31.5)
XML-RPC Request POST / HTTP/1.0 User-Agent: PEAR XML_RPC Host: localhost Content-Type: text/xml Content-Length: 332 <?xml version="1.0" encoding="utf-8"?> <methodcall> <methodname>date_adder</methodname> <params> <param> <value><string><?xml version="1.0"?> <document><pag>10.0</pag><pag> 12.0</pag><pag> 9.5</pag></document></string></value> </param> </params> </methodcall>
XML-RPC Response HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.5.1 Date: Fri, 23 Nov 2007 09:50:52 GMT Content-type: text/xml Content-length: 245 <?xml version='1.0'?> <methodresponse> <params> <param> <value><array><data> <value><datetime.iso8601>20071123t10:50:52</datetime.iso8601></val ue> <value><double>31.5</double></value> </data></array></value> </param> </params> </methodresponse>
XML-RPC from SimpleXMLRPCServer import SimpleXMLRPCServer from datetime import datetime from xml.etree import ElementTree def date_adder(doc): Commento del metodo tree = ElementTree.XML(doc) pags = [float(a.text) for a in tree.findall("./pag")] return (datetime.now(), sum(pags)) srv = SimpleXMLRPCServer(('0.0.0.0',8080)) srv.register_function(date_adder) srv.serve_forever()
XML-RPC CLIENT import xmlrpclib clnt = xmlrpclib.server("http://localhost:8080/") print clnt.date_adder("""<?xml version="1.0" encoding="utf-8"?> <document> <pag>10.0</pag> <pag>12.0</pag> <pag>9.5</pag> </document>""") >>> [<DateTime '20071119T18:50:14' at b7cee20c>, 31.5]
Python vs C/C++ Estesa libreria standard fornita assieme al base system Management automatico degli oggetti (ref count) Tempo di sviluppo infinitamente minore Possibilità di integrare solo piccole componenti in C/C++ per migliorare le performances Multipiattaforma Sintassi più chiara
Python vs PHP Migliori performances Possibilità di distribuire il solo byte-code al posto di tutta l'applicazione Estesa libreria fornita con il sistema di base (anche se il gap si sta lentamente colmando grazie al framework PEAR) PHP è progettato più che altro per l'impiego in applicazioni WEB in abbinata con un Web Server come Apache 2
Esempio in PHP5 <?php function date_adder($doc){ $document = new DOMDocument(); $document->loadxml($doc); $xpath = new domxpath($document); $pags=$xpath->query('/document/pag'); $sum = 0.0; foreach ($pags as $pag){ $sum+=$pag->textcontent; } return array("date"=>getdate(),"sum"=>$sum); } print_r( date_adder('<?xml version="1.0" encoding="utf-8"?> <document> <pag>10.0</pag> <pag>12.0</pag> <pag>9.5</pag> </document>'));?>
XML-RPC server <?php require_once 'XML/RPC/Server.php'; function date_adder($doc){ $document = new DOMDocument(); $document->loadxml($doc); $xpath = new domxpath($document); $pags=$xpath->query('/document/pag'); $sum = 0.0; foreach ($pags as $pag){ $sum+=$pag->textcontent; } return array("date"=>getdate(),"sum"=>$sum); } function date_adder_wrapper($params){ $res = date_adder($params->getparam(0)->scalarval()); return new XML_RPC_Response( new XML_RPC_Value($res['sum'],'double')); } $srv = new XML_RPC_Server(array("date_adder"=>array("function"=>"date_ adder_wrapper")));?>
XML-RPC client <?php include ('XML/RPC.php'); $client = new XML_RPC_Client("/srv.php", "localhost", 80); $msg = new XML_RPC_Message("date_adder",array(new XML_RPC_Value('<?xml version="1.0"?> <document><pag>10.0</pag><pag>12.0</pag><pag>9.5</pag></doc ument>',"string"))); $response = ($client->send($msg)); print_r($response->value());?>
Python vs Perl Estesa libreria fornita assieme al base system Migliori performances Sintassi chiara Object Oriented
Python vs Java (1) Con JSE 6.0 Sun ha aggiunto al sistema base Apache Derby (SQL db puro java) Per applicazioni web è necessario un container j2ee (Apache Geronimo) oppure un servlet container (Apache Tomcat) Java può venire utilizzato per applicazioni su piattaforma mobile Python può essere compilato per piattaforme ove non esiste Java (ad esempio Linux/Sparc)
Python vs Java (2) Jython è un'implementazione dell'ambiente Python 2.2 in Java Fornisce accesso alle strutture dati ed alle API della VM su cui viene utilizzato
Framework per accesso ai dati SQLAlchemy Django Twisted
Object-relational mapping Stabiliscono una relazione oggetto->tabella Offrono un livello di astrazione di livello superiore rispetto a SQL Permettono una più facile portabilità dell'applicazione rispetto al backend scelto per lo storage Gestiscono in maniera automatica gli oggetti riferiti da foreign-key o relazioni molti-a-molti
SQLAlchemy Supporta SQLite, Postgres, MySQL, MS-SQL e Oracle A livello sperimentale Firebird and Informix In fase di sviluppo un driver for DB2 Permette di operare su database già esistenti Gestisce la creazione delle tabelle a partire dal codice che ne definisce gli oggetti Permette di mappare un oggetto su più di una tabella
Django Supporta SQLite,MySQL, PostgreSQL e Oracle Il supporto Oracle è recente C'è in fase di sviluppo un supporto per MS-SQL (attualmente solo via ADO-DB e datato) Permette di operare su database già esistenti Gestisce la creazione delle tabelle a partire dal codice che ne definisce gli oggetti Offre una serie di framework tra cui la gestione delle transazioni e una raffinata amministrazione web creata dinamicamente dalla definizione degli oggetti È anche un framework per la creazione di web application
Twisted È un framework per la realizzazioni di servizi di rete ad elevate prestazioni È basato sul modello ad eventi tramite un oggetto ('reactor') che ne gestisce il passaggio dallo stato di riposo a quello di esecuzione appoggiandosi a specifiche primitive di sistema al posto di utilizzare il modello di programmazione concorrente basato su thread Offre l'implementazione lato server di molti protocolli (IMAP4/POP3/SMTP/DNS/HTTP/SSH/SFTP) Offre un ORM (meno sofisticato dei precedenti) basato sul modello ad eventi
Framework per il WEB CGI PSP Apache + mod_python CherryPy Django
Basic CGI Programming #!/usr/bin/python import cgi def main(): print Content type: text/html\n print <html>\n form_data = cgi.fieldstorage() if form_data.has_key( nome ) and form_data[ nome ].value!= : print <h2>ciao,form_data[ nome ].value, </h2> else: print <h2>errore</h2> print </html>\n main()
PSP (Apache+Mod python) <html> <head> <title>welcome</title> </head> <body> <% title = "<H1>Welcome to the world of Python</H1>" greeting = "If you lived here, you'd be home by now" res.write(title) res.write("<p>") res.write(greeting) %> </body> </html>
CherryPy Un differente approccio filosofico al protocollo HTTP Ogni richiesta da client viene trasformata in una chiamata a funzione i cui parametri di ingresso sono i campi passati nella richiesta GET o POST Ogni oggetto associato ad un URL viene esposto se deve essere accessibile Il metodo index viene invocato in assenza di altra specifica
import cherrypy Esempio class HelloWorld(object): def index(self): return """<html> <form action="test" method="post"> inserisci un valore <input type="text" name="valore"> <input type="submit" value="vai"/> </form> </html>""" index.exposed = True @cherrypy.expose def test(self,valore): return """<html> Hai scritto <h3>%s</h3> </html>""" % valore class Page2(object): def index(self): return "Page2" index.exposed = True cherrypy.root = HelloWorld() cherrypy.root.p2 = Page2() cherrypy.server.start()
Django (1) È un framework completo per lo sviluppo di web application Contiene un ORM molto avanzato Un template engine per il rendering delle pagine WEB Serializzatori per gli oggetti in formato JSON o XML Un sito di amministrazione molto flessibile e generato automaticamente dalla descrizione della web application
Django (2) Un framework per la gestione delle transazioni Un web server Un sistema di integrazione con Apache o con altri web server Gestione delle sessioni Gestione del Caching delle pagine Un sistema per la creazione e la validazione di form web a partire da descrizioni sintetiche oppure dalla descrizione dell'oggetto stesso
Django (3) Supporto multilingue Database introspection Limiti: un database<--->un'applicazione In corso di realizzazione porting su Jython
Qualche esempio > django-admin.py startproject sito > vi settings.py DATABASE_ENGINE = 'sqlite3' DATABASE_NAME = '' DATABASE_USER = '' DATABASE_PASSWORD = '' DATABASE_HOST = '' DATABASE_PORT = '' # 'postgresql_psycopg2', # 'postgresql', 'mysql', # 'sqlite3' or 'ado_mssql'. # Or path to database file # if using sqlite3. # Not used with sqlite3. # Not used with sqlite3. # Set to empty string for # localhost. Not used with # sqlite3. # Set to empty string for # default. Not used with # sqlite3.
> cd esempio >./manage.py startapp news > cd news > vi models.py from django.db import models # Create your models here. class Argomento(models.Model): """Categoria articoli""" nome = models.charfield(maxlength="50",verbose_name="nome") descrizione = models.charfield(maxlength="255",verbose_name="descrizione",blank=true,null=true) def unicode (self): return self.nome def str (self): return self.nome class Admin: search_fields = ['nome'] save_on_top = True class Meta: verbose_name = "Argomento" verbose_name_plural = "Argomenti" class News(models.Model): """Notizia""" titolo = models.charfield(maxlength="100",verbose_name="titolo") testo = models.textfield(verbose_name="testo") argomento = models.foreignkey(argomento,verbose_name="argomento") immagine = models.filefield(verbose_name="img", upload_to="images") def str (self): return self.titolo class Admin: search_fields = ['titolo','testo'] save_on_top = True list_filter = ['argomento'] class Meta: verbose_name = "Notizia" verbose_name_plural = "Notizie"
> vi settings.py # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" MEDIA_ROOT = 'media-root/' # URL that handles the media served from MEDIA_ROOT. # Example: "http://media.lawrence.com" MEDIA_URL = '/media-root/'... INSTALLED_APPS=( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'esempio.news', ) > vi urls.py # Uncomment this for admin: (r'^admin/', include('django.contrib.admin.urls')), #contenuto statico (r'^media-root/(?p<path>.*)$', 'django.views.static.serve', {'document_root': '/esempio/media-root', 'show_indexes': True}), (r'/?$', 'news.views.site_page'), >./manage.py syncdb
Creazione di una view > vi views.py import models as news_models from django.template import Context, loader from django.http import HttpResponse def site_page(request): errors = [] try: cat_id = request.get['cat_id'] news = [i for i in news_models.news.objects.filter(argomento=cat_id)] cat_nome = news_models.argomento.get(cat_id).nome except: news = [i for i in news_models.news.objects.all()] cat_nome = "Tutti" categorie = [] for i in news_models.argomento.objects.all().order_by('nome'): categorie+= [i] t = loader.get_template("page.html") c = Context({ 'categorie': categorie, 'news': news, 'cat_nome': cat_nome, }) return HttpResponse(t.render(c))
Creazione di un template > mkdir templates > vi templates/page.html <html> <h3>on site news</h3> <h1>{{ cat_nome }}</h1> {% for categoria in categorie %} <a href="?cat_id={{ categoria.id }}">{{ categoria.nome }}</a><nbsp/> {% endfor %} {% for notizia in news%} <h2>{{ notizia.titolo }}</h2> {% if notizia.immagine %} <img src="http://127.0.0.1:8080/media-root/{{ notizia.immagine }}"/> {% endif %} {{ notizia.testo }}<p/> {% endfor %} </html>
Bibliografia http://www.python.org http://www.jython.org http://www.iseriespython.com http://www.codeplex.com/wiki/view.aspx?projectname=ironpython http://www.php.net http://shootout.alioth.debian.org http://www.modpython.org http://www.cherrypy.org http://www.sqlalchemy.org http://www.djangoproject.com http://twistedmatrix.com http://java.sun.com http://www.xmlrpc.com