Соглашения о создании констант в Python - PullRequest
15 голосов
/ 16 августа 2011

Я пишу приложение, которое должно выяснить схему базы данных в разных движках. С этой целью я пишу небольшой адаптер базы данных, используя Python. Я решил сначала написать базовый класс, в котором изложены необходимые мне функциональные возможности, а затем реализовать его, используя классы, которые наследуются от этой базы. Попутно мне нужно реализовать некоторые константы, которые должны быть доступны для всех этих классов. Некоторые из этих констант должны быть объединены с использованием побитового ИЛИ в стиле C.

Мой вопрос,

  1. каков стандартный способ разделения таких констант?
  2. как правильно создавать константы, которые можно комбинировать? Я имею в виду код стиля MAP_FIXED | MAP_FILE | MAP_SHARED, который позволяет C.

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

Ответы [ 5 ]

16 голосов
/ 16 августа 2011

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

Во всей стандартной библиотеке наиболее распространенным способом является определение констант как переменных уровня модуля с использованием имен 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

Но так как эта запись длинна и трудна для чтения, использование шестнадцатеричной или двоичной записи сдвига, вероятно, предпочтительнее.

14 голосов
/ 16 августа 2011

Константы обычно идут на уровне модуля.Начиная с PEP 8 :

Константы

Константы обычно определяются на уровне модуля и записываются всеми заглавными буквами с подчеркиванием, разделяющим слова.Примеры включают MAX_OVERFLOW и TOTAL.

Если вы хотите использовать константы на уровне класса, определите их как свойства класса.

3 голосов
/ 16 августа 2011

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

N.B .: Модуль re также использует побитовый стиль аргументов, если вам нужен другой пример.

3 голосов
/ 16 августа 2011

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

class Const:
    x = 33

Const.x

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

2 голосов
/ 01 октября 2011

Именование обычно 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__])
...