
Это одиннадцатая подборка советов про Python и программирование из моего авторского канала @pythonetc.
← Предыдущие подборки

Символ
\ в обычной строке имеет особое значение. \t — это символ табуляции, \r — разрыв строки, и так далее.Чтобы отключить такое поведение, вы можете использовать raw-строки. Тогда
r'\t' превратится всего лишь в обратный слэш и t.Очевидно, что нельзя использовать
' внутри r'...'. И хотя это ограничение можно обойти с помощью \, однако в строке \ всё равно останется:>>> print(r'It\'s insane!') It\'s insane!

Генераторы списков могут содержать больше одной пары выражений
for и if:In : [(x, y) for x in range(3) for y in range(3)] Out: [ (0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2) ] In : [ (x, y) for x in range(3) for y in range(3) if x != 0 if y != 0 ] Out: [(1, 1), (1, 2), (2, 1), (2, 2)]
Кроме того, любое выражение внутри
for и if может использовать все ранее определённые переменные:In : [ (x, y) for x in range(3) for y in range(x + 2) if x != y ] Out: [ (0, 1), (1, 0), (1, 2), (2, 0), (2, 1), (2, 3) ]
Вы можете смешивать
if и for по своему усмотрению:In : [ (x, y) for x in range(5) if x % 2 for y in range(x + 2) if x != y ] Out: [ (1, 0), (1, 2), (3, 0), (3, 1), (3, 2), (3, 4) ]

Функция
sorted позволяет задавать пользовательские способы сортировки. Это делается с помощью аргумента key, который описывает, как нужно преобразовать исходные значения для последующего сравнения:>>> x = [dict(name='Vadim', age=29), dict(name='Alex', age=4)] >>> sorted(x, key=lambda v: v['age']) [{'age': 4, 'name': 'Alex'}, {'age': 29, 'name': 'Vadim'}]
Увы, не все библиотеки, работающие со сравнением, поддерживают аргумент
key. Из тех, что на слуху, можно упомянуть heapq (частичная поддержка) и bisect (нет поддержки).В этой ситуации можно пойти двумя путями. Можно использовать пользовательские объекты, которые поддерживают правильное сравнение:
>>> class User: ... def __init__(self, name, age): ... self.name = name ... self.age = age ... def __lt__(self, other): ... return self.age < other.age ... >>> x = [User('Vadim', 29), User('Alex', 4)] >>> [x.name for x in sorted(x)] ['Alex', 'Vadim']
Однако, вам может понадобиться создать несколько версий подобных классов, потому что сравнивать объекты можно по-разному. Это может быть неудобно, поэтому есть и второй способ.
Вместо создания пользовательских объектов вы можете использовать кортежи
(a, b), в которых a — значение для сравнения (приоритет), а b — исходное значение:>>> users = [dict(name='Vadim', age=29), dict(name='Alex', age=4)] >>> to_sort = [(u['age'], u) for u in users] >>> [x[1]['name'] for x in sorted(to_sort)] ['Alex', 'Vadim']

Разница между определением и генератором функции заключается в наличии ключевого слова
yield в теле функции:In : def f(): ...: pass ...: In : def g(): ...: yield ...: In : type(f()) Out: NoneType In : type(g()) Out: generator
Это означает, что для создания пустого генератора вам нужно сделать так:
In : def g(): ...: if False: ...: yield ...: In : list(g()) Out: []
Но поскольку
yield from поддерживает простые итераторы, то есть более приятная версия:def g(): yield from []

В Python можно создавать цепочки операторов сравнения:
>>> 0 < 1 < 2 True >>> 0 < 1 < 0 False
Такие цепочки не обязаны быть математически корректными, вы можете смешивать
> и <:>>> 0 < 1 > 2 False >>> 0 < 1 < 2 > 1 > 0 True
Также поддерживаются операторы
==. is и in:>>> [] is not 3 in [1, 2, 3] True
Каждый оператор применяется к двум соседним операндам.
a OP1 b OP2 c строго эквивалентно (a OP1 b) AND (b OP2 c). Сравнение a и c не выполняется:class Spy: def __init__(self, x): self.x = x def __eq__(self, other): print(f'{self.x} == {other.x}') return self.x == other.x def __ne__(self, other): print(f'{self.x} != {other.x}') return self.x != other.x def __lt__(self, other): print(f'{self.x} < {other.x}') return self.x < other.x def __le__(self, other): print(f'{self.x} <= {other.x}') return self.x <= other.x def __gt__(self, other): print(f'{self.x} > {other.x}') return self.x > other.x def __ge__(self, other): print(f'{self.x} >= {other.x}') return self.x >= other.x s1 = Spy(1) s2 = Spy(2) s3 = Spy(3) print(s1 is s1 < s2 <= s3 == s3)
Результат:
1 < 2 2 <= 3 3 == 3 True
