在Python中创建常量的约定

时间:2011-08-16 13:12:25

标签: coding-style python

我正在编写一个应用程序,它需要跨引擎找出数据库的模式。为此,我正在使用Python编写一个小型数据库适配器。我决定首先编写一个基类来概述我需要的功能,然后使用从这个基础继承的类来实现它。在此过程中,我需要实现一些需要在所有这些类中可访问的常量。其中一些常量需要使用C风格的按位OR组合。

我的问题是,

  1. 分享这些常量的标准方法是什么?
  2. 创建可以组合的常量的正确方法是什么?我指的是C允许的MAP_FIXED | MAP_FILE | MAP_SHARED样式代码。
  3. 对于前者,我遇到了所有常量首先放入模块的线程。对于后者,我简要地想到使用布尔词典。这两个似乎都太笨拙了。我想这是一个相当普遍的要求,并且认为必须确实存在一些好方法!

5 个答案:

答案 0 :(得分:16)

  

分享这些常量的标准方法是什么?

在整个标准库中,最常见的方法是使用UPPER_CASE_WITH_UNDERSCORES名称将常量定义为模块级变量。

  

创建可以组合的常量的正确方法是什么?我指的是MAP_FIXED | MAP_FILE | C允许的MAP_SHARED样式代码。

与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

但由于这种表示法很冗长且难以阅读,因此使用十六进制或二进制移位表示法可能更为可取。

答案 1 :(得分:14)

常量通常在模块级别进行。来自PEP 8

  

常量

     

常量通常在模块级别定义,并以全部大写字母书写,下划线分隔单词。示例包括MAX_OVERFLOW和TOTAL。

如果你想在类级别使用常量,请将它们定义为类属性。

答案 2 :(得分:3)

您经常在全局范围内找到常量,它们是存在的少数变量之一。还有人使用dicts或像这样的对象编写Constant名称空间。

class Const:
    x = 33

Const.x

有些人将它们放在模块中,而其他人将它们作为实例访问的类变量附加。大多数时候它的个人品味,但只有一些全局变量不能真正伤害那么多。

答案 3 :(得分:3)

Stdlib是一个很好的知识来源,可以在doctest code中找到您想要的内容:

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模块也会使用逐位参数样式。

答案 4 :(得分:2)

命名通常是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__])