Идиомы Python

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

  • Выражение, обозначающее элементарную конструкцию, типичную для одного или нескольких языков программирования
  • Обычно используемый и понятный способ написания кода, то есть общепринятая конструкция
  • Специфический грамматический, синтаксический и структурный характер данного языка программирования
  • и множество других.

Кажется понятным, но не до конца. Поэтому, думаю, лучше перейти к самим идиомам, которые наглядно покажут чем они являются на самом деле. 

Безусловно, в этой статьей представлены далеко не все идиомы, классические и общепринятые конструкции языка, но многим новичкам она будет полезна.

Делайте скрипт как импортируемым, так и исполняемым

Что это значит? Так как Python - скриптовый язык программирования, то в нём реализована возможность запускать отдельный скрипты как полноценные (да простят меня гуру) программы. При этом, как и в большинстве языков программирования, есть возможность импортировать из другого файла класс, функцию, переменную и т.д. (коротко говоря, любой объект Python). Таким образом, чтобы унифицировать свой код - делайте скрипт как импортируемым, так и исполняемым:

def main():
    print('Doing stuff in module', __name__)
if __name__ == '__main__':
    print('Executed from the command line')
    main()

$ python mymodule.py
Executed from the command line
Doing stuff in module __main__
>>> import mymodule
>>> mymodule.main()
Doing stuff in module mymodule

 

Проверка на истинность

# GOOD 
name = 'Safe'
pets = ['Dog', 'Cat', 'Hamster']
owners = {'Safe': 'Cat', 'George': 'Dog'}
if name and pets and owners:
    print('We have pets!')
# OR
if all([name, pets, owners]):
    print('We have pets!')

# NOT SO GOOD
if name != '' and len(pets) > 0 and owners != {}:
    print('We have pets!')
  • Проверка на истинность не зависит от типа проверяемого объекта
  • Проверка на истинность явно показывает смысл и цель конструкции, а не делает акцент на значении переменных.

 

Используйте оператор in

Пример (вхождение / contains)

# GOOD
name = 'Safe Hammad'
if 'H' in name:
    print('This name has an H in it!')
# NOT SO GOOD
name = 'Safe Hammad'
    if name.find('H') != -1:
    print('This name has an H in it!')
  • Использование in для проверки вхождения элемента в последовательность является явной и понятной конструкцией.
  • in может использоваться со списками (list), ключами и значениями словарей (dict keys, dict values), множествами (set), строками (strings) и вашими собственным классами, в которых реализован специальный метод __contains__

Пример (итерирование / iteration)

# GOOD
pets = ['Dog', 'Cat', 'Hamster']
for pet in pets:
    print('A', pet, 'can be very cute!')
# NOT SO GOOD
pets = ['Dog', 'Cat', 'Hamster']
i = 0
while i < len(pets):
    print('A', pets[i], 'can be very cute!')
    i += 1
  • использование оператора in для итерирования выглядит просто, понятно и лаконично
  • in может использоваться с списками (list), ключами словарей (dict keys), множествами (set), строками (strings) и вашими собственным классами, в которых реализован специальный метод __iter__

Смена значений без промежуточных переменных

# GOOD
a, b = 5, 6
print(a, b) # 5, 6
a, b = b, a
print(a, b) # 6, 5
# NOT SO GOOD
a, b = 5, 6
print(a, b) # 5, 6
temp = a
a = b
b = temp
print(a, b) # 6, 5
  • Не засоряйте пространство имён (и ОЗУ) переменными, которые будут использованы всего 1 раз

Создание строк из последовательностей

# GOOD
chars = ['S', 'a', 'f', 'e']
name = ''.join(chars)
print(name) # Safe

# NOT SO GOOD
chars = ['S', 'a', 'f', 'e']
name = ''
for char in chars:
    name += char
print(name) # Safe
  • Скорость создания строки из списка с использованием метода join() зависит линейно от длины переданного списка
  • Скорость добавление к строке с использованием + зависит квадратично.

Enumerate

Ещё одна замечательная конструкция, которая позволяет избежать некрасивого кода.

# GOOD
names = ['Safe', 'George', 'Mildred']
for i, name in enumerate(names):
    print(i, name) # 0 Safe, 1 George etc.
# NOT SO GOOD
names = ['Safe', 'George', 'Mildred']
count = 0
for name in names:
    print(i, name) # 0 Safe, 1 George etc.
    count += 1
  • Доступно начиная с Python 2.3
  • В Python 2.6 был добавлен аргумент start, для указания стартовой точки отсчета (по умолчанию - 0)

List comprehensions

Очень замечательная конструкция. Один из примеров прекрасного синтаксического сахара, которого в Python навалом.

# GOOD
data = [7, 20, 3, 15, 11]
result = [i * 3 for i in data if i > 10]
print(result) # [60, 45, 33]
# NOT SO GOOD (MOST OF THE TIME)
data = [7, 20, 3, 15, 11]
result = []
for i in data:
    if i > 10:
    result.append(i * 3)
print(result) # [60, 45, 33]
  • Очень лаконичный синтаксис
  • Однако, вторая форма записи (стандартный цикл) может быть в некоторых ситуациях более понятной

Использование zip для создания словарей

# GOOD
keys = ['Safe', 'Bob', 'Thomas']
values = ['Hammad', 'Builder', 'Engine']
d = dict(zip(keys, values))
print(d) # {'Bob': 'Builder', 'Safe': 'Hammad', 'Thomas': 'Engine'}

# NOT SO GOOD
keys = ['Safe', 'Bob', 'Thomas']
values = ['Hammad', 'Builder', 'Engine']
d = {}
for i, key in enumerate(keys):
    d[keys] = values[i]
print(d) # {'Bob': 'Builder', 'Safe': 'Hammad', 'Thomas': 'Engine'}
  • Не стоит забывать, что существует гораздо больше способов создания словарей

 

''.join(['С', 'п', 'а', 'с', 'и', 'б', 'о', '!'])