Лямбда или оператор?
Допустим у нас есть список напитков, где каждый элемент – кортеж (название, цена):
Хотим отсортировать их по цене, тогда нужно в функцию
Способ 2 –
Если хотите побольше узнать, как пользоваться
Какой бы способ вы предпочли?
Допустим у нас есть список напитков, где каждый элемент – кортеж (название, цена):
drinks = [
('Juice', 100),
('Beer', 200),
('Soda', 50),
('Cocktail', 400),
('Water', 20)
]
Хотим отсортировать их по цене, тогда нужно в функцию
sorted передать параметр key – функцию, которая достанет из кортежа элемент с индексом 1 – цену. Можно поступить разными способами. Способ 1 – lambda:>>> sorted(drinks, key=lambda d: d[1])
[('Water', 20), ('Soda', 50), ('Juice', 100), ('Beer', 200), ('Cocktail', 400)]Способ 2 –
operator.itemgetter:>>> from operator import itemgetter
>>> sorted(drinks, key=itemgetter(1))
[('Water', 20), ('Soda', 50), ('Juice', 100), ('Beer', 200), ('Cocktail', 400)]Если хотите побольше узнать, как пользоваться
key, то приглашаю прочитать новую заметку. Еще там есть про сортировку по нескольким признакам и про сравнение производительности разных способов задания key.Какой бы способ вы предпочли?
tirinox.ru
Ключ сортировки key
Методы sort, sorted могут принимать именованный аргумент key. Он должен быть функцией (или чем-то другим вызываемым – callable) с одним аргументом. Смысл key в том, что он вызывается ровно один раз для каждого из элементов списка (итератора и т.п.), которой…
При разборе вложенных структур из словарей и списков (например, конфигов), удобно пользоваться блоком
Ловим
Пример:
Альтернативно, вы можете сразу обновлять записи словаря (если они не найдены) методом
Может быть переписан как:
Заметьте, что повторный вызов с другим
Красивого всем кода!
try-except.Ловим
IndexError, если индекс отсутствует в списке, и KeyError, если ключ отсутствует в словаре. Однако, лучше ловить LookupError, который является предком обоих исключений:>>> issubclass(KeyError, LookupError)
True
>>> issubclass(IndexError, LookupError)
TrueПример:
config = {}
try:
admin = config['db'][0]['admins']['list'][0]
except LookupError:
admin = 'all'Альтернативно, вы можете сразу обновлять записи словаря (если они не найдены) методом
dict.setdefault(key, default). Этот метод проверяет, есть ли ключ в словаре, если его нет, то в словарь добавляется значение по умолчанию, и оно же возвращается. А если ключ был в словаре, то вернется значение по этому ключу. Поэтому такой неуклюжий код:if 'workers' not in config:
config['workers'] = 8
workers = config['workers']Может быть переписан как:
workers = config.setdefault('workers', 8) Заметьте, что повторный вызов с другим
default не поменяет уже записанное в первый раз значение:>>> d = {}
>>> d.setdefault('foo', 10)
10
>>> d.setdefault('foo', 20)
10Красивого всем кода!
Помните, недавно рассказывал про библиотеку bit? Она славится быстрыми алгоритмами для генерации ключей. Мне пришла идея, что можно воспользоваться этим, чтобы нагенерить красивых Bitcoin адресов, начинающихся или заканчивающихся с заданного слова. Например такого:
1PyWaytDDQMSsEDSpBHgfPrEUJJg8NiC9w
Так как заранее мы не можем знать, какие символы в адресе, и где они будут, то приходится делать большой перебор и проверять каждый адрес:
Вот код перебора:
Сразу предупреждаю, что слова длиннее 5 букв ищет очень долго (сам дождался только 5-символьного). Как только адрес найден, не забудьте сохранить приватный ключ, если хотите им пользоваться.
В заметке даю дополнительную информацию по теме и советы, как ускорить поиск.
1PyWaytDDQMSsEDSpBHgfPrEUJJg8NiC9w
Так как заранее мы не можем знать, какие символы в адресе, и где они будут, то приходится делать большой перебор и проверять каждый адрес:
PATTERN = 'PyWay'
def predicate(addr: str):
# первый символ – ID сети, пропустим его
return addr[1:].startswith(PATTERN)Вот код перебора:
from bit import Key
while True:
k = Key() # новый случайны ключ
if predicate(k.segwit_address):
print(f'{k.segwit_address} with WIF private key {k.to_wif()}')
breakСразу предупреждаю, что слова длиннее 5 букв ищет очень долго (сам дождался только 5-символьного). Как только адрес найден, не забудьте сохранить приватный ключ, если хотите им пользоваться.
В заметке даю дополнительную информацию по теме и советы, как ускорить поиск.
tirinox.ru
Майним красивый Bitcoin адрес на Python
Сегодня покажу, как найти (намайнить) себе красивый адрес Bitcoin кошелька. Красивый адрес, значит, что его первые несколько символов будут заданым нами словом. Я буду использовать библиотеку bit, если вы с ней еще не знакомы, прочтите эту статью. Здесь нам…
Показываем уведомления на рабочем столе
На macOS это очень просто, даже не нужно ставить дополнительный софт и модули, а использовать встроенный osascript.
На Linux можно пойти схожим путем, задействуя программу notify-send (если у вас Ubuntu, то она почти наверняка уже установлена):
Разработчики на Windows, и о вас я не забуду. Попробуйте win10toast.
Есть ли кросс-платформенное решение? Да, это библиотека plyer от создателей Kivy.
plyer умеет не только уведомления, но и предоставляет унифицированный интерфейс к всевозможным API декстопных и мобильных ОС.
Однако, plyer потребует установки дополнительного софта или модулей для каждой платформы. Когда вы в первый раз запустите код, не удивляйтесь ошибкам. Например, на macOS мне потребовалось установить Cython и pyobjus. Библиотека plyer сам по себе не вытягивает эти зависимости, поэтому в вашем проекте не забудьте их добавить самостоятельно (например, в requirements.txt)
На macOS это очень просто, даже не нужно ставить дополнительный софт и модули, а использовать встроенный osascript.
import os
def notify_macos(title, text):
os.system("""
osascript -e 'display notification "{}" with title "{}"'
""".format(text, title))notify_macos("Поздравляю", "Ген супер-человека найден!")На Linux можно пойти схожим путем, задействуя программу notify-send (если у вас Ubuntu, то она почти наверняка уже установлена):
import subprocess as s
def notify_linux(message, title):
subprocess.Popen(['notify-send', title, message])
return
Разработчики на Windows, и о вас я не забуду. Попробуйте win10toast.
# pip install win10toast
from win10toast import ToastNotifier
toaster = ToastNotifier()
toaster.show_toast("Заголовок",
"Текст",
duration=5)
Есть ли кросс-платформенное решение? Да, это библиотека plyer от создателей Kivy.
# pip install plyer
from plyer import notification
notification.notify(
title='Заголовок',
message='Сообщение',
app_icon=None, # e.g. 'C:\\icon_32x32.ico'
timeout=5, # секунд
)
plyer умеет не только уведомления, но и предоставляет унифицированный интерфейс к всевозможным API декстопных и мобильных ОС.
Однако, plyer потребует установки дополнительного софта или модулей для каждой платформы. Когда вы в первый раз запустите код, не удивляйтесь ошибкам. Например, на macOS мне потребовалось установить Cython и pyobjus. Библиотека plyer сам по себе не вытягивает эти зависимости, поэтому в вашем проекте не забудьте их добавить самостоятельно (например, в requirements.txt)
Счетчик itertools.count
Если вам нужно считать неизвестное заранее количество шагов цикла
Можно написать более лаконично, делегировав функциональность по счету к
Если вам нужно считать неизвестное заранее количество шагов цикла
while, то в место кода вида:attempt = 1
while True:
...
attempt += 1Можно написать более лаконично, делегировав функциональность по счету к
count:from itertools import count
for attempt in count(1):
...
count(start=0, step=1) – бесконечный итератор, который выдает возрастрающую последовательность чисел. По умолчанию счет начинается с 0 с шагом 1: 0, 1, 2, 3, 4, ... Но можно и настроить: первый аргумент – начальное значение, второй – шаг. Таким образом, count(2, 3) выдаст 2, 5, 8, 11, ...О наследовании атрибутов
Видел тут на одном из каналов задачку про поле класса и наследование. Загадывать вам ее не буду, но объяснение приведу. Пусть:
Тут понятно и новичку, что поле foo вроде как "наследуется" классами Barak и Clara у класса Abram. Однако, давайте попробуем его поменять:
Видим, что у класса Barak и Clara значение стало 30, а
Работает это так. При поиске атрибута класса сначала спрашивается у самого класса, есть ли у него этот атрибут, если да, то он вернется, если нет, то идут к следующему классу, который старше по иерархии наследования (Clara → Barak → Abram → object). Если у него тоже нет, то идут еще дальше, пока не найдут, иначе возникнет исключение AttributeError.
В нашем примере будем рассуждать с конца. Чему равно
Предок класса Clara – класс Barak. Как только мы написали
А до этого атрибут foo был изначально только у Abram. Если теперь написать
Вывод: как только мы присвоим атрибут, то атрибуты классов-предков перестают на него влиять. Будьте внимательны, ведь такая же логика действует и для методов класса.
Видел тут на одном из каналов задачку про поле класса и наследование. Загадывать вам ее не буду, но объяснение приведу. Пусть:
class Abram:
foo = 10
class Barak(Abram):
pass
class Clara(Barak):
pass
print(Abram.foo, Barak.foo, Clara.foo) # 10 10 10Тут понятно и новичку, что поле foo вроде как "наследуется" классами Barak и Clara у класса Abram. Однако, давайте попробуем его поменять:
Abram.foo = 20
print(Abram.foo, Barak.foo, Clara.foo) # 20 20 20
Barak.foo = 30
print(Abram.foo, Barak.foo, Clara.foo) # 20 30 30
Abram.foo = 40
print(Abram.foo, Barak.foo, Clara.foo) # 40 30 30Видим, что у класса Barak и Clara значение стало 30, а
Abram.foo живет своей жизнью после Barak.foo = 30 и не перестало влиять на прочие классы.Работает это так. При поиске атрибута класса сначала спрашивается у самого класса, есть ли у него этот атрибут, если да, то он вернется, если нет, то идут к следующему классу, который старше по иерархии наследования (Clara → Barak → Abram → object). Если у него тоже нет, то идут еще дальше, пока не найдут, иначе возникнет исключение AttributeError.
В нашем примере будем рассуждать с конца. Чему равно
Clara.foo? Есть ли атрибут foo у Clara? Вообще говоря, его нет, ведь мы ни разу не присваивали ничего к Clara.foo:>>> 'foo' in Clara.__dict__
False
Предок класса Clara – класс Barak. Как только мы написали
Barak.foo = 30 в классе Barak появился свой собственный foo:>>> Barak.foo = 20
>>> 'foo' in Barak.__dict__
True
А до этого атрибут foo был изначально только у Abram. Если теперь написать
Clara.foo = 50, то у каждого из классов будет свой foo.Clara.foo = 50
print(Abram.foo, Barak.foo, Clara.foo) # 40 30 50
Вывод: как только мы присвоим атрибут, то атрибуты классов-предков перестают на него влиять. Будьте внимательны, ведь такая же логика действует и для методов класса.
Как узнать имя переменной?
Какой-то из каналов про Python писал, что это невозможно узнать имя переменной, которой мы что-то присвоили. Это не совсем так. Представляю вам функцию, которая вернет все имена, ассоциированные с переданным ей объектом. Она использует модуль inspect, который позволяет узнать о загруженном в Python коде все, что можно только придумать, в том числе и имена переменных:
Тестируем:
Так как имен может быть несколько, то возвращается список. Кроме того, может быть ситуация, когда в список запрячутся посторонние имена. Например, на None могут ссылаться встроенные переменные интерпретатора:
Зачем это вообще нужно? Например, можно сделать функцию, что будет составлять словарь из переменных по их именам:
Это весело, но, пожалуйста, будьте с этим осторожны, так как код выше примитивен и написан только в демонстрационных целях. Я уже отмечал, что find_names может зацепить не те имена, поэтому не используйте его в своих программах, если нет очень веских на это причин.
#хаки #секреты
Какой-то из каналов про Python писал, что это невозможно узнать имя переменной, которой мы что-то присвоили. Это не совсем так. Представляю вам функцию, которая вернет все имена, ассоциированные с переданным ей объектом. Она использует модуль inspect, который позволяет узнать о загруженном в Python коде все, что можно только придумать, в том числе и имена переменных:
def find_names(obj):
import inspect
# currentframe - текущий контекст выполнения, т.е. эта же функция
# а f_back - фрейм код, который ее вызвал
parent_frame = inspect.currentframe().f_back
# соберем все глобальные и локальные переменные вызывающего кода
# это словарь имя переменной: ее значение
search = {**parent_frame.f_globals, **parent_frame.f_locals}
for name, v in search.items():
# если переменная ЯВЛЯЕТСЯ искомым объектом вернем ее имя
if v is obj:
yield nameТестируем:
class A: ...
x = A()
y = x
print(list(find_names(x))) # ['x', 'y']Так как имен может быть несколько, то возвращается список. Кроме того, может быть ситуация, когда в список запрячутся посторонние имена. Например, на None могут ссылаться встроенные переменные интерпретатора:
a = None
print(list(find_names(a)))
# ['__doc__', '__package__', '__spec__', '__cached__', 'a']Зачем это вообще нужно? Например, можно сделать функцию, что будет составлять словарь из переменных по их именам:
def make_dict(*args):
return {next(find_names(_arg)): _arg for _arg in args}
a, b, c = 10, 20, 30
d = make_dict(a, b, c)
print(d) # {'a': 10, 'b': 20, 'c': 30}Это весело, но, пожалуйста, будьте с этим осторожны, так как код выше примитивен и написан только в демонстрационных целях. Я уже отмечал, что find_names может зацепить не те имена, поэтому не используйте его в своих программах, если нет очень веских на это причин.
#хаки #секреты
NumPy-бродкастинг
Можно ли сложить NumPy-массивы совершенно разных форм?
Оказывается, да! Не будет никаких ошибок, а форма результата будет
Чтобы бродкастинг работал, формы должны быть все-таки совместимы. Вы выравниваем их друг под другом по правому краю и начинаем сравнивать каждый столбик справа налево (от более глубоких уровней вложенности до наружных). Если числа в столбиках равны – прекрасно, действие не требуется. Если в какое-то число в столбике – единица (1), то не беда, это измерение будет копировано столько раз, сколько нужно, чтобы уравнять размеры. А если размерности не хватает, она будет добавлена (это равносильно единице).
Кстати, кто из читателей знает, как выключить бродкастинг, пишите в наш чат. Лично я не нашел способа, а предложения со Stackoverflow оказались нерабочими.
#numpy #datascience
Можно ли сложить NumPy-массивы совершенно разных форм?
import numpy as np
a = np.ones((8, 1, 6, 1))
b = np.ones((7, 1, 5))
(a + b).shape # ?Оказывается, да! Не будет никаких ошибок, а форма результата будет
(8, 7, 6, 5). Интересно, как это получается? Дело в том, что здесь работает механизм бродкастинга (broadcasting), когда недостающие размеры расширяются путем "копирования" данных. А когда формы массивов выровнены, происходит простое поэлементное сложение.Чтобы бродкастинг работал, формы должны быть все-таки совместимы. Вы выравниваем их друг под другом по правому краю и начинаем сравнивать каждый столбик справа налево (от более глубоких уровней вложенности до наружных). Если числа в столбиках равны – прекрасно, действие не требуется. Если в какое-то число в столбике – единица (1), то не беда, это измерение будет копировано столько раз, сколько нужно, чтобы уравнять размеры. А если размерности не хватает, она будет добавлена (это равносильно единице).
A (4d массив): 8 x 1 x 6 x 1
B (3d массив): 7 x 1 x 5
Результат (4d массив): 8 x 7 x 6 x 5Кстати, кто из читателей знает, как выключить бродкастинг, пишите в наш чат. Лично я не нашел способа, а предложения со Stackoverflow оказались нерабочими.
#numpy #datascience
tirinox.ru
NumPy-бродкастинг
Эта тема не очень освещена на русском языке, но является весьма важной по паре причин: бродкастинг упрощает жизнь, и порой он же ее усложняет. Давайте разберемся что это, и как оно работает? Бродкастинг (broadcasting) – автоматическое расширение размерности…
Чтобы сохранять и загружать данные на уровне отдельных байтов пригодится модуль struct.
Форматная строка указывает в какой последовательности и какие типы данных упакованы в байты. За ней следуют сами данные. Вот пример упаковки:
И распаковки:
Приглашаю прочитать статью про struct, где вы найдете:
• Объяснение форматов
• Таблицы типов данных
• Little vs big endian
• Много примеров
Форматная строка указывает в какой последовательности и какие типы данных упакованы в байты. За ней следуют сами данные. Вот пример упаковки:
>>> import struct
>>> struct.pack('>hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
И распаковки:
>>> struct.unpack('>hhl', _)
(1, 2, 3)
Приглашаю прочитать статью про struct, где вы найдете:
• Объяснение форматов
• Таблицы типов данных
• Little vs big endian
• Много примеров
tirinox.ru
Пакуем байты на Python: struct
Кто сказал, что нельзя делать низкоуровневые вещи на Python? Конечно, можно. Давайте научимся упаковывать данные из Python в байты и распаковывать их обратно. Встроенный модуль struct как раз создан для этих целей. В низкоуровневом деле важны детали, а именно…
Задачка. Имеется такой код, где мы делаем 5 записей в словарь:
d = {}
d[float('nan')] = 1
d[float('nan')] = 2
d[1.0] = 'float'
d[1] = 'int'
d[True] = 'bool'
print(len(d))🌷Всех дам поздравляю с Международным женским днем! 🌷
Желаю вам счастья, любви, здоровья, отличного настроения, улыбок, солнца на улице и в душе!
Мы вас очень любим и ценим!
[код]
Желаю вам счастья, любви, здоровья, отличного настроения, улыбок, солнца на улице и в душе!
Мы вас очень любим и ценим!
[код]
Решение предыдущей задачи
Если кратко, то при поиске словарь проверяет сначала хэш (hash) от ключей. Разные хэши – разные ключи – разные записи. Если хэши равны, то проверяется простое равенство (==) ключей. Если и они равны, то считается, что это один и тот же ключ, и ему отвечает одна и та же запись в словаре.
Все
Кстати, спрашивали, как добраться до этих nan. Вот так:
Теперь ситуация с ключами
Поэтому для словаря – ключи
Таким образом, у нас будет 2 записи от двух nan, и одна запись от
Если кратко, то при поиске словарь проверяет сначала хэш (hash) от ключей. Разные хэши – разные ключи – разные записи. Если хэши равны, то проверяется простое равенство (==) ключей. Если и они равны, то считается, что это один и тот же ключ, и ему отвечает одна и та же запись в словаре.
Все
float('nan') имеют одинаковый хэши, но значение NaN (not a number – не число), не равно никакому другому float, включая само себя и другие float('nan'), поэтому для словаря все nan – разные ключи, и каждому из них отвечает отдельная запись.>>> float('nan') == float('nan')
False
>>> hash(float('nan'))
0
>>> {float('nan'): 1, float('nan'): 2}
{nan: 1, nan: 2}Кстати, спрашивали, как добраться до этих nan. Вот так:
>>> keys = list(d.keys()) # список ключей
>>> d[keys[0]], d[keys[1]] # по ключам добираемся до значений
(1, 2)
>>> del d[keys[0]] # убрать одноТеперь ситуация с ключами
1, 1.0, True. Оказывается, их хэши тоже равны между собой. Нюанс в том, что и сами они равны между собой!>>> hash(1), hash(1.0), hash(True)
(1, 1, 1)
>>> 1 == 1.0 == True
TrueПоэтому для словаря – ключи
1, 1.0, True – одинаковые и дают доступ к одной и той же записи. Фактический ключ будет тот, что был записан самым первым.Таким образом, у нас будет 2 записи от двух nan, и одна запись от
1, 1.0, True. Итого, ответ – 3.Танчики на PyGame
Занятые вышли дни, поэтому не смог написать новых статей. Но, чтобы вы не скучали, вот вам один из моих проектов – Танчики на PyGame.
Игра хоть и не доделана полностью: в ней нет меню, звуков и редактора, но геймплей вполне работоспособный. Танчики спавнятся, атакуют, взрываются, стены разрушаются.
Управление – стрелки и пробел на выстрел.
Возможно, кому-то код пригодится, как учебное пособие, или вдруг найдутся добровольцы, которые внесут в него свой вклад. Ссылка на GitHub.
Занятые вышли дни, поэтому не смог написать новых статей. Но, чтобы вы не скучали, вот вам один из моих проектов – Танчики на PyGame.
Игра хоть и не доделана полностью: в ней нет меню, звуков и редактора, но геймплей вполне работоспособный. Танчики спавнятся, атакуют, взрываются, стены разрушаются.
Управление – стрелки и пробел на выстрел.
main.py – точка входа. Инициализирует PyGame, создает класс Game, обрабатывает ввод с клавиатуры.ai.py – интеллект врагов, включая алгоритм их появления.bonus.py – игровой объект бонуса.bonus_field_protect.py – алгоритм работы бонуса на защиту базы.config.py – конфигурация и ключи запуска.discrete_map.py – объект дискретной 2D карты (нужна для карты поля боя и карты для столкновений).explosion.py – игровой объект взрыва.field.py – игровой объект поля боя, обрабатывает столкновения и разрушение мира.game.py – собирает все объекты вместе и связывает события.my_base.py – игровой объект базы игрока (орел).projectile.py – игровой объект снаряда.score_node.py – игровой объект очков при уничтожении врага.spritesheet.py – загрузчик спрайтов из одной сборной текстуры.tank.py – игровой объект любого танка (своего или вражеского).ui.py – элементы пользовательского интерфейса.util.py – вспомогательные функции и классы, включая аниматор, таймер и базовый игровой объект.Возможно, кому-то код пригодится, как учебное пособие, или вдруг найдутся добровольцы, которые внесут в него свой вклад. Ссылка на GitHub.
Думаю, вы знаете, что при форматировании можно задавать параметры, например, число знаков для дробных чисел или выравнивание текста:
Эти параметры тоже можно задать динамически. Нет нужды дважды вызывать
Также вы без проблем можете получать доступ к элементам списков, словарей или объектов прямо внутри форматных строк:
С богатыми возможностями форматирования вы можете познакомиться на сайте https://pyformat.info/ (англ.)
От себя еще добавлю, что f-строки еще круче, чем
Главное условие, чтобы это выражение допускало обертывание в круглые скобки, поэтому нельзя вот так:
Вообще, способность вычислять выражения внутри строк и подставлять результат в нужно место строки называется: "интерполяция строк". Она работает не зависимо от типа кавычек строки, главно наличии буквы f перед строкой.
>>> '{:.3}'.format(2.7182)
'2.72'
>>> '{:^15}'.format('hello')
' hello 'Эти параметры тоже можно задать динамически. Нет нужды дважды вызывать
format, а достаточно просто добавить фигурные скобки внутрь фигурных скобок:>>> '{:.{prec}}'.format(2.7182, prec=3)
'2.72'
>>> '{:{align}{width}}'.format('hello', align='^', width=15)
' hello 'Также вы без проблем можете получать доступ к элементам списков, словарей или объектов прямо внутри форматных строк:
data = [4, 8, 15, 16, 23, 42]
'{d[4]} {d[5]}'.format(d=data)
# '23 42'
class Plant(object):
type = 'tree'
'{p.type}'.format(p=Plant())С богатыми возможностями форматирования вы можете познакомиться на сайте https://pyformat.info/ (англ.)
От себя еще добавлю, что f-строки еще круче, чем
''.format(...): внутри фигурных скобок возможно поставить вообще любое валидное Python выражение, хоть вызов функций:>>> f'2 + 2 = {2 + 2}'
'2 + 2 = 4'
>>> f'sqrt(2) = {2**0.5:.5}'
'sqrt(2) = 1.4142'
>>> data = [1, 2, 3, 4]
>>> f'data sum = {sum(data)}'
'data sum = 10'Главное условие, чтобы это выражение допускало обертывание в круглые скобки, поэтому нельзя вот так:
>>> f'{import os}'
File "<fstring>", line 1
(import os)
^
SyntaxError: invalid syntaxВообще, способность вычислять выражения внутри строк и подставлять результат в нужно место строки называется: "интерполяция строк". Она работает не зависимо от типа кавычек строки, главно наличии буквы f перед строкой.
📕 #Библиотека XlsxWriter
Белые воротнички не умеют читать файлы JSON? Начальник требует от вас выгружать отчеты в ламповой Эксельке? Не беда. Библиотека XlsxWriter поможет все автоматизировать без головной боли. Просто взгляните на код:
В статье больше примеров!
#xls #excel
Белые воротнички не умеют читать файлы JSON? Начальник требует от вас выгружать отчеты в ламповой Эксельке? Не беда. Библиотека XlsxWriter поможет все автоматизировать без головной боли. Просто взгляните на код:
import xlsxwriter
# откроем файл на запись
workbook = xlsxwriter.Workbook('my_report.xlsx')
# создадим лист
worksheet = workbook.add_worksheet()
# данные
expenses = (
['Аренда', 1000],
['Комуналка', 100],
['Еда', 300],
['Качалка', 50],
)
# формат для денег
money = workbook.add_format({'num_format': '#,##0"₽"'})
# формат жирности шрифта
bold = workbook.add_format({'bold': True})
worksheet.write('A1', 'Наименование', bold)
worksheet.write('B1', 'Потрачено', bold)
for i, (item, cost) in enumerate(expenses, start=2):
worksheet.write(f'A{i}', item)
worksheet.write(f'B{i}', cost, money)
# колонкой ниже добавить подсчет суммы
worksheet.write('A6', 'Итого:', bold)
worksheet.write('B6', '=SUM(B2:B5)', money)
# задать колонкам от 0 до 1 каждой ширину 15
worksheet.set_column(0, 1, 15)
# сохраняем и закрываем
workbook.close()В статье больше примеров!
#xls #excel
tirinox.ru
Пишем файл Excel из Python
Если вдруг вам потребуется, к примеру, выгружать отчеты из вашей программы, почему бы не воспользоваться общепринятым офисным форматом – Excel? В этом нет ничего сложного, потому что есть прекрасная библиотека XlsxWriter. Приведу для вас немного примеров…
Python – это компилятор или интерпретатор?
Ответ неоднозначный. Python – это и первое, и второе. (Здесь мы говорим про самый распространенный CPython)
Когда вы вводите в терминале операторы по одному, то они выполняются сразу после ввода, в этом случае Python играет роль интерпретатора.
А если вы скармливаете Python исходный файл целиком, то он сначала компилирует его в промежуточное представление: низкоуровненый байт-код. Замечали файлы
Набросал для вас реализацию языка Brainfuck, причем в двух вариантах: интерпретатора и компилятора. Интерпретатор читает программу и сразу выполняет ее команда за командой, а компилятор выдает нам исполняемый файл, которым мы запускаем отдельно от компилятора. Уловили разницу?
Ответ неоднозначный. Python – это и первое, и второе. (Здесь мы говорим про самый распространенный CPython)
Когда вы вводите в терминале операторы по одному, то они выполняются сразу после ввода, в этом случае Python играет роль интерпретатора.
А если вы скармливаете Python исходный файл целиком, то он сначала компилирует его в промежуточное представление: низкоуровненый байт-код. Замечали файлы
*.pyc? Вот это уже скомпилированный байт-код. Он выполняется виртуальной машиной Python.Набросал для вас реализацию языка Brainfuck, причем в двух вариантах: интерпретатора и компилятора. Интерпретатор читает программу и сразу выполняет ее команда за командой, а компилятор выдает нам исполняемый файл, которым мы запускаем отдельно от компилятора. Уловили разницу?
tirinox.ru
Пишем Brainfuck на Python
Есть мнение, что каждый программист должен написать в жизни хотя бы один язык программирования, либо реализовать уже существующий, но своими руками. В качестве примера мы начнем с самого простого и создадим Brainfuck. Согласно Вики: Brainfuck — один из и…
Рассказ о том, как я автоматизировал загрузку гербов субъектов РФ из Википедии как небольшой туториал по веб-скрейпингу.
tirinox.ru
Парсим Википедию с Beautiful Soup 4
Для одного из моих проектов понадобилось раздобыть список субъектов РФ с их гербами. Я решил автоматизировать этот процесс, написав скрипт на языке Python. Поделюсь с вами процессом разработки, трудностями, с которыми столкнулся и их решениями. Парсить будем…
Разбор URL
Функция urlparse из модуля urllib.parse разбирает URL на составные части: протокол, имя хоста, порт, путь, запрос и прочие.
Имя хоста, порт, логин и пароль объединены в поле netloc, но их компоненты доступны для чтения по этим атрибутам:
Собрать обратно ParseResult в URL:
Если мы хотим в URL поменять какие-то части, удобно делать вот так:
Однако таким способом нельзя поменять компоненты netloc, например, отдельно порт. netloc нужно менять целиком:
Функция urlparse из модуля urllib.parse разбирает URL на составные части: протокол, имя хоста, порт, путь, запрос и прочие.
>>> u1 = urlparse('https://tirinox:1234@www.site.com:8080/some/page/index.html?page=2&action=login')
>>> u1
ParseResult(scheme='https', netloc='tirinox:1234@www.site.com:8080', path='/some/page/index.html', params='', query='page=2&action=login', fragment='')
>>> u1.scheme, u1.query, u1.netloc
('https', 'page=2&action=login', 'tirinox:1234@www.site.com:8080')Имя хоста, порт, логин и пароль объединены в поле netloc, но их компоненты доступны для чтения по этим атрибутам:
>>> u1.username, u1.password, u1.hostname, u1.port
('tirinox', '1234', 'www.site.com', 8080)Собрать обратно ParseResult в URL:
>>> u1.geturl()
'https://www.site.com:8080/some/page/index.html?page=2&action=login'Если мы хотим в URL поменять какие-то части, удобно делать вот так:
>>> u1._replace(scheme='http').geturl()
'http://www.site.com:8080/some/page/index.html?page=2&action=login'
Однако таким способом нельзя поменять компоненты netloc, например, отдельно порт. netloc нужно менять целиком:
>>> u1._replace(netloc="user:password@www.site.com:8090").geturl()
'https://user:password@www.site.com:8090/some/page/index.html?page=2&action=login'globals(), locals(), vars(), dir()
Программист на Python может узнать, какие именно переменные определенны в данный момент в интерпретаторе. Переменные можно разделить на локальные и глобальные. Глобальные определены на верхнем уровне кода снаружи функций и классов (грубо говоря без отступов слева). Локальные переменные наоборот определены внутри своих зон видимости, ограниченных классами и функциями.
Функция globals() выдает словарь глобальных переменных (ключ – имя переменной). Функция locals() возвращает словарь только локальных переменных. Пример:
Обратите внимание, что переменная y в locals() имеет другое значение, нежели чем в globals(). Это две разные переменные из разных областей, но внутри функции приоритет имеет локальная y.
Еще важно знать, что в список переменных входят не только простые переменные, которые вы определяете через знак присваивания, но и функции, классы и импортированные модули!
Через словари из locals() и globals() переменные можно не только читать, но и создавать, перезаписывать и удалять:
Функция vars() ведет себя как locals(), если вызвана без аргумента, а если с аргументом, то она просто получает
В глобальном контексте все три функции возвращают одно и тоже – глобальные переменные. Проверьте:
Функциия dir(), будучи вызвана без параметра, возвращает список имен переменных. Глобальных или локальных в зависимости от места вызова:
Все рассмотренные выше функции являются встроенными и не требуют импортов.
Программист на Python может узнать, какие именно переменные определенны в данный момент в интерпретаторе. Переменные можно разделить на локальные и глобальные. Глобальные определены на верхнем уровне кода снаружи функций и классов (грубо говоря без отступов слева). Локальные переменные наоборот определены внутри своих зон видимости, ограниченных классами и функциями.
Функция globals() выдает словарь глобальных переменных (ключ – имя переменной). Функция locals() возвращает словарь только локальных переменных. Пример:
x, y = 5, 10
def test():
y, z = 33, 44
print('globals:', globals())
print('locals:', locals())
test()
"""Вывод:
globals: {'__name__': '__main__', ... '__file__': '/Users/.../vars.py', '__cached__': None, 'x': 5, 'y': 10, 'test': <function test at 0x107677280>}
locals: {'y': 33, 'z': 44}"""Обратите внимание, что переменная y в locals() имеет другое значение, нежели чем в globals(). Это две разные переменные из разных областей, но внутри функции приоритет имеет локальная y.
Еще важно знать, что в список переменных входят не только простые переменные, которые вы определяете через знак присваивания, но и функции, классы и импортированные модули!
Через словари из locals() и globals() переменные можно не только читать, но и создавать, перезаписывать и удалять:
>>> x = 10
>>> globals()['x'] = 5
>>> x
5
>>> globals()['new_var'] = 10
>>> new_var
10
>>> del globals()['new_var']
>>> new_var
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'new_var' is not definedФункция vars() ведет себя как locals(), если вызвана без аргумента, а если с аргументом, то она просто получает
_ _ dict _ _ от аргумента. Если его нет у аргумента, то будет TypeError.class Foo:
def __init__(self):
self.x = 5
f = Foo()
print(vars(f)) # {'x': 5}
print(vars(f) == f.__dict__) # TrueВ глобальном контексте все три функции возвращают одно и тоже – глобальные переменные. Проверьте:
print(globals())
print(locals())
print(vars())
print(globals() == locals() == vars()) # TrueФункциия dir(), будучи вызвана без параметра, возвращает список имен переменных. Глобальных или локальных в зависимости от места вызова:
def test():
x = 10
print(dir()) # ['x']
y = 10
test()
print(dir()) # ['__annotations__', ..., '__spec__', 'test', 'y']Все рассмотренные выше функции являются встроенными и не требуют импортов.
В дополнение об областях видимости переменных
В отличие он некоторых других языков в Python блоки типа
Частая ошибка – затирание внешней переменной в цикле for:
Зоны видимости отделяются только функциями, классами и модулями. Здесь все переменные x – разные:
Самая широкая зона видимости называется builtin. В нее попадают все имена, известные интерпретатору в данный момент, включая вещи импортированные из других модулей.
Казалось бы мы затерли pi, но мы затерли его лишь в глобальной области видимости. Повторно импортируя pi, мы получаем старую переменную с тем же адресом, иными словами мы достаем ее из builtin области в global.
Вы знали о всех этих особенностях?
В отличие он некоторых других языков в Python блоки типа
for, if, while, with не создают областей видимости (scope) для переменных, то есть переменная внутри и снаружи блока будет одна и та же:x = 1
if True:
x = 2
print(x) # 2Частая ошибка – затирание внешней переменной в цикле for:
i = 10
for i in range(5): # затирает i
...
print(i) # 4Зоны видимости отделяются только функциями, классами и модулями. Здесь все переменные x – разные:
x = 1
class Foo:
x = 2
def method(self):
x = 3
return x
print(x, Foo.x, Foo().method()) # все 3 разныеСамая широкая зона видимости называется builtin. В нее попадают все имена, известные интерпретатору в данный момент, включая вещи импортированные из других модулей.
>>> from math import pi
>>> pi, id(pi)
(3.141592653589793, 4465320624)
>>> pi = 3
>>> pi, id(pi)
(3, 4462262880)
>>> from math import pi
>>> pi, id(pi)
(3.141592653589793, 4465320624)Казалось бы мы затерли pi, но мы затерли его лишь в глобальной области видимости. Повторно импортируя pi, мы получаем старую переменную с тем же адресом, иными словами мы достаем ее из builtin области в global.
Вы знали о всех этих особенностях?