04.07.2019       Выпуск 289 (01.07.2019 - 07.07.2019)       Статьи

Подборка @pythonetc, июнь 2019

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

Читать>>




Экспериментальная функция:

Ниже вы видите текст статьи по ссылке. По нему можно быстро понять ссылка достойна прочтения или нет

Просим обратить внимание, что текст по ссылке и здесь может не совпадать.

Это одиннадцатая подборка советов про 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





Разместим вашу рекламу

Пиши: mail@pythondigest.ru

Нашли опечатку?

Выделите фрагмент и отправьте нажатием Ctrl+Enter.

Система Orphus