15 February 2010

Be Pythonic

Python

От переводчика


Представляю вашему внимаю перевод статьи Shalabh Chaturvedi «Be Pythonic», рекомендованной в этом топике. Если мое начинание будет поддержано, планирую также перевести две остальные упомянутые там статьи этого автора.

Вступление


Эта статья предназначена для новичков в Python.

При переходе с одного языка на другой некоторые вещи для вас могут остаться неизвестными (см. Transfer of Learning). То, что вам известно о других языках, может быть не всегда полезным в Python. Эта статья содержит некоторые используемые в Python идиомы, которые мне особенно нравятся. Я надеюсь, читатели найдут их полезными для овладения языком.


Счетчики нужны редко, итераторы — лишь иногда


Неправильно:
i = 0
while i<10:
   do_something(i)
   i += 1

Правильно:
for i in xrange(10):
  do_something(i)

В следующем примере программа проходит по списку.
Неправильно:
i = 0
while i<len(L):
  do_something(L[i])
  i += 1

Правильно:
for item in L:
  do_something(item)

Итераторы полезны, когда вы хотите сохранить позицию в цикле между двумя запусками:
itrL = iter(L)

for item in itrL:
  do_something(item)
  if is_some_condition(item):
    break

for item in itrL:  # продолжаем с места, на котором мы вышли из предыдущего цикла
  do_something_else(item)

Может быть, вам не нужен цикл for


Python предоставляет много средств более высокого уровня для работы с последовательностями, например, zip(), max(), min(), list comprehensions (генерация списков), generator expressions (компактная запись генераторов) и т. д. Эти и другие функции описаны в разделе «Built-in Functions» документации.

Вы можете хранить данные в кортежах, списках, словарях и работать с целыми наборами. Например, вот пример кода, который читает CSV-файл (в котором первая строка содержит названия полей), преобразует каждую строку в элемент словаря и считает сумму чисел в столбце «quantity».
f = open('filename.csv')              # f — итератор
field_names = f.next().split(',')     # берем первый элемент итератора с помощью next()
records = [dict(zip(field_names, line.split(','))) for line in f] # получаем оставшиеся строки
print sum(int(record['quantity']) for record in records)

В любом случае вы должны использовать модуль csv, входящий в Python Standard Library, но этот пример иллюстрирует некоторые полезные особенности. Используя zip() и dict(), вы можете объединить кортеж названий и кортеж значений и получить словарь. А в сочетании с генерацией списков вы можете сделать это с целым списком за один шаг.

Кортеж — это не список, который нельзя редактировать


Содержимое кортежа обычно разнородно, например, (first_name, last_name) или (ip_address, port). При этом тип данных может быть одинаковым (и first_name, и last_name — строки). Вы можете думать о кортеже как о строке в реляционной базе данных — фактически строка таблицы даже называется кортежем в формальном описании реляционной модели. Напротив, список имен — это всегда список.

Распаковка кортежей — это полезный способ для извлечения элементов из них. Например:
for (ip_address, port) in all_connections:
  if port<2000:
    print 'Connected to %s on %s' % (ip_address, port)

Этот код показывает, что all_connections — это список (или iterable объект), содержащий кортежи вида (ip_address, port). Это лучше, чем использовать for item in all_connections и вызывать элемент через item[0] или похожим способом.
Также стоит использовать распаковку кортежей, если функция должна возвращать несколько значений:
# разделяем имя файла на основную часть и расширение
name, ext = os.path.splitext(filename)  

Классы предназначены не для группировки функций


C# и Java позволяют размещать код только в классах, поэтому в них много служебных классов, содержащих только статические методы. Например, это математические функции, такие как sin(). В Python вы просто используете модуль, содержащий функции верхнего уровня.

Скажите «нет» геттерам и сеттерам


Да, инкапсуляция важна. Но геттеры и сеттеры — не единственный способ для этого. В Python вы можете использовать property вместо членов класса, то есть полностью изменить способ инкапсуляции без изменения кода, использующего класс.

Функции — это объекты


Функция — это объект, который можно вызвать. Этот пример сортирует список словарей по значению, соответствующему ключу 'price':
# определяем функцию, возвращающую полезные данные из объекта
def get_price(ob):
  return ob['price']

L.sort(key=get_price)  # сортируем список, используя значение ['price'] объектов в списке

* This source code was highlighted with Source Code Highlighter.

Вы также можете использовать sorted(L, key=get_price), чтобы получить новый список вместо изменения имеющегося.

Ссылки по теме


Python is not Java
What is Pythonic
Tags:python
Hubs: Python
Comments 57
Ads