Briciole in Python (1)
Python bits (1)

di leonardo maffi
by leonardo maffi

Ultima revisione: 19 ottobre 2005
Last revision: Oct 19 2005


It seems clear that languages somewhat different from those in existence today would enhance the preparation of structured programs. We will perhaps eventually be writing only small modules which are identified by name as they are used to build larger ones, so that devices like indentation, rather than delimiters, might become feasible for expressing local structure in the source language.
-- Donald Knuth, "Structured Programming with go to Statements", Computing Surveys, Vo. 6, No. 4, December 1974

Tutti questi programmini in Python - All the little Python programs: pythonmix1.zip


In questa pagina mostro alcuni piccoli programmini in Python che ho costruito di recente, che non meriterebbero una pagina tutta per loro, ma che ritengo sufficientemente interessanti da venire comunque mostrati. (I listati colorati li ho ottenuti con una versione modificata di PySourceColor di M.E.Farmer Jr.).
Here I show some tiny Python programs that I've created recently. Each one isn't so important to deserve a full page, so I collect them all in this page. (To produce the colorized Html code I've used a modified version of PySourceColor by M.E.Farmer Jr.).

99 bottiglie di birra sul muro - 99 Bottles of beer on the wall

In questo programmino classico ho cercato di mostrare che il Python può venire usato per scrivere del codice molto comprensibile anche da chi non conosce il Python stesso:
In this little classic program I've tried to show that Python can be used to write code that can be easely understood even by people that don't know Python:
def bottles(n):
    if n == 0:
        return "No bottles"
    if n == 1:
        return "1 bottle"
    else:
        return str(n) + " bottles"

s = "of beer on the wall"
i = 99
while i != 0:
    print bottles(i), s
    print bottles(i), "of beer"
    if i>1:
        print "Take one down, pass it around"
    else:
        print "Take it down, pass it around"
    i = i - 1
    print bottles(i), s
    print


Sequenza audioattiva - Look and say
sequence (also called audioactive sequence)

La famosa sequenza inventata/scoperta dal grande J. H. Conway
http://mathworld.wolfram.com/LookandSaySequence.html
Sequenza A005150 sull'archivio di Sloane: http://www.research.att.com/projects/OEIS?Anum=A005150
Si parte da 1, e un termine si ottiene dal precedente contando quante cifre sono presenti. Per cui il secondo termine e' "un uno" (11), il terzo è "due uno" (21), il quarto è "un due e un uno" (1211), eccetera. Nella sequenza appaiono solo le cifre 1 2 e 3. Ecco i primi termini della sequenza:
This is the famous sequence invented/found by J. H. Conway
http://mathworld.wolfram.com/LookandSaySequence.html
It's the A005150 sequence in the Sloane archive: http://www.research.att.com/projects/OEIS?Anum=A005150
We start with 1, and you can produce the a term from the precedent one conunting how much digits there are. So the second term is "one one" (11), the third is "two ones" (21), the fouth is "one two and one one", etc. Only the digits 1, 2 and 3 appear in any term. Here are the first terms of the sequence:



1, 11, 21, 1211, 111221, 312211, 13112221, 1113213211, 31131211131221, 13211311123113112211, 11131221133112132113212221, 3113112221232112111312211312113211, 1321132132111213122112311311222113111221131221, 11131221131211131231121113112221121321132132211331222113112211, 311311222113111231131112132112311321322112111312211312111322212311322113212221]

Queste funzioni calcolano i primi n termini di questa sequenza. Queste funzioni sono ottimizzate per essere le più veloci (e non le più corte). Questa è la mia più veloce una volta compilata con Psyco:
The following functions give the first n terms of this sequence. The following functions are opmized for speed (and not for shortness). This is my faster one if you can compile it with Psyco:

from itertools import groupby

def audioactive1(n): # faster compiled
    strl = {("1","1","1"): "31", ("1","1"): "21", ("1",): "11",
            ("2","2","2"): "32", ("2","2"): "22", ("2",): "12",
            ("3","3","3"): "33", ("3","3"): "23", ("3",): "13" }
    s = [1]
    prec = str(s[-1])
    for i in xrange(n-1):
        r = []
        for e,l in groupby(prec):
            r.append( strl[tuple(l)] )
        prec = "".join(r)
        s.append( int(prec) )
    return s
E questa è la più veloce se non dispone del compilatore Psyco:
And this is the faster one if you can't use Psyco:
def audioactive2(n): # faster uncompiled
    strl = {("1","1","1"): "31", ("1","1"): "21", ("1",): "11",
            ("2","2","2"): "32", ("2","2"): "22", ("2",): "12",
            ("3","3","3"): "33", ("3","3"): "23", ("3",): "13" }
    result = [1]
    prec = "1"
    for i in xrange(n-1):
        prec = "".join( strl[tuple(l)] for e,l in groupby(prec) )
        result.append( int(prec) )
    return result

Ho definito delle funzioni nestList e split simili a quelle del Mathematica (non riportate qui), con esse il codice per produrre i termini della serie viene molto breve:
I've written the nestList and split functions similar to the Mathematica ones (I don't show them here), with them the code to compute the sequence terms becomes quite short:

from util import split, nestList
print map(int,nestList(lambda s:"".join([str(len(e))+e[0]for e in split(s)]),"1",9))

 

Thue-Morse sequence

Questa è un'altra famosa sequenza:
Another famous sequence:
http://www.research.att.com/projects/OEIS?Anum=A010060

01101001100101101001011001101001..

Ci sono varie varianti di questa sequenza, comunque espressa nella forma binaria data sopra, può essere definita ricorsivamente usando l'operatore di nagezione sui bit. Il primo termine è 0. Quando i primi 2^n termini sono stati specificati, possiamo definirli s, allora i successivi 2^n elementi possono essere ottenuti negando s bit a bit. Adesso abbiamo definito i primi 2^(n+1) elementi, e proseguiamo ricorsivamente.
The Thue-Morse sequence in the form given above, as a sequence of bits, can be defined recursively using the operation of bitwise negation. So, the first element is 0. Then once the first 2^n elements have been specified, forming a string s, then the next 2^n elements must form the bitwise negation of s. Now we have defined the first 2^(n+1) elements, and we recurse.

Eccola qui mentre cresce:
Here is it growing:
0
01
0110
01101001
0110100110010110
...

Espressa in base 10:
Expressed in base 10:
0, 1, 6, 105, 27030, 1771476585, 7608434000728254870, ...

Eccone una implementazione piuttosto breve e veloce, che usa la .translate:
Here is a quite short and fast implementation that uses .translate:

table = [" "] * 256
table[ord("0")] = "1"
table[ord("1")] = "0"
table = "".join(table)

s = "0"
for i in xrange(12):
    s += s.translate(table)
print s

Katà di programmazione n.11 - Code kata #11

http://blogs.pragprog.com/cgi-bin/pragdave.cgi/Practices/Kata/KataEleven.rdoc

Questi Katà sono esercizi di forma, cioè sono esercizi nei quali si può cercare di migliorare sempre più secondo vari metri di giudizio. Questo richiede di ordinare alfabeticamente le lettere di una stringa, convertite in minuscolo e pulite da spazi e punteggiatura. Il tutto deve essere datto senza usare funzioni di ordinamento presenti nella biblioteca del linguaggio. Queste sono la stringa di input e il risultato desiderato di esempio:
Such katas are exercises form, you can try to solve them maximizing different aspects. Problem: sort the letters of a string, stripped of punctuation and spaces, converted in lowercase, and without using the library sort of the language. Here are the example input and the desired output strings:

"When not studying nuclear physics, Bambi likes to play beach volleyball."

aaaaabbbbcccdeeeeeghhhiiiiklllllllmnnnnooopprsssstttuuvwyyyy

Ecco alcune mie versioni:
Here are some of my versions:

s = "When not studying nuclear physics, Bambi likes to play beach volleyball."

# Questa e' la mia versione Python 2.4 piu' corta:
# This is my shortest Python 2.4 version:

print "".join(c for c in sorted(s.lower())if 123>ord(c)>96)

# Versione piu' lenta cyhe usa la biblioteca incorporata di ordinamento:
# Slower version without using the sorting library routine:

print "".join(c*s.lower().count(c)for c in map(chr,range(97,123)))

# Per una stringa enorme gia' in memoria questa puo' essere la versione piu' veloce:
# For a huge string already in memory this can be the faster version:

f = dict().fromkeys( map(chr,range(256)), 0)
for c in s: f[c] += 1
print "".join(chr(i)*(f[chr(i)]+f[chr(i-32)]) for i in range(97,123))

# Per un file piuttosto grande su disco questa puo' essere la versione piu' veloce:
# For a very big file on disk this can be the faster version:

import os, stat, array
filename = "text"
a = array.array('B')
f = open(filename, "rb")
a.fromfile(f, os.stat(filename)[stat.ST_SIZE])
f.close()
f = [0] * 256
for c in a: f[c] += 1
print "".join(chr(c)*(f[c]+f[c-32]) for c in range(97,123)

 

Katà di programmazione n.6 - Code kata #6

http://blogs.pragprog.com/cgi-bin/pragdave.cgi/Practices/Kata/KataSix.rdoc

Questo katà richiede di trovare tutti gli anagrammi dato un dizionario di parole. Questa è una versione tra le più veloci:
This kata asks to find all the anagrams from a word dictionary. This is among the faster versions:

words = open("wordlist.txt", "r").read().split()
dictwords = {}
for iw, w in enumerate(words):
    wsignature = "".join(sorted(list(w.lower())))
    if wsignature in dictwords:
        dictwords[wsignature].append(iw)
    else:
        dictwords[wsignature] = [iw]
for anaglist in dictwords.values():
    if len(anaglist) > 1:
        print [words[i] for i in anaglist]

Versione un po' più lenta, ma più compatta:
Slower but more compact version:
wo = open("wordlist.txt","r").read().split()
d = {}
for i, w in enumerate(wo):
    s = "".join(sorted(list(w.lower())))
    d[s] = d.get(s, []) + [i]
for l in d.values():
    if len(l) > 1:
        print [wo[i] for i in l]


Anagrammi di una parola data - Anagrams of a given word

Ecco un piccolo programma (ottimizzato per la piccola lunghezza) per trovare gli anagrammi di una parola data, utilizzando un dizionario:
Here is a little program (optimized for shortness) to find all the anagrams of a given word, using a dictionary:

anagram = raw_input("Find anagrams of word: ")
words = open('wordlist.txt').read().split()
sa = sorted(anagram.lower())
la = len(anagram)
result = [w for w in words if len(w)==la and sorted(w)==sa]
print "Anagrams:", ' '.join(result)


Parole più frequenti in un testo - Most frequent words in a text

Versione corta:
Short version:

txt = open("text").read().lower()
for c in ".,;:-\\'\"": txt = txt.replace(c," ")
words = txt.split()
f = {}
for w in words:
    f[w] = f.get(w,0) + 1
for w in sorted(f, key=f.get,reverse=True)[:30]:
    print w, f[w]
Versione più veloce:
Faster alternative:
txt = open("text").read().lower()
ctable = [chr(i) for i in range(256)]
for c in ".,;:-\\'\"": ctable[ord(c)] = " "
ctable = "".join(ctable)
words = txt.translate(ctable).split()
f = {}
for w in words:
    f[w] = f.get(w,0) + 1
for w in sorted(f, key=f.get,reverse=True)[:30]:
    print w, f[w]

Risultato:
Output:

the 379
i 314
and 257
to 210
a 160
my 106
of 81
have 80
is 79
in 77
it 66
that 64
as 53
on 46
but 45
be 41
me 40
for 38
am 37
he 34
up 33
you 32
can 31
are 30
time 29
at 29
hir 29
with 28
we 27
was 27

 

Rimescolatore di parole - Word scrambler

Dato un testo, questo programma rimescola le lettere interne ad ogni sua parola, lasciando in generale nella loro posizione solo la prima e l'ultima. La cosa interessante è che il testo risultante è spesso leggibile:
Given a text, this program scrambles the letter of each of its word, generally keeping only the first and last letter in their positions. It's interesting to see that the resulting text is often readable still:

from random import shuffle
symb = set(".,.:;-*!?()\"[]^'\n")

def wscramble(w):
    worig = w
    if w[0] in symb:
        w0 = w[0]
        w = w[1:]
    else:
        w0 = ""
    if w[-1] in symb:
        wm1 = w[-1]
        w = w[:-1]
    else:
        wm1 = ""
    if len(w)>2:
        sw = list(w[1:-1])
        shuffle(sw)
        return w0 + w[0] + "".join(sw) + w[-1] + wm1
    else:
        return worig

t = open("text").read()[:1000].split(" ")
print " ".join(wscramble(w) for w in t if len(w)>1)

Probabilmente il programma si potrebbe scrivere più corto. Ecco un risultato:
Probably this program can be made shorter. Here is an output:

The nghit air seems to thicekn as we wlak out itno the woods naer the cmap. The slmels of nhigt are lkie candy to my sseens and the sudnos of wlidlfie in the dcatnise awkaen deep feneigls of bneliongg. lead us truhgoh the wodos, knwnoig the way to nice aera near slaml sraetm. Nkoo ssnees my ftiaimrialy with the area and fowolls csole bnehid. The pnie nldeees on the path and frnes that grow tilhcky uendr the teers seem to tcark our mvtnmoees. ca’nt hlep but feel taht we are mikang vrey niosy acvdnae onto the emney. My taniring tells me to be senlit as wlak but hvae to reimnd msylef that this is not an “paeoonirt”, just ncie nautre wlak. hop dwon an eennmbamkt and feel the soft garss uednr my pwas. Nkoo is rgiht behnid me. ltitle sraetm fwlos qteiuly out from the fnres and ploos beteewn smoe stomoh rocks. The water is caler and cool and the wlid mnit grwinog nareby adds mgcaail secnt to the gdlae. can snese that Noko is very happy wtih the lcotiaon and shi slwloy

 

Tutti i sottoinsiemi - All subsets

I possibili sottoinsiemi di un insieme di n elementi sono 2^n, e questo suggerisce un algoritmo iterativo ovvio per calcolarli tutti. ma esiste un algoritmo più efficiente per calcolarli. Questa è la versione Python più corta che lo implementa:
All possibile subsets of a set of n elemets are 2^n, and this suggests an obvious algorithm to compute them all. But it exists a faster algorithm to compute them. Here is my shortest Python implementation of it:

def subsets1(s):
    r = [[]]
    for e in s: r += [x+[e] for x in r]
    return r


def subsets(sequence):
    result = [[]] * (2**len(sequence))
    for i,e in enumerate(sequence):
        i2, el = 2**i, [e]
        for j in xrange(i2):
            result[j+i2] = result[j] + el
    return result


def xsubsets(sequence):
    for i in xrange(2**len(sequence)):
        subset, position = [], 0
        while i:
            i, rest = divmod(i, 2)
            if rest: subset.append(sequence[position])
            position += 1
        yield subset
La seconda versione è la più veloce, la terza versione è un generatore, è molto lenta, e sfrutta l'algoritmo ovvio. Questo è un risultato per cinque elementi:
The second version is the faster one, and the third version is a generator, it's very slow, and it uses the obvious algorithm. This is an output for five elements:

[[], [0], [1], [0, 1], [2], [0, 2], [1, 2], [0, 1, 2], [3], [0, 3], [1, 3], [0, 1, 3], [2, 3], [0, 2, 3], [1, 2, 3], [0, 1, 2, 3], [4], [0, 4], [1, 4], [0, 1, 4], [2, 4], [0, 2, 4], [1, 2, 4], [0, 1, 2, 4], [3, 4], [0, 3, 4], [1, 3, 4], [0, 1, 3, 4], [2, 3, 4], [0, 2, 3, 4], [1, 2, 3, 4], [0, 1, 2, 3, 4]]

 

Accesso a Excel su Windows - Excel use

Codice trovato online:

from win32com.client import Dispatch

xlApp = Dispatch("Excel.Application")
xlApp.Visible = 1
xlApp.Workbooks.Add()
xlApp.ActiveSheet.Cells(1,1).Value = 'Something'
xlApp.ActiveWorkbook.ActiveSheet.Cells(1,2).Value = 'Something else'
# xlApp.Close(SaveChanges=0)
xlApp.Quit()
del xlApp

 

Somma sottoliste con sum() - Sublist join with sum()

>>> alist = [[1,2,3], [4,5], [6,7]]
>>> sum(alist, [])
[1, 2, 3, 4, 5, 6, 7]

 

Filtraggio stringhe - String filtering

>>> filter(str.islower, "aAKrUa")
'ara'

Si può vedere che filter applicato su una stringa restituisce una stringa e non una lista, e che come funzione di filtraggio si possono passare anche metodi stringa, dato che in genere i metodi possono venire usati anche così:
It can be seen that filter applied to a string gives a string as output, and not a list; and that as filter function you can use a string method too, because generally methods can be used like this too:

>>> "abba".islower()
True
>>> str.islower("abba") True

Tutti questi programmini in Python - All the little Python programs: pythonmix1.zip

[Vai all'indice - Go back to index]

Pagina visitata volte dal 16 aprile 2005.