В python, как хранить константы для функций только один раз?

Некоторым функциям нужны "постоянные" значения (т.е. не предназначенные для последующего переопределения), которые не подлежат параметризации. Хотя аргументы по умолчанию хранятся только один раз для каждой функции, некоторые просто не очень смысл быть поставлен как параметры (т.е. быть частью signature). Для (не очень полезного) примера:

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

Он потратил время CPU и пространство памяти, чтобы переопределить такую ​​константу для каждого вызова. Некоторые другие способы хранения таких констант, как глобальные уровни уровня модуля, или сделать функцию вызываемым классом, но могут быть и другие способы, возможно?

Когда вы выполняете глобальный путь на уровне модуля, я префикс my (подразумевается как a) постоянная переменная с "_", чтобы показать, что это не для кого-либо. Тем не менее, я чувствую, что пространство имен модулей слегка "загрязнено", не говоря уже о стыд использования что-то как обескураженные как глобальные:

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

Или преобразовать его в класс. Я делаю __call__ a classmethod, чтобы избежать необходимости создания экземпляров:

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

Являются ли эти решения достаточно питонными?

Есть ли другие способы сделать это?

Действительно ли практика использования таких "констант"?

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

Ответ 1

Задайте его как атрибут функции:

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

 

Вызываемый класс или замыкание недостаточно просты ИМО.

Ответ 2

ИМХО, нет ничего плохого в константах уровня модуля.

Обратите внимание, что в соответствии с PEP8 константы должны быть в верхнем регистре, например:

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

Модуль регулярных выражений в стандартной библиотеке использует этот стиль, а также многие известные сторонние библиотеки. Если вы не уверены, просто перейдите в каталог site-packages и grep:

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

Ответ 3

Вы также можете использовать блокировки:

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

Ответ 4

Сделать нечто настолько самодостаточным, насколько это возможно. Вы можете создать класс object object (aka functor) и дать ему метод __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")

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