Dans ma quête sans fin de complication excessive de choses simples, je recherche le moyen le plus `` pythonique '' de fournir des variables de configuration globales à l'intérieur du typique `` config.py '' trouvé dans les packages d'oeufs Python.
La manière traditionnelle (aah, bon vieux #define !) Est la suivante:
MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydb'
MYSQL_DATABASE_TABLES = ['tb_users', 'tb_groups']
Par conséquent, les variables globales sont importées de l'une des manières suivantes:
from config import *
dbname = MYSQL_DATABASE
for table in MYSQL_DATABASE_TABLES:
print table
ou:
import config
dbname = config.MYSQL_DATABASE
assert(isinstance(config.MYSQL_PORT, int))
Cela a du sens, mais peut parfois être un peu compliqué, surtout lorsque vous essayez de vous souvenir des noms de certaines variables. En outre, fournir un objet de «configuration» , avec des variables comme attributs , pourrait être plus flexible. Donc, en prenant l'exemple du fichier bpython config.py, j'ai trouvé:
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)])
et un 'config.py' qui importe la classe et se lit comme suit:
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'
et est utilisé de cette manière:
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))
Ce qui semble être une manière plus lisible, expressive et flexible de stocker et de récupérer des variables globales dans un package.
La moindre idée jamais? Quelle est la meilleure pratique pour faire face à ces situations? Quelle est votre façon de stocker et de récupérer les noms globaux et les variables dans votre package?