Python

индекс
250,37

Be Pythonic

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


Представляю вашему внимаю перевод статьи 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
+80
15 февраля 2010, 19:10
134

комментарии (57)

+5
shemsu #
Спасибо, очень интересно!
+5
angry_elf #
Спасибо, очень интересно!
+5
printf #
Спасибо, очень интересно!
+4
iscander #
Спасибо, очень интересно!
+4
inventor #
Спасибо, очень интересно!
+20
Mad_Fish #
C-C-C-COMBO BREAKER!
+6
torai #
Перечитал 3 раза, захватывающее чтиво.
+5
kAIST #
Очень интересно, спасибо!
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
0
kAIST #
Даешь синусоиду в комментариях :)
НЛО прилетело и опубликовало эту надпись здесь
–3
Houston #
Спасибо, очень интересно!
–3
Belidor #
Спасибо, очень интересно!
–1
prefer #
Ээээ… За что заминусовали человека?
НЛО прилетело и опубликовало эту надпись здесь
–2
Zubchick #
Спасибо, очень интересно!
0
Bytamine #
Спасибо, очень интересно!
+5
iOrange #
Эхх, как мне не хватало подобной статьи когда я начинал знакомиться с Питоном.
Однозначно продолжать!
+3
colriot #
Действительно, куча вот таких вот особенностей может остаться за бортом, если изучаешь Python после C, Java или подобных. Как чуть было не получилось у меня.

Обязательно продолжайте.
0
LighteR #
Я конечно извиняюсь, но вся эта информация содержится в официальном tutorial. Или вы начинали знакомиться с питоном в обход официальной документации?
+3
fatalo #
Жду дальнейших переводов :)
+1
kAIST #
иногда очень помогает перечитать туториалы и whats new.
Я больше года делал вот так, когда нужно было пройтись по всех элементам списка с их нумерацией:
i=0
for x in some_list:
print i,x
i+=1
хотя можно было обойтись функцией enumerate, на которую я наткнулся в whats new какой то версии питона, в более старых учебниках соответственно этого не было
for i,x in enumerate(some_list):
print i,x
+2
Riateche #
Когда у меня возникла такая же задача, я первым делом погуглил, потому что был уверен, что в таком красивом языке должен быть красивый способ.
+1
genk #
я когда сам написал, потому что не знал, что есть готовое
def enumerate(some_list):
  return zip(range(len(some_list), some_list)
+1
hoitytoity #
забавная фраза:

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

Что же это тогда такое — отсюда понять не удается :))
+2
Riateche #
К счастью, это можно понять из следующего предложения. А заголовок призывает не смешивать понятия кортежа и списка.
+1
hoitytoity #
Позволю себе с вами не согласиться:
из следующего тоже непонятно, что такое кортеж :)
Пилгрим пишет, что «Кортеж — это неизменяемый список. С момента создания кортеж не может быть изменен никакими способами.» Ну да и пусть пишет, правда? :)
+1
Riateche #
Здесь есть тонкость. Кортеж — это список (в полном смысле этого русского слова), но не list (понимаемый как тип данных).
+1
kmike #
Кстати, что значит «неизменяемый» применительно к кортежу — тоже не все понимают. И уверены, что код

x = 1,2,3
x += 4,5

работать не будет.

Ну и могут вообще не понять, что тут с кортежами идет работа, особенно если помнят «операцию запятая» в Си и применяют свои знания в питоне.
–5
velial #
очень интересно, хотелось бы еще примеры для переходящих с Пых-Пыха
0
taliban #
ножно купить книжку, говорят, чтение помогает получить новые знания, не дожидаясь «еще примеров» ;)
–3
loststylus #
Здорово, но про «Кортеж — это не список, который нельзя редактировать» не согласен, т.к. в разделе показан пример, который будет работать и со списком, который также можно распаоквывать. Так что лично для меня, tuple по-прежнему остается списком, который нельзя редактировать.

Если я чего-то не знаю, расскажите, пожалуйста.
+2
loststylus #
Упс, это я поторопился. Да, пример верный.
+8
Averrin #
Хм, а я ничего нового не прочел. Видимо я не так плохо знаю Python. Спасибо за поднятие ЧСВ=)
+1
simakazi #
«Этот пример сортирует список словарей по значению, соответствующему ключу 'key'»
Видимо, должно быть: «соответствующему ключу 'price'»
+1
Riateche #
Верно, спасибо.
+1
VYBGSS #
Ждем продолжение.
НЛО прилетело и опубликовало эту надпись здесь
+2
webwarrior #
К хорошему привыкаешь быстро ;-)
НЛО прилетело и опубликовало эту надпись здесь
+4
Riateche #
Да. После питона на php писать становится грустно.
+1
MihailOlenin #
После питона писать надо на питоне, а не на php
+2
Riateche #
Для себя я теперь на php не пишу. Для заказчиков, увы, приходится.
+2
taliban #
кстати в питоне и JS есть очень много общего… на первый взгяд не так заметно, но изнутри очень родные
0
seriyPS #
Ну, Python на Javascript довольно-таки похож. Я за месяц примерно освоился, даже меньше
НЛО прилетело и опубликовало эту надпись здесь
+3
KL7 #
Большое спасибо за статью. Недавно публиковал тут код на Питоне. Пришлось провести немало времени, выясняя, что есть pythonic, а что не очень. Такого рода статьи в тот момент я не нашел. А жаль — очень бы пригодилась.

Думаю такие публикации были бы полезны и по другим языкам, потому что осваивая что-то новое часто бывает очень не просто отказаться от привычек программирования на «родном» языке. А надо. 8)
+1
Cord #
Прочитал про парсинг csv файла и хочу сказать, что это просто охуительно!
Не зря я осваиваю Джангу. Питон — потрясающий язык. Позади — basic)), pascal, asp, perl, php, вот пришел к Питону. Дальше хочу за плюсы.

Питон, я иду! :)
+1
shemsu #
Не пугайте его так, он хороший.
+1
Cord #
Я тоже хороший :)
+4
kmike #
Хорошие советы, кроме «Скажите «нет» геттерам и сеттерам». Использование property может легко сделаеть код не проще и понятнее, а скорее наоборот, запутаннее и «магичнее».

Раздел «функции — это объекты» был бы отличной демонстрацией того, где в питоне стоит применять лямбда-функции:

L.sort(key=lambda item: item['price'])

+2
kmike #
а, ну и название переменной L не по pep-8 :)
+2
garex #
Про выполнение кучи всего в одной строке — не самый удачный пример у изначального автора.

Такие строки не сходу понимаешь и вероятность багов в них растёт, как комменты «Спасибо, понравилось!» в вверху.

Т.е. концепция вроде правильная, но пример для культуры писания не удачен. Писать надо понятно, ибо мы большую часть времени код читаем.
0
MihailOlenin #
С моей точки зрения, если знать эти приемы, то читаемость повысится. Это же строки не в 400 символов длиной
0
garex #
Дык не все же мы знаем — есть старшие программеры, а есть просто программеры.

А код д.б. понимаем всеми как минимум, пусть даже талант к его созданию есть тока у страших товарищей.

Т.е. я лично болею за читаемость. Либо такие заносы в отдельные функции/методы выкидывать.
0
kost_bebix #
Главное так и не было сказано — для цикла for есть конструкция:

for i, item in enumerate(mylist):
    pass

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.