Библиотека Python разработчика | Книги по питону
18.4K subscribers
1.05K photos
403 videos
82 files
1.13K links
Погружение в CPython и архитектуру. Разбираем неочевидное поведение (GIL, Memory), Best Practices (SOLID, DDD) и тонкости Django/FastAPI. Решаем задачи с подвохом и оптимизируем алгоритмы. 🐍

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

РКН clck.ru/3Ko7Hq
Download Telegram
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'


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2👎1
🚀 Подборка полезных IT каналов в Max


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

https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.

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

Программирование C++📌

https://max.ru/cpp_lib Библиотека C/C++ разработчика

Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика

Программирование React📌
https://max.ru/react_lib React

Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика

Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика

GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub

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

Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков

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

Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻

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

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

Книги, статьи для дизайнеров 📌

https://max.ru/odesigners Статьи, книги для дизайнеров

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

Вакансии 📌
https://max.ru/progjob Вакансии в IT

Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных


Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
💩3🤮2🤡1
В 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 предназначены для оптимизации, а не для ограничения набора атрибутов.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍1
Если вы хотите перехватить и IndexError, и KeyError, вы можете и должны использовать LookupError — их общего предка. Это оказывается полезным при работе со сложными вложенными данными:


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


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Каждый класс 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'>)


Второй —```python

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


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


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
В 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]


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
В 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: В списке нет нечетных элементов


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41🔥1
Начиная с Python 3.0, при возникновении нового исключения внутри блока except перехваченное исключение автоматически сохраняется в атрибуте __context__ создаваемого исключения. В результате при выводе будут показаны оба исключения:


try:
1 / 0
except ZeroDivisionError:
raise ValueError('Zero!')



(most recent call last):
File "test.py", line 2, in <module>
1 / 0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "test.py", line 4, in <module>
raise ValueError('Zero!')
ValueError: Zero!


Кроме того, вы можете явно указать причинное исключение, использовав конструкцию raise … from. Тогда в атрибут __cause__ нового исключения будет помещено исходное:


division_error = None

try:
1 / 0
except ZeroDivisionError as e:
division_error = e

raise ValueError('Zero!') from division_error



(most recent call last):
File "test.py", line 4, in <module>
1 / 0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "test.py", line 8, in <module>
raise ValueError('Zero!') from division_error
ValueError: Zero!


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍1
>>> bool(datetime(2018, 1, 1).time())
False
>>> bool(datetime(2018, 1, 1, 13, 12, 11).time())
True


До Python 3.5 объекты datetime.time() считались ложными, если они представляли полночь по UTC. Это могло приводить к трудноуловимым ошибкам. В следующих примерах if not может выполниться не потому, что created_time равен None, а потому, что время — полночь.


def create(created_time=None) -> None:
if not created_time:
created_time = datetime.now().time()


Можно исправить это, явно проверяя на None:


def create(created_time=None) -> None:
if created_time is None:
created_time = datetime.now().time()


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
В Python нет поддержки асинхронных операций с файлами. Чтобы сделать их неблокирующими, нужно использовать отдельные потоки.

Для асинхронного выполнения кода в потоке следует использовать метод loop.run_in_executor.

Сторонний модуль aiofiles делает всё это за тебя, предоставляя простой и удобный интерфейс:


async with aiofiles.open('filename', mode='r') as f:
contents = await f.read()


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
Иногда нужно создать функцию на основе более универсальной.

Например, у функции int() есть параметр base, который мы хотим зафиксировать, чтобы получить новую функцию base2:


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


functools.partial позволяет сделать то же самое, но точнее и семантически понятнее:


base2 = partial(int, base=2)


Это полезно, когда нужно передать функцию как аргумент другой, более общей функции, но при этом некоторые аргументы должны быть зафиксированы:


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


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


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


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
Существует две встроенные функции, которые позволяют анализировать итерируемые объекты без необходимости писать тривиальные и избыточные циклы for. Это all и any.

any возвращает True, если хотя бы одно значение истинно; all возвращает True, только если все значения истинны. Для пустого итерируемого объекта all возвращает True, а anyFalse.

Обе функции особенно полезны в сочетании со списковыми включениями (list comprehensions):


package_broken = any(
part.is_broken() for part in package.get_parts()
)
package_ok = all(
part.ok() for part in package.get_parts()
)


Функции any и all зачастую взаимозаменяемы благодаря законам де Моргана. Используй ту, с которой код будет понятнее.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
🚀 Подборка полезных IT каналов в Max


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

https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
https://max.ru/tipsysdmin Типичный Сисадмин

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

Программирование C++📌

https://max.ru/cpp_lib Библиотека C/C++ разработчика

Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика

Программирование React📌
https://max.ru/react_lib React

Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика

Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика

GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub

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

Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков

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

Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻

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

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

Книги, статьи для дизайнеров 📌

https://max.ru/odesigners Статьи, книги для дизайнеров

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

Вакансии 📌
https://max.ru/progjob Вакансии в IT

Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных


Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
👎3👍1
Если ты хочешь запустить код с изменённой глобальной переменной, лучше использовать контекстный менеджер, а не менять её напрямую:


from contextlib import contextmanager

QUIT_MESSAGE = 'Bye'

def print_quit_mesage():
global QUIT_MESSAGE
print(QUIT_MESSAGE)

@contextmanager
def global_variable_changed(name, value):
orig_value = globals()[name]
globals()[name] = value
yield
globals()[name] = orig_value

with global_variable_changed(
'QUIT_MESSAGE',
'Tschüss'
):
print_quit_mesage()


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🤷‍♀1
Ты можешь создавать словари двумя способами: с помощью литералов или функции dict:


>>> dict(a=1, b=2)
{'a': 1, 'b': 2}
>>> {'a': 1, 'b': 2}
{'a': 1, 'b': 2}


Литералы работают быстрее, чем dict, но у функции есть свои преимущества.

Во-первых, не нужно ставить дополнительные кавычки. Однако это работает только в том случае, если все ключи — допустимые идентификаторы Python:


>>> dict(a=1)
{'a': 1}
>>> dict(1='a')
File "<stdin>", line 1
SyntaxError: keyword can't be an expression


Во-вторых, ты не сможешь случайно указать один и тот же ключ дважды:


>>> {'a': 1, 'a': 1}
{'a': 1}
>>> dict(a=1, a=1)
File "<stdin>", line 1
SyntaxError: keyword argument repeated


В-третьих, легко создать новый словарь на основе уже существующего:


>>> d = dict(b=2)
>>> dict(a=1, **d)
{'a': 1, 'b': 2}


Но учти, что ключи нельзя переопределять при таком способе:


>>> dict(b=3, **d)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type object got multiple values for keyword argument


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Начиная с Python 3.5, стало возможно использовать распаковку в литералах словарей и списков.

Пример со словарём:


{**{'a': 1}, 'b': 2, **{'c': 3}}
# Результат: {'a': 1, 'b': 2, 'c': 3}


Пример со списком:


[1, 2, *[3, 4]]
# Результат: [1, 2, 3, 4]


Для словарей такая форма даже мощнее, чем функция dict, потому что позволяет переопределять значения:


{**{'a': 1, 'b': 1}, 'a': 2, **{'b': 3}}
# Результат: {'a': 2, 'b': 3}


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Если ты хочешь, чтобы контекстный менеджер при входе или выходе из контекста приостанавливал выполнение корутины, следует использовать асинхронные контекстные менеджеры. Вместо вызова m.__enter__() и m.__exit__() Python в этом случае выполняет await m.__aenter__() и await m.__aexit__() соответственно.

Асинхронные контекстные менеджеры нужно использовать с синтаксисом async with:


import asyncio

class Slow:
def __init__(self, delay):
self._delay = delay

async def __aenter__(self):
await asyncio.sleep(self._delay / 2)

async def __aexit__(self, *exception):
await asyncio.sleep(self._delay / 2)

async def main():
async with Slow(1):
print('slow')

loop = asyncio.get_event_loop()
loop.run_until_complete(main())


В этом примере класс Slow симулирует задержку при входе и выходе из контекста.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
Начиная с Python 3.7, модуль contextlib предоставляет декоратор asynccontextmanager, который позволяет определять асинхронные контекстные менеджеры точно так же, как contextmanager:


import asyncio
from contextlib import asynccontextmanager

@asynccontextmanager
async def slow(delay):
half = delay / 2
await asyncio.sleep(half)
yield
await asyncio.sleep(half)

async def main():
async with slow(1):
print('slow')

loop = asyncio.get_event_loop()
loop.run_until_complete(main())


Для более старых версий Python можно использовать @asyncio_extras.async_contextmanager.

📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🚀 Подборка полезных IT каналов в Max


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

https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
https://max.ru/tipsysdmin Типичный Сисадмин

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

Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика

Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика

Программирование React📌
https://max.ru/react_lib React

Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика

Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика

GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub

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

Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков

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

Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻

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

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

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

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

Вакансии 📌
https://max.ru/progjob Вакансии в IT

Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных


Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
👍1👎1🤬1🤮1
Иногда в тестах нужно сравнивать сложные структуры, игнорируя некоторые значения. Обычно это делается путем сравнения отдельных значений внутри структуры:


>>> d = dict(a=1, b=2, c=3)
>>> assert d['a'] == 1
>>> assert d['c'] == 3


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


>>> assert d == dict(a=1, b=ANY, c=3)


Это легко реализовать, определив метод __eq__:


>>> class AnyClass:
... def __eq__(self, another):
... return True
...
>>> ANY = AnyClass()


📲 Мы в MAX

👉@BookPython
Please open Telegram to view this post
VIEW IN TELEGRAM
1💩1