Самый питонический способ предоставить глобальные переменные конфигурации в config.py ?

В моих бесконечных поисках чрезмерного усложнения простых вещей,Я исследую наиболее «питонический» способ предоставить глобальные конфигурационные переменные внутри типичного « config.py », который можно найти в пакетах яиц Python.

Традиционный способ (ах, старый добрый #define !) Выглядит следующим образом:

MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydb'
MYSQL_DATABASE_TABLES = ['tb_users', 'tb_groups']

Следовательно, глобальные переменные импортируются одним из следующих способов:

from config import *
dbname = MYSQL_DATABASE
for table in MYSQL_DATABASE_TABLES:
    print table

или:

import config
dbname = config.MYSQL_DATABASE
assert(isinstance(config.MYSQL_PORT, int))

It имеет смысл, но иногда может быть немного запутанным, особенно когда вы пытаетесь запомнить имена определенных переменных. Кроме того, предоставление объекта «конфигурации» с переменными в качестве атрибутов может быть более гибким. Итак, взяв пример с файла bpython config.py, я придумал:

class Struct(object):

    def __init__(self, *args):
        self.__header__ = str(args[0]) if args else None

    def __repr__(self):
        if self.__header__ is None:
             return super(Struct, self).__repr__()
        return self.__header__

    def next(self):
        """ Fake iteration functionality.
        """
        raise StopIteration

    def __iter__(self):
        """ Fake iteration functionality.
        We skip magic attribues and Structs, and return the rest.
        """
        ks = self.__dict__.keys()
        for k in ks:
            if not k.startswith('__') and not isinstance(k, Struct):
                yield getattr(self, k)

    def __len__(self):
        """ Don't count magic attributes or Structs.
        """
        ks = self.__dict__.keys()
        return len([k for k in ks if not k.startswith('__')\
                    and not isinstance(k, Struct)])

и config.py, который импортирует класс и читается следующим образом:

from _config import Struct as Section

mysql = Section("MySQL specific configuration")
mysql.user = 'root'
mysql.pass = 'secret'
mysql.host = 'localhost'
mysql.port = 3306
mysql.database = 'mydb'

mysql.tables = Section("Tables for 'mydb'")
mysql.tables.users = 'tb_users'
mysql.tables.groups =  'tb_groups'

и используется в этом путь:

from sqlalchemy import MetaData, Table
import config as CONFIG

assert(isinstance(CONFIG.mysql.port, int))

mdata = MetaData(
    "mysql://%s:%s@%s:%d/%s" % (
         CONFIG.mysql.user,
         CONFIG.mysql.pass,
         CONFIG.mysql.host,
         CONFIG.mysql.port,
         CONFIG.mysql.database,
     )
)

tables = []
for name in CONFIG.mysql.tables:
    tables.append(Table(name, mdata, autoload=True))

Что кажется более читаемым, выразительным и гибким способом хранения и выборки глобальных переменных внутри пакета.

Самая отстойная идея? Как лучше всего справляться с такими ситуациями? Как ваш способ хранения и извлечения глобальных имен и переменных внутри вашего пакета?

81
задан Rigel Di Scala 1 June 2011 в 12:09
поделиться

1 ответ

Давайте будем честны, мы должны, вероятно, рассмотреть использование Основа программного обеспечения Python сохраняемая библиотека:

https://docs.python.org/3/library/configparser.html

пример Конфигурации: (ini формат, но JSON доступный)

[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes

[bitbucket.org]
User = hg

[topsecret.server.com]
Port = 50022
ForwardX11 = no

Пример кода:

>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.read('example.ini')
>>> config['DEFAULT']['Compression']
'yes'
>>> config['DEFAULT'].getboolean('MyCompression', fallback=True) # get_or_else

Создание его глобально доступный:

import configpaser
class App:
 __conf = None

 @staticmethod
 def config():
  if App.__conf is None:  # Read only once, lazy.
   App.__conf = configparser.ConfigParser()
   App.__conf.read('example.ini')
  return App.__conf

if __name__ == '__main__':
 App.config()['DEFAULT']['MYSQL_PORT']
 # or, better:
 App.config().get(section='DEFAULT', option='MYSQL_PORT', fallback=3306)
 ....

Оборотные стороны:

  • Неконтролируемый глобальный изменяемый состояние.
0
ответ дан 24 November 2019 в 09:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: