Python Lounge: работа и стажировки для программистов
Open in Telegram
Здесь можно найти интересующую вас работу и стажировки для программистов, а так же полезные статьи про Python. Размещение вакансии только - @perezvonyubot Ссылка на канал: @python_lounge Мы входим в сеть promopoisk.com Реклама: @adtgassetsbot
Show more4 245
Subscribers
No data24 hours
-157 days
-6530 days
Posts Archive
Новая рубрика #кодподписчика
На днях одна подписчица присала мне свой интересный и крайне необычный скрипт, поэтому я решил создать новую рубрику на своём канале, в которой буду выкладывать интересные работы своих подписчиков.
В общем, суть программы в том, что берется произвольная картинка, разбивается на кусочки, создаются папки на рабочем столе и эти кусочки первоначальной картинки ставятся как иконки на папки. То есть получается некая мозаика, которую можно собрать в единую картинку прямо на рабочем столе вашего компьютера. По-моему, это отличный и вполне необычный способ отвлечься от работы, особо ничего не открывая.
Теперь по технической части: скрипт написан на Python с использованием модулей win32api и pillow. Весь исходный код доступен здесь на гитхабе, советую посмотреть. Также подписчица просила в раздел Issues написать ваши идеи насчет того, что можно добавить и улучшить.
Да, теперь каждый может прислать своё любое нетривиальное творение мне в личные сообщения, и я с большой вероятностью опубликую.
Дробные числа в Python могут иметь значение NaN, которое ничему не равно, включая самого себя. Один из способов получить их – использовать модуль math.
>>> math.nan == math.nan
False
Кроме того, объект NaN не является уникальным в отличие от None, вы можете иметь несколько различных объектов NaN из разных источников:
>>> float('nan')
nan
>>> float('nan') is float('nan')
False
Также это означает, что нельзя использовать NaN в качестве ключа в словаре:
>>> d = dict()
>>> d[float('nan')] = 1
>>> d
{nan: 1}
>>> d[float('nan')]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: nanuuid
Стандартный модуль uuid — быстрый и простой способ сгенерировать UUID (universally unique identifier, глобально уникальный идентификатор).
from uuid import uuid4
user_id = uuid4()
print(user_id)
Так мы создаём случайное 128-битное число, которое наверняка будет уникальным.
Существует более 2¹²² возможных UUID. Это более 5 ундециллионов, то есть 36 нулей.
Вероятность нахождения дубликатов в заданном наборе крайне мала. Даже при наличии триллиона UUID вероятность того, что среди них есть дубликат, гораздо меньше, чем один к миллиарду.
Вполне недурно для двух строк кода.В общем, мы создали объединенный чат нескольких каналов для взаимопомощи в программировании и просто общения – @python_chat_ru
Метод get для словарей
У словарей есть метод get, который возвращает значение по ключу, переданному в аргументах функции. Однако если такого ключа в словаре нет, то исключение не выбрасывается, а возвращается значение по умолчанию, которое передаётся вторым аргументом, или же None, если второй аргумент не передан.
В качестве примера создадим словарь с именами, которые можно получить по определенным значениям, и напишем функцию, которая возвращает приветственную фразу со взятием имени из этого словаря:
names = {
382: 'Alice',
590: 'Bob',
951: 'Dilbert'
}
def greeting(user_id):
name = names.get(user_id, 'there')
return f'Hi {name}!'
Смотрим на результат:
greeting(382)
# 'Hi Alice!'
Вызов функции с аргументом в виде несуществующего в словаре ключа:
greeting(0)
# 'Hi there!'Python имеет ужасную репутацию, когда речь идет о возможности параллельных вычислений. Не обращая внимания на типичные рассуждения о его потоках и GIL (который обычно нормально работает), реальная проблема многопоточности Python не техническая, а педагогическая. Распространенные руководства о библиотеках threading и multiprocessing в целом неплохие, но тяжеловаты для понимания.
Именно по этой причине я написал статью в которой рассматриваются возможности multiprocessing, доступные каждому.
Читать статью
Операции над множествами
Set – множество, в котором отсутствуют повторяющиеся элементы:
>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # объединение
{1, 2, 3, 4, 5, 6}
>>> a & b # пересечение
{3, 4}
>>> a < b # подмножества
False
>>> a - b # разница
{1, 2}
>>> a ^ b # симметрическая разность
{1, 2, 5, 6}Функция map
На вход принимает два обязательных аргмумента: функция-обработчик и итерируемый объект, чаще всего это список. Суть map’a заключается в том, что он применяет переданную функцию к каждому элементу последовательности. А возвращает так называемый map-объект, который в дальнейшем можно конвертировать в обычный список и не только.
def add_five(a):
return a + 5
old_nums = [1, 2, 3, 4, 5]
new_nums = map(add_five, old_nums)
print(list(new_nums))
# Output: [6, 7, 8, 9, 10]
Обратите внимание, мы не пишем скобки у функции add_five при вызове map – это означает то, что мы передаем объект функции, а не результат её выполнения.
Тоже самое мы могли записать через анонимую функцию прямо в map'e.
old_nums = [1, 2, 3, 4, 5]
new_nums = map(lambda a: a + 5, old_nums)
print(list(new_nums))
# Output: [6, 7, 8, 9, 10]
Однако в данном примере нагляднее использовать генератор списка.
old_nums = [1, 2, 3, 4, 5]
new_nums = [a + 5 for a in old_nums]
print(new_nums)
# Output: [6, 7, 8, 9, 10]
Хоть map и мощная функция, но лучше исходить от конкретных случаев. А вот вам действительно полезный пример из практики. Мы можем считать несколько чисел с консоли, которые вводят через пробел, разделив всё это функцией split.
a, b, c = map(int, input().split())Распознавание лиц и верификация пользователей по ним – будущее или уже существующая реальность? Даже больше, каждый уже может написать свою подобную программу. Это настолько просто, что требуется буквально двадцать строк кода и всего лишь полчаса времени для понимания.
Читать статью
Заходит однажды тестировщик программного обеспечения в бар. Забегает в бар. Пролезает в бар. Танцуя, проникает в бар. Крадется в бар. Врывается в бар. Прыгает в бар.
И заказывает 0 пива. Заказывает 99999 пив. Заказывает -1 пиво. Заказывает ящерицу в стакане. Заказывает "qwertyuiop". Заказывает одно пиво каждую милисекунду. Заказывает пиво, но отменяет заказ. Заказывает пиво вместе с 10000 посетителями одновременно. Заказывает пиво не заходя в бар. Заказывает drop table.
А кульминация этого анекдота находится на моем новом канале @dank_code
Перечисления
Python 3 поддерживает, благодаря классу Enum, простой механизм работы с перечислениями. Перечисления удобно использовать для хранения списков констант. Константы, в противном случае, оказываются беспорядочно разбросанными в коде.
from enum import Enum, auto
class Monster(Enum):
ZOMBIE = auto()
WARRIOR = auto()
BEAR = auto()
print(Monster.ZOMBIE)
# Monster.ZOMBIE
Из документации по Python 3 можно узнать о том, что перечисление — это набор символических имён, привязанных к уникальным, неизменным значениям. Члены одного перечисления можно сравнивать на идентичность. Перечисления можно обходить.
for monster in Monster:
print(monster)
# Monster.ZOMBIE
# Monster.WARRIOR
# Monster.BEARyield from
Рассмотрим одну страшную конструкцию в Python 3.3+. Для начала напомню, генератор – это объект, который можно проитерировать только однажды. Записывается так:
def gen():
for x in range(100):
yield x
# Или покороче вот так
f = (x for x in range(100))
Когда всего лишь один генератор – всё хорошо. Используем его как итератор и радуемся. Но не редки ситуации, в которых есть несколько генераторов:
gen_1 = (x for x in range(5))
gen_2 = (x for x in range(5, 10))
И стоит задача – проитерировать сначала один генератор, потом второй. Но вернуть значения не в виде списка, а в виде нового генератора.
Здесь на помощь приходит следующая конструкция: yield from <expr>, где <expr> - выражение, вычисление которого даёт итерируемый объект, из которого и вычленяется итератор.
Используя yield form, поставленная выше задача решается так:
def generator():
yield from gen_1
yield from gen_2
gen = generator()
И теперь можно просто проитерироваться по полученному генератору, в итоге получив результаты обоих первоначальных генераторов. Воспользуемся генератором списка, работа которого показана в предыдущем посте.
result = [n for n in gen]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]Генераторы коллекций
В Python есть специальная конструкция, позволяющая быстрее и удобнее создавать заполненные коллекции на основе имеющихся, при этом применяя какое-либо выражение к каждому элементу.
1. Генератор списка (list comprehension)
word = 'hello'
new_list = [c.upper() for c in word]
# ['H', 'E', 'L', 'L', 'O']
2. Генератор множества (set comprehension)
elements = [1, 2, 1, 3, 2]
new_set = {n * 0.1 for n in elements}
# {0.1, 0.2, 0.3}
3. Генератор словаря (dictionary comprehension)
numbers = {'one': 1, 'two': 2, 'three': 3}
new_dict = {v: k for k, v in numbers.items()}
# {1: 'one', 2: 'two', 3: 'three'}Генераторы
Выглядят функции-генераторы также как и обычные, но содержат выражения с ключевым словом yield для последовательного генерирования значений, которые могут быть использованы в циклах for, либо их получения при помощи функции next.
На каждой yield работа функции временно приостанавливается, при этом сохраняется состояние исполнения, включая локальные переменные, указатель на текущую инструкцию, внутренний стек и состояние обработки исключения. При последующем обращении к итератору генератора функция продолжает своё исполнение с места, на котором была приостановлена. Этим функции-генераторы отличаются от обычных функций, при вызове которых исполнение всякий раз начинается с начала.
Если функция достигает инструкции return, либо конца, возбуждается исключение StopIteration и итератор исчерпывает себя.
def generator():
for item in ('first', 'second', 'third'):
yield item
Теперь можно вызывать эту функцию и использовать функцию next.
gen = generator()
value = next(gen)
print(value)
# Output: first
Достаточно часто, а точнее практически всегда, генераторы используют в циклах for. Преимущество такого подхода в том, что можно получить все возможные значения и не словить ошибку StopIteration.
for item in gen:
print(item, end=' ')
# Output: second third
Теперь если вызвать функцию next еще раз, то получим то самое исключение.
next(gen)
# Output:
Traceback (most recent call last):
File "main.py", line 12, in <module>
next(gen)
StopIterationАннотации типов
Всем известно, что Python – язык с динамической типизацией. Аннотации типов нужны для того, чтобы повысить информативность исходного кода, но они никак не влияют на поведение программы.
Для примера потребуется импортировать типы
List (список) и Dict (словарь) из модуля typing:
from typing import List, Dict
Типы данных указывается через двоеточие после именно переменной после её создания. Создадим словарь с числами и сразу же список, состоящий из значений этого словаря:
numbers: Dict[str, int] = {'one': 1, 'two': 2}
values: List[int] = numbers.values()
Потом создадим функцию, возвращающую сумму переданных значений. В аргументах точно так же можно указывать их типы, а также через стрелочку можно указать типа возвращаемого значения:
def sum(a: int, b: int) -> int:
return a + b
Теперь используем эту функцию, передав туда распакованный список:
sum(*values)
# Output: 3
Однако помните, что аннотации типов не влияют на ход исполнения программы, поэтому в ранее написаную функцию мы с таким же успехом можем передать и строки, хотя указывали целочисленный типа данных:
sum('Python ', 'Lounge')
# Output: 'Python Lounge'Поясняю, это была не очередная реклама, а анонс нашего авторского совместного с @programming_python курса.
Сфера чат-ботов активно развивается, однако разработчиков там не хватает, а платят очень даже неплохо.
Так что советуем спешить, пока действует эксклюзивная скидка 20%, начало уже 1 сентября )
Telegram боты
Простая в освоении и практически не занятая ниша – разработка чат-ботов для мессенджеров. Платят за одного такого в среднем от 5 до 20 тысяч рублей, а время создания занимает как правило всего лишь несколько дней.
1 сентября начинается 3-недельный курс по разработке Telegram ботов на Python от программистов с солидным опытом в этой сфере. Обучение будет происходить в закрытом канале.
Базовый (1190 рублей) – доступ ко всему самому свежему и практичному материалу.
Стандартный (1490 рублей) – добавляется доступ в чат, в котором появляется возможность получить кейсы от программистов с опытом, узнать вопросы на интересующие вопросы и получить помощь.
Продвинутый (2190 рублей) – помимо всех перечисленных выше прелестей, у вас есть возможность получить личные консультации и код ревью от мастеров в своем деле.
Для записи пишите в бота @bots_course_bot.
Специально для подписчиков этого канала скидка 20% по промокоду PYTHONLOUNGE.
Форматирование строк
В этом посте разберем доступные в Python методы форматирования строк. Для начала определим две переменные, которые потом и будем вставлять в строки.
name = 'Adrian'
age = 17
Самый древний и уже редко используемый способ – с помощью оператора %. Написание %s и %d зависит от того, что мы туда передаем и что хотим увидеть в итоге, но это уже тема отдельного поста.
'My name is %s and I am %d years old' % (name, age)
В Python 2.6 появился метод .format() с немного отличающимся синтаксисом от существующего оператора %. К слову, этот метод активно используется и по сей день, в отличии от его предшественника.
'My name is {} and I am {} years old'.format(name, age)
Начиная с версии Python 3.6, доступны f-строки – свежий и наиболее производительный способ форматирования строк.
f'My name is {name} and I am {age} years old'Изменение списка во время итерации по нему
Предположим, что требуется удалить все нечетные числа из списка. Проблема со следующим кодом должна быть довольно очевидной:
odd = lambda x: bool(x % 2) # функция проверки числа на нечетность
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in range(10):
if odd(numbers[i]):
del numbers[i] # удаление элемента из списка во время итерации по нему
# Output:
Traceback (most recent call last):
if odd(numbers[i]):
IndexError: list index out of range
Удаление элемента из списка во время его итерации – это проблема, которая хорошо известна любому опытному разработчику.
К счастью, Python включает в себя ряд элегантных парадигм программирования, которые при правильном использовании могут привести к значительному упрощению и оптимизации кода. Одна из таких парадигм – list comprehensions. Генераторы списков часто используют именно для решение подобных проблем, что и показывает реализация кода ниже:
odd = lambda x: bool(x % 2) # функция проверки числа на нечетность
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers = [n for n in numbers if not odd(n)] # генератор нового списка
print(numbers)
# Output:
[2, 4, 6, 8, 10]