Короткие (и полезные) фрагменты питона
В духе существующего вашего наиболее полезного фрагмента C/С++ - поток:
У вас есть короткие, монофункциональные фрагменты Python, которые вы используете (часто), и хотели бы поделиться с сообществом StackOverlow? Пожалуйста, храните записи небольшими (до 25
строки могут быть?) и дать только один пример за сообщение.
Я начну с короткого фрагмента, который я использую время от времени для подсчета sloc (исходных строк кода) в проектах 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)
Ответы
Ответ 1
Инициализация 2D-списка
Хотя это можно сделать безопасно для инициализации списка:
lst = [0] * 3
Тот же трюк не будет работать для 2D-списка (список списков):
>>> 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]]
Оператор * дублирует свои операнды, а дублированные списки, построенные с [], указывают на тот же список. Правильный способ сделать это:
>>> 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]]
Ответ 2
Мне нравится использовать any
и генератор:
if any(pred(x.item) for x in sequence):
...
вместо кода, написанного следующим образом:
found = False
for x in sequence:
if pred(x.n):
found = True
if found:
...
Я впервые узнал об этом методе из статьи .
Ответ 3
Единственный "трюк", который я знаю, действительно поразил меня, когда я узнал, что это перечисление. Он позволяет получить доступ к индексам элементов в цикле 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
Ответ 4
Запустите простой веб-сервер для файлов в текущем каталоге:
python -m SimpleHTTPServer
Полезно для обмена файлами.
Ответ 5
zip(*iterable)
переносит итерацию.
>>> a=[[1,2,3],[4,5,6]]
>>> zip(*a)
[(1, 4), (2, 5), (3, 6)]
Это также полезно с dicts.
>>> d={"a":1,"b":2,"c":3}
>>> zip(*d.iteritems())
[('a', 'c', 'b'), (1, 3, 2)]
Ответ 6
Чтобы сгладить список списков, например
[['a', 'b'], ['c'], ['d', 'e', 'f']]
в
['a', 'b', 'c', 'd', 'e', 'f']
использование
[inner
for outer in the_list
for inner in outer]
Ответ 7
Огромное ускорение для вложенного списка и словарей с помощью:
deepcopy = lambda x: cPickle.loads(cPickle.dumps(x))
Ответ 8
A "индикатор выполнения", который выглядит следующим образом:
|#############################---------------------|
59 percent done
код:
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)
Функция тестирования (для системы Windows измените "очистить" на "CLS" ):
if __name__ == '__main__':
import time, os
pb = ProgressBar()
for i in range(101):
os.system('clear')
print pb(i)
time.sleep(0.1)
Ответ 9
Предположим, что у вас есть список элементов, и вы хотите использовать словарь с этими элементами в качестве ключей. Использовать из клавиш:
>>> items = ['a', 'b', 'c', 'd']
>>> idict = dict().fromkeys(items, 0)
>>> idict
{'a': 0, 'c': 0, 'b': 0, 'd': 0}
>>>
Второй аргумент fromkeys - это значение, предоставляемое всем вновь созданным клавишам.
Ответ 10
Чтобы узнать, является ли строка пустой (т.е. размер 0 или содержит только пробелы), используйте строковый метод в условии:
if not line.strip(): # if line is empty
continue # skip it
Ответ 11
Мне нравится этот, чтобы закрепить все в каталоге. Горячая клавиша для 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()
Ответ 12
Для просмотра списка, требующего текущего, next:
[fun(curr,next)
for curr,next
in zip(list,list[1:].append(None))
if condition(curr,next)]
Для кругового списка zip(list,list[1:].append(list[0]))
.
Для предыдущего, current: zip([None].extend(list[:-1]),list)
circle: zip([list[-1]].extend(list[:-1]),list)
Ответ 13
Жесткие файлы идентичны в текущем каталоге (в unix, это означает, что у них есть общий физический накопитель, что означает гораздо меньше места):
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
Ответ 14
Вот несколько, которые, я думаю, стоит знать, но могут не быть полезными на повседневной основе.
Большинство из них - один лайнер.
Удаление дубликатов из списка
L = list(set(L))
Получение целых чисел из строки (разделенной пробелами)
ints = [int(x) for x in S.split()]
Поиск факториала
fac=lambda(n):reduce(int.__mul__,range(1,n+1),1)
Поиск наибольшего общего делителя
>>> def gcd(a,b):
... while(b):a,b=b,a%b
... return a
Ответ 15
Эмуляция оператора switch. Например, переключатель (x) {..}:
def a():
print "a"
def b():
print "b"
def default():
print "default"
apply({1:a, 2:b}.get(x, default))
Ответ 16
-
как другой человек выше, я сказал "Wow"! когда я обнаружил enumerate()
-
Я похвалил Python, когда обнаружил repr(), что дало мне возможность точно увидеть содержимое строк, которые я хотел проанализировать с помощью регулярного выражения
-
Мне было очень приятно узнать, что print '\n'.join(list_of_strings)
отображается гораздо быстрее с '\n'.join(...), чем for ch in list_of_strings: print ch
-
splitlines (1) с аргументом сохраняет символы новой строки
Эти четыре "трюка", объединенные в один фрагмент, очень полезны для быстрого отображения источника кода веб-страницы, строки после строки, каждой строки, пронумерованной, все специальные символы, такие как "\ t" или новые строки, не интерпретируются, и с новыми символами:
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 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'
С моим не очень быстрым компьютером я получил:
first display took 4.94626048841 seconds
second display took 0.109297410704 seconds
Ответ 17
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
Ответ 18
Для Python 2.4+ или более ранних версий:
for x,y in someIterator:
listDict.setdefault(x,[]).append(y)
В Python 2.5+ есть альтернатива, используя defaultdict.
Ответ 19
Пользовательский список, который при умножении на другой список возвращает декартово произведение... хорошо, что декартово произведение индексируется, а не как произведение itertools.product(но мультипликаторы должны быть последовательностями, а не итераторами).
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))
Ответ 20
Итерации по любому итерируемому (список, набор, файл, поток, строки и т.д.) ЛЮБОГО размера (включая неизвестный размер) кусками элементов x:
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",)
Ответ 21
Я на самом деле просто создал это, но я думаю, что это будет очень полезный инструмент для отладки.
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
Я обычно использую dir() в контексте pdb, но я думаю, что это будет намного полезнее:
(pdb) from pprint import pprint as pp
(pdb) from myUtils import dirValues
(pdb) pp(dirValues(someInstance))
Ответ 22
При отладке вы иногда хотите увидеть строку с основным редактором. Для отображения строки с помощью блокнота:
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])