La plupart des Pythonic façon globale les variables de configuration dans config.py?
Dans ma quête sans fin en plus de compliquer les choses simples, je suis la recherche de la plupart des "Pythonic de façon à assurer la configuration globale des variables à l'intérieur de la typique" config.py " qui se trouve en Python oeuf paquets.
De façon traditionnelle (aah, good ol' #define!) est comme suit:
MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydb'
MYSQL_DATABASE_TABLES = ['tb_users', 'tb_groups']
Par conséquent, les variables globales sont importés dans l'une des façons 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))
C'est logique, mais parfois peut être un peu salissant, surtout quand vous êtes à essayer de se rappeler les noms de certaines variables. En outre, prévoir un 'configuration' objet, avec variables comme des attributs, peut-être plus flexible. Alors, prenant une avance de bpython config.py fichier, je suis venu avec:
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" qu'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 façon:
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))
Qui semble plus lisible, de l'expressivité et de manière flexible de stockage et de récupération des variables globales à l'intérieur d'un package.
Lamest idée jamais? Quelle est la meilleure pratique pour faire face à ces situations? Qu'est-ce que votre moyen de stocker et de récupérer des noms globales et les variables à l'intérieur de votre colis?
- Vous avez déjà pris une décision d'ici qui peut ou peut ne pas être bon. La config en elle-même peuvent être stockés de différentes manières, comme JSON, XML, différentes grammaires pour *nixes et Windows et ainsi de suite. Fonction qui écrit le fichier de config ( un outil, un homme, quel contexte?) différentes grammaires serait peut-être préférable. Le plus souvent, il pourrait ne pas être une bonne idée de laisser le fichier de config être rédigée dans la même langue que vous utilisez pour votre programme, parce qu'il donne trop de pouvoir à l'utilisateur (ce qui pourrait être vous-même, mais vous-même ne pourriez pas vous souvenir de tout ce qui peut mal se passer quelques mois à l'avance).
- Souvent j'arrive à la fin de l'écriture d'un fichier de configuration JSON. Il peut être lu en python structures facilement et aussi être créé par un outil. Il semble avoir le plus de flexibilité et le coût sont certains de l'appareil qui peut être gênant pour l'utilisateur. Je n'ai jamais écrit un Oeuf, bien que. Peut-être que c'est la façon standard. Dans ce cas, il suffit de les ignorer mon commentaire ci-dessus.
- Vous pouvez utiliser "vars(auto)" au lieu de "self.__dict__.les touches()"
- Double Possible de What les bonnes pratiques à appliquer à l'aide d'un fichier de paramètres en Python? on répond "de Nombreuses voies sont possibles, et un bikeshed thread existe déjà. config.py est bon, à moins que vous vous souciez de la sécurité."
Vous devez vous connecter pour publier un commentaire.
Je l'ai fait une fois. En fin de compte j'ai trouvé mon simplifié basicconfig.py suffisant pour mes besoins. Vous pouvez passer dans un espace de noms avec d'autres objets pour lui de référence si vous avez besoin de. Vous pouvez également passer supplémentaires par défaut à partir de votre code. Il a également des cartes de l'attribut et de la cartographie de la syntaxe de style à la même configuration de l'objet.
basicconfig.py
fichier visé semble avoir été déplacé vers github.com/kdart/pycopia/blob/master/core/pycopia/...Que diriez-vous simplement à l'aide de types intégrés comme ceci:
Vous devez accéder à l'valeurs comme suit:
Si vous êtes prêt à sacrifier le potentiel de calculer des expressions à l'intérieur de votre arbre de config, vous pouvez utiliser YAML et jusqu'à la fin avec plus lisible fichier de config comme ceci:
et utiliser une bibliothèque comme PyYAML à conventiently analyser et d'accéder au fichier de config
Similaire à blubb de réponse. Je suggère de les construire avec les lambda fonctions pour réduire code. Comme ceci:
Ce n'est l'odeur, vous pouvez faire une classe, si.
Ou, comme MarkM noté, vous pouvez utiliser
namedtuple
pass
est regrettable nom de la variable, puisque c'est aussi un mot-clé.mkDict
lambda. Si nous appelons notre classeUser
, votre "config" les clés de dictionnaire serait initialisé quelque chose comme{'st3v3': User('password','blonde','Steve Booker')}
. Lorsque votre "user", c'est unuser
variable, vous pouvez ensuite accéder à ses propriétés d'user.hair
, etc.User = namedtuple('User', 'passwd hair name'); config = {'st3v3': User('password', 'blonde', 'Steve Booker')}
J'aime cette solution pour les petites applications:
Et puis d'usage:
.. vous devriez l'aime parce que:
App
,@property
, mais qui nécessite de plus en plus variable de manipulation de code par article et est basé sur l'objet.--Edit--:
Pour les grandes applications, stocker des valeurs dans un fichier YAML (c'est à dire les propriétés de fichier et de la lecture que comme des données immuables, c'est une meilleure approche (c'est à dire blubb/ohaal réponse).
Pour les petites applications, cette solution ci-dessus est plus simple.
Comment sur l'utilisation de classes?
Une petite variation sur Husky idée que j'utilise. Rendre un fichier appelé 'globals' (ou ce que vous voulez), puis de définir plusieurs classes en tant que tel:
Alors, si vous avez deux fichiers de code c1.py et c2.py les deux peuvent avoir en haut
Maintenant tous les code d'accès et peut définir des valeurs, en tant que tel:
Les gens oublient classes existent, même si aucun objet n'est jamais instanciée qui est un membre de cette classe. Et les variables dans une classe qui ne sont pas précédés par "auto." sont partagés entre toutes les instances de la classe, même s'il n'en existe aucune. Une fois 'debug' est changé par du code, tous les autres codes voit le changement.
Par l'importer en tant que gl, vous pouvez avoir plusieurs de ces fichiers et les variables qui vous permet d'accéder et de définir les valeurs dans les fichiers de code, des fonctions, etc., mais avec pas de danger de collision de noms.
Cela manque un peu de de la malin de vérification des erreurs, d'autres approches, mais il est simple et facile à suivre.
globals
, puisque c'est une fonction intégrée qui renvoie une dict à chaque symbole dans le courant de portée mondiale. En outre, PEP8 recommande CamelCase (avec toutes les capitales dans les acronymes) pour les classes (c'est à direDBInfo
) et en majuscules avec des traits de soulignement pour la soi-disant constantes (c'est à direDEBUG
).s'il vous plaît vérifier la IPython de configuration système, mis en œuvre par traitlets pour le type d'application que vous faites manuellement.
Coupé et collé ici à respecter AFIN de lignes directrices pour pas juste de laisser tomber liens que le contenu des liens changements au fil du temps.
traitlets documentation
Pour réaliser cela, ils se sont contentés de définir 3 classes d'objets et leurs relations les uns aux autres:
1) Configuration - fondamentalement, un ChainMap /base dict avec quelques améliorations pour la fusion.
2) Configurable - classe de base classe de toutes les choses que vous auriez souhaitez configurer.
3) Application - objet est instancié à l'exécution d'une fonction de l'application, ou votre application principale pour but unique de logiciel.
Dans leurs mots: