Библиотека питониста | Python, Django, Flask
40.2K subscribers
2.83K photos
79 videos
51 files
4.42K links
Все самое полезное для питониста в одном канале.

Список наших каналов: https://t.me/proglibrary/9197

Курс по ML: https://cl

Для обратной связи: @proglibrary_feeedback_bot

По рекламе: @proglib_adv
РКН: https://gosuslugi.ru/snet/67b885cbd501cf3b2cdb5b36
Download Telegram
Иногда вы хотите использовать генератор, но вас не волнуют значения, которые он дает. Тем не менее, вам небезразличен какой-либо побочный эффект, это может быть исключение, запись в файл, изменение глобальной переменной и т. д.

Удобный и широко используемый способ сделать это - list (gen ()). Тем не менее, этот код сохраняет все значения в памяти только для того, чтобы сразу же их отбросить. Это может быть нежелательно.

#codeexample

Если вы хотите избежать этого, вы можете использовать deque с ограниченным размером:

from collections import deque

def inversed(nums):
for num in nums:
yield 1 / num

try:
deque(inversed([1, 2, 0]), maxlen=0)
except ZeroDivisionError:
print('E')

Чтобы быть более семантически точным, вам лучше определить свою собственную функцию выпуска:

def exhaust(iterable):
for _ in iterable:
pass
Пишем функцию, которая принимает в качестве аргумента K list и возвращает все возможные списки из K элементов, где первый элемент из первого списка, второй -  из второго и т.д.

#codeexample

assert combinations([1, 2], [3, 4]) == [
    [1, 3],
    [1, 4],
    [2, 3],
    [2, 4],
]
#codeexample

Стандартный модуль json имеет интерфейс командной строки, который может быть полезен для предварительного преобразования JSON одним только Python. Модуль для этого называется json.tool и должен выгдядить так:

$ echo '{"a": [], "b": "c"}' | python -m json.tool
{
"a": [],
"b": "c"
}
Когда вы пишете пользовательский __repr__ для какого-либо объекта, вы обычно хотите включить представление его атрибутов. Для этого вы должны выполнить форматирование вызова repr() для объектов, так как он вызывает str() по умолчанию.

#codeexample

Это делается с помощью !r :

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

def __repr__(self):
class_name = type(self).__name__
return f'{class_name}({self.left!r}, {self.right!r})'
Если вы хотите перебрать несколько итераций одновременно, вы можете использовать функцию zip (она не имеет ничего общего с форматом файла ZIP):

#codeexample

from datetime import timedelta

names = [
    'Eleven. Return and Revert',
    'Wilderness',
    'The Menagerie Inside',
    'Evaporate',
]

years = [
    2010,
    2013,
    2015,
    2018,
]

durations = [
    timedelta(minutes=57, seconds=38),
    timedelta(minutes=48, seconds=5),
    timedelta(minutes=46, seconds=34),
    timedelta(minutes=43, seconds=25),
]

print('Midas Fall LPs:')
for name, year, duration in zip(
    names, years, durations
):
    print(f'  * {name} ({year}) — {duration}')

Output:

Midas Fall LPs:
  * Eleven. Return and Revert (2010) — 0:57:38
  * Wilderness (2013) — 0:48:05
  * The Menagerie Inside (2015) — 0:46:34
  * Evaporate (2018) — 0:43:25
#codeexample

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

>>> keys = ['a', 'b', 'c']
>>> {k: True for k in keys}
{'a': True, 'b': True, 'c': True}

Однако, у класса dict есть метод класса fromkeys, разработанный специально для этого случая:

>>> dict.fromkeys(keys, True)
{'a': True, 'b': True, 'c': True}

Вы можете добавлять символы Юникода в строковый литерал не только по его номеру, но и по его имени.

>>> '\N{EM DASH}'
'—'
>>> '\u2014'
'—'

Это также совместимо с f-strings:

>>> width = 800
>>> f'Width \N{EM DASH} {width}'
'Width — 800'
#codeexample

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

>>> x = 42
>>> f'{x:5}+{x:15f}'
' 42+ 42.000000'

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

def print_table(matrix):
cols_width = [
max(len(str(row[col])) for row in matrix)
for col in range(len(matrix[0]))
]

for row in matrix:
for i, cell in enumerate(row):
print(
f'{cell:{cols_width[i]}} ',
end=''
)
print()

albums = [
['Eleven. Return and Revert', 2010],
['Wilderness', 2013],
['The Menagerie Inside', 2015],
['Evaporate', 2018],
]

print_table(albums)

На выходе:

Eleven. Return and Revert 2010
Wilderness 2013
The Menagerie Inside 2015
Evaporate 2018
__init__ позволяет изменить объект сразу после создания. Если вы хотите контролировать то, что уже создано, используйте __new__:

#codeexample

from typing import Tuple, Dict
from cached_property import cached_property

class Numbers:
_LOADED: Dict[Tuple[int, ...], 'Numbers'] = {}

def __new__(cls, ints: Tuple[int, ...]):
if ints not in cls._LOADED:
obj = super().__new__(cls)
cls._LOADED[ints] = obj

return cls._LOADED[ints]

def __init__(self, ints: Tuple[int, ...]):
self._ints = ints

@cached_property
def biggest(self):
print('calculating...')
return max(self._ints)

print(Numbers((4, 3, 5)).biggest)
print(Numbers((4, 3, 5)).biggest)
print(Numbers((4, 3, 6)).biggest)
#codeexample

`complex`- это встроенный тип Python для комплексных чисел:

>>> complex(1, 2).real
1.0
>>> abs(complex(3, 4))
5.0
>>> complex(1, 2) == complex(1, -2).conjugate()
True
>>> str(complex(2, -3))
'(2-3j)'

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

>>> (3 + 4j).imag
4.0
>>> not (3 + 4j)
False
>>> (-3 - 4j) + (2 - 2j)
(-1-6j)
Вы можете перевести или удалить символы строки (как это делает утилита tr) с помощью метода перевода str:

#codeexample

>>> 'Hello, world!'.translate({
... ord(','): ';',
... ord('o'): '0',
... })
'Hell0; w0rld!'

Единственный аргумент перевода - это словарь, отображающий коды символов на символы (или коды). Обычно такой словарь удобнее создавать статическим методом str.maketrans:

>>> 'Hello, world!'.translate(str.maketrans({
... ',': ';',
... 'o': '0',
... }))
'Hell0; w0rld!'

Or even:

>>> 'Hello, world!'.translate(str.maketrans(
... ',o', ';0'
... ))
'Hell0; w0rld!'

Третий аргумент для удаления параметров:

>>> tr = str.maketrans(',o', ';0', '!')
>>> tr
{44: 59, 111: 48, 33: None}
>>> 'Hello, world!'.translate(tr)
'Hell0; w0rld'