Константы, связанные с группами в Python - PullRequest
2 голосов
/ 06 мая 2020

Я ищу pythoni c способ определения нескольких связанных констант в одном файле, который будет использоваться в нескольких модулях. Я придумал несколько вариантов, но все они имеют недостатки.

Подход 1 - простые глобальные константы

# file resources/resource_ids.py

FOO_RESOURCE = 'foo'
BAR_RESOURCE = 'bar'
BAZ_RESOURCE = 'baz'
QUX_RESOURCE = 'qux'
# file runtime/bar_handler.py

from resources.resource_ids import BAR_RESOURCE

# ...

def my_code():
  value = get_resource(BAR_RESOURCE)

Это простой и универсальный вариант, но у него есть несколько недостатков:

  • _RESOURCE должно быть добавлено ко всем именам констант для обеспечения контекста
  • Проверка имени константы в IDE не отобразит другие значения констант

Подход 2 - enum

# file resources/resource_ids.py

from enum import Enum, unique

@unique
class ResourceIds(Enum):
  foo = 'foo'
  bar = 'bar'
  baz = 'baz'
  qux = 'qux'
# file runtime/bar_handler.py

from resources.resource_ids import ResourceIds

# ...

def my_code():
  value = get_resource(ResourceIds.bar.value)

Это решает проблемы первого подхода, но обратной стороной этого решения является необходимость использования .value для получения строкового представления (при условии, что нам нужно строковое значение, а не только согласованное значение перечисления). Невозможность добавления .value может привести к трудным для отладки проблемам во время выполнения.

Подход 3 - переменные класса

# file resources/resource_ids.py

class ResourceIds:
  foo = 'foo'
  bar = 'bar'
  baz = 'baz'
  qux = 'qux'
# file runtime/bar_handler.py

from resources.resource_ids import ResourceIds

# ...

def my_code():
  value = get_resource(ResourceIds.bar)

Это мой любимый подход, но он может быть неправильно истолкован - классы созданы для создания экземпляров. И хотя правильность кода не пострадает от использования экземпляра класса вместо самого класса, я бы хотел избежать этой траты.

Другой недостаток этого подхода в том, что значения на самом деле не постоянны. Любой клиент кода потенциально может их изменить.

Можно ли предотвратить создание экземпляра класса? Мне не хватает какого-то идиоматического c способа группировки тесно связанных констант?

Ответы [ 2 ]

4 голосов
/ 06 мая 2020

Используйте Enum и смешайте str:

@unique
class ResourceIds(str, Enum):
    foo = 'foo'
    bar = 'bar'
    baz = 'baz'
    qux = 'qux'

Тогда вам не нужно будет сравнивать с .value:

>>> ResourceIds.foo == 'foo'
True

И все равно получится информация об отладке:

>>> ResourceIds.foo
<ResourceIds.foo: 'foo'>

>>> list(ResourceIds.foo.__class__)
[
 <ResourceIds.foo: 'foo'>,
 <ResourceIds.bar: 'bar'>,
 <ResourceIds.baz: 'baz'>,
 <ResourceIds.qux: 'qux'>,
]
1 голос
/ 06 мая 2020

Несколько способов сделать это, мне не очень нравится использовать enum в python, потому что на самом деле они вам не нужны IMO;)

Вот как выходит большинство пакетов там сделайте это AFAIK:

# module_name.py
CSV = 'csv'
JSON = 'json'

def save(path, format=CSV):
    # do some thing with format
    ...

# other_module.py
import module_name

module_name.save('my_path', fomat=module_name.CSV)

другой способ выглядит следующим образом:

# module_name.py
options = {
    'csv': some_csv_processing_function
    'json': some_json_processing_function
}

def save(path, format=options.['csv']:
    # do some thing with format
    ...

# other_module.py
import module_name

module_name.save('my_path', fomat=module_name.options['csv'])

(вроде как несвязанный) Вы также можете создавать свои классы dicts:

class DictClass:
    def __init__(self, dict_class):
        self.__dict__ = dict_class

options = DictClass({
    'csv': some_csv_processing_function
    'json': some_json_processing_function
})

теперь вы можете получить доступ к своему словарю как к объекту, например: options.csv

...