1. Внимание! Пользователи форума Null-Prog.ru, сейчас на сайте идёт полное реорганизация. По просьбам большинства, постепенно вводится внутренняя валюта сайта для покупки VIP контента ПОШТУЧНО! В связи с чем ближайшие 4 дня могут быть перебои в работе, недоступность (кратковременная) сайта. Если сейчас УЖЕ вам нужен какой либо контент, обращаемся в личку. Все, купившие VIP ранее, сохраняют свой статус и их эти новшества никак не затрагивают. Касательно использования валюты, будет мануал позже. Спасибо за понимание. 

    Скрыть объявление
  2. На нашем форуме Null-Prog действует серьёзное правило касательно размещения материалов!

    ДЛЯ РЕЛИЗЁРОВ: категорически запрещается выкладка материалов на файлообменники типа Deposit, letitbit и другие, требующие просмотров рекламы, обрезающие скорость и тд. Нарушителям, первые 2 раза предупреждения, далее БАН. Тему по этому поводу можно посмотреть ТУТ

    Скрыть объявление
  3. В тестовом режиме на нашем форуме открыт онлайн конструктор сайтов. Вы можете попробовать создать свой сайт у НАС, интуитивно понятный интерфейс, переведёт на 95%, быстрый экспорт проекта, от вас только перетаскивать элементы и вставить в них необходимый текст!

    Все вопросы ТУТ

    Скрыть объявление

  4. Скрыть объявление
  5. Уважаемые форумчане, открывается новый раздел форума, посвящённый ремонту и эксплуатации автомобилей. Просмотреть его можно ТУТ

    Так как раздел новый, информация будет пополнять каждый день. Если есть какие либо замечания по этому разделу, отписываемся в соответствующий раздел форума, либо в личку.

    Напоминаю, сообщения в разделе АВТО не учитываются, общение не ограничено.

    Скрыть объявление
  6. Объявляется набор Модераторов на различные раздел форума, свои заявки можно оставлять в ЭТОМ разделе, перед оставлением заявки рекомендуется ознакомиться с ПРАВИЛАМИ для модераторов.

Советы Google по кодированию на языке Python. Часть первая: советы по программированию

Тема в разделе "Perl, Python, Ruby", создана пользователем Sam Jack, 8 май 2015.

  1. Sam Jack

    Sam Jack Капитан-Узурпатор
    Команда форума Созидатель

    Регистрация:
    5 май 2015
    Сообщения:
    12.032
    Симпатии:
    2.464
    Программировать на языке Python — подобно песне. Но еще лучше, когда Ваш код читаем и понятен, а значит чуть более поэтичен, чем обычно бывает производстве. У каждого свои правила и свои стереотипы относительно написания и оформления исходного кода на каком бы языке он ни был написан. Множество копий сломано о щиты на форумах, но как ни крути нельзя не считаться с мнением авторитетных товарищей. Так что сейчас будет представлен перевод первой части стайл-гайда для языка Python от Google. А коснется он именно постулатов написания кода (вторая часть тоже скоро появится, а посвящена она будет форматированию исходного кода). Сразу предупреждаю: тут много (если не большинство) прописных истин, которые все знают уже давно. Но я искренне надеюсь, что Вы сможете найти тут что-то новое или хотя бы вспомнить старое. Приступим под катом.
    Google Python Style Guide

    Версия: 2.48
    Авторы: Amit Patel, Antoine Picard, Eugene Jhong, Jeremy Hylton, Matt Smart, Mike Shields.

    Подготовка

    Python является основным скриптовым языком, используемым в Google. Данное руководство это список «хорошо» и «плохо» для программ написанных на языке Python. Чтобы помочь Вам форматировать свой код корректно, мы создали файл настроек для редактора Vim. Для Emacs, его изначальные настройки должны хорошо подходить для наших целей.

    Советы по программированию на Python

    PyChecker

    Используйте PyChecker для проверки своего кода
    Определение

    PyChecker это инструмент для нахождения багов в исходниках Python-программ. Он находит проблемы, которые были бы выявлены компилятором менее динамичных языков, таких как С и С++. Это очень заманчиво. В силу динамической природы языка Python, некоторые предупреждения могут быть несправедливыми, однако ложные предупреждения не должны часто встречаться.

    Плюсы

    Отлавливает трудновыявляемые ошибки, такие как ошибки типов, использование переменных перед их объявлением и т.д.

    Минусы

    PyChecker не идеален. Чтобы получить все его преимущества, порою нам нужно:

      • Писать с оглядкой на него
      • Подавить его предупреждения
      • Исправлять ошибки
      • Либо не обращать внимания на них внимания
    Решение

    Убедитесь, что вы запустили PyChecker с вашим кодом. Для того, чтобы узнать как запустить PyChecker, загляните на его домашнюю страницу. Чтобы подавить предупреждения — вам нужно создать переменную __pychecker__ в данном модуле, и указать какие ошибки должны подавляться. Например:
    Код:
    __pychecker__ = 'no-callinit no-classattr'

    Подавление предупреждений таким путем имеет преимущество следующего плана — мы можем с легкостью производить поиск по подавлениям и возвращаться к ним. Вы можете познакомиться со списком предупреждений PyChecker, если наберете:
    Код:
    pychecker -- help

    Неиспользуемые аргументы могут быть быть опущены при помощи '_' как наименования неиспользуемого аргумента, либо префикса аргумента «unused_». В ситуациях когда изменение имени аргумента невозможно, вы можете упомянуть их в начале функции. Например:
    Код:
    def foo (a, unused_b, unused_c, d=None, e=None)
    _ = d, e
    return a

    В идеале, PyChecker будет доработан, чтобы с уверенностью можно было утверждать, что «неиспользуемые объявления» в действительности таковые.

    Импорты

    Импортируйте только пакеты и модули

    Определение

    Механизм повторного использования открытого кода из одного модуля в другом.

    Плюсы

    Соглашение по пространствам имен очень простое. Местонахождение каждого объекта в коде указывается единым способом. x.Obj говорит о том, что объект Obj объявлен в модуле x.

    Минусы

    Имена модулей могут иногда конфликтовать. Некоторые имена модулей могут быть неудобно длинными.

    Решение

    Используйте import x для импортирования пакетов и модулей.
    Используйте from x import y, когда x префикс пакета и y является именем модуля без префикса.
    Используйте from x import y as z, если два модуля имеют имя y, либо если имя модуля неудобно длинное.
    Например модуль sound.effects.echo может быть импортирован так:
    Код:
    from sound.effects import echo
    ...
    echo.EchoFilter(input, output, delay=0.7, atten=4)

    Не используйте относительные имена в импортах. Даже если модуль находится в том же самом пакете, используйте только полное имя пакета. Это поможет предотвратить ситуацию, когда один и тот же пакет импортирован два раза.

    Пакеты

    Импортируйте каждый модуль используя полный путь до него

    Плюсы

    Обходятся конфликты в именах модулей. Становится проще отыскать модуль на диске.

    Минусы

    Становится сложней переносить код, т.к. вы должны полностью воссоздать полную иерархию модулей.

    Решение

    Весь Ваш новый код должен импортировать каждый модуль по его полному пути в пакете.
    Импорту следует быть таким:
    Код:
    # Ссылка в коде с полным именем
    import sound.effects.echo

    # Ссылка в коде только с именем модуля (предпочтительно)
    from sound.effects import echo

    Исключения

    Исключения разрешены, но должны использоваться осторожно
    Определение
    Исключение является средством выхода из нормального потока управления блока кода для обработки ошибок или других исключительных условий.

    Плюсы
    Поток управления обычного кода не перемешивается с кодом перехвата ошибок. Это так же позволяет потоку выполнения пропускать некоторое количество фреймов, когда выполняется определенное условие — например, возвращение из N-вложенных функций за один шаг вместо множественных обработок кодов ошибок.

    Минусы
    Поток управления может начать выполняться некорректно. Очень просто пропустить ситуацию, в которой будет возбуждена ошибка при вызове функции из библиотеки.

    Решение
    Обработка исключений должна следовать следующим позициям:
    • Возбуждайте исключения таким образом: raise MyException('Error message'), либо raise MyException. Не используйте форму записи с двумя аргументами: (raise MyException, 'Error message'), так же не используйте строковую форму записи (raise 'Error message').
    • Модули (или пакеты) должны определять свои собственные предметно-ориентированные классы исключений, которые должны наследоваться от встроенного класса Exception.
      Основное исключение модуля должно называться Error.
      Код:
      class Error(Exception):
      pass
    • Никогда не используйте исключение, которое ловит все исключительные ситуации, только если вы не собираетесь их перевозбудить позднее, либо вы не находитесь во внешнем блоке кода в треде (и печатается сообщение об ошибке). Pytnon очень терпим в этом отношении, кроме того: вы можете поймать всё что угодно, включая ошибки именования, вызов sys.exit(), прерывание Сtrl+С, провалы тестов и разного типа исключеня, которые Вы просто не хотите ловить.
    • Уменьшите количество кода находящегося в блоке try/except. Чем больше тело блока try, тем вероятней, что исключение будет возбуждено в строке кода, в которой вы не ожидаете возбуждения последнего. В этих случаях блок try/except скрывает реальную ошибку.
    • Искользуйте инструкцию finally чтобы выполнить код независимо от того было ли возбуждено исключение в блокеtry или нет. Это часто бывает полезно для заключительных действий, например — закрытия файла.
    • При перехватывании исключения лучше использовать as, чем запятую:
    Код:
    try:
    raise Error
    except Error as error:
    pass

    Глобальные переменные

    Избегайте использования глобальных переменных
    Определение

    Переменные, которые определены на уровне модуля.
    Плюсы

    Иногда полезны.
    Минусы

    Можно нечаянно изменить поведение модуля при импорте, т.к. присваивание переменных уровня модуля уже завершено когда модуль импортируется.
    Решение

    Избегайте использования глобальных переменных в пользу переменных класса. Несколько исключений ниже:
    · Стандартные настройки скриптов.
    · Константы уровня модуля. Например, PI = 3.14159. Константы должны быть именованы используя только заглавные буквы и подчеркивания. Смотрите правила именования ниже.
    · Иногда полезно использовать глобальные переменные, чтобы кэшировать значения, необходимые для функции или возвращаемые функцией.
    · При необходимости, глобальные переменные должны быть созданы внутри модуля и доступны через общедоступные функции уровня модуля. Смотрите правила наименования ниже.

    Вложенные/локальные/внутренние классы и функции

    Вложенные/локальные/внутренние классы и функции - хороши
    Определение
    Класс может быть определен внутри метода, функции или другого класса. Функция может быть определена внутри метода или другой функции. Вложенные фукнции имеют доступ только на чтение к переменным определенным в родительской области.Плюсы
    Делает возможным определение вспомогательных классов и функций, которые будут использованы только внутри очень ограниченного пространства. Соответствует принципу ADT.Минусы
    Экземпляры вложенных или локальных классов не могут быть сериализированы.Решение
    Они хороши.

    Генераторы списков

    Можно использовать в простых случаях
    Определение
    Генераторы списков и выражения генераторы обеспечивают компактный и эффективный способ создавать списки и итераторы не прибегая к использованию функций map(), filter() или lambda-выражениям.
    Плюсы

    Простой генератор списков может быть чище и проще, чем другие способы создания списков. Выражение генератор может быть очень эффективным, т.к. они не создают весь список сразу.
    Минусы

    Сложные генераторы списков или выражения-генераторы могут быть трудночитаемы.
    Решение

    Можно использовать в простых случаях. Каждая часть должна быть расположена на одной строчке. Определение отображения, инструкция for, условное выражение. Несколько инструкций for или условий недопустимы. Используйте циклы, если Ваши выражения становятся слишком сложными.

    Хорошо:
    Код:
    result = []
    for x in range(10):
    for y in range(5):
    if x * y > 10:
    result.append((x, y))
    for x in xrange(5):
    for y in xrange(5):
    if x != y:
    for z in xrange(5):
    if y != z:
    yield (x, y, z)

    return ((x, complicated_transform(x))
    for x in long_generator_function(parameter)
    if x is not None)

    squares = [x * x for x in range(10)]

    eat(jelly_bean for jelly_bean in jelly_beans
    if jelly_bean.color == 'black')

    Плохо:
    Код:
    result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]

    return ((x, y, z)
    for x in xrange(5)
    for y in xrange(5)
    if x != y
    for z in xrange(5)
    if y != z)

    Стандартные итераторы и операторы

    Используйте стандартные итераторы и опрераторы
    Определение

    Контейнерные типы, такие как словари и списки определяют стандартные итераторы и набор тестовых операторов in иnot in.
    Плюсы

    Стандартные итераторы и операторы — просты и эффективны. Они выражают операцию напрямую, без внутренних перевызовов. А функция, которая использует стандартные операторы — является простой. Она может быть использована с разными типами, которые поддерживают данную операцию.
    Минусы

    И вы не можете назвать типы объектов по названию метода (как например, has_key() обозначает, что это словарь). Это так же является и преимуществом.Решение
    Используйте стандартные итераторы и операторы для типов, которые поддерживают их таких как списки, словари и файлы. Встроенные типы тоже определяют методы итератора. Предпочитайте эти методы методам которые возвращают списки, за исключением того, если вы хотите изменять сам контейнер во время прохождения итераций.

    Хорошо:
    Код:
    for key in adict: ...
    if key not in adict: ...
    if obj in alist: ...
    for line in afile: ...
    for k, v in dict.iteritems(): ...
    Плохо:
    Код:
    for key in adict.keys(): ...
    if not adict.has_key(key): ...
    for line in afile.readlines(): ...

    Генераторы

    Используйте генераторы, по необходимости
    Определение
    Функция-генератор возвращает итератор, который производит значение каждый раз, когда он исполняет выражениеyield. После генерации значения, состояние выполнения функции приостанавливается, до того пока не потребуется следующее значение.
    Плюсы

    Упрощает код, т.к. состояние локальных переменных и потока управления остается прежним для каждого вызова. Генератор требует меньше памяти, чем функция которая создает список значений сразу.
    Минусы

    Минусов нет.
    Решение

    Прекрасно. Отдавайте предпочтение “Генерирует:" нежели «Возвращает:” в строках документации для функций-генераторов.

    Лямбда-функции

    Хороши для инлайновых выражений
    Определение

    Лямбда-функции определяют анонимные функции в выражении, как альтернатива конструкции. Они часто используются чтобы объявить callback-функции или операторы для функций высшего порядка таких как map() и filter().
    Плюсы

    Удобно.
    Минусы

    Труднее читать и отлаживать, чем локальные функции. Отсутствие имен означает, что стек вызовов будет труднее читать. Выразительность ограничена т.к. функция может содержать только одно выражение.
    Решение

    Хорошо подходят для инлайновых выражений. Если код внутри лямбда-функции длиннее чем 60-80 символов, то возможно, лучше определить данную функцию как обычную (или вложенную) функцию. Для простых операций таких как умножение, используйте функции из модуля operator вместо лямбда-функций. Например, лучше используйтеoperator.mul вместо lambda x,y: x*y.

    Условные выражения

    Хороши для инлайновых выражений
    Определение

    Условные выражения это механизм который обеспечивает краткий синтаксис для конструкции if. Например x = 1 if cond else 2.
    Плюсы

    Короче и более удобно, чем конструкция if.
    Минусы

    Может быть более трудночитаемым, чем выражение if. Условие может быть слишком сложным для написания если выражение очень длинное.
    Решение

    Использовать только для инлайновых выражений. В иных случаях отдавать предпочтение использованию полноценной конструкции if.

    Аргументы по-умолчанию

    Можно использовать в большинстве случаев
    Определение

    Вы можете назначить значения для переменных в конце списка аргументов функции, например def foo(a, b=0):
    Если функция foo будет вызвана только с одним аргументом, аргумент b будет равен 0. Если она будет вызвана с двумя аргументами, b будет иметь значение, переданное вторым аргументом.
    Плюсы

    Часто у вас есть функция которая использует много значений по-умолчанию. Но редко Вам необходимо переопределить стандартные значения. Также Python не поддерживает перегрузку методов/функций и стандартные аргументы это простой путь “эмитировать” поведение перегрузки.
    Минусы

    Значения стандартных аргументов вычисляются один раз во время загрузки модуля. Это может являться причиной проблемы если аргумент является изменяемым объектом, таким как список или словарь. Если функция изменяет объект (например, посредством добавления элемента в список), то стандартное значение будет изменено.
    Решение

    Можно использовать со следующими предостережениями:
    Не используйте изменяемые объекты в качестве стандартных значений в функциях или определениях методов.
    Хорошо:
    Код:
    def foo (a, b=None):
    if b is None:
    b = []
    Плохо:
    Код:
    def foo(a, b=[]):
    Вызов кода должен использовать именованные значения для аргументов со значением по-умолчанию. Это позволяет документировать код и несколько помогает предотвращать и выявлять дефекты, когда передано больше аргументов, чем нужно.
    Код:
    def foo (a, b=1):
    ...
    Хорошо:
    Код:
    foo(1)
    foo(1, b=2)
    Плохо:
    Код:
    foo(1, 2)

    Свойства

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

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

    Удобочитаемость повышается за счет исключения явных вызовов get- и set-методов для простого доступа к аттрибуту. Возможны ленивые вычисления. Считается, что поддерживать интерфейс класса есть часть пути Python. С точки зрения производительности, позволяет свойству быть доступным через простейший метод-геттер (аксессор) когда нужен прямой доступ к переменной. Так же позволяет методам доступа быть добавленными позднее, без изменения интерфейса.
    Минусы

    Свойства объявляются после того, как методы get и set были объявлены, требуя сообщить им, что они используются для свойств находящихся ниже в коде (исключая свойства доступные только на чтение созданные с помощью декоратора@property, о нем смотрите ниже). Они должны наследоваться от класса object. Могут скрывать побочные эффекты такие, как оператор перегрузки. Могут вводить в заблуждение классы-наследники.
    Решение

    Используйте свойства в только что написанном коде для доступа или изменения данных там, где вы бы использовали простой get-метод или set-метод. Свойства „только на чтение“ должны создаваться с помощью декоратора @property. Наследование со свойствами может быть не очень прозрачным, если свойство родителя не будет переопределено. Таким образом, необходимо убедиться, что методы-геттеры вызываются косвенно, чтобы обеспечить переопределение методам в подклассах вызываемых через свойство (искользуя паттерн Шаблонный метод)
    Код:
    importmath
    classSquare(object):
            """A square with two properties: a writable area and a read-only perimeter.
            To use:
            >>> sq = Square(3)
            >>> sq.area
            9
            >>> sq.perimeter
            12
            >>> sq.area = 16
            >>> sq.side
            4
            >>> sq.perimeter
            16
            """
            def__init__(self, side):
                self.side = side
            def__get_area(self):
                """Calculates the 'area' property."""
                return self.side ** 2
            def___get_area(self):
                """Indirect accessor for 'area' property."""
                return self.__get_area()
            def__set_area(self, area):
                """Sets the 'area' property."""
                self.side = math.sqrt(area)
            def___set_area(self, area):
                """Indirect setter for 'area' property."""
                self.__set_area(area)
            area = property(___get_area, ___set_area,
                         doc="""Gets or sets the area of the square.""")
            @property
            defperimeter(self):
                return self.side * 4

    Вычисления True/False

    Используйте False явно, если это возможно
    Определение

    Python вычисляет определенные значение в False, когда мы находимся в контексте булевых значений. Самый просто способ запомнить это, знать — что все “пустые” значения, такие как False, 0, None, [], {} — вычисляются в False в булевом контексте.
    Плюсы

    Условные конструкции использующие булевы значения Python более удобочитаемые и меньше подвержены ошибкам. В большинстве случаев, они также работают быстрее.
    Минусы

    Могут выглядеть странно для разработчиков на С/С++.
    Решение

    Используйте False явно, если это возможно, например if foo: лучше, чем if foo != []:. Вы должны помнить несколько исключений:
    · Никогда не используйте == или != для сравнения объектов синглтона, таких как None. Используйте is или is not.
    · Остерегайтесь написания if x: когда вы подразумеваетеif x is not None: например, когда происходит тестирование переменной или аргумента которые по умолчанию равны None, но их значение было изменено на другое. Другое значение может вычисляться в False при булевой проверке.
    · Никогда не сравнивайте булеву переменную с False используя ==. Используйте if not x вместо этого. Если вам нужно отличить False от None, тогда используйте цепочечное выражение, такое как if not x and x is not None.
    · Для последовательностей (строк, списков, кортежей) используйте тот факт, что пустая последовательность вычисляется в False, таким образом if not seq или if seq лучше чем if len(seq) или if not len(seq):.
    · Когда вы работаете с целыми числами, явное сравнение с False несет больший риска чем выгоды (случайная обработка None как 0). Вы можете сравнивать значение которое является целым числом (и не является результатом выполнения функции len()) c нулем.
    Хорошо:
    Код:
    if not users:
        print "no"
    if foo == 0:
        self.handle_zero()
    if i % 10 == 0:
         self.handle_multiple_of_ten()
    Плохо:
    Код:
    if len(users) == 0:
         print 'no users'
    if foo is not None and not foo:
         self.handle_zero()
    if not i % 10:
         self.handle_multiple_of_ten()
    Заметьте, что “0” (т.е. 0 как строка) вычисляется в True.

    Устаревшие возможности языка

    Используйте методы вместо модуля string там, где это возможно
    Используйте методы вместо модуляstringтам, где это возможно. Используйте вызов функции посредством синтаксиса, а не функциюapply. Используйте генераторы списков и циклы for вместо функцийfilterиmapтам, где аргумент функции будет иметь инлайновое лямбда-выражение. Используйте циклы вместоreduce.
    Определение

    Настоящая версия языка Python предоставляет альтернативные конструкции которы люди находят определенно лучшими.Решение
    Мы не используем версии Python которые не поддерживают эти возможности, так что нет причин использовать новые стили.

    Хорошо:
    Код:
    words = foo.split(':')
    [x[1] for x in my_list if x[2] == 5]
    map(math.sqrt, data) # Все хорошо - нет инлайновых лямбда выражений
    fn(*args, **kwargs)
    Плохо:
    Код:
    words = string.split(foo, ':')
    map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))

    Лексический контекст

    Разрешается к использованию

    Определение

    Вложенные функции в питоне могут ссылаться на переменные определенные в объемлющих функциях, но не могут выполнять присваивание им. Связи переменных разрешаются с помощью лексического контекста, который основан на статичном тексте программы. Любое присваивание имени в блоке кода заставляет Python обработать все ссылки на это имя даже если использование предшествует объявлению. Если существует глобальное объявление, имя будет обработано как глобальная переменная.
    Примериспользованияэтойвозможности:
    Код:
    def get_adder(summand1):
    """Returns a function that adds numbers to a given number."""
    def adder (summand2):
    return summand1 + summand2

    return adder
    Плюсы

    Часто приводить к более чистому и элегантному коду. Особенно комфортно с этим работать для Lisp и Scheme (и Haskell и ML и..) программитов.
    Минусы

    Может приводить к странным ошибкам. Таким как в этом примере взятом из PEP-0227:
    Код:
    i = 4
    def foo (x):
    def bar():
    print i,
    # ...
    # Здесь куча кода
    # ...
    for i in x: # Ох, переменная i локальна для Foo, так ее-то Bar и видит.[
    print i,
    bar()
    таким образом foo([1,2,3]) выведет 1 2 3 3, а не 1 2 3 4.
    Решение

    Можно использовать.
     
    #1 Sam Jack, 8 май 2015
    Последнее редактирование: 8 май 2015
    Метки:
    zokenudih нравится это.

Поделиться этой страницей

iHax Community
Рейтинг@Mail.ru Яндекс.Метрика мониторинг сайтов
Форум программного обеспечения/
Загрузка...