Dans l’esprit du "quel est votre extrait de code C/C++ le plus utile" - thread:
Avez-vous les gars (souvent) des extraits de Python monofonctionnels que vous utilisez (souvent) et que vous souhaitez partager avec la communauté StackOverlow? Veuillez garder les entrées petites (moins de 25 lignes .__ peut-être?) Et ne donner qu'un exemple par poste.
Je commencerai par un court extrait que j'utilise de temps en temps pour compter les sloc (lignes de code source) dans les projets Python:
# prints recursive count of lines of python source code from current directory
# includes an ignore_list. also prints total sloc
import os
cur_path = os.getcwd()
ignore_set = set(["__init__.py", "count_sourcelines.py"])
loclist = []
for pydir, _, pyfiles in os.walk(cur_path):
for pyfile in pyfiles:
if pyfile.endswith(".py") and pyfile not in ignore_set:
totalpath = os.path.join(pydir, pyfile)
loclist.append( ( len(open(totalpath, "r").read().splitlines()),
totalpath.split(cur_path)[1]) )
for linenumbercount, filename in loclist:
print "%05d lines in %s" % (linenumbercount, filename)
print "\nTotal: %s lines (%s)" %(sum([x[0] for x in loclist]), cur_path)
Initialiser une liste 2D
Bien que cela puisse être fait en toute sécurité pour initialiser une liste:
lst = [0] * 3
Le même truc ne fonctionnera pas pour une liste 2D (liste de listes):
>>> lst_2d = [[0] * 3] * 3
>>> lst_2d
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> lst_2d[0][0] = 5
>>> lst_2d
[[5, 0, 0], [5, 0, 0], [5, 0, 0]]
L'opérateur * duplique ses opérandes et les listes dupliquées construites avec [] pointent sur la même liste. La bonne façon de faire est:
>>> lst_2d = [[0] * 3 for i in xrange(3)]
>>> lst_2d
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> lst_2d[0][0] = 5
>>> lst_2d
[[5, 0, 0], [0, 0, 0], [0, 0, 0]]
J'aime utiliser any
et un générateur:
if any(pred(x.item) for x in sequence):
...
au lieu d'un code écrit comme ceci:
found = False
for x in sequence:
if pred(x.n):
found = True
if found:
...
J'ai d'abord appris cette technique d'un article de Peter Norvig article .
Le seul "truc" que je connaisse qui m'a vraiment séduit quand j'ai appris qu'il s'agissait d'énumérer. Il vous permet d’avoir accès aux index des éléments d’une boucle for.
>>> l = ['a','b','c','d','e','f']
>>> for (index,value) in enumerate(l):
... print index, value
...
0 a
1 b
2 c
3 d
4 e
5 f
Zip(*iterable)
transpose un itérable.
>>> a=[[1,2,3],[4,5,6]]
>>> Zip(*a)
[(1, 4), (2, 5), (3, 6)]
C'est aussi utile avec les dict.
>>> d={"a":1,"b":2,"c":3}
>>> Zip(*d.iteritems())
[('a', 'c', 'b'), (1, 3, 2)]
Lancez un simple serveur Web pour les fichiers du répertoire en cours:
python -m SimpleHTTPServer
Utile pour partager des fichiers.
Une "barre de progression" qui ressemble à:
|#############################---------------------|
59 percent done
Code:
class ProgressBar():
def __init__(self, width=50):
self.pointer = 0
self.width = width
def __call__(self,x):
# x in percent
self.pointer = int(self.width*(x/100.0))
return "|" + "#"*self.pointer + "-"*(self.width-self.pointer)+\
"|\n %d percent done" % int(x)
Fonction de test (pour le système Windows, remplacez "clear" par "CLS"):
if __== '__main__':
import time, os
pb = ProgressBar()
for i in range(101):
os.system('clear')
print pb(i)
time.sleep(0.1)
Pour aplatir une liste de listes, telles que
[['a', 'b'], ['c'], ['d', 'e', 'f']]
dans
['a', 'b', 'c', 'd', 'e', 'f']
utilisation
[inner
for outer in the_list
for inner in outer]
Grande accélération pour la liste imbriquée et les dictionnaires avec:
deepcopy = lambda x: cPickle.loads(cPickle.dumps(x))
Supposons que vous ayez une liste d'éléments et que vous souhaitiez un dictionnaire avec ces éléments comme clés. Utilisez des clés:
>>> items = ['a', 'b', 'c', 'd']
>>> idict = dict().fromkeys(items, 0)
>>> idict
{'a': 0, 'c': 0, 'b': 0, 'd': 0}
>>>
Le deuxième argument de fromkeys est la valeur à attribuer à toutes les clés nouvellement créées.
Pour savoir si la ligne est vide (c'est-à-dire si la taille est 0 ou ne contient que des espaces), utilisez la bandelette de méthode de chaîne dans une condition, comme suit:
if not line.strip(): # if line is empty
continue # skip it
J'aime celui-ci pour tout compresser dans un répertoire. Hotkey it pour instabackups!
import zipfile
z = zipfile.ZipFile('my-archive.Zip', 'w', zipfile.Zip_DEFLATED)
startdir = "/home/johnf"
for dirpath, dirnames, filenames in os.walk(startdir):
for filename in filenames:
z.write(os.path.join(dirpath, filename))
z.close()
Pour les compréhensions de liste nécessitant une mise à jour, ensuite:
[fun(curr,next)
for curr,next
in Zip(list,list[1:].append(None))
if condition(curr,next)]
Pour la liste circulaire Zip(list,list[1:].append(list[0]))
.
Pour précédent, actuel: Zip([None].extend(list[:-1]),list)
circular: Zip([list[-1]].extend(list[:-1]),list)
Fichiers Hardlink identiques dans le répertoire en cours (sous Unix, cela signifie qu'ils ont un stockage physique partagé, ce qui signifie beaucoup moins d'espace):
import os
import hashlib
dupes = {}
for path, dirs, files in os.walk(os.getcwd()):
for file in files:
filename = os.path.join(path, file)
hash = hashlib.sha1(open(filename).read()).hexdigest()
if hash in dupes:
print 'linking "%s" -> "%s"' % (dupes[hash], filename)
os.rename(filename, filename + '.bak')
try:
os.link(dupes[hash], filename)
os.unlink(filename + '.bak')
except:
os.rename(filename + '.bak', filename)
finally:
else:
dupes[hash] = filename
En voici quelques-unes qui, à mon avis, méritent d’être connues mais qui pourraient ne pas être utiles au quotidien . La plupart d’entre elles sont une seule ligne.
Supprimer les doublons d'une liste
L = list(set(L))
Obtenir les entiers d'une chaîne (espace séparé)
ints = [int(x) for x in S.split()]
Trouver Factorial
fac=lambda(n):reduce(int.__mul__,range(1,n+1),1)
Trouver le plus grand commun diviseur
>>> def gcd(a,b):
... while(b):a,b=b,a%b
... return a
comme une autre personne ci-dessus, j'ai dit 'Wooww !!' quand j'ai découvert enumerate ()
J'ai chanté un éloge à Python quand j'ai découvert repr () qui m'a donné la possibilité de voir précisément le contenu des chaînes que je voulais analyser avec une regex
J'étais très satisfait de découvrir que print '\n'.join(list_of_strings)
est affiché beaucoup plus rapidement avec '\ n'.join (...) que for ch in list_of_strings: print ch
splitlines (1) avec un argument garde les nouvelles lignes
Ces quatre "astuces" combinées dans un extrait sont très utiles pour afficher rapidement le code source d'une page Web, ligne après ligne, chaque ligne étant numérotée, tous les caractères spéciaux comme '\ t' ou les nouvelles lignes n'étant pas interprétés, et avec les nouvelles lignes. présent:
import urllib
from time import clock,sleep
sock = urllib.urlopen('http://docs.python.org/')
ch = sock.read()
sock.close()
te = clock()
for i,line in enumerate(ch.splitlines(1)):
print str(i) + ' ' + repr(line)
t1 = clock() - te
print "\n\nIn 3 seconds, I will print the same content, using '\\n'.join(....)\n"
sleep(3)
te = clock()
# here's the point of interest:
print '\n'.join(str(i) + ' ' + repr(line)
for i,line in enumerate(ch.splitlines(1)) )
t2 = clock() - te
print '\n'
print 'first display took',t1,'seconds'
print 'second display took',t2,'seconds'
Avec mon ordinateur pas très rapide, j'ai eu:
first display took 4.94626048841 seconds
second display took 0.109297410704 seconds
import tempfile
import cPickle
class DiskFifo:
"""A disk based FIFO which can be iterated, appended and extended in an interleaved way"""
def __init__(self):
self.fd = tempfile.TemporaryFile()
self.wpos = 0
self.rpos = 0
self.pickler = cPickle.Pickler(self.fd)
self.unpickler = cPickle.Unpickler(self.fd)
self.size = 0
def __len__(self):
return self.size
def extend(self, sequence):
map(self.append, sequence)
def append(self, x):
self.fd.seek(self.wpos)
self.pickler.clear_memo()
self.pickler.dump(x)
self.wpos = self.fd.tell()
self.size = self.size + 1
def next(self):
try:
self.fd.seek(self.rpos)
x = self.unpickler.load()
self.rpos = self.fd.tell()
return x
except EOFError:
raise StopIteration
def __iter__(self):
self.rpos = 0
return self
Emulation d'une instruction switch. Par exemple, switch (x) {..}:
def a():
print "a"
def b():
print "b"
def default():
print "default"
apply({1:a, 2:b}.get(x, default))
En fait, je viens de créer cela, mais je pense que ce sera un outil de débogage très utile.
def dirValues(instance, all=False):
retVal = {}
for prop in dir(instance):
if not all and prop[1] == "_":
continue
retVal[prop] = getattr(instance, prop)
return retVal
J'utilise habituellement dir () dans un contexte pdb, mais je pense que cela sera beaucoup plus utile:
(pdb) from pprint import pprint as pp
(pdb) from myUtils import dirValues
(pdb) pp(dirValues(someInstance))
Une liste personnalisée qui, multipliée par une autre liste, retourne un produit cartésien ... La bonne chose est que le produit cartésien est indexable, pas comme celui de itertools.product (mais les multiplicandes doivent être des séquences, pas des itérateurs).
import operator
class mylist(list):
def __getitem__(self, args):
if type(args) is Tuple:
return [list.__getitem__(self, i) for i in args]
else:
return list.__getitem__(self, args)
def __mul__(self, args):
seqattrs = ("__getitem__", "__iter__", "__len__")
if all(hasattr(args, i) for i in seqattrs):
return cartesian_product(self, args)
else:
return list.__mul__(self, args)
def __imul__(self, args):
return __mul__(self, args)
def __rmul__(self, args):
return __mul__(args, self)
def __pow__(self, n):
return cartesian_product(*((self,)*n))
def __rpow__(self, n):
return cartesian_product(*((self,)*n))
class cartesian_product:
def __init__(self, *args):
self.elements = args
def __len__(self):
return reduce(operator.mul, map(len, self.elements))
def __getitem__(self, n):
return [e[i] for e, i in Zip(self.elements,self.get_indices(n))]
def get_indices(self, n):
sizes = map(len, self.elements)
tmp = [0]*len(sizes)
i = -1
for w in reversed(sizes):
tmp[i] = n % w
n /= w
i -= 1
return tmp
def __add__(self, arg):
return mylist(map(None, self)+mylist(map(None, arg)))
def __imul__(self, args):
return mylist(self)*mylist(args)
def __rmul__(self, args):
return mylist(args)*mylist(self)
def __mul__(self, args):
if isinstance(args, cartesian_product):
return cartesian_product(*(self.elements+args.elements))
else:
return cartesian_product(*(self.elements+(args,)))
def __iter__(self):
for i in xrange(len(self)):
yield self[i]
def __str__(self):
return "[" + ",".join(str(i) for i in self) +"]"
def __repr__(self):
return "*".join(map(repr, self.elements))
Pour Python 2.4+ ou une version antérieure:
for x,y in someIterator:
listDict.setdefault(x,[]).append(y)
En Python 2.5+, il existe une alternative utilisant defaultdict .
Parcourez tous les éléments itérables (liste, ensemble, fichier, flux, chaînes de caractères, peu importe), de N'IMPORTE QUELLE taille (y compris la taille inconnue), par morceaux de x éléments:
from itertools import chain, islice
def chunks(iterable, size, format=iter):
it = iter(iterable)
while True:
yield format(chain((it.next(),), islice(it, size - 1)))
>>> l = ["a", "b", "c", "d", "e", "f", "g"]
>>> for chunk in chunks(l, 3, Tuple):
... print chunk
...
("a", "b", "c")
("d", "e", "f")
("g",)
Lors du débogage, vous souhaitez parfois voir une chaîne avec un éditeur de base. Pour afficher une chaîne avec le bloc-notes:
import os, tempfile, subprocess
def get_Rand_filename(dir_=os.getcwd()):
"Function returns a non-existent random filename."
return tempfile.mkstemp('.tmp', '', dir_)[1]
def open_with_notepad(s):
"Function gets a string and shows it on notepad"
with open(get_Rand_filename(), 'w') as f:
f.write(s)
subprocess.Popen(['notepad', f.name])