Соглашения о создании констант в Python
Я пишу приложение, которое должно выяснить схему базы данных в разных движках. С этой целью я пишу небольшой адаптер базы данных, используя Python. Я решил сначала написать базовый класс, в котором изложены необходимые мне функциональные возможности, а затем реализовать его, используя классы, наследуемые от этой базы. Попутно мне нужно реализовать некоторые константы, которые должны быть доступны для всех этих классов. Некоторые из этих констант должны быть объединены с использованием побитового ИЛИ в стиле C.
Мой вопрос
- Каков стандартный способ разделения таких констант?
- Как правильно создать константы, которые можно комбинировать? Я имею в виду
MAP_FIXED | MAP_FILE | MAP_SHARED
код стиля, который позволяет C
Для первого я наткнулся на потоки, в которых все константы были сначала помещены в модуль. Что касается последнего, я кратко подумал об использовании слова "логическое значение". Оба из них казались слишком громоздкими. Я полагаю, что это довольно распространенное требование, и думаю, что действительно должен быть какой-то хороший путь!
5 ответов
Каков стандартный способ разделения таких констант?
Во всей стандартной библиотеке наиболее распространенным способом является определение констант как переменных уровня модуля с использованием имен UPPER_CASE_WITH_UNDERSCORES.
Как правильно создать константы, которые можно комбинировать? Я имею в виду MAP_FIXED | MAP_FILE | Код стиля MAP_SHARED, который позволяет C.
Применяются те же правила, что и в C. Вы должны убедиться, что каждое постоянное значение соответствует одному уникальному биту, то есть степени 2 (2, 4, 8, 16, ...).
В большинстве случаев люди используют шестнадцатеричные числа для этого:
OPTION_A = 0x01
OPTION_B = 0x02
OPTION_C = 0x04
OPTION_D = 0x08
OPTION_E = 0x10
# ...
Некоторые предпочитают более понятный человеку стиль, вычисляя значения констант динамически, используя операторы сдвига:
OPTION_A = 1 << 0
OPTION_B = 1 << 1
OPTION_C = 1 << 2
# ...
В Python вы также можете использовать двоичную запись, чтобы сделать это еще более очевидным:
OPTION_A = 0b00000001
OPTION_B = 0b00000010
OPTION_C = 0b00000100
OPTION_D = 0b00001000
Но поскольку эта запись длинна и трудна для чтения, использование шестнадцатеричной или двоичной записи сдвига, вероятно, предпочтительнее.
Константы обычно идут на уровне модуля. Из PEP 8:
Константы
Константы обычно определяются на уровне модуля и пишутся заглавными буквами с подчеркиванием, разделяющим слова. Примеры включают MAX_OVERFLOW и TOTAL.
Если вам нужны константы на уровне класса, определите их как свойства класса.
Stdlib - отличный источник знаний, пример того, что вы хотите, можно найти в коде doctest:
OPTIONS = {}
# A function to add (register) an option.
def register_option(name):
return OPTIONS.setdefault(name, 1 << len(OPTIONS))
# A function to test if an option exist.
def has_option(options, name):
return bool(options & name)
# All my option defined here.
FOO = register_option('FOO')
BAR = register_option('BAR')
FOOBAR = register_option('FOOBAR')
# Test if an option figure out in `ARG`.
ARG = FOO | BAR
print has_option(ARG, FOO)
# True
print has_option(ARG, BAR)
# True
print has_option(ARG, FOOBAR)
# False
Примечание: модуль re также использует побитовый стиль аргументов, если вам нужен другой пример.
Вы часто находите константы на глобальном уровне, и они являются одной из немногих переменных, которые существуют там. Есть также люди, которые пишут пространства имен Constant, используя диктовки или подобные объекты
class Const:
x = 33
Const.x
Некоторые люди помещают их в модули, а другие прикрепляют их как переменные класса, к которым обращаются экземпляры. Большую часть времени это его личный вкус, но только несколько глобальных переменных не могут повредить так сильно.
Именование обычно UPPERCASE_WITH_UNDERSCORE, и они, как правило, уровня модуля, но иногда они живут в своем собственном классе. Одна из веских причин быть в классе - это когда значения являются особыми - например, необходимо иметь степень двойки:
class PowTwoConstants(object):
def __init__(self, items):
self.names = items
enum = 1
for name in items:
setattr(self, name, enum)
enum <<= 1
constants = PowTwoConstants('ignore_case multiline newline'.split())
print constants.newline # prints 4
Если вы хотите иметь возможность экспортировать эти константы на уровень модуля (или любое другое пространство имен), вы можете добавить в класс следующее:
def export(self, namespace):
for name in self.names:
setattr(namespace, name, getattr(self, name))
а потом
import sys
constants.export(sys.modules[__name__])