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?
la source
python-box
, voir cette réponseRéponses:
Je l'ai fait une fois. En fin de compte, j'ai trouvé mon basicconfig.py simplifié adapté à mes besoins. Vous pouvez transmettre un espace de noms avec d'autres objets pour qu'il fasse référence si vous en avez besoin. Vous pouvez également transmettre des valeurs par défaut supplémentaires à partir de votre code. Il mappe également la syntaxe d'attribut et de style de mappage sur le même objet de configuration.
la source
basicconfig.py
fichier mentionné semble avoir été déplacé vers github.com/kdart/pycopia/blob/master/core/pycopia/…ConfigHolder
avec un dict de configurations que je voudrais définir et passer entre les modules?confit
et il prend en charge la fusion de plusieurs sources. Cela fait partie d'un nouveau module devtest.config .Que diriez-vous d'utiliser simplement les types intégrés comme celui-ci:
Vous accéderiez aux valeurs comme suit:
Si vous êtes prêt à sacrifier le potentiel de calcul d'expressions dans votre arbre de configuration, vous pouvez utiliser YAML et vous retrouver avec un fichier de configuration plus lisible comme celui-ci:
et utilisez une bibliothèque comme PyYAML pour analyser et accéder de manière conventionnelle au fichier de configuration
la source
J'aime cette solution pour les petites applications :
Et puis l'utilisation est:
.. vous devriez l'aimer parce que:
App
,@property
, mais cela nécessite plus de code de gestion variable par élément et est basé sur les objets.--Edit-- : Pour les applications volumineuses, stocker les valeurs dans un fichier YAML (c'est-à-dire les propriétés) et le lire comme des données immuables est une meilleure approche (c'est -à-dire la réponse de blubb / ohaal ). Pour les petites applications, cette solution ci-dessus est plus simple.
la source
Que diriez-vous d'utiliser des classes?
la source
Similaire à la réponse de blubb. Je suggère de les construire avec des fonctions lambda pour réduire le code. Comme ça:
Cela sent cependant que vous voudrez peut-être faire un cours.
Ou, comme MarkM l'a noté, vous pouvez utiliser
namedtuple
la source
pass
est un nom de variable malheureux, car c'est aussi un mot-clé.mkDict
méthode lambda. Si nous appelons notre classeUser
, vos clés de dictionnaire "config" seraient initialisées quelque chose comme{'st3v3': User('password','blonde','Steve Booker')}
. Lorsque votre "utilisateur" est dans uneuser
variable, vous pouvez alors accéder à ses propriétés commeuser.hair
, etc.User = namedtuple('User', 'passwd hair name'); config = {'st3v3': User('password', 'blonde', 'Steve Booker')}
Une petite variation sur l'idée de Husky que j'utilise. Créez un fichier appelé 'globals' (ou ce que vous voulez), puis définissez-y plusieurs classes, en tant que telles:
Ensuite, si vous avez deux fichiers de code c1.py et c2.py, les deux peuvent avoir en haut
Maintenant, tout le code peut accéder et définir des valeurs, en tant que telles:
Les gens oublient que les classes existent, même si aucun objet n'est jamais instancié qui soit membre de cette classe. Et les variables d'une classe qui ne sont pas précédées de «self». sont partagées entre toutes les instances de la classe, même s'il n'y en a pas. Une fois que 'debug' est modifié par n'importe quel code, tous les autres codes voient le changement.
En l'important en tant que gl, vous pouvez avoir plusieurs fichiers et variables de ce type qui vous permettent d'accéder et de définir des valeurs dans les fichiers de code, les fonctions, etc., mais sans risque de collision d'espace de noms.
Cela manque une partie de la vérification intelligente des erreurs des autres approches, mais est simple et facile à suivre.
la source
globals
, car c'est une fonction intégrée qui renvoie un dict avec chaque symbole dans la portée globale actuelle. De plus, PEP8 recommande CamelCase (avec toutes les majuscules dans les acronymes) pour les classes (ieDBInfo
) et les majuscules avec des traits de soulignement pour les soi-disant constantes (ieDEBUG
).globals
, l'auteur devrait changer le nomSoyons honnêtes, nous devrions probablement envisager d'utiliser une bibliothèque maintenue par Python Software Foundation :
https://docs.python.org/3/library/configparser.html
Exemple de configuration: (format ini, mais JSON disponible)
Exemple de code:
Rendre accessible à l'échelle mondiale:
Inconvénients:
la source
veuillez consulter le système de configuration IPython, implémenté via des traitlets pour l'application de type que vous effectuez manuellement.
Couper et coller ici pour se conformer aux directives SO pour non seulement supprimer des liens car le contenu des liens change au fil du temps.
documentation traitlets
Pour y parvenir, ils définissent essentiellement 3 classes d'objets et leurs relations entre elles:
1) Configuration - essentiellement un ChainMap / dict de base avec quelques améliorations pour la fusion.
2) Configurable - classe de base pour sous-classer toutes les choses que vous souhaitez configurer.
3) Application - objet qui est instancié pour exécuter une fonction d'application spécifique, ou votre application principale pour un logiciel à usage unique.
Dans leurs mots:
la source