Подборка @pythonetc, июнь 2019
Это одиннадцатая подборка советов про Python и программирование из моего авторского канала @pythonetc.
← Предыдущие подборки
Символ \
в обычной строке имеет особое значение. \t
— это символ табуляции, \r
— разрыв строки, и так далее.
Тогда r'\t'
превратится всего лишь в обратный слэш и t
. Чтобы отключить такое поведение, вы можете использовать raw-строки.
И хотя это ограничение можно обойти с помощью \
, однако в строке \
всё равно останется:
Очевидно, что нельзя использовать '
внутри 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': 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