[gull] Troll: Perl vs Python (was: Transtypage en Perl)

Félix Hauri felix at f-hauri.ch
Fri Jun 26 12:11:31 CEST 2009


Pas terrible, les réactions...

Z'etes déjà tous en vacances?

On Thu, Jun 25, 2009 at 12:15:49AM +0200, Christian Kaenzig wrote:
> > Vouis, a condition que la chaine binaire soit présentée du bit fort au bit
> > faible, 
> 
> C'est comme ça que j'écris un nombre en général :)

Toi, peut-être, mais les ``conventions'' d'écriture en binaire sont foisons!

> Je ne connais pas de fonction qui ces transformations automatiquement, 
> faudrait le faire à la main:
Etonnant!

Il existe probablement un module python qui se charge de ce genre de chose!?

> >>> int("0111011010001000"[::-1],2)
> 4462
> >>> int(''.join(["0110111000010001"[x*8:x*8+8] for x in range(1,-1,-1)]),2)
> 4462
Car cela ne me semble pas très ``élégant'' en regard de ce que l'on m'a
vanté de python...

> > Je dois dire que je n'apprécie pas toujours les contractions qui font
> > que sur ta ligne tu ne mentionne ni commande (say ou print), ni
> C'est l'habitude d'utiliser le shell de l'interpréteur python pour tester des 
> bouts de codes.
Ok, cela signifie clairement que la comparaison à l'origine de ce troll, entre
le ``script abouti'' de Fred et le ``test en console python'' de Christian, est
inapropriée:
 Fred propose un script complet, avec la définition d'une fonction de conversion,
 tandis que Christion présente la méthode qui permettra de définir une fonction
 de conversion que l'on ne pourra utiliser dans un script qu'après l'avoir
 correctement définie.

> On met une expression et il affiche ce que ça retourne. C'est 
> pas un raccourci du language, dans le sens où on ne peut pas mettre juste une 
> expression dans une ligne de script python, mais pour tester, c'est très 
> pratique.
Personnellement, pour tester, j'ai *toujours* une console *shell* à disposition.
Taper: 
 perl -e 'printf "%s\n", quelquechose'
est une opération quotidienne!
Suivit de ``fleche vers le haut'' puis les raccourcis clavier:
  Ctrl-a -> début de ligne, Ctrl-e -> fin de ligne, Ctrl-w -> couper
  Ctrl-y -> coller, Ctrl-_ -> Undo, etc... 
Je peux préparer un script relativement complexe:
$ perl -e 'printf "%s\n", "0"'
0
$ perl -e 'printf "%s\n", unpack "B","R"'
0
$ perl -e 'printf "%s\n", unpack "B8","R"'
01010010
$ perl -e 'printf "%s\n", unpack "B8","RA"'
01010010
$ perl -e 'printf "%s\n", unpack "B8*","RA"'
Invalid type '*' in unpack at -e line 1.
$ perl -e 'printf "%s\n", unpack "B8* ","RA"'
Invalid type '*' in unpack at -e line 1.
$ perl -e 'printf "%s\n", unpack "(B8)* ","RA"'
01010010
$ perl -e 'printf "%s\n", join " ", unpack "(B8)* ","RA"' 
01010010 01000001
$ perl -e 'printf "%s\n", join " ", unpack "(B8)* ","RADIONUMÉRIQUE"'
01010010 01000001 01000100 01001001 01001111 01001110 01010101 01001101
11001001 01010010 01001001 01010001 01010101 01000101

$ perl -e 'printf "%s\n", pack "B8 ","01010010"'
R
$ perl -e 'printf "%s\n", pack "B8 ",qw |01010010|'
R
$ perl -e 'printf "%s\n", pack "B8 ",qw |01010010 01000001|'
R
$ perl -e 'printf "%s\n", pack "B8* ",qw |01010010 01000001|'
Invalid type '*' in pack at -e line 1.
$ perl -e 'printf "%s\n", pack "(B8)* ",qw |01010010 01000001|'
RA
$ perl -e 'printf "%s\n", pack "(B8)* ",qw |01010010 01000001 01000100 01001001 01001111 01001110 01010101 01001101 11001001 01010010 01001001 01010001 01010101 01000101|'
RADIONUMÉRIQUE
 
Le *truc* c'est qu'a force de faire ``fleche vers le haut'', on finit par
taper ``une ligne'' qui peut faire plusieur centaines de caractères et
qui s'affichera dans la console sur plusieur lignes...

Exemple creation d'une presentation perso de la commande DF:
On lancera la commande: ``df -PTkl'' pour recalculer l'espace
occupé en fonction de l'espace libre (considérer les reserves comme
espace occupé):
D'abord la présentation numérique ``human-readable'':
$ perl -e 'printf "%s\n",int(log(1023)/log(1024));'
0
$ perl -e 'printf "%s\n",int(log(1024)/log(1024));'
1
$ perl -e 'printf "%s\n",int(log(1048576)/log(1024));'
2
$ perl -e 'printf "%s\n",int(log(1048575)/log(1024));'
1
Ok, donc
$ perl -e 'my $val=$ARGV[0];my $div=$val;$div=1 unless $div;printf "%s\n",int(log($val)/log(1024));' 1024
1024
quelque ``fleche vers le haut'' plus tard:
$ perl -e 'sub kb2human { my $val=shift;my $div=$val;$div=1 unless $div;my $fac=int(log($div)/log(1024));return sprintf "%.2f%so",$val/1024**$fac,(qw|K M G T P|)[$fac];}; ; printf "%s\n",kb2human 1111' 

... puis enfin:
$ perl -e 'sub kb2human { my $val=shift;my $div=$val;$div=1 unless $div;my $fac=int(log($div)/log(1024));return sprintf "%.2f%so",$val/1024**$fac,(qw|K M G T P|)[$fac];}; open FH, "df -TPkl|" or die; while (<FH>) { /^(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\S+\s+(\S+)$/ && do { printf "%-20s %9s %9s %9s %7.2f%% (%s)\n", $6,kb2human($3),kb2human($4),kb2human($5),100*($3-$5)/$3,$2; };};' 

Alors, il suffit de remplacer ``perl -e'' par ``echo >/tmp/script.pl''
et mon script est pondu, ou mieux: ajouter à la fin de ligne :
 ``| perltidy >/tmp/script.pl'' et remplacer ``perl -e'' par ``echo'',
on obtiendra un script perl ``lisible'' et du coup éditable.

Du coup, voici un CGI utilisable:
$ echo $'#!/usr/bin/perl -w\n''use strict; use CGI qw|:standard embed|;sub kb2human { my $val=shift;my $div=$val;$div=1 unless $div;my $fac=int(log($div)/log(1024));return sprintf "%.2f%so",$val/1024**$fac,(qw|K M G T P|)[$fac];}; open FH, "df -TPkl|" or die;print header.start_html;my @out; while (<FH>) { /^(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\S+\s+(\S+)$/ && do { my $prct=sprintf("%.2f",100*($3-$5)/$3); push @out,td([$6,kb2human($3),kb2human($4),kb2human($5),$prct."%",$2,embed({-height=>60,-width=>80,-src=>"http://www.f-hauri.ch/image/pie.svg?".$prct})]); };};print table(TR(\@out));' | perltidy >/tmp/df.cgi

(Attention au copier-coller: *La* ligne fait 620 caractères!)

La commande ``perltidy'' transforme cette ligne unique et ``pénible à lire'' en
un script indenté et lisible, de 38 lignes.

> > Bref, cela semble plus simple en python, comme ça, mais c'est lourd
> > de sous-entendus (ou manipulation tacites)...
> 
> La fonction int() interprète des chaines de caractères représentant des 
> nombres en int, et on peut choisir la base (d'où le ,2). Donc on ne peut pas 
> spécifier différentes interprétations. On aurait pas non plus l'idée d'écrire un 
> nombre en base 10 avec le chiffre de poids fort à droite...
Pas en base dix, mais en binaire, encore une fois, les conventions sont 
nombreuses.

> C'est donc pas la même optique que les fonctions pack et unpack de perl.
> ...


> > Enfin, comment fait un pythoniste pour lancer python en ligne de commande
> > et executer un truc tout simple comme
> > $ perl -e 'printf "%s\n",join "\n",unpack("(B8)* ","RADIONUMÉRIQUE")'
> python -c 'print "\n".join(map(lambda c:bin(ord(c))[2:].zfill(8), "RADIONUMÉRIQUE"))'
J'ai essayé:
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 1, in <lambda>
NameError: global name 'bin' is not defined


> ou
> python -c 'print "\n".join([bin(ord(c))[2:].zfill(8) for c in "RADIONUMÉRIQUE"])'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: name 'bin' is not defined

Marche po...

> Un poil plus compliqué parce que la chaine binaire sortie par bin() parce que 
> ça la sort sous forme 0b1001001 (comme ça sortirait 0x49 pour une chaine 
> hexa).
En plus...

Merci pour ces infos, je sens que je vais continuer à pondre mes moniteurs
en ``write-only'' Perl.

-- 
 Félix Hauri  -  <felix at f-hauri.ch>  -  http://www.f-hauri.ch


More information about the gull mailing list