Python Craftsman: использование переменных для улучшения качества кода

задняя часть Python Язык программирования Django

Автор оригинала: piglei

Оригинальная ссылка:Woohoo.Самая любовь и тому подобное.Таланты/статьи/друзья…

Что такое "Мастер Питона"?

Я всегда считал программирование в некотором смысле «ремеслом», потому что элегантный и эффективный код так же приятен для глаз, как и совершенная ручная работа.

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

Цикл статей "Мастер Python" - это моя маленькая попытка. Он фокусируется на том, чтобы поделиться некоторыми «мелкими» вещами в программировании на Python. Я надеюсь, что это может помочь каждому мастеру на пути программирования.

Серия статей:

Переменные и качество кода

В качестве первой статьи из серии "Python Craftsman" я хочу рассказать о "Переменных". Потому что определение и использование переменных всегда было одним из первых навыков, которые необходимо освоить при изучении любого языка программирования.

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

как назвать переменные

В информатике есть известная поговорка (однострочник):

В компьютерных науках есть только две сложные вещи: инвалидация кеша и присвоение имен вещам. В информатике есть только две сложные вещи: истечение срока действия кеша и присвоение имен вещам.

-- Phil Karlton

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

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

Следующие пункты являются основными принципами, которые я обобщил при именовании переменных.

1. Имена переменных должны быть описательными и не слишком широкими.

существуетв допустимых пределах, чем точнее имя переменной может описать содержимое, на которое оно указывает, тем лучше. Итак, постарайтесь не использовать эти слишком широкие слова в качестве имен ваших переменных:

  • BAD: day, host, cards, temp
  • GOOD: day_of_week, hosts_to_reboot, expired_cards

2. Имена переменных должны заставлять людей угадывать тип

Любой, кто изучает Python, знает, что Python — это язык с динамической типизацией, который (по крайней мере, вPEP 484перед появлением) без объявления типа переменной. Поэтому, когда вы видите переменную, нет простого способа узнать ее тип, кроме как догадаться по контексту.

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

"Какое имя будет считаться логическим типом? 』

Самая большая особенность булевой переменной заключается в том, что она может иметь только два возможных значения ** «да» ** или"нет". Итак, используйтеis,hasИмена переменных, измененные черными и белыми словами, были бы хорошим выбором. Принцип:Заставьте людей, которые читают имя переменной, думать, что переменная может иметь только значение «да» или «нет»..

Вот несколько хороших примеров:

  • is_superuser: "Является ли это суперпользователь", всего два значения: да/нет
  • has_error: "Есть ли ошибка", всего два значения: да/нет
  • allow_vip: "Разрешен ли VIP", всего два значения: разрешить/запретить
  • use_msgpack: "использовать ли msgpack", здесь всего два значения: использовать/не использовать
  • debug: «Включить ли режим отладки», считается логическим в основном из-за соглашения

«Какие имена считаются типами int/float? 』

Когда люди видят имена, связанные с числами, они по умолчанию используют тип int/float. Чаще встречаются следующие:

  • Все слова интерпретируются как числа, например:port(端口号),age(年龄),radius(半径)так далее
  • Используйте слова, оканчивающиеся на _id, например:user_id,host_id
  • Используйте слова, которые начинаются или заканчиваются на длина/количество, например:length_of_username,max_length,users_count

**Примечание.** Не используйте обычные комплексные числа для представления переменной типа int, напримерapples,trips, лучше всего использоватьnumber_of_apples,trips_countзаменить.

другие типы

Для сложных типов, таких как str, list, tuple и dict, сложно иметь единое правило, позволяющее угадывать тип переменной по имени. Напримерheaders, который может быть либо списком заголовков, либо словарем, содержащим заголовки.

Для этих типов имен переменных наиболее рекомендуемым способом является написание канонической документации в строке документа функций и методов с использованием формата sphinx (Инструменты документации, используемые официальной документацией Python), чтобы аннотировать тип всех переменных.

3. Надлежащее использование «венгерской номенклатуры»

Зная в первый разВенгерская номенклатура', вСообщение в блоге Джоэла о программном обеспечениисередина. Короче говоря, венгерская нотация заключается в сокращении «типа» переменной и размещении его в начале имени переменной.

Ключевым моментом является то, что упомянутая здесь переменная type не относится к типу int/str/list в традиционном смысле, а относится к тем типам, которые относятся к бизнес-логике вашего кода.

Например, в вашем коде есть две переменные:studentsа такжеteachers, они указывают на список объектов Person. После использования «венгерской нотации» два имени можно переписать следующим образом:

students -> pl_students teachers -> pl_teachers

где плperson listаббревиатура от . Когда имя переменной имеет префикс, если вы видитеpl_Переменная в начале может знать тип значения, на который она указывает.

Во многих случаях использование "венгерской нотации" является хорошей идеей, потому что это может улучшить читабельность вашего кода, особенно когда имеется много переменных и несколько вхождений одного и того же типа. Только будьте осторожны, чтобы не злоупотреблять этим.

4. Делайте имена переменных как можно более короткими, но никогда не слишком короткими

Ранее мы упоминали, что имена переменных должны быть описательными. Если вы не накладываете никаких ограничений на этот принцип, вы, скорее всего, будете писать такие описательные имена переменных:how_much_points_need_for_level2. Если код переполнен такими длинными именами переменных, это катастрофа для удобочитаемости кода.

Хорошее имя переменной, длина должна контролироваться воколо двух-трех слов. Например, приведенное выше имя можно сократить какpoints_level2.

В большинстве случаев следует избегать коротких имен, состоящих всего из одной или двух букв., например массив, индексирующий Three Musketeersi,j,k, всегда лучше заменить их осмысленными именами, такими как session_index .

Исключения в использовании кратких имен

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

Например, при импорте модулей в Python в качестве псевдонимов часто используются короткие имена, такие как те, которые обычно используются в переводах Django i18n.gettextМетоды часто обозначаются аббревиатурой_использовать *(из django.utils.translation импортировать ugettext как _)*

5. Другие примечания

Некоторые другие соображения по именованию переменных:

  • Не используйте имена переменных, которые слишком похожи в одном фрагменте кода, например, появляются в одно и то же время.users,users1,user3эта последовательность
  • Не используйте имена переменных с отрицательным значением, используйтеis_specialзаменятьis_not_normal

Лучшее использование переменных

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

1. Будьте последовательны

Если вы вызываете переменную изображения внутри методаphoto, не меняйте его наimage, что только сбивает с толку читателя кода: "imageа такжеphotoЭто то же самое? 』

Кроме того, хотя Python является языком с динамической типизацией, это не означает, что вы можете использовать одно и то же имя переменной для представления типа str в один момент времени, а затем изменить его на список позднее.Типы переменных, на которые ссылаются одни и те же имена переменных, также должны быть согласованы.

2. Старайтесь не использовать globals()/locals()

Возможно, вы были взволнованы, когда впервые обнаружили пару встроенных функций globals()/locals(), и вам не терпелось написать следующий предельно «краткий» код:

def render(request, user_id, trip_id):
    user = User.objects.get(id=user_id)
    trip = get_object_or_404(Trip, pk=trip_id)
    is_suggested = is_suggested(user, trip)
    # 利用 locals() 节约了三行代码,我是个天才!
    return render(request, 'trip.html', locals())

Не делайте этого, это только заставит людей, которые прочитают этот код (включая вас через три месяца), ненавидеть вас, потому что им нужно помнить все переменные, определенные в этой функции (думаю, эта функция вырастет до двух. Что насчет 100 строк?), не говоря уже о том, что locals() также пропускает некоторые ненужные переменные.

не говоря уж о,Дзен PythonСкажи это ясно:Явное лучше неявного.. Итак, давайте честно напишем такой код:

    return render(request, 'trip.html', {
        'user': user,
        'trip': trip,
        'is_suggested': is_suggested
    })

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

Этот принцип общеизвестен. У многих людей (включая меня) есть привычка, когда они впервые учатся программировать. Это значит записать все определения переменных вместе и поместить их в начало функции или метода.

def generate_trip_png(trip):
    path = []
    markers = []
    photo_markers = []
    text_markers = []
    marker_count = 0
    point_count = 0
    ... ...

Это только сделает ваш код «чистым», но не улучшит его читабельность.

Еще лучше,Держите определения переменных как можно ближе к использованию. Таким образом, когда вы читаете код, вы можете лучше понять логику кода, вместо того, чтобы пытаться думать о том, что это за переменная и где она определена?

4. Используйте namedtuple/dict с умом, чтобы функции возвращали несколько значений

Функции Python могут возвращать несколько значений:

def latlon_to_address(lat, lon):
    return country, province, city

# 利用多返回值一次解包定义多个变量
country, province, city = latlon_to_address(lat, lon)

Однако такое использование создает небольшую проблему: если однаждыlatlon_to_addressЧто делать, если функция должна вернуть «Район»?

Если написано выше, то нужно найти все вызовыlatlon_to_addressместо, компенсируйте лишнюю переменную, иначеValueError: too many values to unpackнайдет вас:

country, province, city, district = latlon_to_address(lat, lon)
# 或者使用 _ 忽略多出来的返回值
country, province, city, _ = latlon_to_address(lat, lon)

Для таких потенциально изменчивых функций с множественным возвратом удобнее использовать namedtuple/dict. Когда вы добавляете новое возвращаемое значение, оно не оказывает деструктивного эффекта на предыдущие вызовы функций:

# 1. 使用 dict
def latlon_to_address(lat, lon):
    return {
        'country': country,
        'province': province,
        'city': city
    }

addr_dict = latlon_to_address(lat, lon)

# 2. 使用 namedtuple
from collections import namedtuple

Address = namedtuple("Address", ['country', 'province', 'city'])

def latlon_to_address(lat, lon):
    return Address(
        country=country,
        province=province,
        city=city
    )

addr = latlon_to_address(lat, lon)

Однако это тоже плохо, потому что, хотя совместимость кода с изменениями улучшилась, вы не можете продолжать использовать прежнийx, y = f()способ распаковки для одновременного определения нескольких переменных. Выбор за вами.

5. Контролируйте количество переменных в одной функции

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

6. Удалите эти бесполезные переменные вовремя

Этот принцип очень прост и легок в исполнении. Но если вы не будете следовать ему, это ухудшит качество вашего кода. Заставляет людей, читающих ваш код, чувствовать, что их обманывают.

def fancy_func():
    # 读者心理:嗯,这里定义了一个 fancy_vars
    fancy_vars = get_fancy()
    ... ...(一大堆代码过后)

    # 读者心理:这里就结束了?之前的 fancy_vars 去哪了?被猫吃了吗?
    return result

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

7. Нельзя определить переменную, не определив ее

Иногда умственная деятельность, когда мы определяем переменную, выглядит так: «Ну, это значение может быть изменено/использовано дважды в будущем», давайте сначала определим его как переменную!

def get_best_trip_by_user_id(user_id):
    user = get_user(user_id)
    trip = get_best_trip(user_id)
    result = {
        'user': user,
        'trip': trip
    }
    return result

На самом деле "будущее", как вы думаете, никогда не наступит.Три временные переменные в этом коде можно полностью удалить и сделать вот так:

def get_best_trip_by_user_id(user_id):
    return {
        'user': get_user(user_id),
        'trip': get_best_trip(user_id)
    }

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

Эпилог

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

Это первая статья из серии "Python Craftsman" Интересно, у вас есть на что пожаловаться после прочтения статьи? Пожалуйста, оставьте сообщение, чтобы сказать мне.

Запись обновления статьи:

  • 2018.04.09: Добавлен раздел namedtuple, предложенный @onlyice.