在python中,如何只为函数存储一次“常量”?

时间:2013-03-19 09:13:22

标签: python global-variables constants

某些函数需要“常量”值(即,未设计为稍后重新定义),不需要参数化。虽然stored only once的默认参数为each function,但有些参数作为参数(即成为signature的一部分)并不是很有意义。对于(一个不是很有用)的例子:

def foo(bar):
    my_map = {"rab": barType, "oof": fooType}
    return my_map.get(bar,defaultType)()

浪费了CPU时间和RAM空间来为每个调用重新定义这样的常量。其他一些方法是将这些常量存储为模块级全局变量或使该函数成为可调用类,但可能还有其他方法,可能吗?

当执行模块级全局方式时,我将我的(意思是)常量变量加上“_”前缀,以表明它是对任何人的兴趣。我仍觉得模块命名空间略微“污染”,完全没有提到shame of using as discouraged as globals的内容:

_my_map = {"rab": barType, "oof": fooType}
def foo(bar):
    return _my_map.get(bar,defaultType)()

将其转换为类方式。我将__call__设为classmethod,以避免创建实例的需要:

class foo:
   my_map = {"rab": barType, "oof": fooType}
   @classmethod
   def __call__(cls,bar):
       return cls.my_map.get(bar,defaultType)()

这些解决方案是否足够pythonic?

还有其他方法吗?

使用这种'常数'是否可以作为一种做法?

注意我的示例中的这些对象不一定是实际的常量,而是根据其目的使用(并且可以被认为)。

4 个答案:

答案 0 :(得分:11)

将其设置为函数的属性:

def foo(bar):
    return foo.my_map.get(bar, defaultType)()
foo.my_map = {"rab": barType, "oof": fooType}

可调用类或闭包不够简单IMO。

答案 1 :(得分:3)

恕我直言,模块级常量没有任何问题。

请注意,根据PEP8,常量应该都是大写的,如下所示:

_MY_MAP = {"rab": barType, "oof": fooType}
def foo(bar):
    return _MY_MAP.get(bar,defaultType)()

标准库中的正则表达式模块使用此样式,许多已建立的第三方库也可以使用。如果您不相信,只需转到site-packages目录和grep:

egrep "^_?[A-Z]+ =" *

答案 2 :(得分:2)

你也可以使用闭包:

def make_foo():
    my_map = {"rab": barType, "oof": fooType}
    def foo(bar):
        return my_map.get(bar,defaultType)()
    return foo
foo = make_foo()

答案 3 :(得分:2)

制作尽可能独立的东西。您可以创建一个function object(又名仿函数)类,并为其提供__call__()方法一个classmethod(但可能不是):

class bazType(object): pass
class barType(object): pass
class fooType(object): pass

class Foo(object):
    _DEFAULT_TYPE = bazType
    _MY_MAP = {"rab": barType, "oof": fooType}

    def __call__(self, bar):
        return self._MY_MAP.get(bar, self._DEFAULT_TYPE)()

    @classmethod
    def foo(cls, bar):
        return cls._MY_MAP.get(bar, cls._DEFAULT_TYPE)()

# using classmethod
print Foo.foo("rab")

# using __call__ method
foo = Foo()
print foo("baz")

# alternative way to use classmethod
foo = Foo.foo
print foo("oof")

另一个替代方案是定义一个staticmethod,我不会说明,因为它与其他两个非常相似 - 但你得到了我希望的想法。