Какие менее известные, но полезные функции языка программирования Python?
.get по умолчанию для словаряimport this__missing__ товаров.pth файлыtry/except/elseprint()with





Основные сообщения :)
import this
# btw look at this module's source :)
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Есть идеи, почему источник был зашифрован таким образом? Это было просто для развлечения или была какая-то другая причина?
способ написания источника идет вразрез с дзеном!
Было бы легче понять, если бы вместо 65 он использовал ord ("A"), ord ("a") вместо 97 и ord ("z") - ord ("a") вместо 26. Остальное просто шифр Цезаря по 13 (AKA ROT13). Но на самом деле было бы более питонично использовать метод str.translate :-p
Я обновил свой /usr/lib/python2.6/this.py, заменив старый код этим print s.translate("".join(chr(64<i<91 and 65+(i-52)%26 or 96<i<123 and 97+(i-84)%26 or i) for i in range(256))), и теперь он выглядит намного лучше !! :-D
год, это называется иронией. (причина, почему они это сделали)
@MiniQuark: краткий урок истории: wefearchange.org/2010/06/import-this-and-zen-of-python.html
Я на днях нашел эту историю import this. Достаточно интересно: wefearchange.org/2010/06/import-this-and-zen-of-python.html
@ Дэн: Черт. Я не видел вашего комментария до сих пор.
Я думаю, что источник был замаскирован, чтобы замаскировать коммит, поэтому пасхальное яйцо действительно будет сюрпризом даже для людей, просматривающих коммиты.
Составьте список
Сравните более традиционные (без понимания списка):
foo = []
for x in xrange(10):
if x % 2 == 0:
foo.append(x)
к:
foo = [x for x in xrange(10) if x % 2 == 0]
Каким образом понимание списков является функцией скрытый Python?
Они, вероятно, «спрятаны» для бывших программистов на C и Java, которые раньше не видели таких возможностей, не думайте их искать и игнорируйте, если они увидят это в учебнике. OTOH программист на Haskell это сразу заметит.
Вопрос действительно требует «пример и краткое описание функции, а не просто ссылку на документацию». Есть ли шанс добавить один?
Понимание списков было реализовано Грегом Юингом, который был постдоком на факультете, где они преподавали функциональное программирование в работе первого года обучения.
Если бы это была скрытая функция python, сегодня на python было бы написано на 40% больше строк кода.
Мне потребовалось возраст, чтобы найти понимание списков в Python. Конечно, сейчас без них жить не могу ...
+1 Думаю, стоит упомянуть и о вложенных списках: stackoverflow.com/questions/1198777/…
Метаклассы
конечно :-) Что такое метакласс в Python?
Специальные методы
Это моя любимая вещь в Python. Я особенно операторы перегрузки люблю. ИМХО object1.add(object2) всегда должен быть object1 + object2.
Я воспринимаю object1.add () как деструктивную операцию, а + как операцию, возвращающую результат без изменения object1.
Создание объектов-генераторов
Если вы напишете
x=(n for n in foo if bar(n))
вы можете достать генератор и назначить его x. Теперь это означает, что ты можешь сделать
for n in x:
Преимущество этого в том, что вам не нужно промежуточное хранилище, которое вам понадобилось бы, если бы вы
x = [n for n in foo if bar(n)]
В некоторых случаях это может привести к значительному ускорению.
Вы можете добавить множество операторов if в конец генератора, в основном реплицируя вложенные циклы for:
>>> n = ((a,b) for a in range(0,2) for b in range(4,6))
>>> for i in n:
... print i
(0, 4)
(0, 5)
(1, 4)
(1, 5)
Вы также можете использовать для этого понимание вложенного списка, да?
Особо следует отметить экономию на накладных расходах памяти. Значения вычисляются по запросу, поэтому у вас никогда не будет в памяти полного результата понимания списка. Это особенно желательно, если позже вы перебираете только часть понимания списка.
Я использую ifilter для таких вещей: docs.python.org/library/itertools.html#itertools.ifilter
Это не особо "скрытый" imo, но также стоит отметить тот факт, что вы не можете перематывать объект генератора, тогда как вы можете повторять по списку любое количество раз.
то же подозревает. Хотя это очень круто, это задокументированная функция Python docs.python.org/tutorial/classes.html. Использование обратных вызовов с вашими генераторами, также задокументированное, делает генераторы более крутыми. python.org/dev/peps/pep-0255
Функция генераторов «без перемотки» может вызвать некоторую путаницу. В частности, если вы распечатываете содержимое генератора для отладки, а затем используете его позже для обработки данных, это не сработает. Данные производятся, потребляются print () и становятся недоступными для нормальной обработки. Это не относится к составным спискам, поскольку они полностью хранятся в памяти.
Аналогичный (дубли?) Ответ: stackoverflow.com/questions/101268/hidden-features-of-python /… Обратите внимание, однако, что в ответе, который я здесь связал, упоминается ДЕЙСТВИТЕЛЬНО ХОРОШАЯ презентация о мощности генераторов. Тебе действительно стоит это проверить.
Вот хорошая статья об использовании генератора для решения реальных проблем dabeaz.com/generators/Generators.pdf
Декораторы
Декораторы позволяет заключить функцию или метод в другую функцию, которая может добавлять функциональные возможности, изменять аргументы или результаты и т. д. Вы пишете декораторы на одну строку над определением функции, начиная со знака «at» (@).
В примере показан декоратор print_args, который печатает аргументы декорированной функции перед ее вызовом:
>>> def print_args(function):
>>> def wrapper(*args, **kwargs):
>>> print 'Arguments:', args, kwargs
>>> return function(*args, **kwargs)
>>> return wrapper
>>> @print_args
>>> def write(text):
>>> print text
>>> write('foo')
Arguments: ('foo',) {}
foo
При определении декораторов я бы рекомендовал украсить декоратор @decorator. Он создает декоратор, который сохраняет сигнатуру функции при интроспекции. Подробнее здесь: phyast.pitt.edu/~micheles/python/documentation.html
Как это скрытая функция?
Что ж, его нет в большинстве простых руководств по Python, и я наткнулся на него спустя долгое время после того, как начал использовать Python. Это то, что я бы назвал скрытой функцией, примерно такой же, как и другие популярные сообщения здесь.
vetler, вопросы касаются «менее известных, но полезных функций языка программирования Python». Как вы оцениваете «менее известные, но полезные функции»? Я имею в виду, какие из этих ответов скрыты?
@vetler Большинство вещей здесь вряд ли "спрятано".
Скрытый? это задокументированная функция python.org/dev/peps/pep-0318
Если стандарт заключается в том, задокументирована ли функция, то этот вопрос следует закрыть.
Я думал, что мы должны перечислить скрытые функции python, а не удивительные возможности python. ;-)
почему это может быть полезно, кроме очень редких ситуаций? Почему бы просто не переопределить функцию и не добавить необязательные параметры?
@Dexter: потому что этот декоратор может быть универсальным - его можно на короткое время прикрепить к любой функции, например когда нужно его отладить, то очень легко удаляется. Кроме того, декораторы могут использоваться не только для отладки.
Украсить декоратора декоратором-декоратором? Мы должны пойти глубже.
Что касается полезных (спорных), то несколько более распространенных: @ property, @ classmethod, @ staticmethod, @ coroutine, @ _o (monocle)
Декораторы чрезвычайно удобны, но они могут быть PITA для написания. Существует так много вариантов - на основе классов и не на основе классов, декораторы, которые могут украшать методы и функции (или и то, и другое), добавлять дескрипторы, декораторы, принимающие аргументы, и т. д. Таким образом, хотя приведенный выше простой пример не может быть «скрытой» функцией Python, я бы сказал, считайте его отправной точкой для изучения довольно сложной темы языка, и он должен быть в списке.
Читаемые регулярные выражения
В Python вы можете разбить регулярное выражение на несколько строк, назвать совпадения и вставить комментарии.
Пример подробного синтаксиса (из Погрузитесь в Python):
>>> pattern = """
... ^ # beginning of string
... M{0,4} # thousands - 0 to 4 M's
... (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
... # or 500-800 (D, followed by 0 to 3 C's)
... (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
... # or 50-80 (L, followed by 0 to 3 X's)
... (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
... # or 5-8 (V, followed by 0 to 3 I's)
... $ # end of string
... """
>>> re.search(pattern, 'M', re.VERBOSE)
Пример совпадения имен (из Регулярное выражение HOWTO)
>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'
Вы также можете подробно написать регулярное выражение без использования re.VERBOSE благодаря конкатенации строковых литералов.
>>> pattern = (
... "^" # beginning of string
... "M{0,4}" # thousands - 0 to 4 M's
... "(CM|CD|D?C{0,3})" # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
... # or 500-800 (D, followed by 0 to 3 C's)
... "(XC|XL|L?X{0,3})" # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
... # or 50-80 (L, followed by 0 to 3 X's)
... "(IX|IV|V?I{0,3})" # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
... # or 5-8 (V, followed by 0 to 3 I's)
... "$" # end of string
... )
>>> print pattern
"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"
Я не знаю, действительно ли я считаю, что это функция Python, у большинства двигателей RE есть подробный вариант.
Да, но поскольку вы не можете сделать это в grep или в большинстве редакторов, многие люди не знают, что это там есть. Тот факт, что у других языков есть эквивалентная функция, не делает ее бесполезной и малоизвестной функцией python.
В большом проекте с множеством оптимизированных регулярных выражений (читай: оптимизированных для машин, но не для людей) я укусил пулю и преобразовал все их в подробный синтаксис. Теперь знакомить с проектами новых разработчиков стало намного проще. С этого момента мы применяем подробные RE для каждого проекта.
Я бы предпочел просто сказать: 100 = "(CM | CD | D? C {0,3})" # 900 (CM), 400 (CD) и т. д. В языке уже есть способ давать имена объектам, способ добавления комментариев и способ объединения строк. Зачем использовать здесь специальный синтаксис библиотеки для вещей, с которыми язык уже отлично справляется? Похоже, это прямо противоречит 9-й эпиграмме Перлиса.
@Ken: регулярное выражение не всегда может быть непосредственно в источнике, его можно прочитать из настроек или файла конфигурации. Разрешение комментариев или просто дополнительных пробелов (для удобства чтения) может быть большим подспорьем.
Если вы пишете программу на Python, а ваш файл конфигурации не является Python, тогда (Йегге сказал бы, и я согласен с этим) «вы говорите обоими устами», как OO: sites.google.com/site/steveyegge2/the-emacs-problem
Отлично! При конкатенации строковых литералов комментарии анализируются как фактические.
Я начинаю свои подробные шаблоны с (?x) # Use verbose mode, который кажется более самодокументированным, чем использование re.VERBOSE на этапе компиляции. Это должны быть самые первые символы в шаблоне - без ведущих пробелов. Кроме того, при использовании подробного шаблона не забудьте указать \s или [ ] для обозначения пробелов (в зависимости от того, хотите ли вы захватить все пробелы или только пробелы). Об этом легко забыть при преобразовании стандартных шаблонов в подробные.
+1 для конкатенации строковых литералов, но -1 для Python даже с флагом re.VERBOSE, что, как мне кажется, приводит к ужасно читаемому коду.
Понятия вложенных списков и выражения генератора:
[(i,j) for i in range(3) for j in range(i) ]
((i,j) for i in range(4) for j in range(i) )
Они могут заменить огромные фрагменты кода вложенного цикла.
"for j in range (i)" - это опечатка? Обычно вам нужны фиксированные диапазоны для i и j. Если вы обращаетесь к 2-мерному массиву, вы упустите половину своих элементов.
В этом примере я не обращаюсь к каким-либо массивам. Единственная цель этого кода - показать, что выражения из внутренних диапазонов могут обращаться к выражениям из внешних. Побочный продукт - это список пар (x, y) таких, что 4> x> y> 0.
вроде как двойное интегрирование в исчислении или двойное суммирование.
Ключевой момент, который следует здесь запомнить (что мне потребовалось много времени, чтобы осознать), заключается в том, что порядок операторов for должен быть написан в том порядке, в котором они должны быть написаны в стандартном цикле for, снаружи внутрь.
Чтобы добавить к комментарию Сикоры: представьте, что вы начинаете со стека for и if с yield x внутри. Чтобы преобразовать это в выражение генератора, сначала переместите x, удалите все двоеточия (и yield) и заключите все это в круглые скобки. Вместо этого, чтобы сделать список понятным, замените внешние скобки квадратными скобками.
Замечательный комментарий, Кен, мне тоже трудно представить себе это, но любой может понять ваш комментарий.
Функции получения в операторе модуля
Функции attrgetter() и itemgetter() в модуле operator могут использоваться для создания функций быстрого доступа для использования при сортировке и поиске объектов и словарей.
Глава 6.7 в документации библиотеки Python
Этот ответ заслуживает хороших примеров, например, в сочетании с map().
Отправка значений в функции генератора. Например, имея эту функцию:
def mygen():
"""Yield 5 until something else is passed back via send()"""
a = 5
while True:
f = (yield a) #yield a and possibly get f in return
if f is not None:
a = f #store the new value
Вы можете:
>>> g = mygen()
>>> g.next()
5
>>> g.next()
5
>>> g.send(7) #we send this back to the generator
7
>>> g.next() #now it will yield 7 until we send something else
7
Согласовано. Давайте рассматривать это как неприятный пример скрытой функции Python :)
На других языках я считаю, что это волшебное устройство называется «переменной».
сопрограммы должны быть сопрограммами, и генератор тоже должен быть самим собой, без смешивания. Мега отличная ссылка, а также обсуждение и примеры по этому поводу здесь: dabeaz.com/coroutines
@finnw: пример реализует нечто похожее на переменную. Однако эту функцию можно использовать и многими другими способами ... в отличие от переменной. Также должно быть очевидно, что аналогичная семантика может быть реализована с использованием объектов (в частности, класса, реализующего метод Python вызов).
Это слишком банальный пример для людей, которые никогда не видели (и, вероятно, не поймут) сопрограмм. Пример, который реализует скользящее среднее без риска переполнения переменной суммы, является хорошим.
Подробнее о доходности здесь: stackoverflow.com/questions/231767/…
@finnw и его сторонники, я думаю, вы неправильно поняли суть этого экзамена. Важным битом является не сохранение значения в 'a', это то, что 'mygen' действует как функция с несколькими точками входа и с возможностью приостановить выполнение на полпути и вернуть значение вызывающей стороне, но затем возобновить выполнение. позже, из той же точки, со всеми локальными переменными без изменений. Подробнее о них можно прочитать здесь en.m.wikipedia.org/wiki/Coroutine
Возможность замены даже таких вещей, как удаление файла, открытие файла и т. д. - прямое управление языковой библиотекой. Это огромное преимущество, когда тестирование. Вам не нужно все упаковывать в сложные контейнеры. Просто замените функцию / метод и вперед. Это также называется обезьяна-патч..
Создание тестовой оснастки, которая предоставляет классы с теми же интерфейсами, что и объекты, которыми будет управлять тестируемый код (субъекты нашего тестирования), называется «Mocking» (они называются «Mock Classes», а их экземпляры - «Имитация объектов»).
>>> x=[1,1,2,'a','a',3]
>>> y = [ _x for _x in x if not _x in locals()['_[1]'] ]
>>> y
[1, 2, 'a', 3]
"locals () ['_ [1]']" - это "секретное имя" создаваемого списка. Очень полезно, когда состояние создаваемого списка влияет на последующие решения по сборке.
Фу. Это «имя» списка результатов зависит от слишком многих факторов, поэтому его нельзя рассматривать больше, чем злоупотребление конкретной реализацией (и специфической для конкретной версии для загрузки). Кроме того, это алгоритм O (n ^ 2). Фу.
Что ж, по крайней мере, никто не будет утверждать, что это не спрятано.
Аргумент шага в операторах среза. Например:
a = [1,2,3,4,5]
>>> a[::2] # iterate over the whole list in 2-increments
[1,3,5]
Особый случай x[::-1] - полезная идиома для «x, перевернутый».
>>> a[::-1]
[5,4,3,2,1]
На мой взгляд, гораздо понятнее функция reversed (). >>> список (обратный (диапазон (4))) [3, 2, 1, 0]
тогда как лучше написать "this i a string" [:: - 1]? перевернутый, похоже, не помогает
"" .join (обратное ("это строка"))
Проблема с reversed () заключается в том, что он возвращает итератор, поэтому, если вы хотите сохранить тип обратной последовательности (кортеж, строка, список, юникод, типы пользователей ...), вам понадобится дополнительный шаг для его обратного преобразования. .
def reverse_string (строка): строка возврата [:: - 1]
@pi Я думаю, что если кто-то знает достаточно, чтобы определить reverse_string, как у вас, то можно оставить [:: - 1] в своем коде и быть довольным его значением и ощущением, что оно уместно.
Есть ли разница в скорости между [::-1] и reversed()?
-1, потому что он не скрыт и вы узнаете его достаточно рано, но это полезная функция
ох, заметил, что [1,2,3,4,5][::-2] тоже работает как положено, что довольно круто
С его помощью вы можете сделать крутой поисковик палиндрома!
@Berry list (перевернутый ('бла-бла'))
@Austin: да, со строками огромная разница: pastebin.com/ZV6cHYhP
@Trufa: да, очень легко найти палиндром: если someseq == (someseq[::-1]), то это палиндром, и он будет работать с любым типом последовательности (строки, списки и т. д.).
Неявная конкатенация:
>>> print "Hello " "World"
Hello World
Полезно, если вы хотите уместить длинный текст в несколько строк в скрипте:
hello = "Greaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Hello " \
"Word"
или же
hello = ("Greaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Hello "
"Word")
Чтобы длинный текст умещался в несколько строк, можно также использовать тройные кавычки.
Ваш пример неверен и вводит в заблуждение. После его запуска часть «Слово» не будет в конце строки приветствия. Он не будет объединяться. Чтобы продолжить на следующей строке, вам потребуется неявное продолжение строки и конкатенация строк, и это произойдет только в том случае, если вы используете какой-либо разделитель, например () или [].
Неправильно только одно: табуляция перед словом (опечатка). Более того, вы действительно недружелюбны, особенно по отношению к тем, кто даже не нашел времени, чтобы проверить, работает ли это (поскольку вы бы это видели). Вы можете прочитать это: steve.yegge.googlepages.com/bambi-meets-godzilla
Любой, кто когда-либо забывал запятую в списке строк, знает, насколько зла эта «особенность».
Что ж, для того, чтобы избавиться от этого, Гвидо решил оставить его себе. Думаю, это больше полезно, чем ненавистно. На самом деле недостатки не так опасны (нет проблем с безопасностью), и для длинных струн это очень помогает.
Это, наверное, моя любимая функция Python. Вы можете забыть правильный синтаксис, но он останется правильным.
даже лучше: hello = "Greaaaaa Привет \ <представь, что здесь разрыв строки> Мир"
Я всегда пишу + в конце строки (хотя я все еще использую неявное продолжение строки в круглых скобках). Это просто упрощает чтение.
Вы можете использовать свойство, чтобы сделать интерфейсы вашего класса более строгими.
class C(object):
def __init__(self, foo, bar):
self.foo = foo # read-write property
self.bar = bar # simple attribute
def _set_foo(self, value):
self._foo = value
def _get_foo(self):
return self._foo
def _del_foo(self):
del self._foo
# any of fget, fset, fdel and doc are optional,
# so you can make a write-only and/or delete-only property.
foo = property(fget = _get_foo, fset = _set_foo,
fdel = _del_foo, doc = 'Hello, I am foo!')
class D(C):
def _get_foo(self):
return self._foo * 2
def _set_foo(self, value):
self._foo = value / 2
foo = property(fget = _get_foo, fset = _set_foo,
fdel = C.foo.fdel, doc = C.foo.__doc__)
В Python 2.6 и 3.0:
class C(object):
def __init__(self, foo, bar):
self.foo = foo # read-write property
self.bar = bar # simple attribute
@property
def foo(self):
'''Hello, I am foo!'''
return self._foo
@foo.setter
def foo(self, value):
self._foo = value
@foo.deleter
def foo(self):
del self._foo
class D(C):
@C.foo.getter
def foo(self):
return self._foo * 2
@foo.setter
def foo(self, value):
self._foo = value / 2
Чтобы узнать больше о том, как работает собственность, обратитесь к дескрипторы.
Было бы хорошо, если бы ваши примеры до 2.6 и ваши 2.6 и 3.0 на самом деле представляли одно и то же: имя класса другое, есть комментарии в версии до 2.6, версии 2.6 и 3.0 не содержат кода инициализации.
>>> x = 5
>>> 1 < x < 10
True
>>> 10 < x < 20
False
>>> x < 10 < x*10 < 100
True
>>> 10 > x <= 9
True
>>> 5 == x > 4
True
Если вы думаете, что он делает 1 < x, который получается как True, а затем сравнивает True < 10, который также является True, тогда нет, это действительно не то, что происходит (см. Последний пример). Это действительно переводится в 1 < x and x < 10 и x < 10 and 10 < x * 10 and x*10 < 100, но с меньшим набором текста, и каждый термин оценивается только один раз.
10 > x <= 9 - это не то же самое, что x <= 9 (то есть игнорировать перегруженные операторы)
Конечно. Это был просто пример смешивания разных операторов.
Это очень полезно. Он должен быть стандартным для всех языков. К сожалению, это не так.
вам следует добавить несколько примеров, которые также возвращают false. например >>> 10 <x <20 False
Это применимо и к другим операторам сравнения, поэтому люди иногда удивляются, почему код вроде (5 в [5] имеет значение True) имеет значение False (но для начала явно не проверять такие логические значения).
Они действительно должны быть на всех языках, я полностью согласен.
В Лиспе нет ничего похожего?
Не то, что я знаю о. Однако в Perl 6 есть такая возможность :)
Хорошо, но следите за равным приоритетом, например in и =. «A в B == C в D» означает «(A в B) и (B == C) и (C в D)», что может быть неожиданным.
Азафе: Сравнение Лиспа естественно работает таким образом. Это не особый случай, потому что другого (разумного) способа интерпретировать (< 1 x 10) нет. Вы даже можете применить их к отдельным аргументам, например (= 10): cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/…
@Miles менее запутанным примером может быть «a == b в c», что эквивалентно «a == b и b в c». См. docs.python.org/reference/expressions.html#notin
@Charles Merriam для меня это не неожиданно, просто логично. Хотя использовать A in B == C in D некрасиво.
Это также отлично подходит для тестов. Вы можете выполнить a == b == c, и он вернет True, только если все три элемента равны.
is not и not in тоже на удивление хороши. Очевидно is not - это бинарный оператор 1, а не бинарный, а затем унарный. not in тоже самое. Это делает код вроде 'foo' is not 'bar' более читабельным.
Кен: Мне нравится версия Python больше, чем версия Lisp, поскольку она позволяет смешивать разные виды сравнений, такие как a <= b <c. Mathematica, которая больше или является диалектом Lisp, действительно позволяет вам использовать разные сравнения - она использует то, что было бы в синтаксисе Lisp (неравенство a '<= b' <c).
Все динамично
«Нет времени компиляции». Все в Python - это среда выполнения. Модуль «определяется» путем выполнения исходного кода модуля сверху вниз, как и сценарий, а результирующее пространство имен является пространством атрибутов модуля. Точно так же класс «определяется» путем выполнения тела класса сверху вниз, а результирующее пространство имен является пространством атрибутов класса. Тело класса может содержать полностью произвольный код, включая операторы импорта, циклы и другие операторы класса. Создать класс, функцию или даже модуль «динамически», как иногда просят, несложно; на самом деле избежать этого невозможно, поскольку все «динамично».
Это дает Python замечательную функцию reload ().
Все динамично ... За исключением классов и модулей, реализованных на C, которые не так динамичны, как все остальное. (попробуйте что-то вроде dict.x = 3, и Python вам не позволит)
Да, модули и типы, определенные в C, определены во время компиляции, но они по-прежнему созданный во время выполнения. Кроме того, dict.x = 3 не имеет ничего общего с динамикой, но с типом dict, который не позволяет назначать атрибуты. Вы можете создавать свои собственные классы на Python, которые этого не позволяют. Вы можете создать свой собственный тип на языке C, который это позволяет. Это не связано.
Как это скрытая функция?
Я часто это слышу, но это не совсем так. Когда вы импортируете модуль, все сразу компилируется. Если где-либо в модуле есть какие-либо синтаксические ошибки, ничего не будет выполнено. Большая разница между Python и более традиционно компилируемыми языками заключается в том, что определения классов и функций - это операторы, которые выполняются во время выполнения (и, следовательно, их можно пропустить с помощью операторов if и исключений, произвольно вложенных и т. д.).
Повторное поднятие исключений:
# Python 2 syntax
try:
some_operation()
except SomeError, e:
if is_fatal(e):
raise
handle_nonfatal(e)
# Python 3 syntax
try:
some_operation()
except SomeError as e:
if is_fatal(e):
raise
handle_nonfatal(e)
Оператор Raise без аргументов внутри обработчика ошибок сообщает Python, что нужно повторно вызвать исключение с оригинальной трассировкой нетронутой, позволяя вам сказать: «О, извините, извините, я не хотел это уловить, извините, извините».
Если вы хотите распечатать, сохранить или поиграть с исходной трассировкой, вы можете получить ее с помощью sys.exc_info (), а печать ее, как это сделал бы Python, выполняется с помощью модуля «трассировки».
Извините, но это хорошо известная и общая черта почти для всех языков.
Обратите внимание на текст, выделенный курсивом. Некоторые люди вместо этого будут использовать raise e, который не сохраняет исходную трассировку.
Возможно, более волшебный, exc_info = sys.exc_info(); raise exc_info[0], exc_info[1], exc_info[2] эквивалентен этому, но вы можете изменить эти значения (например, изменить тип исключения или сообщение)
@Lucas S. Ну, я этого не знал и рад, что здесь написано.
Возможно, я показываю здесь свою молодость, но я всегда без проблем использовал синтаксис Python 3 в Python 2.7.
Синтаксис Python 3 также работает в 2.6 и 2.7, да.
Замена значений на месте
>>> a = 10
>>> b = 5
>>> a, b
(10, 5)
>>> a, b = b, a
>>> a, b
(5, 10)
Правая часть присваивания - это выражение, которое создает новый кортеж. Левая часть присваивания немедленно распаковывает этот (без ссылки) кортеж на имена a и b.
После присвоения новый кортеж не имеет ссылки и помечается для сборки мусора, а значения, привязанные к a и b, меняются местами.
Как отмечено в Раздел учебника Python по структурам данных,
Note that multiple assignment is really just a combination of tuple packing and sequence unpacking.
Использует ли это больше реальной памяти, чем традиционный способ? Я бы предположил, что это так, поскольку вы создаете кортеж, а не только одну переменную подкачки
Он не использует больше памяти. Он использует меньше ... Я просто написал это в обоих направлениях и декомпилировал байт-код ... компилятор оптимизирует, как вы и надеетесь. Результаты показали, что он настраивает вары, а затем ROT_TWOing. ROT_TWO означает «поменять местами две самые верхние вары стека» ... На самом деле, довольно шикарно.
Вы также непреднамеренно указываете на еще одну приятную особенность Python, заключающуюся в том, что вы можете неявно создать кортеж из элементов, просто разделив их запятыми.
Я бы предпочел (a, b) = (b, a). Я не думаю, что обязательно ясно, какой приоритет имеет , или =.
Дана Разумный: присвоение в Python - это оператор, а не выражение, поэтому это выражение было бы недействительным, если бы = имело более высокий приоритет (т.е. оно интерпретировалось как a, (b = b), a).
royal: он действительно создавал кортежи в более старых версиях Python (я думаю, до 2.4).
Это наименее скрытая функция, которую я здесь читал. Красиво, но подробно описано в каждом руководстве по Python.
Мне нравится эта функция, но мы должны быть осторожны с семантикой обмениваемых объектов. Меня укусили, когда я делал foo[x:y], bar[x:y] = bar[x:y], foo[x:y], когда foo и bar были массивами numpy, потому что нарезка массивов numpy создает представления, а не копии данных!
Они - волшебство целого ряда основных функций Python.
Когда вы используете точечный доступ для поиска члена (например, x.y), Python сначала ищет член в словаре экземпляра. Если он не найден, он ищет его в словаре классов. Если он находит его в словаре классов и объект реализует протокол дескриптора, вместо того, чтобы просто возвращать его, Python выполняет его. Дескриптор - это любой класс, реализующий методы __get__, __set__ или __delete__.
Вот как можно реализовать свою собственную (только для чтения) версию свойства с использованием дескрипторов:
class Property(object):
def __init__(self, fget):
self.fget = fget
def __get__(self, obj, type):
if obj is None:
return self
return self.fget(obj)
и вы бы использовали его так же, как встроенное свойство ():
class MyClass(object):
@Property
def foo(self):
return "Foo!"
Дескрипторы используются в Python, среди прочего, для реализации свойств, связанных методов, статических методов, методов класса и слотов. Их понимание позволяет легко понять, почему многие вещи, которые раньше выглядели как «причуды» Python, являются такими, какие они есть.
У Раймонда Хеттингера есть отличный учебник, который описывает их гораздо лучше, чем я.
Это же дубликат декораторов, не правда ли !? (stackoverflow.com/questions/101268/…)
нет, декораторы и дескрипторы - это совершенно разные вещи, хотя в примере кода я создаю декоратор дескриптора. :)
Другой способ сделать это - использовать лямбду: foo = property(lambda self: self.__foo).
@PetePeterson Да, но сам property реализован с помощью дескрипторов, о чем я и писал.
Пример взят из документации Python:
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
If the result is small enough to fit in an int, return an int.
Else return a long.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
def _test():
import doctest
doctest.testmod()
if __name__ == "__main__":
_test()
Доктесты - это, конечно, круто, но мне действительно не нравится вся эта чушь, которую нужно набирать, чтобы проверить, должно ли что-то вызывать исключение
Доктесты переоценены и загрязняют документацию. Как часто вы тестируете автономную функцию без setUp ()?
кто сказал, что у вас не может быть настройки в доктесте? напишите функцию, которая генерирует контекст и возвращает locals(), а затем в вашем doctest do locals().update(setUp()) = D
Это удобно для того, чтобы убедиться, что примеры в строках документации не рассинхронизируются.
Если автономная функция требует setUp, велики шансы, что ее следует отделить от каких-либо несвязанных вещей или поместить в класс. Затем пространство имен doctest класса можно повторно использовать в doctests метода класса, так что оно немного похоже на setUp, только DRY и читаемое.
«Как часто вы тестируете автономную функцию» - много. Я считаю, что документы часто возникают естественным образом в процессе проектирования, когда я выбираю фасады.
Doctest сложно использовать с некоторыми модулями и фреймворками, такими как Django. Обычно использование Doctest затрудняется тем, что какая-то часть дизайна API является тяжелой, чрезмерно связанной с другими компонентами или имеет много зависимостей. Doctest имеет некоторые проблемы и ограничения, но большую часть времени я чувствую, что API, затрудняющее использование Doctest, является более сложным, чем это необходимо.
Я думаю, что доктесты неправильно называют. Они действительно полезны, если рассматривать их как небольшие примеры использования, с гарантией их выполнения.
Я никогда не понимал смысла doctest-ов: если у вас есть фрагмент кода, который проверяет функцию, поместите его в соответствующий модульный тест.
iter () может принимать вызываемый аргумент
Например:
def seek_next_line(f):
for c in iter(lambda: f.read(1),'\n'):
pass
Функция iter(callable, until_value) многократно вызывает callable и возвращает результат до тех пор, пока не будет возвращен until_value.
Как новичок в Python, не могли бы вы объяснить, почему здесь необходимо ключевое слово lambda?
@SiegeX без лямбда, f.read (1) будет оцениваться (возвращая строку) перед передачей в функцию iter. Вместо этого лямбда создает анонимную функцию и передает ее iter.
Слишком ленив, чтобы инициализировать каждое поле в словаре? Без проблем:
В Python> 2.3:
from collections import defaultdict
В Python <= 2.3:
def defaultdict(type_):
class Dict(dict):
def __getitem__(self, key):
return self.setdefault(key, type_())
return Dict()
В любой версии:
d = defaultdict(list)
for stuff in lots_of_stuff:
d[stuff.name].append(stuff)
Обновлено:
Спасибо Кен Арнольд. Я повторно реализовал более сложную версию defaultdict. Он должен вести себя точно так же, как тот, что в стандартной библиотеке.
def defaultdict(default_factory, *args, **kw):
class defaultdict(dict):
def __missing__(self, key):
if default_factory is None:
raise KeyError(key)
return self.setdefault(key, default_factory())
def __getitem__(self, key):
try:
return dict.__getitem__(self, key)
except KeyError:
return self.__missing__(key)
return defaultdict(*args, **kw)
Возможно, вам будет интересно узнать о collections.defaultdict (list).
Спасибо. Однако не работает в моей производственной среде. Python 2.3.
Осторожно, повторная реализация defaultdict приводит к вызову type_ при каждом поиске, а не только при отсутствии элемента.
До python 2.2 вы не могли создать подкласс dict напрямую, поэтому вам нужно было создать подкласс от UserDict.UserDict. Лучше бы еще было обновиться.
Интерпретатор Python
>>>
Возможно, не менее известная, но, безусловно, одна из моих любимых функций Python.
Причина №1, по которой Python лучше всего остального. </fanboi>
Все остальное вы видели. </smuglispweenie>
И у него также есть iPython, который намного лучше, чем интерпретатор по умолчанию.
Хотел бы я использовать iPython как SLIME во всей красе
Первоклассные функции
На самом деле это не скрытая функция, но тот факт, что функции являются объектами первого класса, просто великолепен. Вы можете передавать их, как любую другую переменную.
>>> def jim(phrase):
... return 'Jim says, "%s".' % phrase
>>> def say_something(person, phrase):
... print person(phrase)
>>> say_something(jim, 'hey guys')
'Jim says, "hey guys".'
Это также делает создание обратного вызова и перехвата (и, следовательно, создание плагина для ваших скриптов Python) настолько тривиальным, что вы можете даже не знать, что делаете это.
Любой язык, в котором нет функций первого класса (или, по крайней мере, какой-либо хорошей замены, например указатели функций C), является ошибкой. Обойтись без него совершенно невыносимо.
Это может быть более глупый вопрос, чем я предполагал, но разве это не указатель на функцию? Или я это перепутал?
@ InspectorG4dget: это, безусловно, связано с указателями на функции, поскольку может выполнять все те же задачи, но оно немного более общее, более мощное и интуитивно понятное. Особенно мощно, если вы объедините это с тем фактом, что функции могут иметь атрибуты, или тем фактом, что экземпляры определенных классов могут быть вызваны, но это начинает становиться непонятным.
>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"
что в точности совпадает с
>>> class NewType(object):
>>> x = "hello"
>>> n = NewType()
>>> n.x
"hello"
Наверное, не самое полезное, но это приятно знать.
Редактировать: фиксированное имя нового типа, должно быть NewType, чтобы совпадать с оператором class.
Редактировать: название изменено для более точного описания функции.
Это имеет большой потенциал для полезности, например, JIT ORM.
Я использую его для создания классов HTML-форм на основе динамического ввода. Очень хорошо!
Я также использовал его для создания динамических форм django (пока не обнаружил наборы форм)
Примечание: все классы создаются во время выполнения. Таким образом, вы можете использовать оператор class в условном выражении или внутри функции (очень полезно для создания семейств классов или классов, которые действуют как замыкания). Улучшение, которое приносит "тип", - это возможность аккуратно определять динамически генерируемый набор атрибутов (или баз).
Чрезвычайно полезно в Django для создания динамических моделей, которые обертывают существующие наборы таблиц схожими структурами.
Вы также можете создавать анонимные типы с пустой строкой, например: type ('', (object,), {'x': 'blah'})
Может быть очень полезно для инъекций кода.
Вы также можете создать экземпляр этого класса в одной строке. x = type("X", (object,), {'val':'Hello'})()
Чередование if и for в понимании списков
>>> [(x, y) for x in range(4) if x % 2 == 1 for y in range(4)]
[(1, 0), (1, 1), (1, 2), (1, 3), (3, 0), (3, 1), (3, 2), (3, 3)]
Я никогда не осознавал этого, пока не изучил Haskell.
способ круто. docs.python.org/tutorial/…
Не так уж и круто, у вас просто понимание списка с двумя циклами for. Что в этом такого удивительного?
@Olivier: между двумя циклами for есть if.
@Torsten: ну, понимание списка уже включает в себя for .. if, так что же такого интересного? Можно написать: [x for i in range(10) if i%2 for j in range(10) if j%2], ничего особо крутого и интересного. Если в середине вашего примера не имеет ничего общего со вторым for.
Мне было интересно, есть ли способ сделать это с помощью else? [ a for (a, b) in zip(lista, listb) if a == b else: '-' ]
в [ _ for _ in _ if _ ] фильтр if для приведенного выше примера должен быть [ _ if _ else _ for _ ].
Менеджеры контекста и заявление "with"
Представленный в PEP 343, менеджер контекста - это объект, который действует как контекст времени выполнения для набора операторов.
Поскольку функция использует новые ключевые слова, она вводится постепенно: она доступна в Python 2.5 через директиву __future__. В Python 2.6 и выше (включая Python 3) он доступен по умолчанию.
Я много использовал заявление "с", потому что считаю это очень полезной конструкцией, вот небольшая демонстрация:
from __future__ import with_statement
with open('foo.txt', 'w') as f:
f.write('hello!')
За кулисами здесь происходит то, что заявление "с" вызывает специальные методы __enter__ и __exit__ для файлового объекта. Детали исключения также передаются в __exit__, если какое-либо исключение было вызвано из тела оператора with, что позволяет обрабатывать исключения там.
Что это значит для вас в данном конкретном случае, так это то, что он гарантирует, что файл будет закрыт, когда выполнение выходит за рамки набора with, независимо от того, происходит ли это нормально или было вызвано исключение. По сути, это способ абстрагироваться от общего кода обработки исключений.
Другие распространенные варианты использования включают блокировку с помощью потоков и транзакций базы данных.
Я бы не одобрил обзор кода, который импортировал бы что-либо из будущее. Эти функции скорее милые, чем полезные, и обычно они просто сбивают с толку новичков в Python.
Да, такие «милые» функции, как вложенные области видимости и генераторы, лучше оставить тем, кто знает, что делает. И всем, кто хочет быть совместимым с будущими версиями Python. Для вложенных областей видимости и генераторов «будущие версии» Python означают 2.2 и 2.5 соответственно. Для оператора with «будущие версии» Python означают 2.6.
Это может быть само собой разумеющимся, но с python v2.6 + вам больше не нужно импортировать из будущее. with теперь является ключевым словом первого класса.
В 2.7 может быть несколько withs :) with open('filea') as filea and open('fileb') as fileb: ...
@Austin, я не мог заставить этот синтаксис работать на 2.7. это, однако, сработало: with open('filea') as filea, open('fileb') as fileb: ...
Было бы полезно объяснить, почему и в каких случаях этот оператор with отличается от f = open('foo.txt', 'w').
Некоторые из фаворитов встроенный, map (), reduce () и filter (). Все очень быстро и мощно.
Будьте осторожны с reduce (). Если вы не будете осторожны, вы можете писать очень медленные сокращения.
И будьте осторожны с map (), она устарела в версии 2.6 и удалена в версии 3.0.
Понимание списков может достичь всего, что вы можете сделать с любой из этих функций.
Он также может запутать код Python, если вы злоупотребляете им.
@sil: map все еще существует в Python 3, как и filter, и reduce существует как functools.reduce.
@recursive: я не хочу, чтобы вы создали выражение понимания / генератора списка, которое выполняет действие reduce()
Правильное утверждение: «reduce() может достичь всего, что вы можете делать с map(), filter() или списком понимания».
Распаковка аргументов функции
Вы можете распаковать список или словарь в качестве аргументов функции, используя * и **.
Например:
def draw_point(x, y):
# do some magic
point_foo = (3, 4)
point_bar = {'y': 3, 'x': 2}
draw_point(*point_foo)
draw_point(**point_bar)
Очень полезный ярлык, поскольку списки, кортежи и словари широко используются в качестве контейнеров.
Используй это все время, люби это.
* также известен как оператор splat
Мне нравится эта функция, но, к сожалению, pylint нет.
Совет Пилинта - это не закон. Другой способ - apply (callable, arg_seq, arg_map) - устарел, начиная с 2.3.
Совет pylint может и не быть законом, но это чертовски хороший совет. Отладка кода, чрезмерно увлекающегося подобными вещами, - настоящий ад. Как отмечается на оригинальном плакате, это полезный ярлык.
Однажды я видел, как это использовалось в коде, и подумал, что он делает. К сожалению, поиск в Google "Python **" затруднен.
Это называется оператором splat. Таким образом, вы можете найти в Google "python splat", но вряд ли кто-то узнает имя, если он не знает эту функцию :-p
@andrew: Pylint имеет тенденцию жаловаться на множество классических идиом, таких как try / except ImportError
@ e-satis: это потому, что многие из этих «классических идиом» - плохая практика. Я согласен с тем, что Pylint может быть излишне «придирчивым», но в подавляющем большинстве случаев, если у вас нет явной причины не придерживаться его рекомендаций, лучше всего подчиниться (а в случаях, когда у вас есть веская причина, вы всегда можете сделать pylint-disable для подавления предупреждения в конкретном случае)
@ Адам: не поймите меня неправильно, у меня на самом деле запускается pylint каждый раз, когда мой документ сохраняется автоматически. но ошибка Try / except действительно полезна. Понимание словаря тоже, а pylint их не понимает. Pylint обычно много жалуется в модульном тестировании, если вы устанавливаете переменные без их использования, потому что на самом деле этого требует тест. Важно не впадать в психику с предупреждениями о pylint, иначе вы просто перестанете кодировать. И использование * или ** на самом деле является чистым кодом, а не грязным.
Странно, у меня никогда не было Pylint жаловаться на понимание слов, и я использую их все время. Большинство предупреждений модульного теста связано с тем, что модуль unittest не совместим с PEP-8 (например: принудительно присвоить методу настройки имя «setUp» вместо «set_up»). Но да, я согласен, что Пилинт может быть (скажем так) временами чрезмерно усердным. Что я делаю, так это каждый раз, когда я добавляю директиву disable-pylint, я сопровождаю ее комментарием, оправдывающим ее использование. Я считаю, что это хорошо работает, и несколько раз моя команда бросала мне вызов, и в конце концов я нашел лучший способ что-то сделать.
Если pylint жалуется на понимание dict, значит, он работает под управлением python 2.6 (версия, встроенная в vim). Чтобы исправить это, запустите pylint с помощью 2.7 (что для меня в OSX означало, что мне пришлось самому скомпилировать macvim tartley.com/?p=1355, но на других платформах я Думаю, существуют бинарные файлы vim с поддержкой 2.7. Для этого вам нужно установить 2.7, macvim его использует.
Да, предупреждение pylint о "** magic" глупо и может быть отключено глобально.
В словарях есть метод get (). Если вы сделаете d ['key'], а ключа там нет, вы получите исключение. Если вы сделаете d.get ('key'), вы вернетесь None, если 'key' там нет. Вы можете добавить второй аргумент, чтобы вернуть этот элемент вместо None, например: d.get ('key', 0).
Он отлично подходит для таких вещей, как сложение чисел:
sum[value] = sum.get(value, 0) + 1
также проверьте метод setdefault.
также класс checkout collections.defaultdict.
Если вы используете Python 2.7 или новее, или 3.1 или новее, проверьте класс Counter в модуле коллекций. docs.python.org/library/collections.html#collections.Counter
Ой, все это время я занимался get(key, None). Не имел понятия, что None предоставляется по умолчанию.
Если вы используете exec в функции, правила поиска переменных кардинально меняются. Замыкания больше невозможны, но Python допускает произвольные идентификаторы в функции. Это дает вам "изменяемые locals ()" и может использоваться для импорта идентификаторов звездочкой. С другой стороны, это замедляет каждый поиск, потому что переменные попадают в dict, а не в слоты во фрейме:
>>> def f():
... exec "a = 42"
... return a
...
>>> def g():
... a = 42
... return a
...
>>> import dis
>>> dis.dis(f)
2 0 LOAD_CONST 1 ('a = 42')
3 LOAD_CONST 0 (None)
6 DUP_TOP
7 EXEC_STMT
3 8 LOAD_NAME 0 (a)
11 RETURN_VALUE
>>> dis.dis(g)
2 0 LOAD_CONST 1 (42)
3 STORE_FAST 0 (a)
3 6 LOAD_FAST 0 (a)
9 RETURN_VALUE
Просто для придирки: это относится только к голому exec. Если вы укажете пространство имен для использования, например, "d = {}; exec" a = 42 "in d", этого не произойдет.
Начиная с версии 2.5 в dicts есть специальный метод __missing__, который вызывается для недостающих элементов:
>>> class MyDict(dict):
... def __missing__(self, key):
... self[key] = rv = []
... return rv
...
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}
В collections также есть подкласс dict, называемый defaultdict, который делает почти то же самое, но вызывает функцию без аргументов для несуществующих элементов:
>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}
Я рекомендую преобразовывать такие диктовки в обычные, прежде чем передавать их функциям, которые не ожидают таких подклассов. Многие коды используют d[a_key] и перехватывают KeyErrors, чтобы проверить, существует ли элемент, который добавит новый элемент в dict.
Сюда я кладу вилочные бомбы.
Я предпочитаю использовать setdefault. m = {}; m.setdefault ('фу', 1)
@grayger имел в виду именно m = {}; m.setdefault('foo', []).append(1).
Однако есть случаи, когда передача defaultdict очень удобна. Функция может, например, перебирать значение, и она работает для неопределенных ключей без дополнительного кода, поскольку по умолчанию это пустой список.
defaultdict в некоторых случаях лучше, чем setdefault, поскольку он не создает объект по умолчанию пока не, ключ отсутствует. setdefault создает его независимо от того, отсутствует он или нет. Если ваш объект по умолчанию требует больших затрат на создание, это может снизить производительность - я получил приличное ускорение одной программы, просто изменив все вызовы setdefault.
defaultdict также более мощный, чем метод setdefault в других случаях. Например, для счетчика - dd = collections.defaultdict(int) ... dd[k] += 1 против d.setdefault(k, 0) += 1.
Если вы используете дескрипторы в своих классах, Python полностью обходит __dict__ для этого ключа, что делает его удобным местом для хранения таких значений:
>>> class User(object):
... def _get_username(self):
... return self.__dict__['username']
... def _set_username(self, value):
... print 'username set'
... self.__dict__['username'] = value
... username = property(_get_username, _set_username)
... del _get_username, _set_username
...
>>> u = User()
>>> u.username = "foo"
username set
>>> u.__dict__
{'username': 'foo'}
Это помогает поддерживать dir() в чистоте.
Если вам не нравится использовать пробелы для обозначения областей действия, вы можете использовать стиль C {}, выполнив:
from __future__ import braces
Это зло. :)
>>> from __future__ импортировать фигурные скобки Файл "<stdin>", строка 1 SyntaxError: не шанс: P
Подождите, а разве будущий пакет не является будущим дополнением к языку? Планируют ли они когда-нибудь добавить фигурные скобки?
Динамические пробелы - половина достоинств Python. Это ... искажено.
это кощунство!
Я думаю, что здесь может быть синтаксическая ошибка, не должна ли она быть "из фигурных скобок импорта __прошлый__"?
из __cruft__ импортировать фигурные скобки
Признаюсь, это забавно, но, наоборот, что насчет слепых? Я помню, как некоторое время назад читал человека, который был слеп и разочарован тем, что он / она не может использовать Python из-за отсутствия скобок для утверждений.
Я могу понять использование фигурных скобок для минификации кода :)
Полностью нарушает идиому Python
@ Дэвид: Чем брекеты лучше для слепых? В лучшем случае (код с хорошим отступом, который обеспечивает Python) фигурные скобки добавят лишь крохотной ясности. На мой взгляд, гораздо легче заметить блок текста с пробелами раньше, чем наличие небольшого типографского символа. Разборчивость фигурных скобок зависит от того, в какую версию OTBS верит этот человек. Встроенные фигурные скобки, которые я предпочитаю, было бы ужасно читать без надлежащего зрения.
@Alex: Как читатель текста определяет уровень отступа? Вам понадобится программа для чтения текста Python, которая сообщит вам: «для <stuff> двоеточие, переход новой строки, переходите новую строку <следующий оператор>». Теперь добавьте несколько отступов: «indent indent indent для <stuff> двоеточие newline indent indent indent indent pass newline indent indent indent <следующий оператор>»
jmucchiello: Да, вам нужно что-то специфичное для Python. Программа чтения с экрана должна произносить токены, которые использует интерпретатор Python, «намерение в», «отступ».
@David, @jmucchiello: есть скрипт, который добавляет фигурные скобки к каждому блоку в комментарии (# }), и на самом деле я читал о слепых людях, которые используют его, чтобы позволить им писать Python :)
@David, @jmucchiello: Ах, вы имели в виду слепых, а не просто «ужасно плохое зрение» - слепых.
Я знаю нескольких разработчиков, изучающих Python (но знающих язык стиля c), которым это понравится. Просто потому, что они ничего не знают;)
Слепой программист может использовать этот синтаксис: python.org/doc/humor/…
Действительно странная особенность. Реквизит для того, чтобы поделиться первым, о чем я не знал, когда читал эту ветку.
Мне сняли брекеты, когда я выросла!
Существует пирамиды, кодировка, которую вы можете использовать для файлов исходного кода Python, чтобы действительно включить фигурные скобки. ;)
Это чертовски пасхальное яйцо. Я люблю сообщества oss ...
__slots__ - хороший способ сэкономить память, но очень сложно определить значения объекта. Представьте себе следующий объект:
class Point(object):
__slots__ = ('x', 'y')
Теперь у этого объекта, очевидно, есть два атрибута. Теперь мы можем создать его экземпляр и построить его следующим образом:
>>> p = Point()
>>> p.x = 3
>>> p.y = 5
>>> dict((k, getattr(p, k)) for k in p.__slots__)
{'y': 5, 'x': 3}
Однако это не сработает, если точка была разделена на подклассы и были добавлены новые слоты. Однако Python автоматически реализует __reduce_ex__, чтобы помочь модулю copy. Этим можно злоупотребить, чтобы получить диктат ценностей:
>>> p.__reduce_ex__(2)[2][1]
{'y': 5, 'x': 3}
Ого, мне это может пригодиться!
Помните, что __reduce_ex__ можно переопределить в подклассах, и, поскольку он также используется для травления, это часто бывает. (Если вы создаете контейнеры данных, вам следует подумать об их использовании! Или это младшие братья и сестры __getstate__ и __setstate__.)
Тогда вы все еще можете использовать object.__reduce_ex__(p, 2)[2][1].
Расширенная операция нарезки Python имеет малоизвестный элемент синтаксиса - многоточие:
>>> class C(object):
... def __getitem__(self, item):
... return item
...
>>> C()[1:2, ..., 3]
(slice(1, 2, None), Ellipsis, 3)
К сожалению, это практически бесполезно, поскольку многоточие поддерживается только в том случае, если используются кортежи.
см. stackoverflow.com/questions/118370/… для получения дополнительной информации
На самом деле многоточие весьма полезно при работе с многомерными массивами из модуля numpy.
Предполагается, что это будет более полезно в Python 3, где многоточие станет буквальным. (Попробуйте, вы можете ввести ... в интерпретаторе Python 3, и он вернет Eillipsis)
Встроенные методы или функции не реализуют протокол дескриптора, что делает невозможным выполнение таких действий:
>>> class C(object):
... id = id
...
>>> C().id()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: id() takes exactly one argument (0 given)
Однако вы можете создать небольшой дескриптор привязки, который сделает это возможным:
>>> from types import MethodType
>>> class bind(object):
... def __init__(self, callable):
... self.callable = callable
... def __get__(self, obj, type=None):
... if obj is None:
... return self
... return MethodType(self.callable, obj, type)
...
>>> class C(object):
... id = bind(id)
...
>>> C().id()
7414064
Проще и проще сделать это как свойство, в данном случае: class C (object): id = property (id)
лямбда также является хорошей альтернативой: class C(object): id = lambda s, *a, **kw: id(*a, **kw); и лучшая версия привязки: def bind(callable): return lambda s, *a, **kw: callable(*a, **kw)
% -форматирование требует словаря (также применяется проверка% i /% s и т. д.).
>>> print "The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42}
The answer is 42.
>>> foo, bar = 'question', 123
>>> print "The %(foo)s is %(bar)i." % locals()
The question is 123.
А поскольку locals () также является словарем, вы можете просто передать его как dict и получить% -подстановки из ваших локальных переменных. Я думаю, что это не одобряется, но все упрощает ...
Форматирование нового стиля
>>> print("The {foo} is {bar}".format(foo='answer', bar=42))
Будет прекращено и в конечном итоге заменено методом строки format ().
Именованное форматирование очень полезно для переводчиков, поскольку они обычно видят строку формата без имен переменных для контекста.
По-видимому, работает в python 3.0.1 (необходимо добавить круглые скобки вокруг вызова печати).
а хэш, а? Я вижу, откуда ты.
% -форматирование не исчезнет в ближайшее время, но метод "форматирования" строк - это новый (текущий) метод передового опыта. Он поддерживает все, что делает% -форматирование, и большинство людей думают, что API и синтаксис форматирования намного лучше. (Я включен.) В Python есть третий метод, string.Template, добавленный в версии 2.4; в основном это никому не нравится.
Форматирование% s не будет прекращено. str.format (), безусловно, более питоничен, но на самом деле в 10 раз медленнее для простой замены строки. Я считаю, что форматирование% s по-прежнему является лучшей практикой.
Для полноты картины locals()-эквивалентом для форматирования нового стиля, конечно же, является print "The {foo} is {bar}".format(**locals()).
Мне нравится locals (), но у него есть неприятный побочный эффект: если вы используете pylint, вы часто будете получать ошибки из-за того, что не используете переменную в области видимости функции.
В Python 3.2 эквивалентом locals() является print("The {foo} is {bar}".format_map(locals())).
Этот формат медленнее, его можно исправить. В конце концов, он делает то же самое, что и% форматирование. И в 3.1.3 time он дает мне следующие измерения скорости: >>> timeit('''"a %(b)s" % {"b": "c"}''') 0.2503829002380371 >>> timeit('''"a {b}".format(b = "c")''') 0.41667699813842773
Эй, @matt, непонятно, против какого формата вы рекомендуете, и особенно неясно, почему.
Будьте осторожны с изменяемыми аргументами по умолчанию
>>> def foo(x=[]):
... x.append(1)
... print x
...
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]
Вместо этого вы должны использовать значение дозорного, обозначающее «не задано», и заменить его изменяемым значением по умолчанию:
>>> def foo(x=None):
... if x is None:
... x = []
... x.append(1)
... print x
>>> foo()
[1]
>>> foo()
[1]
Это определенно одна из самых неприятных скрытых функций. Время от времени я сталкивался с этим.
Мне стало намного легче понять это, когда я узнал, что аргументы по умолчанию находятся в кортеже, который является атрибутом функции, например foo.func_defaults. Которая, будучи кортежем, неизменна.
Не могли бы вы подробно объяснить, как это происходит?
@grayger: при выполнении оператора def его аргументы оцениваются интерпретатором. Это создает (или повторно связывает) имя с объектом кода (набором функции). Однако аргументы по умолчанию создаются как объекты во время определения. Это верно для любого времени объекта по умолчанию, но важно только (демонстрируя видимую семантику), когда объект является изменяемым. Невозможно повторно привязать это имя аргумента по умолчанию в закрытии функции, хотя оно, очевидно, может быть переопределено для любого вызова или вся функция может быть переопределена).
@Robert, конечно, кортеж аргументов может быть неизменным, но объекты, на которые он указывает, не обязательно неизменяемы.
Один быстрый прием, который сделает вашу инициализацию немного короче: x = x или []. Вы можете использовать это вместо 2-строчного оператора if.
Значения по умолчанию также становятся неприятными, если вы используете более одного из них. Например, вы написали такую функцию, как: <function> def f (a = [], b = [], c = []): a.append (3) </ function>. Вы случайно изменили значения a, b и c, не прикасаясь к ним. Это потому, что похожие значения по умолчанию, похоже, указывают на одно и то же в памяти. Возникают неприятные ошибки
эта особенность / бородавка или как вы бы это назвали - одна из самых важных вещей, которые нужно понять, когда вы начинаете изучать Python. он напрямую связывает вас с пониманием того, что делается в программе, и без этого знания любой код, превышающий довольно низкий порог сложности, не может быть написан.
Это похоже на ошибку в компиляторе, не так ли?
Просто замечание, что pylint сильно жалуется на такое использование, как и должно.
@davemankoff: Я считаю, что это плохая привычка, потому что рано или поздно вы по ошибке отклоните действительное ложное значение.
Это был буквально вопрос собеседования для моей нынешней работы. :) Это, наверное, классический Python то.
Распаковка кортежа:
>>> (a, (b, c), d) = [(1, 2), (3, 4), (5, 6)]
>>> a
(1, 2)
>>> b
3
>>> c, d
(4, (5, 6))
Более того, вы можете сделать это в аргументах функции (в Python 2.x; Python 3.x больше этого не допускает):
>>> def addpoints((x1, y1), (x2, y2)):
... return (x1+x2, y1+y2)
>>> addpoints((5, 0), (3, 5))
(8, 5)
Как бы то ни было, распаковка кортежей в определениях функций прекращается в python 3.0.
В основном потому, что, насколько я понимаю, это делает реализацию действительно неприятной. (Например, в inspect.getargs в стандартной библиотеке - нормальный путь (без аргументов кортежа) составляет около 10 строк, и есть около 30 дополнительных строк для обработки аргументов кортежа (которые используются только изредка).) Мне все же грустно.
Похоже, в версии 3.0: / вынимают часть батареек.
Хорошо, что они его удалили, потому что это некрасиво, и вы можете просто имитировать это, набрав: x1, x2 = x; y1, y2 = y (если у вас есть аргументы x, y)
Это позор. Я надеялся, что для остальных аргументов будет добавлена поддержка *, чтобы вы могли делать такие вещи, как a, b, * c = [1, 2, 3, 4, 5] (эквивалентно a = 1, b = 2, c = [3, 4, 5]).
@yangyang: добавлен был. Единственное, что было удалено, - это распаковка кортежей в определениях функций. Вместо этого вы просто переносите такую распаковку в первую строку реализации функции.
разархивировать ненужное в Python
Кто-то написал в блоге о том, что Python не имеет функции распаковки для zip (). unzip легко вычислить, потому что:
>>> t1 = (0,1,2,3)
>>> t2 = (7,6,5,4)
>>> [t1,t2] == zip(*zip(t1,t2))
True
Поразмыслив, я бы предпочел явную unzip ().
def unzip (x): return zip (* x) Готово!
Решение немного тонкое (я могу понять точку зрения любого, кто его спросит), но я также могу понять, почему это было бы лишним
+1. Я собирался добавить это, но, похоже, меня это опередило.
Чтобы добавить больше модулей Python (особенно сторонних), большинство людей, похоже, используют переменные среды PYTHONPATH или добавляют символические ссылки или каталоги в свои каталоги пакетов сайтов. Другой способ - использовать файлы * .pth. Вот официальное объяснение документа Python:
"The most convenient way [to modify python's search path] is to add a path configuration file to a directory that's already on Python's path, usually to the .../site-packages/ directory. Path configuration files have an extension of .pth, and each line must contain a single path that will be appended to sys.path. (Because the new paths are appended to sys.path, modules in the added directories will not override standard modules. This means you can't use this mechanism for installing fixed versions of standard modules.)"
Я никогда не устанавливал связи между этим файлом .pth в каталоге site-packages из setuptools и этой идеей. классно.
Исключение еще предложение:
try:
put_4000000000_volts_through_it(parrot)
except Voom:
print "'E's pining!"
else:
print "This parrot is no more!"
finally:
end_sketch()
Использование предложения else лучше, чем добавление дополнительного кода в предложение try, поскольку оно позволяет избежать случайного перехвата исключения, которое не было вызвано кодом, защищаемым оператором try ... except.
См. http://docs.python.org/tut/node10.html
+1 это круто. Если блок try выполняется без ввода каких-либо блоков исключений, то вводится блок else. И, конечно же, выполняется блок finally.
Наконец-то я понимаю, почему здесь «еще»! Спасибо.
Было бы разумнее использовать continue, но я думаю, он уже занят;)
Обратите внимание, что в более старых версиях Python2 у вас не может быть обоих предложений else: и finally: для одного и того же блока try:
@ Paweł Praak: Я не думаю, что это так. Поскольку continue и break относятся к циклам, и это единственный условный оператор.
@IsaacRemuant, вы правы. Может быть, что-то вроде ожидаемого или дефолта, или действия, или нормального? :)
@ Paweł Praak, как упомянул Кевин Хорн, этот синтаксис был введен после первоначального выпуска Python, и добавление новых зарезервированных ключевых слов к существующему языку всегда проблематично. Вот почему существующее ключевое слово обычно используется повторно (например, «auto» в недавнем стандарте C++).
Синтаксис for ... else (см. http://docs.python.org/ref/for.html)
for i in foo:
if i == 0:
break
else:
print("i was never 0")
Блок «else» обычно выполняется в конце цикла for, если не вызывается break.
Приведенный выше код можно эмулировать следующим образом:
found = False
for i in foo:
if i == 0:
found = True
break
if not found:
print("i was never 0")
Я думаю, что синтаксис for / else неудобен. Кажется, что предложение else должно быть выполнено, если тело цикла никогда не выполняется.
Это становится менее неудобным, если мы думаем об этом как о / if / else, где else принадлежит if. И это настолько полезная идиома, что я удивляюсь, что разработчики других языков не подумали о ней!
ах. Никогда не видел этого! Но я должен сказать, что это неправильно. Кто мог ожидать, что блок else будет выполняться только в том случае, если break никогда не выполняется? Я согласен с codeape: похоже, что else введено для пустого foos.
Я добавил эквивалентный код, не использующий else.
Я считаю это гораздо менее полезным, чем выполнение предложения else, если бы не выполнялся цикл for. Я так много раз хотел этого, но никогда не находил случая, когда бы мне хотелось это использовать.
Кто-нибудь помнит FOR var… NEXT var… END FOR var в Sinclair QL SuperBasic? Все, что находится между NEXT и END FOR, будет выполняться в конце цикла, если только не был выдан EXIT FOR. Синтаксис Который стал чище :)
похоже, что ключевое слово должно быть наконец, а не иначе
За исключением того, что finally уже используется таким образом, чтобы этот набор всегда выполнялся.
Это действительно удобно, и я им пользуюсь, но каждый раз требует поясняющего комментария.
Определенно не должно быть «else». Может быть, «then» или что-то в этом роде, а затем «else», когда цикл никогда не выполнялся.
Я использовал это в задании по программированию для класса и потерял баллы, потому что оценщик никогда не видел этого раньше ... полностью получил их обратно.
Эй, люди забыли упомянуть, что эта идиома также работает для петель while.
Я всегда думал, что конструкция for...then...else была бы лучше, где then выполняется только в случае успеха for, else, когда невозможно ввести for (например: for i in []; pass; else; print "empty list". Но тогда я новичок. :)
Работает ли это ТОЛЬКО, если в цикле for есть оператор break или есть другие обстоятельства, при которых этот трюк работает таким образом?
@ InspectorG4dget: отлично работает без перерыва ... но бесполезно, если нет перерыва. (Код в else может быть просто вытеснен на один уровень)
@jkerian: Большое спасибо. Я наблюдал за этим поведением, но меня интересовало, что такое «будет ли это работать так же, если бы вместо break использовалось return?»
я избегаю этой функции. каждый раз, когда я хочу его использовать, мне приходится его читать, а потом мне все равно трудно понять.
Да, использование этого синтаксиса заставило меня закричать парочка программистов на PHP и C. Иди разберись. :-)
Никогда не используйте for-else. Он не делает того, что думает следующий программист, который увидит ваш код.
Раньше меня тоже сбивало с толку это поведение, пока я не подумал о нем с точки зрения try.. except.. else... Поведение Python for.. else.. согласуется с тем, как выполняются блоки try. Если содержимое try или for удачно, перейдите к else.
Операторы, изменяющие поток управления (например, break), обычно являются плохим выбором для начала, объедините это с необычным использованием ключевого слова (в данном случае "else"), и вы получите код, который еще труднее читать, особенно для новичков. Я бы определенно уклонился от этого.
if any(i == 0 for i in foo): ... Я бы выбрал формулировку для такого кода. Может быть, это мое влияние на Haskell.
Многие люди не знают о функции "dir". Это отличный способ выяснить, что объект может делать из интерпретатора. Например, если вы хотите увидеть список всех строковых методов:
>>> dir("foo")
['__add__', '__class__', '__contains__', (snipped a bunch), 'title',
'translate', 'upper', 'zfill']
А затем, если вам нужна дополнительная информация о конкретном методе, вы можете вызвать по нему «помощь».
>>> help("foo".upper)
Help on built-in function upper:
upper(...)
S.upper() -> string
Return a copy of the string S converted to uppercase.
dir () необходим для разработки. Для больших модулей я улучшил его, добавив фильтрацию. См. pixelbeat.org/scripts/inpy
Вы также можете напрямую использовать help: help ('foo')
Если вы используете IPython, вы можете добавить вопросительный знак, чтобы получить справку по переменной / методу.
см .: Альтернатива Python dir (). Легко печатать; легко читать! Только для людей: github.com/inky/see
Я называю это справочные страницы python, и их также можно реализовать для работы, когда вызывается man, а не help.
@compie - see () очень удобен. Очень хорошо! Намного легче читать, чем вывод dir ()
Access Dictionary elements as attributes (properties). so if an a1=AttrDict() has key 'name' -> instead of a1['name'] we can easily access name attribute of a1 using -> a1.name
class AttrDict(dict):
def __getattr__(self, name):
if name in self:
return self[name]
raise AttributeError('%s not found' % name)
def __setattr__(self, name, value):
self[name] = value
def __delattr__(self, name):
del self[name]
person = AttrDict({'name': 'John Doe', 'age': 66})
print person['name']
print person.name
person.name = 'Frodo G'
print person.name
del person.age
print person
нет названия или объяснения? где здесь скрытая особенность?
Функция сортировки Python правильно сортирует кортежи (т. Е. Используя знакомый лексикографический порядок):
a = [(2, "b"), (1, "a"), (2, "a"), (3, "c")]
print sorted(a)
#[(1, 'a'), (2, 'a'), (2, 'b'), (3, 'c')]
Полезно, если вы хотите отсортировать список людей по возрасту, а затем по имени.
Это следствие корректной работы сравнения кортежей, т.е. (1, 2) <(1, 3).
Это полезно для кортежей версий: (1, 9) <(1, 10).
Условное присвоение
x = 3 if (y == 1) else 2
Он делает именно то, что звучит: «присвоить 3 переменной x, если y равно 1, в противном случае присвоить 2 переменной x». Обратите внимание, что скобки не обязательны, но мне они нравятся для удобства чтения. Вы также можете связать его, если у вас есть что-то более сложное:
x = 3 if (y == 1) else 2 if (y == -1) else 1
Хотя в какой-то момент это заходит слишком далеко.
Обратите внимание, что вы можете использовать if ... else в любом выражении. Например:
(func1 if y == 1 else func2)(arg1, arg2)
Здесь будет вызываться func1, если y равно 1, и func2 в противном случае. В обоих случаях соответствующая функция будет вызываться с аргументами arg1 и arg2.
Аналогично верно и следующее:
x = (class1 if y == 1 else class2)(arg1, arg2)
где class1 и class2 - два класса.
Задание - это не особая часть. Вы можете так же легко сделать что-то вроде: return 3 if (y == 1) else 2.
Другой способ сделать это: y == 1 и 3 или 2
Этот альтернативный путь чреват проблемами. Во-первых, обычно это работает: if y == 1: # 3 else if y == 70: # 2 Почему? y == 1 оценивается только, ТО y == 70, если y == 1 ложно. В этом операторе: y == 1 и 3 или 2 - 3 и 2 оцениваются так же, как y == 1.
Этот альтернативный способ - первый раз, когда я увидел запутанный Python.
Кайлбрукс: В этом случае логические операторы не замыкаются. Он будет оценивать только 2, если bool (3) == False.
это кодирование в обратном стиле сбивает меня с толку. что-то вроде x = ((y == 1) ? 3 : 2) имеет для меня больше смысла
Я чувствую полную противоположность @Mark, тернарные операторы в стиле C всегда сбивали меня с толку, правая сторона или середина оцениваются при ложном условии? Я предпочитаю тернарный синтаксис Python.
@Mark "x = (y == 1) and 3 or 2" также действителен.
Я думаю, что тернарные операторы в стиле C проще, больше похожи на английский: 'am I drunk' ? 'yes, make out with her' : 'no, dont even think about it'
x = 3 if (y == 1) else 2 - Я считаю, что во многих случаях x = (2, 3)[y==1] на самом деле более читабелен (обычно с очень длинными операторами, поэтому вы можете сохранить результаты (2, 3) вместе).
Каким-то образом Гвидо и ребятам из Python удалось сделать одну из наиболее искаженных частей языка C удобочитаемой и легко понятной, даже если вы не знаете, что это такое.
@Infinity, вам следует проконсультироваться с врачом, чтобы заменить постоянную постоянную "я пьян" недетерминированной функцией am_i_drunk ().
Когда я впервые увидел тройную операцию в Python, мне показалось, что ее трудно читать, в основном из-за моего знакомства с оператором в стиле C. Не уверен, какой из них лучше («трава мокрая, если идет дождь, иначе трава сухая» или «если идет дождь, то трава мокрая, иначе трава сухая»)
>>> (a for a in xrange(10000)) <generator object at 0x81a8fcc> >>> b = 'blah' >>> _ <generator object at 0x81a8fcc>
>>> import webbrowser
>>> webbrowser.open_new_tab('http://www.stackoverflow.com')python -m SimpleHTTPServer 8000
>>> import atexit
Почему не просто SimpleHTTPServer?
Стоит отметить, что _ доступен только в интерактивном режиме. при запуске скриптов из файла _ не имеет особого значения.
@TokenMacGuy: Фактически, вы можете определить _ как переменную в файле (на всякий случай, если вы делать захотите использовать запутанный Python).
примечание: вы также можете использовать __ для предпоследнего и ___ для третьего последнего
@asmeurer Я часто использую _ как имя для переменных, которые меня не интересуют (например, for _, desired_value, _ in my_tuple_with_some_irrelevant_values). Да, как прологер :)
__getattr __ ()
getattr - действительно хороший способ создания универсальных классов, что особенно полезно, если вы пишете API. Например, в FogBugz Python APIgetattr используется для беспрепятственной передачи вызовов методов веб-службе:
class FogBugz:
...
def __getattr__(self, name):
# Let's leave the private stuff to Python
if name.startswith("__"):
raise AttributeError("No such attribute '%s'" % name)
if not self.__handlerCache.has_key(name):
def handler(**kwargs):
return self.__makerequest(name, **kwargs)
self.__handlerCache[name] = handler
return self.__handlerCache[name]
...
Когда кто-то вызывает FogBugz.search(q='bug'), они не получают вызова метода search. Вместо этого getattr обрабатывает вызов, создавая новую функцию, которая обертывает метод makerequest, который создает соответствующий HTTP-запрос к веб-API. Любые ошибки будут отправлены веб-службой и возвращены пользователю.
Таким же образом можно создавать полу-нестандартные типы.
перечислять
Оберните итерацию с помощью enumerate, и она выдаст элемент вместе с его индексом.
Например:
>>> a = ['a', 'b', 'c', 'd', 'e']
>>> for index, item in enumerate(a): print index, item
...
0 a
1 b
2 c
3 d
4 e
>>>
Рекомендации:
Я удивлен, что это обычно не рассматривается в учебных пособиях, посвященных спискам Python.
это такая классная функция / функция
я думаю, что это устарело в python3
И все это время я кодировал так: for i in range (len (a)): ... и затем использовал [i] для получения текущего элемента.
@ Берри Цакала: Насколько мне известно, он не устарел.
короче, чем использование zip и count для индекса, элемент в zip (itertools.count (), a): print (index, item)
Отличная особенность, +1. @Draemon: это фактически описано в учебнике Python, который поставляется вместе с Python (есть раздел о различных конструкциях цикла), поэтому я всегда удивляюсь, что об этом так мало известно.
Это хорошо, когда вы выполняете итерацию более чем одного цикла одновременно.
Черт возьми, это круто. for i in xrange (len (a)): всегда была моей наименее любимой идиомой о Python.
@ Берри Цакала: определенно не рекомендуется.
Извините за мое незнание, но этого недостаточно, чтобы просто сделать: a = ["a","b","c"] >>> for x in enumerate(a): ... print x, почему вы делаете for index, item in enumerate(a): print index, item
Я всегда взламывал idx, elem in itertools.izip(itertools.count(), iterable): ...
@Tufa: возможно, вы не захотите использовать индекс и элемент в одном выражении. В этом простом примере ваш код эквивалентен, но в более сложном сценарии он не сможет делать все, что может делать for inx, itm in enumerate(a):.
for i in range(len(a)) по-прежнему намного лучше, чем for (int i=0;i<a.size();i++) ....
enumerate может начинаться с произвольного индекса, необязательно 0. Пример: 'for i, item in enumerate (список, start = 1): print i, item' начнет перечисление с 1, а не с 0.
Не устарело в Py3K docs.python.org/py3k/library/…
Тернарный оператор
>>> 'ham' if True else 'spam'
'ham'
>>> 'ham' if False else 'spam'
'spam'
Это было добавлено в 2.5, до этого вы могли использовать:
>>> True and 'ham' or 'spam'
'ham'
>>> False and 'ham' or 'spam'
'spam'
Однако, если значения, с которыми вы хотите работать, будут считаться ложными, есть разница:
>>> [] if True else 'spam'
[]
>>> True and [] or 'spam'
'spam'
До 2.5, "foo = bar and 'ham' or 'spam'"
@a платный ботаник - не совсем так: 1 == 1 и 0 или 3 => 3. И замыкает на 0 (поскольку это эквивалентно False - то же самое с "" и None).
Вы можете создать словарь из набора последовательностей длиной 2. Очень удобно, когда у вас есть список значений и список массивов.
>>> dict([ ('foo','bar'),('a',1),('b',2) ])
{'a': 1, 'b': 2, 'foo': 'bar'}
>>> names = ['Bob', 'Marie', 'Alice']
>>> ages = [23, 27, 36]
>>> dict(zip(names, ages))
{'Alice': 36, 'Bob': 23, 'Marie': 27}
self.data = {} _i = 0 для ключей в self.VDESC.split (): self.data [keys] = _data [_i] _i + = 1 Я заменил свой код этим однострочным :) self.data = dict (zip (self.VDESC.split (), _data)) Спасибо за полезный совет.
Также помогает в Python2.x, где нет синтаксиса понимания слов. Вы можете написать dict((x, x**2) for x in range(10)).
Распаковка кортежей в циклах for, составлении списков и выражениях генератора:
>>> l=[(1,2),(3,4)]
>>> [a+b for a,b in l ]
[3,7]
Полезно в этой идиоме для перебора пар (ключ, данные) в словарях:
d = { 'x':'y', 'f':'e'}
for name, value in d.items(): # one can also use iteritems()
print "name:%s, value:%s" % (name,value)
печатает:
name:x, value:y
name:f, value:e
Это также полезно при замене l на zip(something).
«Распаковка» в параметры функции
def foo(a, b, c):
print a, b, c
bar = (3, 14, 15)
foo(*bar)
При выполнении отпечатков:
3 14 15
Это каноническая альтернатива старой встроенной функции apply ().
Объекты в логическом контексте
Пустые кортежи, списки, словари, строки и многие другие объекты эквивалентны False в логическом контексте (а непустые эквивалентны True).
empty_tuple = ()
empty_list = []
empty_dict = {}
empty_string = ''
empty_set = set()
if empty_tuple or empty_list or empty_dict or empty_string or empty_set:
print 'Never happens!'
Это позволяет логическим операциям возвращать один из его операндов вместо True / False, что полезно в некоторых ситуациях:
s = t or "Default value" # s will be assigned "Default value"
# if t is false/empty/none
на самом деле это не рекомендуется, вы должны использовать «новый» s = t if t else «значение по умолчанию»
Первоклассность всего («все есть объект») и хаос, который это может вызвать.
>>> x = 5
>>> y = 10
>>>
>>> def sq(x):
... return x * x
...
>>> def plus(x):
... return x + x
...
>>> (sq,plus)[y>x](y)
20
Последняя строка создает кортеж, содержащий две функции, затем оценивает y> x (True) и использует это как индекс кортежа (путем преобразования его в int, 1), а затем вызывает эту функцию с параметром y и показывает результат.
Для дальнейшего злоупотребления, если вы возвращали объект с индексом (например, список), вы можете добавить дополнительные квадратные скобки в конце; если содержимое было вызываемым, добавляйте скобки и т. д. Для дополнительного извращения используйте результат такого кода как выражение в другом примере (т.е. замените y> x этим кодом):
(sq,plus)[y>x](y)[4](x)
Это демонстрирует два аспекта Python - философию «все есть объект», доведенную до крайности, и методы, с помощью которых неправильное или плохо продуманное использование синтаксиса языка может привести к полностью нечитаемому, не поддерживаемому спагетти-коду, который умещается в одном выражении. .
зачем тебе вообще это делать? вряд ли это обоснованная критика языка, чтобы показать, как им можно намеренно злоупотреблять. случайное злоупотребление допустимо, но никогда не произойдет случайно.
@Gorgapor: последовательность Python и отсутствие исключений и особых случаев - вот что делает его легким в изучении и, по крайней мере, для меня, красивым. Любой мощный инструмент, применяемый неправомерно, может вызвать «хаос». Вопреки вашему мнению, я считаю, что возможность индексировать последовательность функций и вызывать ее в одном выражении - это мощная и полезная идиома, и я использовал ее не раз с пояснительными комментариями.
@Don: Ваш вариант использования, индексация последовательности функций, хорош и очень полезен. Вариант использования Дэна Удей, использующий логическое значение в качестве индекса во встроенном кортеже функций, ужасен и бесполезен, который без нужды запутывается.
@Gorganpor: Извини, я хотел адресовать свой комментарий Дэну Удэю, а не тебе. Я полностью с вами согласен.
Назначение и удаление срезов:
>>> a = range(10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:5] = [42]
>>> a
[42, 5, 6, 7, 8, 9]
>>> a[:1] = range(5)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> del a[::2]
>>> a
[1, 3, 5, 7, 9]
>>> a[::2] = a[::-2]
>>> a
[9, 3, 5, 7, 1]
Примечание: при назначении расширенным слайсам (s[start:stop:step]) назначенная итерация должна иметь ту же длину, что и слайс.
Конструктор dict принимает аргументы ключевого слова:
>>> dict(foo=1, bar=2)
{'foo': 1, 'bar': 2}
Пока аргументы ключевого слова являются действительными идентификаторами (именами) Python. Вы не можете использовать: dict (1 = "one", two = 2 ...), потому что "1" не является допустимым идентификатором, даже если это совершенно допустимый ключ словаря.
Идеально подходит для копирования и обновления: base = {'a': 4, 'b': 5}; обновлено = dict (основание, c = 5)
Получите дерево синтаксического анализа регулярного выражения Python для отладки вашего регулярного выражения.
Регулярные выражения - отличная особенность Python, но их отладка может быть сложной задачей, и слишком легко ошибиться в регулярном выражении.
К счастью, python может распечатать дерево синтаксического анализа регулярных выражений, передав недокументированный экспериментальный скрытый флаг re.DEBUG (на самом деле 128) в re.compile.
>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
subpattern None
literal 61
subpattern 1
in
literal 45
literal 43
max_repeat 1 2
in
range (48, 57)
literal 93
subpattern 2
min_repeat 0 65535
any None
in
literal 47
literal 102
literal 111
literal 110
literal 116
Как только вы поймете синтаксис, вы сможете обнаружить свои ошибки. Здесь мы видим, что я забыл сбежать от [] в [/font].
Конечно, вы можете комбинировать его с любыми флагами, которые захотите, например с закомментированными регулярными выражениями:
>>> re.compile("""
^ # start of a line
\[font # the font tag
(?:=(?P<size> # optional [font=+size]
[-+][0-9]{1,2} # size specification
))?
\] # end of tag
(.*?) # text between the tags
\[/font\] # end of the tag
""", re.DEBUG|re.VERBOSE|re.DOTALL)
За исключением синтаксического анализа HTML с использованием регулярных выражений, это медленный и болезненный процесс. Даже встроенный модуль синтаксического анализатора html не использует регулярные выражения для выполнения работы. И если модуль html вам не нравится, существует множество модулей синтаксического анализатора XML / HTML, которые справятся с этой задачей без необходимости изобретать колесо.
Ссылка на документацию по синтаксису вывода была бы замечательной.
Это должна быть официальная часть Python, а не экспериментальная ... Регулярное выражение всегда сложно, и возможность отслеживать, что происходит, действительно помогает.
Встроенные кодеки base64, zlib и rot13
Строки имеют методы encode и decode. Обычно это используется для преобразования str в unicode и наоборот, например с u = s.encode('utf8'). Но есть и другие удобные встроенные кодеки. Сжатие и распаковка с помощью zlib (и bz2) доступны без явного импорта:
>>> s = 'a' * 100
>>> s.encode('zlib')
'x\x9cKL\xa4=\x00\x00zG%\xe5'
Точно так же вы можете кодировать и декодировать base64:
>>> 'Hello world'.encode('base64')
'SGVsbG8gd29ybGQ=\n'
>>> 'SGVsbG8gd29ybGQ=\n'.decode('base64')
'Hello world'
И, конечно же, можно rot13:
>>> 'Secret message'.encode('rot13')
'Frperg zrffntr'
К сожалению, это перестанет работать в Python 3
Ой, он перестанет работать? Это очень плохо :/. Я просто подумал, насколько хороша эта функция. Потом увидел твой комментарий.
Ужасно, base64 был очень полезен в интерактивных сессиях, обрабатывающих данные из Интернета.
На мой взгляд, это какой-то тип кодирования / декодирования, но с другой стороны, должен быть «только один путь к этому», и я думаю, что эти вещи лучше поместить в отдельный модуль!
Очевидно, антигравитационный модуль. xkcd # 353
Наверное, мой самый используемый модуль. После модуля души, конечно.
Что действительно работает. Попробуйте поставить "импорт антигравитации" в новейшую версию Py3K.
@ Эндрю Сзето ... что он делает?
@ Джим Роберт: открывает веб-браузер на сайт xkcd;)
модуль skynet тоже весьма полезен ...
Генераторы
Я думаю, что многие начинающие разработчики Python обходятся без генераторов, не понимая, для чего они нужны, и не осознавая их возможности. Только когда я прочитал презентацию PyCon Дэвида М. Бизли о генераторах (она доступна здесь), я понял, насколько они полезны (действительно важны). Эта презентация осветила то, что было для меня совершенно новым способом программирования, и я рекомендую его всем, кто не имеет глубокого понимания генераторов.
Ух ты! Мозг у меня сгорел, и это были только первые 6 частей. Начиная с 7, мне приходилось рисовать картинки, чтобы посмотреть, действительно ли я понимаю, что происходит с конвейерами многопроцессорной / многопоточной / многопоточной обработки. Потрясающие вещи!
+1 за ссылку на презентацию
Заполнение вкладки интерактивного переводчика
try:
import readline
except ImportError:
print "Unable to load readline module."
else:
import rlcompleter
readline.parse_and_bind("tab: complete")
>>> class myclass:
... def function(self):
... print "my function"
...
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__ class_instance.__module__
class_instance.__doc__ class_instance.function
>>> class_instance.f<TAB>unction()
Вам также нужно будет установить переменную среды PYTHONSTARTUP.
Это очень полезная функция. Настолько, что у меня есть простой скрипт для его включения (плюс пара других улучшений интроспекции): pixelbeat.org/scripts/inpy
IPython дает вам это плюс множество других полезных вещей
Это было бы более полезно в приглашении pdb, чем в обычном приглашении python (поскольку IPython в любом случае служит этой цели). Однако это, похоже, не работает в приглашении pdb, вероятно, потому, что pdb связывает свою собственную вкладку для вкладки (что менее полезно). Я попытался вызвать parse_and_bind () в командной строке pdb, но это все равно не сработало. Альтернатива получения приглашения pdb с помощью IPython требует больше работы, поэтому я стараюсь не использовать ее.
Нашел этот рецепт, но у меня это не сработало (с использованием python 2.6): code.activestate.com/recipes/498182
@haridsv - easy_install ipdb - тогда вы можете использовать import ipdb; ipdb.set_trace()
Для меня лучшим советом было использовать try: except: else :. Я забыл об остальном в блоке try
На osx [и я представляю себе другие системы, использующие libedit] вы должны использовать readline.parse_and_bind ("bind ^I rl_complete").
Python имеет GOTO
... и это реализовано внешний модуль на чистом Python :)
from goto import goto, label
for i in range(1, 10):
for j in range(1, 20):
for k in range(1, 30):
print i, j, k
if k == 3:
goto .end # breaking out from a deeply nested loop
label .end
print "Finished"
Может быть, лучше оставить эту функцию скрытой.
Что ж, фактическая скрытая функция здесь - это механизм, используемый для реализации GOTO.
Конечно, для выхода из вложенного цикла вы можете просто вызвать исключение, не так ли?
+1 первый, о котором я вообще не знал.
@shylent: исключения должны быть исключительными. По этой причине они оптимизированы для случая, когда их не бросают. Если вы ожидаете, что условие возникнет в ходе нормальной обработки, вам следует использовать другой метод.
@shylent, правильный способ выйти из вложенного цикла - это поместить цикл в функцию и вернуться из функции
Внешние модули не должны включаться в этот список. GOTO не является функцией Python.
@TokenMacGuy: не в Python. Исключения используются внутри для завершения циклов с помощью StopIteration. Исключения вовсе не исключение.
Использование динамической природы Python для создания приложений config в синтаксисе Python. Например, если у вас были следующие в файле конфигурации:
{
"name1": "value1",
"name2": "value2"
}
Тогда вы могли бы банально прочитать это так:
config = eval(open("filename").read())
Я согласен. Я начал использовать файл settings.py или config.py, который затем загружаю как модуль. Несомненно, это лучше, чем дополнительные шаги по синтаксическому анализу файлов некоторых других форматов.
Я вижу, что это становится проблемой безопасности.
Может быть, но иногда это не так. В таких случаях это круто.
Python может быть гораздо более выразительным языком конфигурации, чем любое количество файлов XML или INI. Я пытаюсь избежать явной конфигурации, используя только сценарий вызова, который «импортирует myapp; приложение = myapp.Application (...); app.run () ». Параметры по умолчанию разумны, но их можно изменить с помощью аргументов конструктора.
(Это предполагает, что конфигурация времени выполнения в самом приложении хранится в базе данных. Более значительная конфигурация возможна, если пользователю разрешено создавать подклассы Application и устанавливать свойства / методы для этого подкласса.)
Это смелое решение даже для не враждебной среды. eval () - это заряженное оружие, требующее особой осторожности при обращении. С другой стороны, использование JSON (теперь в stdlib 2.6) намного безопаснее и переносимо для переноса конфигурации.
Я бы никогда не одобрил обзор кода, который содержал eval.
@ Ричард Уэйт: Обычно это проблема безопасности, если злоумышленник может изменить ваш файл конфигурации ...
Я согласен, это чрезвычайно полезно во многих быстрых и грязных сценариях. Но лучше использовать execfile вместо eval + open + read.
Даже в доверенной среде это неприемлемая проблема безопасности. Если вам нужно проанализировать файлы конфигурации, используйте ConfigParser - 10 строк кода дают вам полноценный механизм для создания универсально читаемого файла конфигурации. Ваш подход действительно непереносимый и не расширяемый.
Тогда почему Django хранит настройки сайта в файле .py (включая пароль db)? Они в своем уме, не используют eval () или что-то мне не хватает?
Мне лично не нравится использовать eval() ни для чего, особенно для настроек. Я всегда оборачиваю настройки Django вокруг ConfigParser и сохраняю актуальную информацию в файле с защищенными правами доступа. Как сказал Расмус Лердорф: «Если eval () - это ответ, вы почти наверняка задаете неправильный вопрос».
eval () имеет те же проблемы безопасности, что и import, поэтому отказать сценарию, который использует его для проблем безопасности, не имеет смысла. Это обычная проблема, заключающаяся в том, чтобы никогда не исключать ненадежный пользовательский ввод, но если файл заканчивается на .py и импортируется, он все равно запускается. Причина использования импорта заключается в том, что он аккуратно помещает вашу конфигурацию в другое пространство имен. Вы также можете использовать execfile (ConfigFile, ConfigDict) для хранения файлов конфигурации в словаре.
нет необходимости в eval, назовите свой dict (config) и импортируйте его из своего модуля… (из configfile import config)
Повторная привязка параметров вложенной функции
def create_printers(n):
for i in xrange(n):
def printer(i=i): # Doesn't work without the i=i
print i
yield printer
он работает без него, но иначе. :-)
Нет, без него не работает. Опустите i = i и посмотрите разницу между map (apply, create_printers (10)) и map (apply, list (apply_printers (10))), где преобразование в список потребляет генератор, и теперь все десять функций принтера привязаны к i. с тем же значением: 9, где вызов их по одному вызывает их до того, как следующая итерация генератора изменит, к которому привязан int i во внешней области.
Я думаю, что @ kaizer.se говорит, что когда вы опускаете i=i, i в функции printer ссылается на i из цикла for, а не на локальный i, который создается при создании новой функции printer с ключевым словом i=i arg. Таким образом, он по-прежнему работает (он дает функции, каждая из которых имеет доступ к закрытию), но он работает не так, как вы ожидаете, без явного создания локальной переменной.
Небольшая ошибка питона. Обычный быстрый способ объединить список строк:
''.join(list_of_strings)
есть очень веские причины, по которым это метод строки, а не метод списка. это позволяет одной и той же функции присоединяться к любому итерируемому типу вместо дублирования соединения для каждого итеративного типа.
Да, я знаю, почему это происходит - но узнал бы кто-нибудь об этом, если бы им не сказали?
Обнаружить? Это тоже довольно сложно запомнить, и я использовал python, так как до того, как появились методы om strings.
Если это слишком уродливо для вас, вы можете написать то же самое, что и str.join('',list_of_strings), но другие питонисты могут насмехаться над вами за попытку написать java.
@TokenMacGuy: причина, по которой предпочтительнее '' .join ([...]), заключается в том, что многие люди часто путают порядок аргументов в string.join (..., ...); поставив '.join (), все станет яснее
Я почти уверен, что единственная причина, по которой большинство питонистов используют "".join(iterable) вместо str.join("",iterable), заключается в том, что он на 4 символа короче.
@TokenMacGuy Нет. А что плохого в том, чтобы разделить и присоединиться к классу str? Это легко запомнить и кстати. это пример того, что «практичность лучше чистоты».
этот ответ уже был дан
В Python есть обычная идиома для обозначения методов и других членов класса, которые не предназначены для того, чтобы быть частью внешнего API класса, давая им имена, начинающиеся с подчеркивания. Это удобно и очень хорошо работает на практике, но создает ложное впечатление, что Python не поддерживает истинную инкапсуляцию частного кода и / или данных. Фактически, Python автоматически предоставляет вам лексические замыкания, что позволяет очень легко инкапсулировать данные гораздо более надежным способом, когда ситуация действительно этого требует. Вот надуманный пример класса, использующего эту технику:
class MyClass(object):
def __init__(self):
privateData = {}
self.publicData = 123
def privateMethod(k):
print privateData[k] + self.publicData
def privilegedMethod():
privateData['foo'] = "hello "
privateMethod('foo')
self.privilegedMethod = privilegedMethod
def publicMethod(self):
print self.publicData
А вот надуманный пример его использования:
>>> obj = MyClass()
>>> obj.publicMethod()
123
>>> obj.publicData = 'World'
>>> obj.publicMethod()
World
>>> obj.privilegedMethod()
hello World
>>> obj.privateMethod()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute 'privateMethod'
>>> obj.privateData
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute 'privateData'
Ключ в том, что privateMethod и privateData на самом деле вообще не являются атрибутами obj, поэтому к ним нельзя получить доступ извне, и они не отображаются в dir() или аналогичных. Это локальные переменные в конструкторе, полностью недоступные за пределами __init__. Однако из-за магии замыканий они действительно являются переменными для каждого экземпляра с тем же временем жизни, что и объект, с которым они связаны, даже несмотря на то, что нет никакого способа получить к ним доступ извне, кроме как (в этом примере) путем вызова privilegedMethod. Часто такая очень строгая инкапсуляция является излишней, но иногда она действительно может быть очень удобна для поддержания безупречной чистоты API или пространства имен.
В Python 2.x единственный способ иметь изменяемое частное состояние - использовать изменяемый объект (такой как dict в этом примере). Многие отмечали, насколько это может раздражать. Python 3.x снимет это ограничение, введя ключевое слово nonlocal, описанное в PEP 3104.
это почти никогда не бывает хорошей идеей.
«Это локальные переменные в конструкторе, полностью недоступные за пределами в этом». Неправда: >>> [c.cell_contents для c в obj.privilegedMethod.func_closure] -> [{'foo': 'hello'}, <function privateMethod at 0x65530>]
Правильный способ предотвращения доступа к атрибутам - наличие сигнального устройства __getattribute__ или __getattr__ и соответствующая маршрутизация принятых вызовов. Опять же, секретность и питон - не лучшая идея.
Использование аргументов ключевого слова как присваивания
Иногда хочется построить набор функций в зависимости от одного или нескольких параметров. Однако это может легко привести к тому, что все закрытия будут ссылаться на один и тот же объект и значение:
funcs = []
for k in range(10):
funcs.append( lambda: k)
>>> funcs[0]()
9
>>> funcs[7]()
9
Этого поведения можно избежать, превратив лямбда-выражение в функцию, зависящую только от его аргументов. Параметр ключевого слова хранит текущее привязанное к нему значение. Вызов функции изменять не нужно:
funcs = []
for k in range(10):
funcs.append( lambda k = k: k)
>>> funcs[0]()
0
>>> funcs[7]()
7
Менее хакерский способ сделать это (imho) - просто использовать отдельную функцию для создания лямбда-выражений, которые не закрываются для переменной цикла. Как это: def make_lambda(k): return lambda: k.
«менее хакерский»? .... это личное предпочтение, я думаю, но это основная штука Python, а не хакерство. Вы, конечно, можете структурировать его (используя функции), чтобы читателю не нужно было понимать, как работают аргументы Python по умолчанию, - но если вы действительно понимаете, как работают аргументы по умолчанию, вы прочитаете "lambda: k=k:k" и сразу поймете, что он «сохраняет» текущее значение «k» (когда создается лямбда) и присоединение его к самой лямбде. То же самое работает и с обычными функциями def.
Ответ Джейсона Орендорфа правильный, но именно так мы имитировали замыкания в Python, прежде чем Гвидо окончательно согласился с тем, что вложенные области видимости - хорошая идея.
Замена метода для экземпляра объекта
Вы можете заменить методы уже созданных экземпляров объекта. Он позволяет создавать экземпляры объекта с разными (исключительными) функциями:
>>> class C(object):
... def fun(self):
... print "C.a", self
...
>>> inst = C()
>>> inst.fun() # C.a method is executed
C.a <__main__.C object at 0x00AE74D0>
>>> instancemethod = type(C.fun)
>>>
>>> def fun2(self):
... print "fun2", self
...
>>> inst.fun = instancemethod(fun2, inst, C) # Now we are replace C.a by fun2
>>> inst.fun() # ... and fun2 is executed
fun2 <__main__.C object at 0x00AE74D0>
Как мы видим, C.a был заменен на fun2() в экземпляре inst (self не изменился).
В качестве альтернативы мы можем использовать модуль new, но он устарел, начиная с Python 2.6:
>>> def fun3(self):
... print "fun3", self
...
>>> import new
>>> inst.fun = new.instancemethod(fun3, inst, C)
>>> inst.fun()
fun3 <__main__.C object at 0x00AE74D0>
Узел: Это решение не должно использоваться в качестве общей замены механизма наследования! Но это может быть очень удобно в некоторых конкретных ситуациях (отладка, насмешка).
Предупреждение: Это решение не будет работать для встроенных типов и для новых классов стилей, использующих слоты.
Лично я предпочитаю оставлять instancemethod классам; обычно так, чтобы поведение привязки foo.method работало нормально. Если я привязываю себя явно, я вместо этого использую functools.partial, который дает тот же эффект, но делает более ясным, что поведение привязки является явным.
Вы можете ссылаться на составление списка с помощью символа '_ [1]'. Например, следующая функция присваивает уникальность списку элементов без изменения их порядка, ссылаясь на его понимание списка.
def unique(my_list):
return [x for x in my_list if x not in locals()['_[1]']]
Отличный трюк. Знаете ли вы, приемлемо ли это поведение или это скорее грязный взлом, который может измениться в будущем? Подчеркивание заставляет меня думать о последнем.
Интересно. Я думаю, что это будет грязный взлом словаря locals (), но мне было бы любопытно узнать наверняка.
Великолепно, буквально вчера я это искал!
не лучшая идея как по алгоритмическим, так и по практическим причинам. Алгоритмически это даст вам линейный поиск по списку до сих пор на каждой итерации, изменяя ваш цикл O (n) на O (n ** 2); гораздо лучше потом просто составить список в набор. На практике это недокументировано, может измениться и, вероятно, не работает в ironpython / jython / pypy.
Это недокументированная деталь реализации, а не скрытая функция. Было бы плохой идеей полагаться на это.
Если вы хотите ссылаться на список при его создании, используйте обычный цикл. Это очень зависит от реализации - CPython использует скрытое имя в локальном dict, потому что это удобно, но другие реализации не обязаны делать то же самое.
Вероятно, встроенная функция python, которую легко упустить из виду, - это "set / frozenset".
Полезно, когда у вас есть список, подобный этому, [1,2,1,1,2,3,4], и вам нужны только такие уникальные объекты [1,2,3,4].
Используя set (), вы получите:
>>> x = [1,2,1,1,2,3,4]
>>>
>>> set(x)
set([1, 2, 3, 4])
>>>
>>> for i in set(x):
... print i
...
1
2
3
4
И, конечно же, чтобы получить количество уникальных посетителей в списке:
>>> len(set([1,2,1,1,2,3,4]))
4
Вы также можете узнать, является ли список подмножеством другого списка, используя set (). Issubset ():
>>> set([1,2,3,4]).issubset([0,1,2,3,4,5])
True
Начиная с Python 2.7 и 3.0, вы можете использовать фигурные скобки для создания набора:
myset = {1,2,3,4}
а также установить понимание:
{x for x in stuff}
Больше подробностей: http://docs.python.org/library/stdtypes.html#set
Также полезно в случаях, когда словарь использовался только для проверки наличия значения.
Я использую набор примерно столько же, сколько кортеж и список.
для подмножеств, я считаю, что это issubset, а не isasubset. в любом случае оператор подмножества <= в любом случае лучше.
вы также можете выполнять понимание dict в python 2.7 следующим образом {x: x * 2 for x in range (3)} Это, вероятно, сбивает с толку, если вы не знаете, что делаете, imho
Функциональная поддержка.
Генераторы и выражения генераторов, в частности.
Ruby снова сделал это мейнстримом, но Python тоже может это сделать. Не так распространен в библиотеках, как в Ruby, что очень плохо, но мне больше нравится синтаксис, он проще.
Поскольку они не так распространены, я не вижу так много примеров того, почему они полезны, но они позволили мне написать более чистый и эффективный код.
При отладке сложных структур данных пригодится модуль pprint.
Цитата из документов ..
>>> import pprint
>>> stuff = sys.path[:]
>>> stuff.insert(0, stuff)
>>> pprint.pprint(stuff)
[<Recursion on list with id=869440>,
'',
'/usr/local/lib/python1.5',
'/usr/local/lib/python1.5/test',
'/usr/local/lib/python1.5/sunos5',
'/usr/local/lib/python1.5/sharedmodules',
'/usr/local/lib/python1.5/tkinter']
pprint также хорош для печати словарей в doctests, так как он всегда сортирует вывод по ключам
>>> from functools import partial
>>> bound_func = partial(range, 0, 10)
>>> bound_func()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> bound_func(2)
[0, 2, 4, 6, 8]
не совсем скрытая функция, но частичная чрезвычайно полезна для поздней оценки функций.
вы можете связать столько или меньше параметров в начальном вызове с частичным, сколько хотите, и вызвать его с любыми оставшимися параметрами позже (в этом примере я привязал аргументы начала / конца к диапазону, но вызываю его во второй раз с шаг arg)
См. документация.
Я бы хотел, чтобы каррификация добавила достойного оператора в Python.
is_ok() and "Yes" or "No"
Это странно. Интересно, но странно. >>> Верно и «Да» или «Нет», «Да» >>> Ложно и «Да» или «Нет», «Нет» >>> x = «Да» >>> y = «Нет» >>>> >> Ложь и х или у
Предпочтительный способ сделать это в Python 2.5 или новее - «'Yes' if is_ok () else 'No'».
Независимо от того, предпочтительнее это или нет, способ правильный, я использую его все время, и я считаю его элегантным. поскольку это действительно интересный вопрос о скрытых функциях, этот пост получил отрицательное голосование,
«Предпочтительный» аргумент открыт для обсуждения, потому что в этом случае порядок выполнения совпадает с логическим порядком, в то время как «Да», если True, иначе «Нет» не такой.
«Предпочтительный» В этом случае означает, что условный оператор работает должным образом для всех возможных операндов. В частности, True and False or True - это правда, но False if True else True - ложь, что почти наверняка соответствует вашим ожиданиям. Это особенно важно, когда операнды имеют побочные эффекты, и условный оператор НИКОГДА оценивает более одного из своих условных предложений.
Это часто используемая функция во многих языках [особенно в bash, где && || синтаксис используется для имитации тернарного оператора]
... что dict.get() имеет значение значение по умолчанию, равное None, что позволяет избежать ошибок KeyErrors:
In [1]: test = { 1 : 'a' }
In [2]: test[2]
---------------------------------------------------------------------------
<type 'exceptions.KeyError'> Traceback (most recent call last)
<ipython console> in <module>()
<type 'exceptions.KeyError'>: 2
In [3]: test.get( 2 )
In [4]: test.get( 1 )
Out[4]: 'a'
In [5]: test.get( 2 ) == None
Out[5]: True
и даже указать это «на месте происшествия»:
In [6]: test.get( 2, 'Some' ) == 'Some'
Out[6]: True
И вы можете использовать setdefault(), чтобы значение было установлено и возвращено, если оно не существует:
>>> a = {}
>>> b = a.setdefault('foo', 'bar')
>>> a
{'foo': 'bar'}
>>> b
'bar
Вы можете легко транспонировать массив с помощью zip.
a = [(1,2), (3,4), (5,6)]
zip(*a)
# [(1, 3, 5), (2, 4, 6)]
В основном zip(*a)расстегиваетa. Так что если b = zip(a), то a == zip(*b).
map (None, * a) может пригодиться, если ваши кортежи имеют разную длину: map (None, * [(1,2), (3,4,5), (5,)]) => [(1 , 3, 5), (2, 4, Нет), (Нет, 5, Нет)]
Только что нашел эту функцию на docs.python.org/library/functions.html и собирался поделиться ею здесь. Похоже, ты меня опередил.
Я помню, как это работает: «zip * превращает список пар в пару списков» (и наоборот)
Отрицательный раунд
Функция round() округляет число с плавающей запятой до заданной точности в десятичных разрядах, но точность может быть отрицательной:
>>> str(round(1234.5678, -2))
'1200.0'
>>> str(round(1234.5678, 2))
'1234.57'
Примечание:round() всегда возвращает число с плавающей запятой, str(), использованное в приведенном выше примере, потому что математика с плавающей запятой неточна, а в версии 2.x второй пример может печатать как 1234.5700000000001. Также см. Модуль decimal.
Очень часто мне приходится округлять число до кратного. Например, округлите 17 до числа, кратного 5 (15). Но раунд Python не позволяет мне этого сделать! ИМО, он должен быть структурирован как round(num, precision=1) - round "num" to the nearest multiple of "precision"
@wallacoloo в чем дело с (17/5) * 5? Разве это не коротко и выразительно?
@silviot попробуйте это с (19/5) * 5. 19, округленное до ближайшего 5, должно быть 20, не так ли? Но это, кажется, возвращает 15. Кроме того, это полагается на правила целочисленного деления Python 2.x. Это не будет работать так же в 3.x. Самое краткое и правильное решение imo: roundNearest = lambda n, m: round(float(n)/m)*m
Или вообще roundNearest = lambda n, m: (n + (m/2)) / m * m. Это в два раза быстрее, чем при использовании round(float) в моей системе.
Переводчик внутри переводчика
Модуль код стандартной библиотеки позволяет вам включить собственный цикл чтения-оценки-печати в программу или запустить весь вложенный интерпретатор. Например. (скопировал мой пример из здесь)
$ python
Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> shared_var = "Set in main console"
>>> import code
>>> ic = code.InteractiveConsole({ 'shared_var': shared_var })
>>> try:
... ic.interact("My custom console banner!")
... except SystemExit, e:
... print "Got SystemExit!"
...
My custom console banner!
>>> shared_var
'Set in main console'
>>> shared_var = "Set in sub-console"
>>> import sys
>>> sys.exit()
Got SystemExit!
>>> shared_var
'Set in main console'
Это чрезвычайно полезно в ситуациях, когда вы хотите принять ввод по сценарию от пользователя или запросить состояние виртуальной машины в режиме реального времени.
TurboGears использует это для большого эффекта, имея веб-консоль, из которой вы можете запрашивать состояние вашего живого веб-приложения.
Перегрузка оператора для встроенного set:
>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # Union
{1, 2, 3, 4, 5, 6}
>>> a & b # Intersection
{3, 4}
>>> a < b # Subset
False
>>> a - b # Difference
{1, 2}
>>> a ^ b # Symmetric Difference
{1, 2, 5, 6}
Подробнее из справочника стандартной библиотеки: Типы наборов
В учебнике частично docs.python.org/tutorial/datastructures.html#sets
Вы можете переопределить MRO класса с помощью метакласса
>>> class A(object):
... def a_method(self):
... print("A")
...
>>> class B(object):
... def b_method(self):
... print("B")
...
>>> class MROMagicMeta(type):
... def mro(cls):
... return (cls, B, object)
...
>>> class C(A, metaclass=MROMagicMeta):
... def c_method(self):
... print("C")
...
>>> cls = C()
>>> cls.c_method()
C
>>> cls.a_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'a_method'
>>> cls.b_method()
B
>>> type(cls).__bases__
(<class '__main__.A'>,)
>>> type(cls).__mro__
(<class '__main__.C'>, <class '__main__.B'>, <class 'object'>)
Вероятно, это скрыто по уважительной причине. :)
Это игра с огнем и просьба о вечном проклятии. Лучше иметь вескую причину;)
Не работает с python 2.x. Вместо этого используйте __metaclass__ = MROMagicMeta.
Встроенный reversed(). Во многих случаях это значительно упрощает итерацию.
быстрый пример:
for i in reversed([1, 2, 3]):
print(i)
производит:
3
2
1
Однако reversed() также работает с произвольными итераторами, такими как строки в файле или выражения генератора.
Дзен Python
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Скрытый? OTOH, это один из плюсов Python.
Мне нравится расцветка синтаксиса, особенно. для Dutch.
Дубликат предыдущего ответа
Дубликат предыдущего ответа
pdb - Отладчик Python
Как программист, одно из первых, что вам нужно для серьезной разработки программы, - это отладчик. У Python есть один встроенный модуль, который доступен в виде модуля под названием pdb (естественно, для Python DeBugger!).
Объекты малых целых чисел (-5 .. 256) никогда не создавались дважды:
>>> a1 = -5; b1 = 256
>>> a2 = -5; b2 = 256
>>> id(a1) == id(a2), id(b1) == id(b2)
(True, True)
>>>
>>> c1 = -6; d1 = 257
>>> c2 = -6; d2 = 257
>>> id(c1) == id(c2), id(d1) == id(d2)
(False, False)
>>>
Редактировать: Объекты списка никогда не уничтожаются (только объекты в списках). Python имеет массив, в котором хранится до 80 пустых списков. Когда вы уничтожаете объект списка - python помещает его в этот массив, а когда вы создаете новый список - python получает последний добавленный список из этого массива:
>>> a = [1,2,3]; a_id = id(a)
>>> b = [1,2,3]; b_id = id(b)
>>> del a; del b
>>> c = [1,2,3]; id(c) == b_id
True
>>> d = [1,2,3]; id(d) == a_id
True
>>>
Эта функция зависит от реализации, поэтому полагаться на нее не стоит.
Как сказал Денис, не стоит полагаться на такое поведение. Это не работает, например, в PyPy, и ваш код будет ужасно ломаться, если вы попытаетесь его использовать.
Создание словаря из двух последовательностей, имеющих связанные данные
In [15]: t1 = (1, 2, 3)
In [16]: t2 = (4, 5, 6)
In [17]: dict (zip(t1,t2))
Out[17]: {1: 4, 2: 5, 3: 6}
Моделирование третичного оператора с помощью и и или.
Операторы and and or в python возвращают сами объекты, а не логические значения. Таким образом:
In [18]: a = True
In [19]: a and 3 or 4
Out[19]: 3
In [20]: a = False
In [21]: a and 3 or 4
Out[21]: 4
Однако Py 2.5, похоже, добавил явный третичный оператор
In [22]: a = 5 if True else '6'
In [23]: a
Out[23]: 5
Что ж, это работает, если вы уверены, что ваше предложение true не оценивается как False. пример:
>>> def foo():
... print "foo"
... return 0
...
>>> def bar():
... print "bar"
... return 1
...
>>> 1 and foo() or bar()
foo
bar
1
Чтобы понять это правильно, вам нужно немного больше:
>>> (1 and [foo()] or [bar()])[0]
foo
0
Однако это не так красиво. если ваша версия Python поддерживает это, используйте условный оператор.
>>> foo() if True or bar()
foo
0
Осторожно: >>> a и "" или ":(" вы всегда получите хмурое лицо в ответ, независимо от того, истинно оно или ложно.
Marius, только, если а ложь. В противном случае вы бы хотели, чтобы ":(" поскольку "" ложно.
(falseValue, trueValue)[cond] - это более чистый (IMO) способ имитации тернарного оператора.
Модуль осмотреть - тоже классная функция.
spam в стандартном PythonОн используется для тестирования.
Выбрал из ctypes учебник. Попробуй сам:
>>> import __hello__
Hello world...
>>> type(__hello__)
<type 'module'>
>>> from __phello__ import spam
Hello world...
Hello world...
>>> type(spam)
<type 'module'>
>>> help(spam)
Help on module __phello__.spam in __phello__:
NAME
__phello__.spam
FILE
c:\python26\<frozen>
извините, почему и как вы бы это использовали?
@Casey: прочтите раздел «Доступ к значениям, экспортированным из dll» в руководстве по ctypesstarship.python.net/crew/theller/ctypes/…
Ваш пример непонятен.
Управление памятью
Python динамически выделяет память и использует сборку мусора для восстановления неиспользуемого пространства. Как только объект выходит за рамки и никакие другие переменные не ссылаются на него, он будет восстановлен. Мне не нужно беспокоиться о переполнении буфера и медленно растущих серверных процессах. Управление памятью также является функцией других динамических языков, но Python просто отлично с этим справляется.
Конечно, мы должны следить за циклическими ссылками и сохранять ссылки на объекты, которые больше не нужны, но здесь очень помогают слабые ссылки.
Тот факт, что вы можете вызывать функцию каждый раз, когда что-то соответствует регулярному выражению, очень удобен. Здесь у меня есть пример замены каждого «Привет» на «Привет», «там» на «Фред» и т. д.
import re
def Main(haystack):
# List of from replacements, can be a regex
finds = ('Hello', 'there', 'Bob')
replaces = ('Hi,', 'Fred,', 'how are you?')
def ReplaceFunction(matchobj):
for found, rep in zip(matchobj.groups(), replaces):
if found != None:
return rep
# log error
return matchobj.group(0)
named_groups = [ '(%s)' % find for find in finds ]
ret = re.sub('|'.join(named_groups), ReplaceFunction, haystack)
print ret
if __name__ == '__main__':
str = 'Hello there Bob'
Main(str)
# Prints 'Hi, Fred, how are you?'
Это безумие. Я понятия не имел, что это существует. классно. большое спасибо.
Никогда раньше такого не видел, но лучшим примером может быть re.sub('[aeiou]', lambda match: match.group().upper()*3, 'abcdefghijklmnopqrstuvwxyz').
Мне лично нравится 3 разных цитаты
str = "I'm a string 'but still I can use quotes' inside myself!"
str = """ For some messy multi line strings.
Such as
<html>
<head> ... </head>"""
Также круто: не нужно экранировать регулярные выражения, избежать ужасного салата с обратной косой чертой с помощью сырые струны:
str2 = r"\n"
print str2
>> \n
'''Мне нравится, когда ' и " делают в коде примерно одно и то же. Моя IDE выделяет строки из двух разными цветами, и это позволяет легко отличать короткие строки (с ') от более длинных (с ").
Одно слово: IPython
Самоанализ вкладок, красивая печать, %debug, управление историей, pylab, ... стоит потратить время, чтобы хорошо изучить.
Это не встроено в ядро Python, не так ли?
Вы правы, это не так. И, вероятно, не без оснований. Но я безоговорочно рекомендую его любому программисту на Python. (Тем не менее, я настоятельно рекомендую отключить автоматический вызов. Когда он делает что-то, чего вы не ожидаете, может быть очень трудно понять, почему.)
Еще я люблю IPython. Я пробовал BPython, но он был для меня слишком медленным (хотя я согласен, что в нем есть несколько интересных функций).
Перезагрузка модулей позволяет использовать стиль «живого кодирования». Но экземпляры класса не обновляются. Вот почему и как это обойти. Помните, все, да, все - это объект.
>>> from a_package import a_module
>>> cls = a_module.SomeClass
>>> obj = cls()
>>> obj.method()
(old method output)
Теперь вы меняете метод в a_module.py и хотите обновить свой объект.
>>> reload(a_module)
>>> a_module.SomeClass is cls
False # Because it just got freshly created by reload.
>>> obj.method()
(old method output)
Вот один из способов обновить его (но считайте, что он работает ножницами):
>>> obj.__class__ is cls
True # it's the old class object
>>> obj.__class__ = a_module.SomeClass # pick up the new class
>>> obj.method()
(new method output)
Это «работа ножницами», потому что внутреннее состояние объекта может отличаться от ожидаемого новым классом. Это работает для действительно простых случаев, но помимо этого pickle - ваш друг. Тем не менее, все же полезно понять, почему это работает.
+1 за предложение pickle (или cPickle). Несколько недель назад это было действительно полезно для меня.
Не очень скрыто, но у функций есть атрибуты:
def doNothing():
pass
doNothing.monkeys = 4
print doNothing.monkeys
4
Это потому, что функции можно рассматривать как объекты с определенной функцией __call __ ().
Это потому, что функции можно рассматривать как дескрипторы с определенной функцией __call __ ().
Подождите, а у __call__() тоже есть функция __call__()?
Готов поспорить, что это функции __call __ () полностью вниз.
Вы можете украсить функции классами - заменив функцию экземпляром класса:
class countCalls(object):
""" decorator replaces a function with a "countCalls" instance
which behaves like the original function, but keeps track of calls
>>> @countCalls
... def doNothing():
... pass
>>> doNothing()
>>> doNothing()
>>> print doNothing.timesCalled
2
"""
def __init__ (self, functionToTrack):
self.functionToTrack = functionToTrack
self.timesCalled = 0
def __call__ (self, *args, **kwargs):
self.timesCalled += 1
return self.functionToTrack(*args, **kwargs)
После небольшого объема работы модуль потоковой обработки становится удивительно простым в использовании. Этот декоратор изменяет функцию так, чтобы она выполнялась в собственном потоке, возвращая экземпляр класса-заполнителя вместо обычного результата. Вы можете проверить ответ, проверив placeolder.result, или дождаться его, вызвав placeholder.awaitResult ()
def threadify(function):
"""
exceptionally simple threading decorator. Just:
>>> @threadify
... def longOperation(result):
... time.sleep(3)
... return result
>>> A= longOperation("A has finished")
>>> B= longOperation("B has finished")
A doesn't have a result yet:
>>> print A.result
None
until we wait for it:
>>> print A.awaitResult()
A has finished
we could also wait manually - half a second more should be enough for B:
>>> time.sleep(0.5); print B.result
B has finished
"""
class thr (threading.Thread,object):
def __init__(self, *args, **kwargs):
threading.Thread.__init__ ( self )
self.args, self.kwargs = args, kwargs
self.result = None
self.start()
def awaitResult(self):
self.join()
return self.result
def run(self):
self.result=function(*self.args, **self.kwargs)
return thr
Возможно, вас заинтересует модуль concurrent.futures, добавленный в Python 3.2.
ROT13 является допустимой кодировкой для исходного кода, когда вы используете правильное объявление кодировки в верхней части файла кода:
#!/usr/bin/env python
# -*- coding: rot13 -*-
cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")
Большой! Обратите внимание, как байтовые строки воспринимаются буквально, но строки Unicode декодируются: попробуйте cevag h"Uryyb fgnpxbiresybj!"
к сожалению, он удален из py3k
Это хорошо для обхода антивируса.
Это не имеет ничего общего с кодировкой, это просто Python, написанный на валлийском языке. :-П
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!
видеть? вы можете писать непонятный код на любых языках, даже на python
Урыыб fgnpxbiresybj! -> Привет, stackoverflow!
@ Мануэль Феррерия: извините, но я не мог понять, что вы сказали ... это ROT13 ??
@amyassin Я тоже был в шоке, пока не вспомнил про гугл и не нашел en.wiktionary.org/wiki/…
Если вы переименовали класс в своем приложении, в котором вы загружаете сохраненные пользователем файлы через Pickle, и один из переименованных классов хранится в старом сохранении пользователя, вы не сможете загрузить этот файл.
Однако просто добавьте ссылку на определение вашего класса, и все будет хорошо:
например, до:
class Bleh:
pass
сейчас же,
class Blah:
pass
Итак, маринованный сохраненный файл вашего пользователя содержит ссылку на Bleh, которая не существует из-за переименования. Исправление?
Bleh = Blah
просто!
Разумный хакер, но почему изменилось название класса? было ли это потому, что это противоречит чему-то другому? Выполнение такого рода действий сводит на нет любую выгоду, которую вы могли бы получить от переименования класса в первую очередь.
Я моделировал классы на инструментах «рисования» - пером, прямоугольником, выделением и т. д. И использовал имя класса в качестве меток кнопок графического интерфейса. Затем я перешел на переменную класса, чтобы представить имя позже.
Тот факт, что ВСЕ является объектом и как таковой является расширяемым. Я могу добавить переменные-члены в качестве метаданных к функции, которую я определяю:
>>> def addInts(x,y):
... return x + y
>>> addInts.params = ['integer','integer']
>>> addInts.returnType = 'integer'
Это может быть очень полезно для написания динамических модульных тестов, например
Большинство вещей - объекты; а некоторые объекты не так успешно принимают присвоение свойств.
Встроенная функция getattr:
>>> class C():
def getMontys(self):
self.montys = ['Cleese','Palin','Idle','Gilliam','Jones','Chapman']
return self.montys
>>> c = C()
>>> getattr(c,'getMontys')()
['Cleese', 'Palin', 'Idle', 'Gilliam', 'Jones', 'Chapman']
>>>
Полезно, если вы хотите, чтобы функция диспетчеризации зависела от контекста. См. Примеры в Dive Into Python (Здесь)
Простой способ проверить, находится ли ключ в dict:
>>> 'key' in { 'key' : 1 }
True
>>> d = dict(key=1, key2=2)
>>> if 'key' in d:
... print 'Yup'
...
Yup
Надеюсь, это не скрыто для любого программиста, не являющегося новым Python!
Или даже новые, поскольку они представлены в учебнике.
Классы как объекты первого класса (показаны в определении динамического класса)
Обратите внимание на использование крышки. Если этот конкретный пример выглядит как «правильный» подход к проблеме, внимательно пересмотрите ... несколько раз :)
def makeMeANewClass(parent, value):
class IAmAnObjectToo(parent):
def theValue(self):
return value
return IAmAnObjectToo
Klass = makeMeANewClass(str, "fred")
o = Klass()
print isinstance(o, str) # => True
print o.theValue() # => fred
Открытие изменяемых буферов
Использование Python от Буферный протокол до выставлять изменяемые байтовые буферы в Python (2.5 / 2.6).
(К сожалению, здесь нет кода. Требуется использование низкоуровневого API C или существующего модуля адаптера).
Иногда бывает полезно расширить (изменить) значение, "возвращаемое" дескриптором в подклассе. Это легко сделать с помощью super():
class A(object):
@property
def prop(self):
return {'a': 1}
class B(A):
@property
def prop(self):
return dict(super(B, self).prop, b=2)
Сохраните это в test.py и запустите python -i test.py (еще одна скрытая функция: опция -i выполняет сценарий и позволяет продолжить работу в интерактивном режиме):
>>> B().prop
{'a': 1, 'b': 2}
+1 свойства! Не могу насытиться ими.
Питоническая идиома x = ... if ... else ... намного превосходит x = ... and ... or ..., и вот почему:
Хотя заявление
x = 3 if (y == 1) else 2
Эквивалентно
x = y == 1 and 3 or 2
если вы используете идиому x = ... and ... or ..., однажды вас может укусить такая запутанная ситуация:
x = 0 if True else 1 # sets x equal to 0
и поэтому не эквивалентен
x = True and 0 or 1 # sets x equal to 1
Чтобы узнать больше о том, как это сделать, см. Скрытые возможности Python.
Python может понимать любые цифры в Юникоде, а не только в виде ASCII:
>>> s = u'10585'
>>> s
u'\uff11\uff10\uff15\uff18\uff15'
>>> print s
10585
>>> int(s)
10585
>>> float(s)
10585.0
Что касается реализации Ником Джонсоном Класс недвижимости (просто демонстрация дескрипторов, конечно, а не замена встроенного), я бы включил сеттер, который вызывает AttributeError:
class Property(object):
def __init__(self, fget):
self.fget = fget
def __get__(self, obj, type):
if obj is None:
return self
return self.fget(obj)
def __set__(self, obj, value):
raise AttributeError, 'Read-only attribute'
Включение установщика делает это дескриптором данных, а не дескриптором метода / не-данных. Дескриптор данных имеет приоритет над словарями экземпляров. Теперь экземпляру не может быть назначен другой объект для имени свойства, и попытки назначить свойство вызовут ошибку атрибута.
Синтаксис распаковки был обновлен в последней версии, как видно на примере.
>>> a, *b = range(5)
>>> a, b
(0, [1, 2, 3, 4])
>>> *a, b = range(5)
>>> a, b
([0, 1, 2, 3], 4)
>>> a, *b, c = range(5)
>>> a, b, c
(0, [1, 2, 3], 4)
никогда раньше такого не видел, это очень мило!
какая версия? так как это не работает в 2.5.2
работает с 3.1, но не с 2.7
Приятно - давно на это надеялся! Жаль, что разрушение пошло.
Управление пределом рекурсии
Получение или установка максимальной глубины рекурсии с помощью sys.getrecursionlimit () и sys.setrecursionlimit ().
Мы можем ограничить его, чтобы предотвратить переполнение стека, вызванное бесконечной рекурсией.
Умножение на логическое значение
Одна вещь, которую я постоянно делаю в веб-разработке, - это опциональная печать параметров HTML. Все мы видели такой код на других языках:
class='<% isSelected ? "selected" : "" %>'
В Python вы можете умножить на логическое значение, и он сделает именно то, что вы ожидаете:
class='<% "selected" * isSelected %>'
Это связано с тем, что умножение приводит логическое значение к целому числу (0 для False, 1 для True), а в python умножение строки на int повторяет строки N раз.
+1, это хорошо. OTOH, поскольку это немного загадочно, легко понять, почему вы, возможно, не захотите этого делать из соображений удобочитаемости.
Я бы написал bool(isSelected) и для надежности, и для удобочитаемости.
вы также можете использовать что-то вроде: ('not-selected', 'selected')[isSelected], если вам также нужна опция для значения False ..
Правильный условные выражения был добавлен в Python в версии 2.5. Если вы используете версию 2.5+, вам, вероятно, не следует использовать эти уловки по причинам удобочитаемости.
Мод корректно работает с отрицательными числами
-1% 5 - это 4, как и должно быть, а не -1, как в других языках, таких как JavaScript. Это делает «витые окна» более чистыми в Python, вам просто нужно сделать следующее:
index = (index + increment) % WINDOW_SIZE
На большинстве языков number = coefficient x quotient + remainder. В Python (и Ruby) quotient отличается от JavaScript (или C или Java), потому что целочисленное деление в Python округляется до отрицательной бесконечности, а в JavaScript оно округляется до нуля (усекает). Я согласен с тем, что % в Python имеет больше смысла, но я не знаю, есть ли у /. См. en.wikipedia.org/wiki/Modulo_operation для получения подробной информации по каждому языку.
В общем, если abs (приращение) <WINDOW_SIZE, то вы можете сказать index = (index + WINDOW_SIZE + increment) на любом языке и заставить его делать правильные вещи.
Вы можете построить функцию kwargs по запросу:
kwargs = {}
kwargs[str("%s__icontains" % field)] = some_value
some_function(**kwargs)
Вызов str () почему-то нужен, поскольку в противном случае python жалуется, что это не строка. Не знаю почему;) Я использую это для динамических фильтров в объектной модели Djangos:
result = model_class.objects.filter(**kwargs)
Причина жалоб заключается, вероятно, в том, что "field" является Unicode, что делает всю строку Unicode.
Угадание целочисленной базы
>>> int('10', 0)
10
>>> int('0x10', 0)
16
>>> int('010', 0) # does not work on Python 3.x
8
>>> int('0o10', 0) # Python >=2.6 and Python 3.x
8
>>> int('0b10', 0) # Python >=2.6 and Python 3.x
2
itertools
Этот модуль часто упускают из виду. В следующем примере используется itertools.chain()
чтобы сгладить список:
>>> from itertools import *
>>> l = [[1, 2], [3, 4]]
>>> list(chain(*l))
[1, 2, 3, 4]
См. http://docs.python.org/library/itertools.html#recipes для дополнительных приложений.
Объекты Monkeypatching
Каждый объект в Python имеет член __dict__, в котором хранятся атрибуты объекта. Итак, вы можете сделать что-то вроде этого:
class Foo(object):
def __init__(self, arg1, arg2, **kwargs):
#do stuff with arg1 and arg2
self.__dict__.update(kwargs)
f = Foo('arg1', 'arg2', bar=20, baz=10)
#now f is a Foo object with two extra attributes
Это можно использовать для произвольного добавления к объектам как атрибутов, так и функций. Это также можно использовать для создания быстроразвивающегося типа struct.
class struct(object):
def __init__(**kwargs):
self.__dict__.update(kwargs)
s = struct(foo=10, bar=11, baz = "i'm a string!')
кроме классов с __slots__
За исключением некоторых «примитивных» типов, реализованных на C (я думаю, из соображений производительности). Например, после a = 2 нет a.__dict__
Создание перечислений
В Python вы можете сделать это, чтобы быстро создать перечисление:
>>> FOO, BAR, BAZ = range(3)
>>> FOO
0
Но «перечисления» не обязательно должны иметь целочисленные значения. Вы даже можете сделать это:
class Colors(object):
RED, GREEN, BLUE, YELLOW = (255,0,0), (0,255,0), (0,0,255), (0,255,255)
#now Colors.RED is a 3-tuple that returns the 24-bit 8bpp RGB
#value for saturated red
Вы можете напрямую управлять кешем модулей, делая модули доступными или недоступными по своему желанию:
>>> import sys
>>> import ham
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named ham
# Make the 'ham' module available -- as a non-module object even!
>>> sys.modules['ham'] = 'ham, eggs, saussages and spam.'
>>> import ham
>>> ham
'ham, eggs, saussages and spam.'
# Now remove it again.
>>> sys.modules['ham'] = None
>>> import ham
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named ham
Это работает даже для модулей, доступных находятся, и в некоторой степени для модулей, которые уже импортированы:
>>> import os
# Stop future imports of 'os'.
>>> sys.modules['os'] = None
>>> import os
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named os
# Our old imported module is still available.
>>> os
<module 'os' from '/usr/lib/python2.5/os.pyc'>
Как показано в последней строке, изменение sys.modules влияет только на будущие операторы import, а не на прошлые, поэтому, если вы хотите повлиять на другие модули, важно внести эти изменения перед, вы даете им возможность попробовать и импортировать модули - так что раньше вы обычно импортируете их. None - это специальное значение в sys.modules, используемое для отрицательного кэширования (указывающее, что модуль не был найден в первый раз, поэтому нет смысла искать снова). Любое другое значение будет результатом операции import, даже если это не так. объект модуля. Вы можете использовать это для замены модулей объектами, которые ведут себя точно так, как вы хотите. Удаление записи из sys.modules приводит к тому, что следующий import выполняет обычный поиск модуля, даже если он уже был импортирован ранее.
И вы можете сделать sys.modules['my_module'] = MyClass(), чтобы реализовать «модуль» атрибутов только для чтения, если MyClass имеет правильные хуки.
В Python нет секретов;)
Многие функции Python принимают кортежи, что тоже не похоже. Например, вы хотите проверить, является ли ваша переменная числом, вы можете сделать:
if isinstance (number, float) or isinstance (number, int):
print "yaay"
Но если вы передадите нам кортеж, это будет выглядеть намного чище:
if isinstance (number, (float, int)):
print "yaay"
круто, это вообще задокументировано?
Да, но об этом почти никто не знает.
Какие еще функции это поддерживают ?? Хороший совет
Не уверен в других функциях, но это предполагается в статьях except (FooError, BarError).
Вы можете присвоить несколько переменных одному и тому же значению
>>> foo = bar = baz = 1
>>> foo, bar, baz
(1, 1, 1)
Полезно для компактной инициализации нескольких переменных значением None.
Вы также можете сделать: foo, bar, baz = [None] * 3, чтобы получить тот же результат.
Вы также можете сравнить несколько вещей одновременно, например foo == bar == baz. По сути, это то же самое, что и главный ответ (который есть прямо сейчас).
Также имейте в виду, что это создаст значение только один раз, и все переменные будут ссылаться на это одно и то же значение. Однако для None это нормально, поскольку это одноэлементный объект.
threading.enumerate () предоставляет доступ ко всем объектам Thread в системе, а sys._current_frames () возвращает текущие кадры стека всех потоков в системе, поэтому объедините эти два, и вы получите дампы стека в стиле Java:
def dumpstacks(signal, frame):
id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
code = []
for threadId, stack in sys._current_frames().items():
code.append("\n# Thread: %s(%d)" % (id2name[threadId], threadId))
for filename, lineno, name, line in traceback.extract_stack(stack):
code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
if line:
code.append(" %s" % (line.strip()))
print "\n".join(code)
import signal
signal.signal(signal.SIGQUIT, dumpstacks)
Сделайте это в начале многопоточной программы на Python, и вы получите доступ к текущему состоянию потоков в любое время, отправив SIGQUIT. Вы также можете выбрать signal.SIGUSR1 или signal.SIGUSR2.
Брекеты
def g():
print 'hi!'
def f(): (
g()
)
>>> f()
hi!
>>> def f (): (... g () ... g () Файл "<stdin>", строка 3 g () ^ SyntaxError: недопустимый синтаксис
Я пытался показать, что ваша функция не работает, если в фигурных скобках указано несколько операторов.
Всем известно, что Python использует #{ и #} для фигурных скобок. Подлежит определенным лексическим ограничениям.
Совершенно секретные атрибуты
>>> class A(object): pass
>>> a = A()
>>> setattr(a, "can't touch this", 123)
>>> dir(a)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', "can't touch this"]
>>> a.can't touch this # duh
File "<stdin>", line 1
a.can't touch this
^
SyntaxError: EOL while scanning string literal
>>> getattr(a, "can't touch this")
123
>>> setattr(a, "__class__.__name__", ":O")
>>> a.__class__.__name__
'A'
>>> getattr(a, "__class__.__name__")
':O'
АААА! Плохо, плохо, плохо!
Хорошая обработка бесконечной рекурсии в словарях:
>>> a = {}
>>> b = {}
>>> a['b'] = b
>>> b['a'] = a
>>> print a
{'b': {'a': {...}}}
Это просто «хорошее обращение» с «печатью», оно не подразумевает хорошего обращения с языком.
И str(), и repr() возвращают строку, которую вы разместили выше. Однако оболочка ipython возвращает немного другое, более информативное: {'b': {'a': <Recursion on dict with id = 17830960>}}
@denilson: python использует модуль pprint, который доступен в стандартной оболочке python.
+1 за первый, о котором я совершенно не имел ни малейшего представления.
Множественные ссылки на итератор
Вы можете создать несколько ссылок на один и тот же итератор, используя умножение списка:
>>> i = (1,2,3,4,5,6,7,8,9,10) # or any iterable object
>>> iterators = [iter(i)] * 2
>>> iterators[0].next()
1
>>> iterators[1].next()
2
>>> iterators[0].next()
3
Это можно использовать для группировки итерируемого объекта в куски, например, как в этом примере из Документация itertools
def grouper(n, iterable, fillvalue=None):
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
Вы можете сделать обратное с itertools.tee - взять один итератор и вернуть n, который дает то же самое, но не разделяет состояние.
На самом деле я не вижу разницы в этом: «a = iter (i)», а затем «b = a». Я также получаю несколько ссылок на один и тот же итератор - для меня в этом нет никакого волшебства, никаких скрытых особенность, что это просто обычный справочный материал для копирования языка. Что сделано, так это создание итератора, затем (умножение списка) копирование этого итератора несколько раз. Все, все на языке.
@Juergen: действительно, a = iter(i); b = a делает то же самое, и я мог бы записать это в ответ вместо [iter(i)] * n. В любом случае, никакого "волшебства" в этом нет. Это ничем не отличается от любого другого ответа на этот вопрос - ни один из них не является «волшебным», они все на языке. Что делает функции «скрытыми», так это то, что многие люди не осознают, что они возможны, или не осознают интересных способов их использования, пока на них не укажут явно.
Ну, во-первых, вы можете сделать это произвольное количество раз с [iter(i)]*n. Кроме того, не обязательно хорошо известно (что опасно для многих), что list*int создает ссылочные, а не фактические копии элементов списка. Приятно видеть, что это действительно как-то полезно.
Вы можете спросить любой объект, из какого модуля он пришел, посмотрев на его свойство __ module__. Это полезно, например, если вы экспериментируете с командной строкой и много чего импортировали.
Аналогичным образом вы можете спросить модуль, откуда он взялся, посмотрев на его свойство __ file__. Это полезно при отладке проблем с путями.
изменение итерации с использованием отрицательного шага
>>> s = "Hello World"
>>> s[::-1]
'dlroW olleH'
>>> a = (1,2,3,4,5,6)
>>> a[::-1]
(6, 5, 4, 3, 2, 1)
>>> a = [5,4,3,2,1]
>>> a[::-1]
[1, 2, 3, 4, 5]
Полезно знать, но второстепенный момент: это работает только с последовательностями, которые в целом не повторяются. То есть (n for n in (1,2,3,4,5))[::-1] не работает.
Эта нотация фактически создаст новый (перевернутый) экземпляр этой последовательности, что в некоторых случаях может быть нежелательным. Для таких случаев лучше использовать функцию reversed(), так как она возвращает обратный итератор вместо выделения новой последовательности.
При использовании интерактивной оболочки "_" содержит значение последнего напечатанного элемента:
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> _
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
Я всегда забываю об этом! Это отличная функция.
Автоматическая переменная _ - лучшая функция при использовании оболочки Python в качестве калькулятора. Кстати, очень мощный калькулятор.
Я все еще пытаюсь использовать %% в оболочке python из слишком большого количества Mathematica в предыдущей жизни ... Если бы только %% было допустимым именем переменной, я бы установил %% = _...
Это уже кто-то дал (не знаю, было ли это раньше, но проголосовали выше).
__ для предпоследнего и ___ для предпоследнего
Срезы и изменчивость
Копирование списков
>>> x = [1,2,3]
>>> y = x[:]
>>> y.pop()
3
>>> y
[1, 2]
>>> x
[1, 2, 3]
Замена списков
>>> x = [1,2,3]
>>> y = x
>>> y[:] = [4,5,6]
>>> x
[4, 5, 6]
Совместите распаковку с функцией печати:
# in 2.6 <= python < 3.0, 3.0 + the print function is native
from __future__ import print_function
mylist = ['foo', 'bar', 'some other value', 1,2,3,4]
print(*mylist)
Я предпочитаю что-то вроде print(' '.join([str(x) for x in mylist])). Использовать такую распаковку слишком умно.
С точки зрения производительности, я думаю, что «умная» версия быстрее (после проведения некоторых совершенно ненаучных тестов). Кроме того, вы знаете, что * означает, что вы распаковываете список или кортеж, и можете использовать ключевое слово sep.
Я нахожу это простым и понятным, но мне всегда интересно, почему Пилинт настаивает на том, что в нем слишком много магии;)
@ Paweł Praak: Я считаю, что PyLint просто считает * и ** слишком волшебными, и точка.
возможно, у некоторых людей просто аллергия на * и ** из-за сходства указателя и двойного указателя;)
@Brian Я бы отбросил список и использовал генератор print(' '.join(word for word in mylist))
Этот ответ был перенесен в сам вопрос по просьбе многих людей.
+1 за удивительность, время и преданность делу.
Можно ли принять этот ответ или перенести его в вопрос? Было бы неплохо, чтобы такой индекс был наверху.
Из словаря python 3.1 (2.7) поддерживаются определения наборов:
{ a:a for a in range(10) }
{ a for a in range(10) }
не существует такой вещи, как понимание кортежей, и это не синтаксис для понимания dict.
Отредактировал опечатку с пониманием слов.
ох, похоже, мне нужно обновить свою версию python, чтобы я мог играть с dict и устанавливать понимания
для словарей это лучше, но dict( (a,a) for a in range(10) ) тоже работает, и ваша ошибка, вероятно, связана с запоминанием этой формы
Я не могу ждать использовать эту функцию.
Python 2.x игнорирует запятые, если они находятся после последнего элемента последовательности:
>>> a_tuple_for_instance = (0,1,2,3,)
>>> another_tuple = (0,1,2,3)
>>> a_tuple_for_instance == another_tuple
True
Завершающая запятая приводит к тому, что одиночный элемент в скобках обрабатывается как последовательность:
>>> a_tuple_with_one_element = (8,)
Python3 также игнорирует их.
** Using sets to reference contents in sets of frozensets**
Как вы, наверное, знаете, наборы являются изменяемыми и, следовательно, не хешируемыми, поэтому необходимо использовать frozensets, если вы хотите создать набор наборов (или использовать наборы в качестве ключей словаря):
>>> fabc = frozenset('abc')
>>> fxyz = frozenset('xyz')
>>> mset = set((fabc, fxyz))
>>> mset
{frozenset({'a', 'c', 'b'}), frozenset({'y', 'x', 'z'})}
Однако можно проверить членство и удалить / отбросить членов, используя обычные наборы:
>>> abc = set('abc')
>>> abc in mset
True
>>> mset.remove(abc)
>>> mset
{frozenset({'y', 'x', 'z'})}
Цитата из документов стандартной библиотеки Python:
Note, the
elemargument to the__contains__(),remove(), anddiscard()methods may be a set. To support searching for an equivalent frozenset, theelemset is temporarily mutated during the search and then restored. During the search, theelemset should not be read or mutated since it does not have a meaningful value.
К сожалению, и, возможно, удивительно, то же самое нельзя сказать о словарях:
>>> mdict = {fabc:1, fxyz:2}
>>> fabc in mdict
True
>>> abc in mdict
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
TypeError: unhashable type: 'set'
Служебная функция textwrap.dedent в python может оказаться весьма полезной для проверки того, что возвращенная многострочная строка равна ожидаемому результату, не нарушая отступы ваших модульных тестов:
import unittest, textwrap
class XMLTests(unittest.TestCase):
def test_returned_xml_value(self):
returned_xml = call_to_function_that_returns_xml()
expected_value = textwrap.dedent("""\
<?xml version = "1.0" encoding = "utf-8"?>
<root_node>
<my_node>my_content</my_node>
</root_node>
""")
self.assertEqual(expected_value, returned_xml)
Срезы как lvalues. Это Решето Эратосфена создает список, который имеет либо простое число, либо 0. Элементы обнуляются при назначении среза в цикле.
def eras(n):
last = n + 1
sieve = [0,0] + list(range(2, last))
sqn = int(round(n ** 0.5))
it = (i for i in xrange(2, sqn + 1) if sieve[i])
for i in it:
sieve[i*i:last:i] = [0] * (n//i - i + 1)
return filter(None, sieve)
Для работы левому срезу должен быть назначен список справа такой же длины.
Лямбда-функции обычно используются для быстрого преобразования одного значения в другое, но их также можно использовать для обертывания значения в функции:
>>> f = lambda: 'foo'
>>> f()
'foo'
Они также могут принимать обычный синтаксис *args и **kwargs:
>>> g = lambda *args, **kwargs: args[0], kwargs['thing']
>>> g(1, 2, 3, thing='stuff')
(1, 'stuff')
Основная причина, по которой я хочу сохранить лямбду: defaultdict(lambda: 1).
Многострочные струны
Один из подходов - использовать обратную косую черту:
>>> sql = "select * from some_table \
where id > 10"
>>> print sql
select * from some_table where id > 10
Другой вариант - использовать тройную кавычку:
>>> sql = """select * from some_table
where id > 10"""
>>> print sql
select * from some_table where id > 10
Проблема с ними в том, что они не имеют отступа (плохо выглядят в вашем коде). Если вы попытаетесь сделать отступ, он просто напечатает введенные вами пробелы.
Третье решение, которое я нашел недавно, - разделить строку на строки и заключить их в круглые скобки:
>>> sql = ("select * from some_table " # <-- no comma, whitespace at end
"where id > 10 "
"order by name")
>>> print sql
select * from some_table where id > 10 order by name
обратите внимание, что между строками нет запятой (это не кортеж), и вы должны учитывать любые конечные / ведущие пробелы, которые должна иметь ваша строка. Между прочим, все они работают с заполнителями (например, "my name is %s" % name).
давно искали это
Это хорошо при написании длинного кода в коде, сохраняя при этом небольшую длину строки!
Существует менее известный третий аргумент встроенной функции pow(), который позволяет вычислять xy по модулю z более эффективно, чем просто выполнение (x ** y) % z:
>>> x, y, z = 1234567890, 2345678901, 17
>>> pow(x, y, z) # almost instantaneous
6
Для сравнения, (x ** y) % z не дал результата в течение одной минуты на моей машине при тех же значениях.
Мне всегда было интересно, какой вариант использования для этого. Я не встречал ни одного, но опять же, я не занимаюсь научными вычислениями.
@buzkor: это тоже очень полезно для криптографии
Помните, что это функция встроенныйpow(). Это нет, функция math.pow(), которая принимает только 2 аргумента.
Я помню, как категорически заявлял, что я не смогу кодировать криптографию на чистом Python без этой функции. Это было в 2003 году, поэтому версия Python, с которой я работал, была 2.2 или 2.3. Интересно, дурачился ли я, и тогда у pow был этот третий параметр или нет.
pow имел этот третий параметр, по крайней мере, начиная с Python 2.1. Однако, согласно документации, «[i] в Python 2.1 и более ранних версиях pow() с тремя аргументами с плавающей запятой возвращал платформо-зависимые результаты в зависимости от случайностей округления с плавающей запятой».
Самое замечательное здесь то, что вы можете отвергать это поведение в своих собственных объектах, используя __pow__. Вам просто нужно определить необязательный третий аргумент. И для получения дополнительной информации о том, где это будет использоваться, см. en.wikipedia.org/wiki/Modular_exponentiation.
Маленькая теорема Ферма сделана быстро!
Обратные косые черты внутри необработанных строк по-прежнему могут избегать кавычек. Видеть это:
>>> print repr(r"aaa\"bbb")
'aaa\"bbb'
Обратите внимание, что в последней строке присутствуют как обратная косая черта, так и двойные кавычки.
Как следствие, вы не можете заканчивать необработанную строку обратной косой чертой:
>>> print repr(r"C:\")
SyntaxError: EOL while scanning string literal
>>> print repr(r"C:\"")
'C:\"'
Это происходит потому, что необработанные строки были реализованы для помощи в написании регулярных выражений, а не для записи путей Windows. Прочтите подробное обсуждение этого вопроса на Попался - обратная косая черта в именах файлов Windows.
Обратите внимание, что обратная косая черта является частью Все еще строки после этого ... Так что можно не рассматривать это как обычное экранирование.
Вам, вероятно, лучше использовать одинарные кавычки ' для внешней строки.
Или просто используйте (прямые) косые черты, так как Windows API будет переводить их автоматически, и тогда вы, наконец, можете забыть о путях в стиле DOS. (Хотя вы должен используете обратную косую черту для ресурсов стиля "\\ server \ share \ path \ file")
Умножение последовательности и отраженные операнды
>>> 'xyz' * 3
'xyzxyzxyz'
>>> [1, 2] * 3
[1, 2, 1, 2, 1, 2]
>>> (1, 2) * 3
(1, 2, 1, 2, 1, 2)
Тот же результат мы получаем с отраженными (переставленными) операндами
>>> 3 * 'xyz'
'xyzxyzxyz'
Это работает так:
>>> s = 'xyz'
>>> num = 3
Чтобы оценить выражение, интерпретатор s * номер вызывает s .___ mul ___ (число)
>>> s * num
'xyzxyzxyz'
>>> s.__mul__(num)
'xyzxyzxyz'
Чтобы оценить выражение, интерпретатор число * с вызывает число .___ муль ___ (s)
>>> num * s
'xyzxyzxyz'
>>> num.__mul__(s)
NotImplemented
Если вызов возвращает Не реализована, тогда интерпретатор вызывает отраженная операция s .___ rmul ___ (число), если операнды имеют разные типы
>>> s.__rmul__(num)
'xyzxyzxyz'
См. http://docs.python.org/reference/datamodel.html#object.rmul
+1 Я знал об умножении последовательностей, но отраженные операнды для меня в новинку.
@Space, в конце концов, было бы непифонично иметь x * y != y * x :)
В python у вас май есть x * y! = Y * x (этого достаточно, чтобы поиграть с методами 'мул').
Увидев много вопросов о проблемах с x= [] * 20, я думаю, не было бы лучше делать мелкие копии операндов по умолчанию.
enumerate частично описан в этот ответ, но недавно я обнаружил еще более скрытую функцию enumerate, которая, как мне кажется, заслуживает отдельной публикации, а не просто комментария.
Начиная с Python 2.6, вы можете указать начальный индекс enumerate во втором аргументе:
>>> l = ["spam", "ham", "eggs"]
>>> list(enumerate(l))
>>> [(0, "spam"), (1, "ham"), (2, "eggs")]
>>> list(enumerate(l, 1))
>>> [(1, "spam"), (2, "ham"), (3, "eggs")]
Одно место, где я нашел это чрезвычайно полезным, - это когда я перечисляю элементы симметричной матрицы. Поскольку матрица симметрична, я могу сэкономить время, перебирая только верхний треугольник, но в этом случае я должен использовать enumerate с другим начальным индексом во внутреннем цикле for, чтобы правильно отслеживать индексы строки и столбца:
for ri, row in enumerate(matrix):
for ci, column in enumerate(matrix[ri:], ri):
# ci now refers to the proper column index
Как ни странно, такое поведение enumerate не задокументировано в help(enumerate), только в онлайн-документация.
help(enumerate) имеет правильную сигнатуру функции в python2.x, но не в py3k. Полагаю, нужно исправить ошибку.
help(enumerate) определенно ошибочен в Python 2.6.5. Возможно, они уже исправили это в Python 2.7.
help(enumerate) из Python 3.1.2 говорит перечислить класс (объект) | перечислить (итерируемый) -> итератор для индекса, значение итерируемого, но трюк из ответа работает нормально.
Похоже, это было добавлено в Python 2.6, так как в Python 2.5 это не работает.
Не «скрытый», но весьма полезный и редко используемый
Быстрое создание таких функций соединения строк
comma_join = ",".join
semi_join = ";".join
print comma_join(["foo","bar","baz"])
'foo,bar,baz
и
Возможность создавать списки строк более элегантно, чем кавычки, запятые.
l = ["item1", "item2", "item3"]
заменен на
l = "item1 item2 item3".split()
Я думаю, что и то, и другое делают материал более длинным и запутанным.
Я не знаю. Я нашел места, где разумное использование облегчало чтение.
Модель объектных данных
Вы можете переопределить оператор любой в языке для своих собственных классов. См. Полный список в эта страница. Некоторые примеры:
Вы можете изменить любой оператор (* + - / // % ^ == < > <= >= . и т. д.). Все это делается путем переопределения __mul__, __add__ и т. д. В ваших объектах. Вы даже можете переопределить такие вещи, как __rmul__, чтобы обрабатывать отдельно your_object*something_else и something_else*your_object. . - это доступ к атрибутам (a.b), который можно переопределить для обработки любого произвольного b с помощью __getattr__. Также сюда включен a(…) с использованием __call__.
Вы можете создать свой собственный синтаксис среза (a[stuff]), который может быть очень сложным и сильно отличаться от стандартного синтаксиса, используемого в списках (numpy имеет хороший пример силы этого в своих массивах), используя любую комбинацию ,, : и …, который вам нравится, используя объекты Slice.
Обращайте особое внимание на то, что происходит со многими ключевыми словами в языке. Включены del, in, import и not.
Обработайте то, что происходит, когда с вашим объектом вызывается множество встроенных функций. Стандартные __int__, __str__ и т. д. Идут сюда, но также идут __len__, __reversed__, __abs__ и три аргумента __pow__ (для модульного возведения в степень).
Для in необходимо переопределить __contains__.
распаковка кортежей в Python 3
в python 3 вы можете использовать синтаксис, идентичный необязательным аргументам в определении функции для распаковки кортежа:
>>> first,second,*rest = (1,2,3,4,5,6,7,8)
>>> first
1
>>> second
2
>>> rest
[3, 4, 5, 6, 7, 8]
но менее известная и более мощная функция позволяет вам иметь неизвестное количество элементов в середине списка:
>>> first,*rest,last = (1,2,3,4,5,6,7,8)
>>> first
1
>>> rest
[2, 3, 4, 5, 6, 7]
>>> last
8
Довольно аскетично :) крутой :)
мне нравится, облом не работает в 2.7 ..
вставить против добавления
не особенность, но может быть интересно
предположим, вы хотите вставить некоторые данные в список, а затем отменить его. самая легкая вещь
count = 10 ** 5
nums = []
for x in range(count):
nums.append(x)
nums.reverse()
тогда вы думаете: а как насчет того, чтобы вместо этого вставить числа с начала? так:
count = 10 ** 5
nums = []
for x in range(count):
nums.insert(0, x)
но оказывается в 100 раз медленнее! если мы установим count = 10 ** 6, он будет в 1000 раз медленнее; это потому, что insert - O (n ^ 2), а append - O (n).
причина этой разницы в том, что insert должен перемещать каждый элемент в списке каждый раз, когда он вызывается; append просто добавьте в конец списка эти элементы (иногда приходится перераспределять все, но это все равно намного быстрее)
Или вы можете использовать nums.reverse () и сделать это ядром - без необходимости использовать range ()
я не понял твою точку зрения, извини ..
Интересен факт реализации списков Python с помощью массивов; однако этот пример не так полезен, потому что идиоматический способ перевернуть список - это использовать обратный метод без каких-либо дополнительных шагов.
И поэтому существует collections.deque - вы можете вставлять и выталкивать записи с любого конца в O (1)
>>> node = namedtuple('node', "a b")
>>> node(1,2) + node(5,6)
(1, 2, 5, 6)
>>> (node(1,2), node(5,6))
(node(a=1, b=2), node(a=5, b=6))
>>>
Еще несколько экспериментов для ответа на комментарии:
>>> from collections import namedtuple
>>> from operator import *
>>> mytuple = namedtuple('A', "a b")
>>> yourtuple = namedtuple('Z', "x y")
>>> mytuple(1,2) + yourtuple(5,6)
(1, 2, 5, 6)
>>> q = [mytuple(1,2), yourtuple(5,6)]
>>> q
[A(a=1, b=2), Z(x=5, y=6)]
>>> reduce(operator.__add__, q)
(1, 2, 5, 6)
Итак, namedtuple - это подтип интересно для tuple.
На этом этапе вы потеряли всякий контекст. Если вам не нужен контекст или данные не структурированы определенным образом, зачем вообще кортеж? Неужели вы просто используете это как список?
@Samir Talwar Вопрос / ответ о скрытых функциях. Вы знали об этом? Я не защищаю тот или иной дизайн, а просто указываю на то, что там есть. Когда я впервые попытался использовать именованные кортежи, я подумал, что они не будут совпадать, как кортежи, но ... Позвольте мне расширить пример, чтобы показать вам.
@Apalala: Я предполагал это, но никогда не проверял. Вы правы: это интересная и скрытая особенность. Думаю, полезный - другое дело.
Также интересно то, что вы можете передать результат вызова namedtuple непосредственно в определение класса, как в class rectangle(namedtuple("rectangle", "width height")):, чтобы добавить собственные методы.
@Samir Talwar Я использую namedtuple в качестве представления для деревьев синтаксического анализа, и их поведение было полезно при слиянии братьев и сестер, поэтому они больше походили на списки. Представьте себе типичные грамматические конструкции для списка ...
@ Апалала: Хорошо, ты меня продал. Не могу сказать, как я подхожу к проблеме, но эта функция явно полезна.
@ Бен Бланк. Я не понял вашего комментария о том, как давать имена классам.
@Apalala - Вот пример: pastebin.com/d6e5VMgb
@ Бен Бланк. Невероятный! Это заслуживает отдельного ответа.
Модуль экспортирует ВСЕ в свое пространство имен
Включая имена, импортированные из других модулей!
# this is "answer42.py"
from operator import *
from inspect import *
Теперь проверьте, что можно импортировать из модуля.
>>> import answer42
>>> answer42.__dict__.keys()
['gt', 'imul', 'ge', 'setslice', 'ArgInfo', 'getfile', 'isCallable', 'getsourcelines', 'CO_OPTIMIZED', 'le', 're', 'isgenerator', 'ArgSpec', 'imp', 'lt', 'delslice', 'BlockFinder', 'getargspec', 'currentframe', 'CO_NOFREE', 'namedtuple', 'rshift', 'string', 'getframeinfo', '__file__', 'strseq', 'iconcat', 'getmro', 'mod', 'getcallargs', 'isub', 'getouterframes', 'isdatadescriptor', 'modulesbyfile', 'setitem', 'truth', 'Attribute', 'div', 'CO_NESTED', 'ixor', 'getargvalues', 'ismemberdescriptor', 'getsource', 'isMappingType', 'eq', 'index', 'xor', 'sub', 'getcomments', 'neg', 'getslice', 'isframe', '__builtins__', 'abs', 'getmembers', 'mul', 'getclasstree', 'irepeat', 'is_', 'getitem', 'indexOf', 'Traceback', 'findsource', 'ModuleInfo', 'ipow', 'TPFLAGS_IS_ABSTRACT', 'or_', 'joinseq', 'is_not', 'itruediv', 'getsourcefile', 'dis', 'os', 'iand', 'countOf', 'getinnerframes', 'pow', 'pos', 'and_', 'lshift', '__name__', 'sequenceIncludes', 'isabstract', 'isbuiltin', 'invert', 'contains', 'add', 'isSequenceType', 'irshift', 'types', 'tokenize', 'isfunction', 'not_', 'istraceback', 'getmoduleinfo', 'isgeneratorfunction', 'getargs', 'CO_GENERATOR', 'cleandoc', 'classify_class_attrs', 'EndOfBlock', 'walktree', '__doc__', 'getmodule', 'isNumberType', 'ilshift', 'ismethod', 'ifloordiv', 'formatargvalues', 'indentsize', 'getmodulename', 'inv', 'Arguments', 'iscode', 'CO_NEWLOCALS', 'formatargspec', 'iadd', 'getlineno', 'imod', 'CO_VARKEYWORDS', 'ne', 'idiv', '__package__', 'CO_VARARGS', 'attrgetter', 'methodcaller', 'truediv', 'repeat', 'trace', 'isclass', 'ior', 'ismethoddescriptor', 'sys', 'isroutine', 'delitem', 'stack', 'concat', 'getdoc', 'getabsfile', 'ismodule', 'linecache', 'floordiv', 'isgetsetdescriptor', 'itemgetter', 'getblock']
>>> from answer42 import getmembers
>>> getmembers
<function getmembers at 0xb74b2924>
>>>
Это хорошая причина не для from x import *, а для определения __all__ =.
Как это скрытая функция? __all__ существует для ограничения того, что экспортируется, и это даже в учебнике.
@PiotrLegnica Знаете ли вы, что модуль экспортирует также то, что он импортирует, если не используется _все_? Это не похоже на большинство языков с модулями, и я не читал об этой «возможности» в документации, поэтому для меня она квалифицируется как скрытый.
@Apalala: почему не следует экспортировать импортированные (под) модули, учитывая тот факт, что они находятся в пространстве имен основного модуля?
@Cristian Ciuptu. В большинстве других языков модуль (или его эквивалент) экспортирует только то, что он определяет, плюс, неявно, то, что доступно из того, что он определяет. Это традиционно часть разделения задач и сокрытия реализации. Модуль может импортировать, скажем, math для выполнения своей задачи и справиться со стандартной арифметикой в более поздних версиях; импортирующие модули не должны знать об этом (традиционно).
IOW, если вы хотите использовать math.sqrt(), вам следует импортировать его из math, а не из answer42.
@Apala: В первую очередь я понял вашу точку зрения относительно других языков, но, учитывая динамический характер Python и объектную ориентацию, такое поведение не вызывает удивления.
@Cristian Ciupitu. Это строго плохо документированный выбор дизайна, который не имеет ничего общего с динамикой языка. Это также настолько необычно, неожиданно и бесполезно, что может считаться недостатком дизайна.
@Apalala: чем модуль отличается от класса или, скажем, типа int или float? Все они являются объектами, и все они находятся в пространстве имен модуля. Дизайн выдержан. Это позволяет вам делать такие вещи, как def f(m, x): return m.sqrt(x); f(math, x), хотя это не совсем хороший стиль кодирования. Эта «особенность» необычна и неожиданна, только если вы сравните ее с другими языками (которые менее «динамичны», что бы это ни значило).
@Apalala: если вы хотите увидеть хороший вариант использования, ознакомьтесь с исходным кодом модуля os. Он делает такие вещи, как import posixpath as path или import ntpath as path, posixpath и ntpath, конечно же, другие модули.
@Cristian Ciupitu Я уступаю. Это полезно и постоянно используется. Но мне все еще не нравится, что это так недокументировано.
Операторы можно вызывать как функции:
from operator import add
print reduce(add, [1,2,3,4,5,6])
? как вы думаете, операторы?
извините, я не поняла ... как вы думаете, что такое операторы?
@Ant, если вы уже знали, что операторы являются функциями, можете проигнорировать этот совет. Не все языки реализуют операторы как функции, поэтому человек, пришедший с другого языка, мог этого не знать.
Простота:
>>> 'str' in 'string'
True
>>> 'no' in 'yes'
False
>>>
это то, что мне нравится в Python, вместо этого я видел много не очень питонической идиомы:
if 'yes'.find("no") == -1:
pass
Я не согласен с этим, потому что это несовместимо с поведением in в других типах последовательностей. 1 in [3, 2, 1] - это True, но [2, 1] in [3, 2, 1] - это False, и это действительно могло бы стать проблемой, если бы это был True. Но это то, что потребуется, чтобы привести его в соответствие с описанным здесь поведением строки. Поэтому я думаю, что подход .find() на самом деле более питонический, хотя, конечно, .find() должен был возвращать None вместо -1.
Также обратите внимание: 'str' не входит в 'abc' #true
Динамически добавляемые атрибуты
Это может быть полезно, если вы думаете о добавлении некоторых атрибутов в свои классы, просто вызывая их. Это можно сделать, переопределив функцию-член __getattribute__, которая вызывается при использовании операнда точка. Итак, давайте посмотрим, например, фиктивный класс:
class Dummy(object):
def __getattribute__(self, name):
f = lambda: 'Hello with %s'%name
return f
Когда вы создаете экземпляр объекта-пустышки и выполняете вызов метода, вы получите следующее:
>>> d = Dummy()
>>> d.b()
'Hello with b'
Наконец, вы даже можете установить атрибут для своего класса, чтобы его можно было определять динамически. Это может быть полезно, если вы работаете с веб-фреймворками Python и хотите выполнять запросы, анализируя имя атрибута.
У меня есть суть в github с этим простым кодом и его эквивалентом на Ruby, сделанным другом.
Заботиться!
Изменение метки функции во время выполнения:
>>> class foo:
... def normal_call(self): print "normal_call"
... def call(self):
... print "first_call"
... self.call = self.normal_call
>>> y = foo()
>>> y.call()
first_call
>>> y.call()
normal_call
>>> y.call()
normal_call
...
Я не уверен, где (и есть ли) это в документах Python, но для python 2.x (по крайней мере, 2.5 и 2.6, которые я только что пробовал) оператор print можно вызывать с круглыми скобками. Это может быть полезно, если вы хотите иметь возможность легко переносить некоторый код Python 2.x на Python 3.x.
Пример:
print('We want Moshiach Now') должен печатать We want Moshiach Now, работающий в python 2.5, 2.6 и 3.x.
Кроме того, оператор not можно вызывать с круглыми скобками в Python 2 и 3:
not False
и
not(False)
оба должны вернуть True.
Круглые скобки также могут работать с другими операторами и операторами.
РЕДАКТИРОВАТЬ: НЕ стоит ставить круглые скобки вокруг операторов not (и, вероятно, любых других операторов), поскольку это может привести к неожиданным ситуациям, подобным этой (это происходит потому, что круглые скобки на самом деле окружают 1):
>>> (not 1) == 9
False
>>> not(1) == 9
True
Это также может работать для некоторых значений (я думаю, что это недопустимое имя идентификатора), например:
not'val' должен вернуть False, а print'We want Moshiach Now' должен вернуть We want Moshiach Now. (но not552 вызовет ошибку NameError, поскольку это действительное имя идентификатора).
Побочный эффект одного из основных правил проектирования синтаксиса Python. Скобки и пробелы можно изменять практически любым способом, что не делает их значение неоднозначным. (Вот почему вы получаете больше свободы при переносе слов, таких как операторы if / while, если вы помещаете тестовое тело в скобки.)
То, что сказал ssokolow, правильно. В python 2.6 язык был обновлен, чтобы быть (более) совместимым с python 3. В python 3+ скобки необходимы для вызова print. см. здесь для получения дополнительной информации: docs.python.org/whatsnew/2.6.html#pep-3105-print-as-a-functi в
Переменные, которые начинаются, но не заканчиваются двойным подчеркиванием, становятся закрытыми, и не только по соглашению. Фактически __var превращается в _Classname__var, где Classname - это класс, в котором была создана переменная. Они не передаются по наследству и не могут быть отменены.
>>> class A:
... def __init__(self):
... self.__var = 5
... def getvar(self):
... return self.__var
...
>>> a = A()
>>> a.__var
Traceback (most recent call last):
File "", line 1, in
AttributeError: A instance has no attribute '__var'
>>> a.getvar()
5
>>> dir(a)
['_A__var', '__doc__', '__init__', '__module__', 'getvar']
>>>
ммм ... не совсем "настоящие частные переменные". Вам ничего не мешает получить доступ к _A__var ...
Ничто также не мешает вам получить доступ к частным ячейкам памяти в программах на C++ для работы с частными переменными, но это серьезно осуждается.
В C++ это ограничение того, как язык обращается к памяти. Если вы хотите рискнуть привести к сбою вашей программы или побудить к этому кого-то, менее знакомого с кодом, этого нельзя предотвратить, не нарушив совместимость с языком C. «Изменение имени члена» Python не предназначено для использования в качестве механизма частных переменных. Он предназначен для публичных членов, которым необходимо отказаться от обычных правил наследования / переопределения. Назвать это «поддержкой частных переменных», потому что один популярный язык не может предложить полную изоляцию переменных, только обесценивает эту концепцию.
Вы правы, я не подобрал хороших слов для описания функциональности - это не настоящие приватные переменные. Отредактировал как мог.
Кому нужны частные переменные? Когда ты тупой, никто не может помешать тебе делать глупые вещи на любом языке программирования. Когда кто-то хочет изменить константу (написанную полностью в верхнем регистре), он может это сделать, но он не получает свой код через проверку кода.
В дополнение к этому, упомянутому ранее haridsv:
>>> foo = bar = baz = 1
>>> foo, bar, baz
(1, 1, 1)
также можно сделать это:
>>> foo, bar, baz = 1, 2, 3
>>> foo, bar, baz
(1, 2, 3)
Совсем не скрытая функция, но все же приятно:
import os.path as op
root_dir = op.abspath(op.join(op.dirname(__file__), ".."))
Сохраняет множество персонажей при манипулировании путями!
Возможно, это не функция программирование как таковая, но она настолько полезна, что я все же опубликую ее.
$ python -m http.server
... за которым следует $ wget http://<ipnumber>:8000/filename где-то еще.
Если вы все еще используете более старую (2.x) версию Python:
$ python -m SimpleHTTPServer
Вы также можете указать порт, например. python -m http.server 80 (поэтому вы можете опустить порт в URL-адресе, если у вас есть корень на стороне сервера)
Идентификатор Unicode в Python3:
>>> 'Unicode字符_تكوين_Variable'.isidentifier()
True
>>> Unicode字符_تكوين_Variable='Python3 rules!'
>>> Unicode字符_تكوين_Variable
'Python3 rules!'
Конечно, использование символов, отличных от ascii, в исходном коде Python по любой причине, кроме написания имен участников в документации по заголовку, является нарушением правил стиля кода pep-8.
Умножьте строку, чтобы она повторилась
print "SO"*5
дает
SOSOSOSOSO
Вы также можете сделать это со списками: [3]*3 == [3, 3, 3]
commands.getoutput
Если вы хотите получить вывод функции, которая выводится напрямую на stdout или stderr, как в случае с os.system, на помощь приходит commands.getoutput. Весь модуль просто потрясающий.
>>> print commands.getoutput('ls')
myFile1.txt myFile2.txt myFile3.txt myFile4.txt myFile5.txt
myFile6.txt myFile7.txt myFile8.txt myFile9.txt myFile10.txt
myFile11.txt myFile12.txt myFile13.txt myFile14.txt module.py
Учитывая, что это в основном предшественник модуля subprocess только для UNIX и был удален в Python 3.0, разве вы не должны говорить о subprocess вместо commands?
Туш! Однако я использую 2.7 для Windows (не только для UNIX) на работе. Это работает здесь, и я только что обнаружил это. Таким образом, я подумал, что об этом стоит упомянуть.
в частности, subprocess.check_output
Когда-либо использовали xrange (INT) вместо range (INT) .... Он использует меньше памяти и не зависит от размера целого числа. Ура !! Разве это не хорошо?
В Python 3 оба они одинаковы.
getattr принимает третий параметрgetattr(obj, attribute_name, default) похож на:
try:
return obj.attribute
except AttributeError:
return default
за исключением того, что attribute_name может быть любой строкой.
Это может быть действительно полезно для утка печатать. Может у вас есть что-то вроде:
class MyThing:
pass
class MyOtherThing:
pass
if isinstance(obj, (MyThing, MyOtherThing)):
process(obj)
(кстати, isinstance(obj, (a,b)) означает isinstance(obj, a) or isinstance(obj, b).)
Когда вы создаете что-то новое, вам нужно будет добавлять его в кортеж везде, где он встречается. (Эта конструкция также вызывает проблемы при перезагрузке модулей или импорте одного и того же файла под двумя именами. Это случается чаще, чем люди хотят признавать.) Но вместо этого вы могли бы сказать:
class MyThing:
processable = True
class MyOtherThing:
processable = True
if getattr(obj, 'processable', False):
process(obj)
Добавьте наследование, и оно станет еще лучше: все ваши примеры обрабатываемых объектов могут наследовать от
class Processable:
processable = True
но вам не нужно убеждать всех наследовать от вашего базового класса, просто чтобы установить атрибут.
mapreduce с использованием функций map и reduce
создать простой продукт следующим образом:
def sumprod(x,y):
return reduce(lambda a,b:a+b, map(lambda a, b: a*b,x,y))
пример:
In [2]: sumprod([1,2,3],[4,5,6])
Out[2]: 32
Простой встроенный инструмент для тестирования производительности
Стандартная библиотека Python поставляется с очень простым в использовании модулем тестирования производительности под названием «timeit». Вы даже можете использовать его из командной строки, чтобы увидеть, какая из нескольких языковых конструкций самая быстрая.
Например.,
% python -m timeit 'r = range(0, 1000)' 'for i in r: pass'
10000 loops, best of 3: 48.4 usec per loop
% python -m timeit 'r = xrange(0, 1000)' 'for i in r: pass'
10000 loops, best of 3: 37.4 usec per loop
бесконечная рекурсия в списке
>>> a = [1,2]
>>> a.append(a)
>>> a
[1, 2, [...]]
>>> a[2]
[1, 2, [...]]
>>> a[2][2][2][2][2][2][2][2][2] == a
True
я не думаю, что это особенность Python. ни это скрыто. где это можно использовать?
в то время как не очень питонический, вы можете записать в файл с помощью print
print>>outFile, 'I am Being Written'
This form is sometimes referred to as “
write()method as described above. With this extended form, the subsequent expressions are printed to this file object. If the first expression evaluates toNone, thensys.stdoutis used as the file for output.
спасибо за добавление объяснения. Мне было любопытно, где я это видел раньше, я просто использовал это некоторое время. Кто-то прокомментировал это вчера вечером, и я понял, что другие, вероятно, не знакомы с его использованием.
Этот синтаксис был обновлен в Python 3, поэтому теперь вы можете использовать print('I am being writtten', file=outFile). Я как раз читал про перемены. Так что теперь он стал намного более питоническим.
очень хорошо. В последнее время я наслаждаюсь pypy, что может только задержать мой переход на python3.
Кодировки string-escape и unicode-escape
Допустим, у вас есть строка из внешнего источника, содержащая \n, \t и так далее. Как преобразовать их в новую строку или вкладку? Просто декодируйте строку, используя кодировку string-escape!
>>> print s
Hello\nStack\toverflow
>>> print s.decode('string-escape')
Hello
Stack overflow
Другая проблема. У вас есть обычная строка с литералами Unicode, такими как \u01245. Как заставить работать? Просто декодируйте строку, используя кодировку unicode-escape!
>>> s = '\u041f\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442!'
>>> print s
\u041f\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442!
>>> print unicode(s)
\u041f\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442!
>>> print unicode(s, 'unicode-escape')
Привіт, світ!
list с помощью sum().Встроенная функция sum() может использоваться для __add__list вместе, обеспечивая удобный способ сгладить list для list:
Python 2.7.1 (r271:86832, May 27 2011, 21:41:45)
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> l = [[1, 2, 3], [4, 5], [6], [7, 8, 9]]
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Это убийца из Алекс Мартелли. Все экземпляры Borg имеют общее состояние. Это устраняет необходимость использования одноэлементного шаблона (экземпляры не имеют значения, когда состояние является общим) и является довольно элегантным (но более сложным с новыми классами).
Значение foo можно переназначить в любом случае, и все будет обновлено, вы даже можете переназначить весь dict. Борг - идеальное имя, подробнее здесь.
class Borg:
__shared_state = {'foo': 'bar'}
def __init__(self):
self.__dict__ = self.__shared_state
# rest of your class here
Это идеально подходит для совместного использования eventlet.GreenPool для управления параллелизмом.
чтобы активировать автозаполнение в IDE, которая его принимает (например, IDLE, Editra, IEP), вместо того, чтобы делать: "Здравствуй". (а затем вы нажимаете TAB), вы можете обмануть в IDE, просто сделайте привет ". (и вы нажимаете клавишу TAB) (как вы можете видеть, в начале нет одинарной кавычки), потому что он будет следовать только за последней пунктуацией, это похоже на то, когда вы добавляете: и нажимаете Enter, он добавляет непосредственно отступ, не знаю, внесет ли он изменения, но это не подсказка :)
Может кто-нибудь пояснить, что это значит?
что, когда вы нажимаете вкладку, выбор может быть доступен, даже если это не строка, просто сделайте это, например, IEP: ". и нажмите TAB, вы получите варианты, которые предлагают их при работе со строками ... или сделайте этот другой намек :: и нажмите Enter, вы получите идентификацию :)
Похоже, это всего лишь одна или две функции обычного редактора.
Вот 2 пасхальных яйца:
Один в самом питоне:
>>> import __hello__
Hello world...
И еще один в модуле Werkzeug, который немного сложно выявить, вот он:
Глядя на исходный код Werkzeug, в werkzeug/__init__.py есть строка, которая должна привлечь ваше внимание:
'werkzeug._internal': ['_easteregg']
Если вам немного любопытно, это должно побудить вас взглянуть на werkzeug/_internal.py, там вы найдете функцию _easteregg(), которая принимает в качестве аргумента приложение wsgi, она также содержит некоторые данные в кодировке base64 и 2 вложенные функции, которые кажется, что делает что-то особенное, если в строке запроса находится аргумент с именем macgybarchakku.
Итак, чтобы раскрыть это пасхальное яйцо, похоже, вам нужно обернуть приложение функцией _easteregg(), давайте:
from werkzeug import Request, Response, run_simple
from werkzeug import _easteregg
@Request.application
def application(request):
return Response('Hello World!')
run_simple('localhost', 8080, _easteregg(application))
Теперь, если вы запустите приложение и посетите http: // локальный: 8080 /? macgybarchakku, вы должны увидеть пасхальное яйцо.
Вот полезная функция, которую я использую при отладке ошибок типа
def typePrint(object):
print(str(object) + " - (" + str(type(object)) + ")")
Он просто печатает ввод, за которым следует тип, например
>>> a = 101
>>> typePrint(a)
101 - (<type 'int'>)
for line in open('foo'):
print(line)
что эквивалентно (но лучше):
f = open('foo', 'r')
for line in f.readlines():
print(line)
f.close()
Это совсем не эквивалент, потому что вы не можете предсказать, когда файл будет закрыт. Это зависит от переводчика. Насколько мне известно, мусор CPython собирает объекты как можно быстрее, но другие интерпретаторы могут этого не делать.
Печатать многострочные строки по одному за раз
Не очень полезная функция, скрытая в классе site._Printer, экземпляром которого является объект license. Последний при вызове распечатывает лицензию Python. Можно создать другой объект того же типа, передав строку - например, содержимое файла - в качестве второго аргумента и назовите его:
type(license)(0,open('textfile.txt').read(),0)()
Это будет печатать содержимое файла, разделенное на определенное количество строк за раз:
...
file row 21
file row 22
file row 23
Hit Return for more, or q (and Return) to quit:
Интерактивная отладка скриптов (и строк документации)
Я не думаю, что это так широко известно, как могло бы быть, но добавьте эту строку в любой скрипт python:
import pdb; pdb.set_trace()
вызовет появление отладчика PDB с курсором выполнения в этой точке кода. Что еще менее известно, я думаю, это то, что вы можете использовать ту же строку в doctest:
"""
>>> 1 in (1,2,3)
Becomes
>>> import pdb; pdb.set_trace(); 1 in (1,2,3)
"""
Затем вы можете использовать отладчик для проверки среды тестирования. Вы не можете пройти через doctest, потому что каждая строка запускается автономно, но это отличный инструмент для отладки doctest globs и окружения.
В Python 2 вы можете сгенерировать строковое представление выражения, заключив его в обратные кавычки:
>>> `sorted`
'<built-in function sorted>'
Этого нет в python 3.X.
Не функция программирования, но полезна при использовании Python с bash или shell scripts.
python -c"import os; print(os.getcwd());"
См. документация python здесь. Дополнительные моменты, на которые следует обратить внимание при написании более длинные скрипты Python, можно увидеть в это обсуждение.
У Python есть исключения для очень неожиданных вещей:
Импорт
Это позволит вам импортировать альтернативу, если библиотека отсутствует.
try:
import json
except ImportError:
import simplejson as json
Итерация
Для циклов сделайте это внутренне и перехватите StopIteration:
iter([]).next()
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
iter(a).next()
StopIteration
Утверждение
>>> try:
... assert []
... except AssertionError:
... print "This list should not be empty"
This list should not be empty
Хотя это более подробный вариант для одной проверки, таким образом можно сократить несколько проверок, смешивающих исключения и логические операторы с одним и тем же сообщением об ошибке.
Целые числа округления: В Python есть функция round, которая возвращает числа типа double:
>>> print round(1123.456789, 4)
1123.4568
>>> print round(1123.456789, 2)
1123.46
>>> print round(1123.456789, 0)
1123.0
У этой функции есть чудесное волшебное свойство:
>>> print round(1123.456789, -1)
1120.0
>>> print round(1123.456789, -2)
1100.0
Если вам нужно целое число в результате, используйте int для преобразования типа:
>>> print int(round(1123.456789, -2))
1100
>>> print int(round(8359980, -2))
8360000
Спасибо Грегор.
некоторые интересные функции с сокращением и оператором.
>>> from operator import add,mul
>>> reduce(add,[1,2,3,4])
10
>>> reduce(mul,[1,2,3,4])
24
>>> reduce(add,[[1,2,3,4],[1,2,3,4]])
[1, 2, 3, 4, 1, 2, 3, 4]
>>> reduce(add,(1,2,3,4))
10
>>> reduce(mul,(1,2,3,4))
24
Позиционные расширения и расширения ключевых слов Python можно использовать «на лету», а не только из сохраненного списка.
l=lambda x,y,z:x+y+z
a=1,2,3
print l(*a)
print l(*[a[0],2,3])
Обычно это более полезно с такими вещами:
a=[2,3]
l(*(a+[3]))
Диктограммы
>>> {i: i**2 for i in range(5)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Установить понимание
>>> {i**2 for i in range(5)}
set([0, 1, 4, 16, 9])
Это уже описано в stackoverflow.com/a/224747/497043.
Не совсем скрытая функция, но то, что может пригодиться.
для просмотра элементов в списке попарно
for x, y in zip(s, s[1:]):
>>> float('infinity')
inf
>>> float('NaN')
nan
Больше информации:
Люди слишком часто об этом забывают. Я видел такие вещи, как наличие аргумента "count" для функции, который затем уменьшается на единицу, пока не дойдет до нуля, по умолчанию используется специальное значение, которое означает, что не нужно останавливаться, когда float('inf') будет хорошо работать, не требуя любой специальный код вообще (inf - 1 == inf).
Люблю источник для этого: D