15 февраля 2010 в 19:10

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
Автор оригинала: Shalabh Chaturvedi
Павел @Riateche
карма
233,0
рейтинг 0,0
Самое читаемое Разработка

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

  • +5
    Спасибо, очень интересно!
    • +5
      Спасибо, очень интересно!
      • +5
        Спасибо, очень интересно!
        • +4
          Спасибо, очень интересно!
          • +4
            Спасибо, очень интересно!
            • +20
              C-C-C-COMBO BREAKER!
            • +6
              Перечитал 3 раза, захватывающее чтиво.
            • +5
              Очень интересно, спасибо!
            • НЛО прилетело и опубликовало эту надпись здесь
              • НЛО прилетело и опубликовало эту надпись здесь
            • 0
              Даешь синусоиду в комментариях :)
          • НЛО прилетело и опубликовало эту надпись здесь
          • –3
            Спасибо, очень интересно!
          • –3
            Спасибо, очень интересно!
            • –1
              Ээээ… За что заминусовали человека?
              • НЛО прилетело и опубликовало эту надпись здесь
          • –2
            Спасибо, очень интересно!
        • 0
          Спасибо, очень интересно!
  • +5
    Эхх, как мне не хватало подобной статьи когда я начинал знакомиться с Питоном.
    Однозначно продолжать!
    • +3
      Действительно, куча вот таких вот особенностей может остаться за бортом, если изучаешь Python после C, Java или подобных. Как чуть было не получилось у меня.

      Обязательно продолжайте.
    • 0
      Я конечно извиняюсь, но вся эта информация содержится в официальном tutorial. Или вы начинали знакомиться с питоном в обход официальной документации?
  • +3
    Жду дальнейших переводов :)
  • +1
    иногда очень помогает перечитать туториалы и 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
      Когда у меня возникла такая же задача, я первым делом погуглил, потому что был уверен, что в таком красивом языке должен быть красивый способ.
    • +1
      я когда сам написал, потому что не знал, что есть готовое
      def enumerate(some_list):
        return zip(range(len(some_list), some_list)
      
  • НЛО прилетело и опубликовало эту надпись здесь
    • +2
      К счастью, это можно понять из следующего предложения. А заголовок призывает не смешивать понятия кортежа и списка.
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          Здесь есть тонкость. Кортеж — это список (в полном смысле этого русского слова), но не list (понимаемый как тип данных).
    • +1
      Кстати, что значит «неизменяемый» применительно к кортежу — тоже не все понимают. И уверены, что код

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

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

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

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

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

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

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

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

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

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

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

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

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

    for i, item in enumerate(mylist):
        pass

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