Pipe e funzioni deprecate

Quando ho scoperto Unix (allora Sys V.2) la cosa che mi stupì di più fu senz’altro la pipe (non so mai che genere usare, forse qualcuno dice il pipe, chissà!).

A quei tempi Unix aveva due grossi difetti: costava caro ed era difficile da usare. Non so riguardo ai costi ma è da notare che allora ogni macchina aveva un sistema operativo proprio, o quasi, vero IBM?

Il fatto che Unix fosse difficile credo fosse dovuto al fatto che era nuovo e sconvolgeva convenzioni e abitudini. Fino ad allora era normale scrivere TUTTO IN MAIUSCOLO, e comunque per gli eccentrici il SO provvedeva alla normalizzazione (cioè conversione in maiuscolo) di quasi tutto. Naturalmente le lettere accentate erano assenti e comunque proibite. Altra cosa balzana di Unix erano i nomi dei comandi: cp invece di copy, rm invece di remove o delete, ls invece di dir (tutti sanno che directory vuol dire elenco) o cata (catalog, vuol dire catalogo); anzi cat faceva tutt’altra cosa, rubava il lavoro a print.

E che dire di roba tipo ls -l|more?
Di quest’ultima opzione abbiamo il nome del colpevole: Douglas McIlroy.

Anche nei linguaggi di programmazione il concetto di pipe è presente e fondamentale. Esempio (silly lo so) d’uso per un caso pratico.
Se volessimo reinventare il comando ls -l potremmo scrivere qualcosa come (OK, trascuriamo * come sys.argv):

import os

os.system('ls -l > tmp.tmp')
f = open('tmp.tmp')
ele = f.read()
f.close()
os.system('rm tmp.tmp')
print ele

Abbiamo bisogno di 8 righe e creare un file temporaneo.
Otteniamo qualcosa come:

* : /media/algol/lab/OKp/popen $ python con-ft.py
totale 56
-rw-r--r-- 1 n1n0 n1n0   43 2010-08-11 10:18 call-gimp.py
-rw-r--r-- 1 n1n0 n1n0   35 2010-08-11 10:59 chnnum
-rw-r--r-- 1 n1n0 n1n0  119 2010-08-09 09:59 con-ft.py
-rw-r--r-- 1 n1n0 n1n0 3810 2010-08-12 09:23 dep func
-rw-r--r-- 1 n1n0 n1n0   83 2010-08-11 10:21 goo.py
-rw-r--r-- 1 n1n0 n1n0  199 2010-08-07 09:12 has_hey
drwxr-xr-x 7 n1n0 n1n0 4096 2010-08-12 09:10 mat
-rw-r--r-- 1 n1n0 n1n0  294 2010-08-11 11:04 r-has_key.py
-rw-r--r-- 1 n1n0 n1n0   68 2010-08-09 09:56 senza-ft.py
-rw-r--r-- 1 n1n0 n1n0   61 2010-08-11 10:12 sp-gimp-err.py
-rw-r--r-- 1 n1n0 n1n0   60 2010-08-11 10:11 sp-gimp-ns.py
-rw-r--r-- 1 n1n0 n1n0   74 2010-08-11 10:06 sp-gimp.py
-rw-r--r-- 1 n1n0 n1n0  121 2010-08-11 09:57 subp.py
-rw-r--r-- 1 n1n0 n1n0    0 2010-08-12 09:27 tmp.tmp
-rw-r--r-- 1 n1n0 n1n0  266 2010-08-10 10:53 urls

* : /media/algol/lab/OKp/popen $

Ma si può fare di meglio:

import os

f = os.popen('ls -l')
ele = f.read()
f.close()
print ele

e vediamo che otteniamo lo stesso risultato senza bisogno di creare un file temporaneo e, probabilmente, con un minor utilizzo di risorse (anche se trascurabile).
La brutta notizia è questa:

os.popen(command[, mode[, bufsize]])
[...]
Deprecated since version 2.6: This function is obsolete. Use the subprocess module.
[...]

e con essa ci sono os.tmpfile(), os.popen2(), os.popen3(), os.popen4() e os.system(). Poi dalla versione 3.0 è deprecata anche has_key(), e forse altre ancora. Python si evolve, è normale.

Se uno googla per python subprocess example trova tante richieste di aiuto e tanti messagi di gente perplessa e spersa.
Panico?
No! ancora una volta la cosa migliore è di seguire l’aurea regola

leggere quel ROT13(“pnmmb”) di manuale!

che nel nostro caso è questa pagina, dove c’è tutto quello che serve. Per avere una visione più completa dei motivi che hanno portato a questa piccola rivoluzione è utile leggere anche questo PEP (Python Enhancement Proposal) del del 19 nov. 2003. Quindi non è un fulmine a ciel sereno, ce l’avevano detto da tempo, solo io non lo sapevo. O è come la storia dei gas serra, CO2 in primis, di origine antropica che continuiamo a ignorare, ricavando l’energia che ci serve bruciando succo di dinosauro?

Chiusa la parentesi ecologica (e continuando a trascurare, come al solito, il problema del riscaldamento globale) vediamo come riscrivere lo script, senza lasciarci prendere dal panico, ovviamente

import subprocess

f = subprocess.Popen('ls -l', stdout = subprocess.PIPE, shell = True).stdout
ele = f.read()
print ele

Fatto. Semplice vero? Nel nostro caso serve shell = True perché ls è un comando di sistema.

Altro caso: lanciare gimp

import subprocess

res = subprocess.Popen('gimp')
print res

che può essere semplificato in

import subprocess

subprocess.call('gimp')

Ancora: lanciare google con xdg-open

import subprocess

subprocess.call('xdg-open http://www.google.com', shell = True)

OK, subprocess non ci fa più impanicare, altri casi si possono presentare ma sappiamo come affrontarli: visto che serve leggere il manuale, oggi sempre a portata di mano online.

E quando sarà ora (ma possiamo farlo anche adesso) rimpiazzeremo has_key() in questo modo

diz = {'yi':1, 'er':2, 'san':3 ,'si':4, 'wu':5,
         'liu':6, 'qi':7, 'ba':8, 'jiu':9 ,'shi':10}

print 'modo vecchio, con has_key()'
print diz.has_key('ba')
print diz.has_key('yiu')
print diz.has_key('sh')

print '\nmodo nuovo, con in'
print 'ba' in diz
print 'yiu' in diz
print 'sh' in diz

ottenendo:

* : /media/algol/lab/OKp/popen $ python r-has_key.py
modo vecchio, con has_key()
True
False
False

modo nuovo, con in
True
False
False
* : /media/algol/lab/OKp/popen $

Doug diceva “Keep it simple, make it general, and make it intelligible.” Non avrei saputo dirlo meglio e peccato che l’abbia già detto lui 😉

Posta un commento o usa questo indirizzo per il trackback.

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

%d blogger hanno fatto clic su Mi Piace per questo: