Библиотека Python разработчика | Книги по питону
19.5K subscribers
1.05K photos
391 videos
82 files
987 links
Полезные материалы для питониста по Фреймворкам Django, Flask, FastAPI, Pyramid, Tornado и др.

По всем вопросам @evgenycarter

РКН clck.ru/3Ko7Hq
Download Telegram
Подборка Telegram каналов для программистов

Системное администрирование 📌
https://t.me/sysadmin_girl Девочка Сисадмин
https://t.me/srv_admin_linux Админские угодья
https://t.me/linux_srv Типичный Сисадмин

https://t.me/linux_odmin Linux: Системный администратор
https://t.me/devops_star DevOps Star (Звезда Девопса)
https://t.me/i_linux Системный администратор
https://t.me/linuxchmod Linux
https://t.me/sys_adminos Системный Администратор
https://t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
https://t.me/sysadminof Книги для админов, полезные материалы
https://t.me/i_odmin Все для системного администратора
https://t.me/i_odmin_book Библиотека Системного Администратора
https://t.me/i_odmin_chat Чат системных администраторов
https://t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
https://t.me/sysadminoff Новости Линукс Linux

1C разработка 📌
https://t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С

Программирование C++📌
https://t.me/cpp_lib Библиотека C/C++ разработчика
https://t.me/cpp_knigi Книги для программистов C/C++
https://t.me/cpp_geek Учим C/C++ на примерах

Программирование Python 📌
https://t.me/pythonofff Python академия. Учи Python быстро и легко🐍
https://t.me/BookPython Библиотека Python разработчика
https://t.me/python_real Python подборки на русском и английском
https://t.me/python_360 Книги по Python Rus

Java разработка 📌
https://t.me/BookJava Библиотека Java разработчика
https://t.me/java_360 Книги по Java Rus
https://t.me/java_geek Учим Java на примерах

GitHub Сообщество 📌
https://t.me/Githublib Интересное из GitHub

Базы данных (Data Base) 📌
https://t.me/database_info Все про базы данных

Мобильная разработка: iOS, Android 📌
https://t.me/developer_mobila Мобильная разработка
https://t.me/kotlin_lib Подборки полезного материала по Kotlin

Фронтенд разработка 📌
https://t.me/frontend_1 Подборки для frontend разработчиков
https://t.me/frontend_sovet Frontend советы, примеры и практика!
https://t.me/React_lib Подборки по React js и все что с ним связано

Разработка игр 📌
https://t.me/game_devv Все о разработке игр

Библиотеки 📌
https://t.me/book_for_dev Книги для программистов Rus
https://t.me/programmist_of Книги по программированию
https://t.me/proglb Библиотека программиста
https://t.me/bfbook Книги для программистов
https://t.me/books_reserv Книги для программистов

БигДата, машинное обучение 📌
https://t.me/bigdata_1 Data Science, Big Data, Machine Learning, Deep Learning

Программирование 📌
https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://t.me/coddy_academy Полезные советы по программированию
https://t.me/rust_lib Полезный контент по программированию на Rust
https://t.me/golang_lib Библиотека Go (Golang) разработчика
https://t.me/itmozg Программисты, дизайнеры, новости из мира IT
https://t.me/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻
https://t.me/nodejs_lib Подборки по Node js и все что с ним связано
https://t.me/ruby_lib Библиотека Ruby программиста

QA, тестирование 📌
https://t.me/testlab_qa Библиотека тестировщика

Шутки программистов 📌
https://t.me/itumor Шутки программистов

Защита, взлом, безопасность 📌
https://t.me/thehaking Канал о кибербезопасности
https://t.me/xakep_1 Статьи из "Хакера"

Книги, статьи для дизайнеров 📌
https://t.me/ux_web Статьи, книги для дизайнеров

Английский 📌
https://t.me/UchuEnglish Английский с нуля

Математика 📌
https://t.me/Pomatematike Канал по математике
https://t.me/phis_mat Обучающие видео, книги по Физике и Математике

Excel лайфхак📌
https://t.me/Excel_lifehack

https://t.me/tikon_1 Новости высоких технологий, науки и техники💡
https://t.me/mir_teh Мир технологий (Technology World)

Вакансии 📌
https://t.me/sysadmin_rabota Системный Администратор
https://t.me/progjob Вакансии в IT
Если вы пишете много Python-кода, наверняка сталкивались с типичной задачей: определение класса с простым конструктором и базовыми методами вроде __repr__. Например:


class Server:
def __init__(self, ip, version=4):
self.ip = ip
self._version = version

def __repr__(self):
return '{klass}("{ip}", {version})'.format(
klass=type(self).__name__,
ip=self.ip,
version=self._version,
)


Это выглядит однообразно, но легко автоматизируется. Популярный пакет attrs позволяет избавиться от такого шаблонного кода:


from attrs import define, field

@define
class Server:
ip = field()
_version = field(default=4)

server = Server(ip='192.168.0.0.1', version=4)


Пакет attrs генерирует конструктор, метод __repr__, а также методы сравнения (__eq__, __lt__, и т.д.) — всё это минимальными усилиями.

Однако с появлением Python 3.7 разработчики получили встроенное решение для этой задачи — data classes. Это стандартный инструмент, который использует аннотации типов для автоматического создания тех же самых методов:


from dataclasses import dataclass

@dataclass
class InventoryItem:
name: str
unit_price: float
quantity_on_hand: int = 0

def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand


Почему стоит обратить внимание на data classes:
1. Чистый код: Конструкция читается просто и выглядит лаконично.
2. Поддержка стандартной библиотеки: Не нужно добавлять зависимости.
3. Типы и валидация: С аннотациями типов ваш код становится более понятным и безопасным.

attrs остаётся полезным инструментом, особенно если вам нужны более продвинутые возможности (например, валидация значений полей), но для большинства задач data classes — отличное решение прямо "из коробки".

👉@BookPython
Пагинация — это стандартная задача, с которой ежедневно сталкиваются тысячи разработчиков. Если вы используете реляционную базу данных, то можно задать смещение через LIMIT, например:


SELECT *
FROM table
LIMIT 1001, 100;


Этот запрос действительно вернет 100 записей, с 1001-й по 1100-ю. Но проблема в том, что для базы данных это так же сложно, как и выборка всех первых 1001 записей. Чем дальше запрашиваемая страница, тем медленнее будет выполняться запрос.

Более оптимальным решением является использование фильтрации через WHERE, где клиент передает идентификатор последней записи текущей страницы ($last_seen_id в примере):


SELECT *
FROM table
WHERE id > $last_seen_id
ORDER BY id ASC
LIMIT 100;


Этот подход позволяет избежать сканирования всех предыдущих строк, что значительно ускоряет работу с большими объемами данных.

Если хотите разобраться подробнее, рекомендую почитать отличную статью на эту тему!

👉 @BookPython
Как ускорить вычисления в Python с помощью multiprocessing.Pool

Когда речь заходит о ресурсоемких задачах, которые нагружают ваш CPU, стоит обратить внимание на библиотеку multiprocessing, а именно на класс Pool. Он позволяет задействовать все доступные ядра процессора, автоматически распределяя задачи между ними.

Вот простой пример:


import math
from multiprocessing import Pool

# Генерируем список входных данных
inputs = [i ** 2 for i in range(100, 130)]

# Функция для вычислений
def f(x):
return len(str(math.factorial(x)))

# Последовательное выполнение
%timeit [f(x) for x in inputs]
# Результат: ~1.44 сек

# Параллельное выполнение
p = Pool(4) # Создаем пул из 4 процессов
%timeit p.map(f, inputs)
# Результат: ~451 мс


👉 @BookPython
Модуль multiprocessing в Python: потоки против процессов

Модуль multiprocessing позволяет создавать не только процессы, но и потоки. Однако стоит помнить о главной особенности CPython — GIL (Global Interpreter Lock). Этот механизм блокирует выполнение байт-кода Python несколькими потоками одновременно.

Это означает, что потоки полезны в основном в случаях, когда программа выполняет операции, не связанные с Python-интерпретатором, например, ожидание ввода-вывода (IO). К примеру, загрузка трёх различных статей из Википедии будет одинаково эффективной как с потоками, так и с процессами. Причём результат в три раза быстрее по сравнению с выполнением задачи в одном процессе:


from multiprocessing import Pool
from multiprocessing.pool import ThreadPool
import requests

def download_wiki_article(article):
url = 'http://de.wikipedia.org/wiki/'
return requests.get(url + article)

process_pool = Pool(3)
thread_pool = ThreadPool(3)

thread_pool.map(download_wiki_article, ['a', 'b', 'c'])
# ~376 ms

process_pool.map(download_wiki_article, ['a', 'b', 'c'])
# ~373 ms

[download_wiki_article(a) for a in ['a', 'b', 'c']]
# ~1.09 s


Однако использование потоков для задач, нагружающих CPU, практически бессмысленно:


import math
from multiprocessing import Pool
from multiprocessing.pool import ThreadPool

def f(x):
return len(str(math.factorial(x)))

process_pool = Pool(4)
thread_pool = ThreadPool(4)
inputs = [i ** 2 for i in range(100, 130)]

[f(x) for x in inputs]
# ~1.48 s

thread_pool.map(f, inputs)
# ~1.48 s

process_pool.map(f, inputs)
# ~478 ms


При задачах, требующих интенсивных вычислений, использование процессов вместо потоков даст значительный прирост производительности благодаря распределению нагрузки между несколькими ядрами процессора.

👉 @BookPython
Если вам нужно выполнить поиск в отсортированной коллекции, то бинарный поиск — это именно то, что вам нужно. Этот простой алгоритм сравнивает искомое значение с элементом в середине массива; результат определяет, какую половину нужно искать дальше.

Стандартная библиотека Python предоставляет возможность использовать бинарный поиск без его непосредственной реализации. Функция bisect_left возвращает самую левую позицию элемента в отсортированном списке, а bisect_right — самую правую.


from random import randrange
from bisect import bisect_left

n = 1000000
look_for = 555555
lst = sorted(randrange(0, n) for _ in range(n))

%timeit look_for in lst
# 69.7 ms ± 449 µs на цикл

%timeit look_for == lst[bisect_left(lst, look_for)]
# 927 ns ± 2.28 ns на цикл


Результаты демонстрируют, что использование бинарного поиска через bisect_left быстрее, чем стандартный поиск в списке с помощью оператора in.

👉 @BookPython
📌 О представлении данных в байтах в Python

Когда мы храним данные в памяти или на устройстве хранения, их необходимо представить в виде байтов. Python позволяет работать с абстракцией данных, не задумываясь об их байтовом представлении. Однако при записи строки в файл мы фактически работаем с физической структурой данных.

Чтобы записать символы в файл, их нужно преобразовать в байты — это называется кодированием (encoding). Когда вы читаете байты из файла и хотите преобразовать их в понятные символы, этот процесс называется декодированием (decoding).

🔤 Кодировки и их применение

Существует множество методов кодирования. Один из самых популярных — Unicode, но сам по себе Unicode не является кодировкой в традиционном смысле. Unicode определяет соответствие между символами и их числовыми кодами. Например, 🐍 имеет код 128 013.

Однако, чтобы записать числа в файл, нужна настоящая кодировка. Unicode обычно используется с utf-8, которая (в большинстве случаев) является кодировкой по умолчанию в Python. При чтении из файла Python автоматически декодирует данные, используя utf-8.

Если вы хотите использовать другую кодировку, просто укажите её с помощью параметра encoding= в функции open. А чтобы работать с "чистыми" байтами, добавьте символ b к режиму открытия файла.

Пример:

# Кодирование строки в файл
with open('example.txt', 'w', encoding='utf-8') as f:
f.write('Привет, мир!')

# Чтение в байтовом режиме
with open('example.txt', 'rb') as f:
data = f.read()
print(data) # Вывод: b'\xd0\x9f\xd1\x80\xd0\xb8...'


👉 @BookPython
🔑 Использование объектов в качестве ключей словаря в Python

В Python вы можете использовать любой объект в качестве ключа словаря, если он реализует метод __hash__. Этот метод возвращает целое число, но при этом важно соблюдать одно ключевое требование: равные объекты должны иметь одинаковый хэш (обратное утверждение необязательно).

👉 Не используйте изменяемые объекты в качестве ключей! Если объект изменяется после добавления в словарь, он становится "невидимым" для поиска, так как его хэш может измениться.

🌀 Странность с отрицательными хэшами

Есть интересная особенность, которая может вас удивить при отладке или написании юнит-тестов. Рассмотрим следующий пример:


class A:
def __init__(self, x):
self.x = x

def __hash__(self):
return self.x


Результаты хэширования экземпляров класса:


>>> hash(A(2))
2
>>> hash(A(1))
1
>>> hash(A(0))
0
>>> hash(A(-1)) # внимание!
-2
>>> hash(A(-2))
-2


💡 В CPython значение -1 зарезервировано для внутренних ошибок. Если хэш-значение равно -1, интерпретатор автоматически преобразует его в -2. Это может вызывать неожиданные проблемы при сравнении или использовании объектов в качестве ключей.

👉 @BookPython
Иногда нужно создать функцию на основе более универсальной. Например, у функции int() есть параметр base, который можно зафиксировать, чтобы получить новую функцию base2:


>>> int("10")
10
>>> int("10", 2)
2
>>> def base2(x):
... return int(x, 2)
...
>>> base2("10")
2


Для более точной и семантически понятной реализации можно использовать functools.partial:


from functools import partial

base2 = partial(int, base=2)


Это удобно, когда нужно передать функцию в качестве аргумента в другую функцию высшего порядка, но с заблокированными значениями некоторых аргументов:


>>> list(map(partial(int, base=2), ["1", "10", "100"]))
[1, 2, 4]


Без использования partial пришлось бы писать код так:


>>> list(map(lambda x: int(x, base=2), ["1", "10", "100"]))
[1, 2, 4]


👉@BookPython
Визуализация данных — это ключевой этап анализа, который помогает выявить скрытые закономерности, а также улучшить понимание структуры данных для дальнейшего применения машинного обучения

Приглашаем на открытый урок «Визуализация данных на Python», посвященный курсу «Machine Learning» от Otus.

Практика: визуализация данных Python на основных библиотеках: Matplotlib; Seaborn; Plotly

👉 Регистрация и подробности: https://vk.cc/cH48zk

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
Метод format в Python для строк — мощный инструмент, поддерживающий множество возможностей, о которых вы, возможно, даже не знали. Каждый заменяемый плейсхолдер ({...}) может содержать три части: имя поля, преобразование и спецификацию формата.

Имя поля используется для указания, какой именно аргумент должен быть подставлен:


>>> '{}'.format(42)
'42'
>>> '{1}'.format(1, 2)
'2'
>>> '{y}'.format(x=1, y=2)
'2'


Преобразование позволяет указать, что вместо str() следует использовать repr() (или ascii()) при преобразовании объектов в строки:


>>> '{!r}'.format(datetime.now())
'datetime.datetime(2018, 5, 3, 23, 48, 49, 157037)'
>>> '{}'.format(datetime.now())
'2018-05-03 23:49:01.060852'


Спецификация формата задаёт, как значения будут представлены:


>>> '{:+,}'.format(1234567)
'+1,234,567'
>>> '{:>19}'.format(1234567)
' 1234567'


Эта спецификация может быть применена и к отдельному объекту с помощью функции format (не метода str):


>>> format(5000000, '+,')
'+5,000,000'


Функция format вызывает метод __format__ объекта, поэтому вы можете изменить его поведение для своих типов.

👉@BookPython
Функция itertools.chain позволяет объединить несколько итерируемых объектов, чтобы работать с ними, как с единым целым:


from itertools import chain

print(list(chain(['a', 'b'], range(3), set('xyz'))))
# Вывод: ['a', 'b', 0, 1, 2, 'x', 'z', 'y']


Иногда нужно проверить, пуст ли генератор (точнее, исчерпан ли он). Для этого можно попытаться получить следующий элемент с помощью next(). Если элемент есть, его нужно вернуть обратно в генератор, но сделать это напрямую невозможно. Однако можно «приклеить» его обратно с помощью chain:


from itertools import chain

def sum_of_odd(gen):
try:
first = next(gen) # Пытаемся получить первый элемент
except StopIteration:
raise ValueError('Empty generator') # Если генератор пуст, выбрасываем исключение

# Используем chain для возврата первого элемента и объединения с остальными
return sum(
x for x in chain([first], gen)
if x % 2 == 1 # Суммируем только нечетные числа
)


Пример использования:


print(sum_of_odd(x for x in range(1, 6))) # Вывод: 9 (1 + 3 + 5)
print(sum_of_odd(x for x in range(2, 3))) # Вывод: 0 (нет нечетных чисел)
print(sum_of_odd(x for x in range(2, 2))) # ValueError: Empty generator


👉@BookPython
В Python блок else можно использовать не только после if, но и после циклов for и while. Код внутри else выполняется только в том случае, если цикл завершился естественным образом, то есть не был прерван с помощью break.

Наиболее распространённый случай использования этого — поиск элемента в цикле с прерыванием через break, если элемент найден:


# Пример 1: Список содержит нечётное число
first_odd = None
for x in [2, 3, 4, 5]:
if x % 2 == 1: # Проверяем, является ли число нечётным
first_odd = x
break # Прерываем цикл, так как элемент найден
else:
raise ValueError('No odd elements in list') # Выполнится, если цикл завершился без break

print(first_odd) # Результат: 3


Если в списке нет подходящего элемента, цикл завершается естественным образом, и выполняется блок else:


# Пример 2: Список не содержит нечётных чисел
for x in [2, 4, 6]:
if x % 2 == 1:
first_odd = x
break
else:
raise ValueError('No odd elements in list') # Исключение будет поднято

# ValueError: No odd elements in list


👉@BookPython
Когда вы создаете кастомный метод __repr__ для объекта, обычно нужно включить представление его атрибутов. Однако важно помнить, что нужно явно вызывать repr(), так как форматирование вызывает str() вместо repr().

Пример простого кода:


class Pair:
def __init__(self, left, right):
self.left = left
self.right = right

def __repr__(self):
class_name = type(self).__name__
repr_left = repr(self.left)
repr_right = repr(self.right)
return f'{class_name}({repr_left}, {repr_right})'


Проблема возникает, если вы вызываете repr для объекта, который содержит ссылку на самого себя. Это может привести к рекурсии:


In : p = Pair(1, 2)
In : p
Out: Pair(1, 2)
In : p.right = p
In : p
Out: [...]
RecursionError: maximum recursion depth exceeded while calling a Python object


Для решения этой проблемы можно использовать декоратор reprlib.recursive_repr, который обрабатывает рекурсивные вызовы:


@reprlib.recursive_repr()
def __repr__(self):
class_name = type(self).__name__
repr_left = repr(self.left)
repr_right = repr(self.right)
return f'{class_name}({repr_left}, {repr_right})'


Теперь код работает корректно:


In : p = Pair(1, 2)
In : p.right = p
In : p
Out: Pair(1, ...)


👉@BookPython
Чтобы читать строки из stdin в Python до версии 3, использовалась функция raw_input вместо input. Проблема с использованием input заключалась в том, что она выполняла введённую строку как код:


$ echo '[x ** 2 for x in range(10)]' | python2 -c 'print input()'
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]


В Python 3 функция input просто читает строку, а raw_input больше не существует.

Если вы хотите поддерживать код, работающий как в Python 2, так и в Python 3, можно использовать следующий подход:


from contextlib import suppress

with suppress(NameError):
input = raw_input


Популярный модуль six уже реализует этот механизм для вас. Он предоставляет функцию input, которая просто читает строку, независимо от версии Python.

👉@BookPython
Тесты могут требовать временные файлы или директории. Для этого отлично подойдет модуль tempfile.

Так как временные файлы обычно нужно удалять после использования, tempfile предоставляет как контекстный менеджер, так и простые функции:


import os
import tempfile

with tempfile.TemporaryDirectory() as dir_path:
open(os.path.join(dir_path, 'a'), 'w').close()
open(os.path.join(dir_path, 'b'), 'w').close()
open(os.path.join(dir_path, 'c'), 'w').close()

assert files_of(dir_path) == ['a', 'b', 'c']


👉@BookPython
Нативные значения float в Python используют аппаратные возможности вашего компьютера, поэтому любое значение внутренне представлено в виде двоичной дроби.

Это означает, что в большинстве случаев вы работаете с приближениями, а не с точными значениями:


In : format(0.1, '.17f')
Out: '0.10000000000000001'


Модуль decimal позволяет использовать десятичную арифметику с произвольной точностью:


In : Decimal(1) / Decimal(3)
Out: Decimal('0.3333333333333333333333333333')


Однако и этого может быть недостаточно:


In [61]: Decimal(1) / Decimal(3) * Decimal(3) == Decimal(1)
Out[61]: False


Для точных вычислений можно использовать fractions, где любое число хранится в виде рационального:


In : Fraction(1) / Fraction(3) * Fraction(3) == Fraction(1)
Out: True


Очевидным ограничением остается то, что иррациональные числа (например, π) все равно будут представлены только в приближенной форме.

👉@BookPython
Подборка Telegram каналов для программистов

Системное администрирование 📌
https://t.me/sysadmin_girl Девочка Сисадмин
https://t.me/srv_admin_linux Админские угодья
https://t.me/linux_srv Типичный Сисадмин

https://t.me/linux_odmin Linux: Системный администратор
https://t.me/devops_star DevOps Star (Звезда Девопса)
https://t.me/i_linux Системный администратор
https://t.me/linuxchmod Linux
https://t.me/sys_adminos Системный Администратор
https://t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
https://t.me/sysadminof Книги для админов, полезные материалы
https://t.me/i_odmin Все для системного администратора
https://t.me/i_odmin_book Библиотека Системного Администратора
https://t.me/i_odmin_chat Чат системных администраторов
https://t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
https://t.me/sysadminoff Новости Линукс Linux

1C разработка 📌
https://t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С

Программирование C++📌
https://t.me/cpp_lib Библиотека C/C++ разработчика
https://t.me/cpp_knigi Книги для программистов C/C++
https://t.me/cpp_geek Учим C/C++ на примерах

Программирование Python 📌
https://t.me/pythonofff Python академия. Учи Python быстро и легко🐍
https://t.me/BookPython Библиотека Python разработчика
https://t.me/python_real Python подборки на русском и английском
https://t.me/python_360 Книги по Python Rus

Java разработка 📌
https://t.me/BookJava Библиотека Java разработчика
https://t.me/java_360 Книги по Java Rus
https://t.me/java_geek Учим Java на примерах

GitHub Сообщество 📌
https://t.me/Githublib Интересное из GitHub

Базы данных (Data Base) 📌
https://t.me/database_info Все про базы данных

Мобильная разработка: iOS, Android 📌
https://t.me/developer_mobila Мобильная разработка
https://t.me/kotlin_lib Подборки полезного материала по Kotlin

Фронтенд разработка 📌
https://t.me/frontend_1 Подборки для frontend разработчиков
https://t.me/frontend_sovet Frontend советы, примеры и практика!
https://t.me/React_lib Подборки по React js и все что с ним связано

Разработка игр 📌
https://t.me/game_devv Все о разработке игр

Библиотеки 📌
https://t.me/book_for_dev Книги для программистов Rus
https://t.me/programmist_of Книги по программированию
https://t.me/proglb Библиотека программиста
https://t.me/bfbook Книги для программистов
https://t.me/books_reserv Книги для программистов

БигДата, машинное обучение 📌
https://t.me/bigdata_1 Data Science, Big Data, Machine Learning, Deep Learning

Программирование 📌
https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://t.me/coddy_academy Полезные советы по программированию
https://t.me/rust_lib Полезный контент по программированию на Rust
https://t.me/golang_lib Библиотека Go (Golang) разработчика
https://t.me/itmozg Программисты, дизайнеры, новости из мира IT
https://t.me/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻
https://t.me/nodejs_lib Подборки по Node js и все что с ним связано
https://t.me/ruby_lib Библиотека Ruby программиста

QA, тестирование 📌
https://t.me/testlab_qa Библиотека тестировщика

Шутки программистов 📌
https://t.me/itumor Шутки программистов

Защита, взлом, безопасность 📌
https://t.me/thehaking Канал о кибербезопасности
https://t.me/xakep_1 Статьи из "Хакера"

Книги, статьи для дизайнеров 📌
https://t.me/ux_web Статьи, книги для дизайнеров

Английский 📌
https://t.me/UchuEnglish Английский с нуля

Математика 📌
https://t.me/Pomatematike Канал по математике
https://t.me/phis_mat Обучающие видео, книги по Физике и Математике

Excel лайфхак📌
https://t.me/Excel_lifehack

https://t.me/tikon_1 Новости высоких технологий, науки и техники💡
https://t.me/mir_teh Мир технологий (Technology World)

Вакансии 📌
https://t.me/sysadmin_rabota Системный Администратор
https://t.me/progjob Вакансии в IT
Соединять части пути к файлу удобно с помощью функции os.path.join:


In : dir_path = '/home/vadim/'
In : file_name = 'test.py'
In : os.path.join(dir_path, file_name)
Out: '/home/vadim/test.py'


Это обычно лучше, чем использование строковой конкатенации:


In : dir_path + '/' + file_name
Out: '/home/vadim//test.py'


os.path.join использует правильный разделитель для текущей платформы (например, \ для Windows) и предотвращает появление двойного разделителя (//).

Начиная с Python 3.4, можно использовать класс Path из модуля pathlib. (С версии Python 3.6 его экземпляры также можно передавать в os.path.join.) Класс Path поддерживает объединение путей через оператор /:


In : Path('/home/vadim/') / Path('test.py')
Out: PosixPath('/home/vadim/test.py')


👉@BookPython
UTF-8 — это кодировка с переменной длиной. Один символ может быть закодирован с использованием одного, двух, трёх или четырёх байтов. Это означает, что нельзя начать чтение строки в кодировке UTF-8 с произвольного байта, так как это может случайно разрушить символ:


In : lion = 'Löwe'
In : lion.encode('utf-8')[2:]
Out: b'\xb6we'
In : lion.encode('utf-8')[2:].decode('utf-8')
...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb6 in position 0: invalid start byte


Также это означает, что для пропуска первых N символов строки их необходимо прочитать и декодировать. Рассчитать смещение заранее невозможно.

Однако можно пропустить фиксированное количество байтов, принимая во внимание некоторые особенности. Вот как может быть закодирован символ в UTF-8:


0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx


Как видно, байт является начальным байтом символа, если его вид не совпадает с 10xxxxxx. Такие байты называются продолжением символа (continuation bytes). Давайте пропустим их:


def cut_bytes(s, n):
result = s.encode('utf-8')[n:]
mask = int('11000000', 2)
conbyte = int('10000000', 2)
while result[0] and result[0] & mask == conbyte:
result = result[1:]

return result.decode('utf-8')


Пример использования:


In : cut_bytes(lion, 2)
Out: 'we'
In : cut_bytes(lion, 1)
Out: 'öwe'


👉@BookPython
Иногда вам нужно запустить блок кода с несколькими контекстными менеджерами. Например:


with open('f') as f:
with open('g') as g:
with open('h') as h:
pass


Начиная с Python 2.7 и 3.1, это можно сделать с помощью одного выражения with:


o = open
with o('f') as f, o('g') as g, o('h') as h:
pass


До этого можно было использовать функцию contextlib.nested:


with nested(o('f'), o('g'), o('h')) as (f, g, h):
pass


Однако в современных версиях Python эта функция устарела и вызывает предупреждение. Вместо неё рекомендуется использовать более продвинутый инструмент — contextlib.ExitStack. Он позволяет войти в любое количество контекстов в произвольное время, но гарантирует их корректное завершение:


from contextlib import ExitStack

with ExitStack() as stack:
f = stack.enter_context(o('f'))
g = stack.enter_context(o('g'))
other = [
stack.enter_context(o(filename))
for filename in filenames
]


Это особенно полезно, когда количество контекстных менеджеров неизвестно заранее.

👉@BookPython