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

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

РКН clck.ru/3Ko7Hq
Download Telegram
В Python сортировка по умолчанию является стабильной, то есть сохраняет порядок равных элементов:


a = [2, -1, 0, 1, -2]
sorted(a, key=lambda x: x**2)
# [0, -1, 1, 2, -2]


Функции max и min тоже стараются быть согласованными с поведением sorted.
max работает аналогично sorted(a, reverse=True)[0], а min — как sorted(a)[0].
Это означает, что обе функции возвращают самый левый возможный результат:


max([2, -2], key=lambda x: x**2)
# 2

max([-2, 2], key=lambda x: x**2)
# -2

min([2, -2], key=lambda x: x**2)
# 2

min([-2, 2], key=lambda x: x**2)
# -2


👉@BookPython
Модуль collections предоставляет класс ChainMap, который позволяет использовать несколько отображений (словарей) как одно объединённое:


from collections import ChainMap

d = ChainMap(dict(a=1), dict(a=2, b=2))
d['a'] # 1
d['b'] # 2
d['c'] # ...
# KeyError: 'c'


ChainMap последовательно просматривает все вложенные отображения и возвращает первое найденное значение. Однако все операции изменения затрагивают только первое отображение:


d = ChainMap(dict(a=1), dict(a=2, b=2))
d['c'] = 3
d
# ChainMap({'a': 1, 'c': 3}, {'a': 2, 'b': 2})


👉@BookPython
🔍Тестовое собеседование на Middle Python-разработчика в четверг

22 мая(в четверг) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Python-разработчика.

Собес проведет Вадим Пуштаев, ex. head of backend в 💙, автор канала @pythonetc, архитектор в европейской компании

Как это будет:
📂 Вадим будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Вадим будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Вадиму

Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Python-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.

Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_py_bot

Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2VtzqwKtUmr
Please open Telegram to view this post
VIEW IN TELEGRAM
В Python можно использовать любой объект в качестве ключа словаря, если он реализует метод __hash__. Этот метод может возвращать любое целое число, но есть одно обязательное условие: равные объекты должны иметь одинаковые хэши (обратное не обязательно).

Также не стоит использовать изменяемые объекты в качестве ключей, потому что если объект изменится и станет не равным самому себе в прошлом, его больше нельзя будет найти в словаре.

Есть и один странный момент, который может удивить во время отладки или написания unit-тестов:


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 зарезервировано для внутренних ошибок, поэтому оно неявно преобразуется в -2.

👉@BookPython
Наверное, самая распространённая ошибка новичков в Python — это использование изменяемого объекта в качестве значения по умолчанию для аргумента функции. Такой объект будет общим для всех вызовов функции, что может привести к неожиданным результатам:


def append_length(lst=[]):
lst.append(len(lst))
return lst

print(append_length([1, 2])) # [1, 2, 2]
print(append_length()) # [0]
print(append_length()) # [0, 1]


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


def fact(x, cache={0: 1}):
if x not in cache:
cache[x] = x * fact(x - 1)
return cache[x]

print(fact(5))


В этом примере мы сохраняем вычисленные значения факториала внутри значения аргумента по умолчанию. Причём к этому значению даже можно обратиться напрямую:


>>> fact.__defaults__
({0: 1, 1: 1, 2: 2, 3: 6, 4: 24, 5: 120},)


👉@BookPython
🚀 Открой для себя идеальный путь к лидерству с карьерным тестом от ОЭЗ «Алабуга»! 🌟

Мечтаете о карьере в крупной компании, где ваш потенциал раскроется на полную? Наш тест поможет вам определить вашу уникальную лидерскую роль. Может быть, именно вы станете тем лидером, который выведет команду на новый уровень?

После прохождения теста вы можете заполнить заявку и получить приглашение на эксклюзивную лидерскую программу. Участие в программе открывает реальные перспективы трудоустройства в ОЭЗ «Алабуга», предоставляя шанс начать путь к профессиональному признанию.

Сделайте первый шаг к своему будущему сегодня! Пройдите тест, подайте заявку и начните строить свою карьеру вместе с нами. 🎯
Некоторым генераторам нужно возвращать все элементы другого генератора:


>>> def enclose(gen, before='{', after='}'):
... yield before
... for x in gen:
... yield x
... yield after
...
>>> list(enclose(range(5)))
['{', 0, 1, 2, 3, 4, '}']


Однако предпочтительнее использовать yield from:


>>> def enclose(gen, before='{', after='}'):
... yield before
... yield from gen
... yield after


yield from не только работает быстрее, но и автоматически обрабатывает передачу значений во вложенные генераторы, возврат значений из генераторов и даже выброс исключений внутри вложенного генератора.

👉@BookPython
Самые интересные фичи Python 3.12, которые уже можно тестить и встраивать в проекты


1️⃣ Улучшенный match-case

Теперь можно использовать «захват» значений прямо в паттернах:


def http_status(code):
match code:
case 200 | 201 | 202 as ok:
return f"Success: {ok}"
case 400 as bad | 404 as bad:
return f"Client error: {bad}"
case _:
return "Other"


Большая гибкость и меньше «шаблонных» переменных!



2️⃣ Новый оператор f”{…=}" для отладки

Позволяет вывести и имя, и значение переменной в одной строке:


user = "Alice"
age = 29
print(f"{user=}, {age=}")
# Выведет: user='Alice', age=29


Больше никаких лишних print("user", user)!



3️⃣ Оптимизация работы с памятью и скорость

Команда CPython продолжает ускорение интерпретатора:

* Выделение объектов стало быстрее
* Сборщик мусора реже «паузит» приложение

Это особенно заметно в тяжёлых сервисах и бэкендах.



4️⃣ Новые API для типов

Добавили typing.Self и более гибкие Generic-типизации:


from typing import Self

class Builder:
def set_name(self, name: str) -> Self:
self.name = name
return self

b = Builder().set_name("Demo")


Удобнее писать цепочки вызовов без «# type: ignore»!



💡 Что попробовать прямо сейчас?

1. Установить Python 3.12 pre-release:


pyenv install 3.12.0b4

2. Переписать пару функций с match-case.
3. Пощупать f"{var=}" в дебаге.

👉@BookPython
Python позволяет работать с путями файловой системы через модуль os.path. Модуль содержит множество функций, которые обрабатывают строки как пути и выполняют полезные операции, такие как объединение путей и прочее:


>>> import os.path
>>> os.path.join('/usr', 'local')
'/usr/local'
>>> os.path.dirname('/var/log')
'/var'


Однако, начиная с Python 3.4, доступен новый модуль pathlib, предлагающий объектно-ориентированный подход:


>>> from pathlib import Path
>>> Path('/usr') / Path('local')
PosixPath('/usr/local')
>>> Path('/usr') / 'local'
PosixPath('/usr/local')
>>> Path('/var/log').parent
PosixPath('/var')
>>> Path('/var/log').parent.name
'var'


👉@BookPython
В Python объекты хранят свои атрибуты в словарях, доступ к которым можно получить через магический атрибут dict:


class A: pass
a = A()
a.x = 1
a.__dict__
# {'x': 1}


При прямом доступе к этому словарю можно даже создать атрибуты, которые не являются допустимыми идентификаторами Python (то есть получить их через стандартный синтаксис obj.attr не получится):


a.__dict__[' '] = ' '
getattr(a, ' ')
# ' '


Можно также попросить Python хранить атрибуты непосредственно в памяти (как у простых структур C) с помощью slots. Это экономит память и немного ускоряет доступ к атрибутам, так как не происходит поиска в словаре.


class Point:
__slots__ = ['x', 'y']


Есть несколько моментов, которые нужно помнить при использовании slots. Во-первых, нельзя задавать атрибуты, не указанные в slots. Во-вторых, если класс наследуется от класса с slots, его slots не перекрывают родительские, а добавляются к ним:


class Parent: __slots__ = ['x']
class Child(Parent): __slots__ = ['y']
c = Child()
c.x = 1
c.y = 2


В-третьих, нельзя наследоваться сразу от двух разных классов с непустыми slots, даже если они совпадают.

Помни, что slots предназначены для оптимизации, а не для ограничения набора атрибутов.

👉@BookPython
В Python можно создавать вызываемые объекты не только с помощью функций (def или lambda). Объект также считается вызываемым, если у него реализован магический метод call:


class truncater:
def __init__(self, length):
self._length = length

def __call__(self, s):
return s[0:self._length]


print(truncater(4)('abcdabcd')) # abcd


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


class cached:
def __init__(self, func):
self._func = func
self._cache = {}

def __call__(self, arg):
if arg not in self._cache:
self._cache[arg] = self._func(arg)

return self._cache[arg]


@cached
def sqr(x):
return x * x


👉@BookPython
Проблема с вызовом repr других объектов в своём собственном методе repr заключается в том, что нельзя гарантировать, что ни один из других объектов не равен self, и вызов не окажется рекурсивным:


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**
return f'{class_name}({self.left!r}, {self.right!r})'


Теперь всё работает:


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


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

Системное администрирование, DevOps 📌

https://t.me/bash_srv Bash Советы
https://t.me/win_sysadmin Системный Администратор Windows
https://t.me/sysadmin_girl Девочка Сисадмин
https://t.me/srv_admin_linux Админские угодья
https://t.me/linux_srv Типичный Сисадмин
https://t.me/devopslib Библиотека девопса | DevOps, SRE, Sysadmin
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С
https://t.me/DevLab1C 1С:Предприятие 8
https://t.me/razrab_1C 1C Разработчик
https://t.me/buh1C_prog 1C Программист | Бухгалтерия и Учёт
https://t.me/rabota1C_rus Вакансии для программистов 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 академия.
https://t.me/BookPython Библиотека Python разработчика
https://t.me/python_real Python подборки на русском и английском
https://t.me/python_360 Книги по Python

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/bigdata_1 Big Data, Machine Learning

Программирование 📌
https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
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 программиста
https://t.me/lifeproger Жизнь программиста. Авторский канал.

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

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

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

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

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

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

https://t.me/mir_teh Мир технологий (Technology World)

Вакансии 📌
https://t.me/sysadmin_rabota Системный Администратор
https://t.me/progjob Вакансии в IT
Если вы хотите перехватить и IndexError, и KeyError, вы можете и должны использовать LookupError — их общего предка. Это оказывается полезным при работе со сложными вложенными данными:


try:
db_host = config['databases'][0]['hosts'][0]
except LookupError:
db_host = 'localhost'


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


from itertools import tee

def neighbours(iterable, n):
neighbours = tee(iterable, n)
for i, neighbour in enumerate(neighbours):
for _ in range(i):
next(neighbour)

return zip(*neighbours)

fibb = [1, 1, 2, 3, 5, 8, 13, 21]

for a, b, c in neighbours(fibb, 3):
assert c == a + b


В этом примере мы разветвляем исходный итерируемый объект с помощью tee, затем сдвигаем полученные итераторы с помощью next, чтобы второй начинался со второго элемента исходного итерируемого объекта, а третий — с третьего, и затем объединяем их обратно с помощью zip.

👉@BookPython
PEP 424 позволяет генераторам и другим итерируемым объектам, у которых нет заранее определённого точного размера, предоставлять «подсказку» о длине. Например, следующий генератор, скорее всего, вернёт примерно 50 элементов:


(x for x in range(100) if random() > 0.5)


Если вы пишете свой итерируемый объект и хотите добавить такую подсказку, определите метод __length_hint__. Если же длина известна точно, лучше использовать len.

Если вы используете итерируемый объект и хотите узнать его ожидаемую длину, применяйте функцию operator.length_hint.

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

Первый — __bases__; он возвращает непосредственных родителей класса:


class A:
pass

class B(A):
pass

class C(A):
pass

class D(B, C):
pass


print(D.__bases__)
# (<class '__main__.B'>, <class '__main__.C'>)


Второй —


class B
он возвращает кортеж со всеми классами, которые задействованы при разрешении методов (отсюда и название), то есть родителей, их родителей и так далее:


print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)


👉@BookPython
Класс объекта доступен через атрибут __class__:


>>> [1, 2].__class__
<class 'list'>


Однако более привычный способ получить класс — использовать функцию type. Это также единственный способ, который работает для классов старого стиля.


>>> type([1, 2])
<class 'list'>


Кроме того, если вы хотите проверить, является ли некоторый объект экземпляром данного класса, следует использовать isinstance вместо прямого сравнения:


>>> class A:
... pass
...
>>> class B(A):
... pass
...
>>> type(B())
<class '__main__.B'>
>>> isinstance(B(), A)
True


👉@BookPython
Оператор in можно использовать с генераторами: x in g. Python будет итерировать g, пока x не найдётся или генератор не исчерпается.


>>> def g():
... print(1)
... yield 1
... print(2)
... yield 2
... print(3)
... yield 3
...
>>> 2 in g()
1
2
True


Однако range() делает для вас больше. В нём переопределён магический метод __contains__, который позволяет оператору in работать с сложностью O(1):


In [1]: %timeit 10**20 in range(10**30)
375 ns ± 10.7 ns per loop


Учтите, что это не работает для функции xrange() в Python 2.

👉@BookPython
В Python операторы += и + являются разными. За их поведение отвечают методы __iadd__ и __add__ соответственно.


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

def __iadd__(self, another):
self.x += another.x
return self

def __add__(self, another):
return type(self)(self.x + another.x)


Если __iadd__ не определён, выражение a += b сводится к простому a = a + b.

Обычно разница между += и + в том, что первый изменяет объект, а второй создаёт новый:


>>> a = [1, 2, 3]
>>> b = a
>>> a += [4]
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
>>> a = a + [5]
>>> a
[1, 2, 3, 4, 5]
>>> b
[1, 2, 3, 4]


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

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


>>> first_odd = None
>>> for x in [2, 3, 4, 5]:
... if x % 2 == 1:
... first_odd = x
... break
... else:
... raise ValueError('В списке нет нечетных элементов')
...
>>> first_odd
3



>>> for x in [2, 4, 6]:
... if x % 2 == 1:
... first_odd = x
... break
... else:
... raise ValueError('В списке нет нечетных элементов')
...
...
ValueError: В списке нет нечетных элементов


👉@BookPython