In meiner endlosen Suche nach überkomplizierten einfachen Dingen erforsche ich die 'Pythonic'-Methode, um globale Konfigurationsvariablen innerhalb der typischen' config.py ' bereitzustellen , die in Python-Ei-Paketen zu finden ist.
Der traditionelle Weg (aah, good ol ' #define !) Ist wie folgt:
MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydb'
MYSQL_DATABASE_TABLES = ['tb_users', 'tb_groups']
Daher werden globale Variablen auf eine der folgenden Arten importiert:
from config import *
dbname = MYSQL_DATABASE
for table in MYSQL_DATABASE_TABLES:
print table
oder:
import config
dbname = config.MYSQL_DATABASE
assert(isinstance(config.MYSQL_PORT, int))
Es ist sinnvoll, kann aber manchmal etwas chaotisch sein, insbesondere wenn Sie versuchen, sich die Namen bestimmter Variablen zu merken. Außerdem kann die Bereitstellung eines Konfigurationsobjekts mit Variablen als Attributen flexibler sein. Also, eine Leitung von der Einnahme bpython config.py Datei, kam ich mit:
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)])
und eine 'config.py', die die Klasse importiert und wie folgt lautet:
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'
und wird folgendermaßen verwendet:
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))
Dies scheint eine lesbarere, aussagekräftigere und flexiblere Methode zum Speichern und Abrufen globaler Variablen in einem Paket zu sein.
Die lahmste Idee überhaupt? Was ist die beste Vorgehensweise, um mit diesen Situationen umzugehen? Wie können Sie globale Namen und Variablen in Ihrem Paket speichern und abrufen?
quelle
python-box
Antworten:
Ich habe das einmal gemacht. Letztendlich fand ich meine vereinfachte basicconfig.py für meine Bedürfnisse angemessen. Sie können einen Namespace mit anderen Objekten übergeben, auf die bei Bedarf verwiesen werden soll. Sie können auch zusätzliche Standardeinstellungen aus Ihrem Code übergeben. Außerdem werden die Attribut- und Zuordnungsstilsyntax demselben Konfigurationsobjekt zugeordnet.
quelle
basicconfig.py
Datei, auf die verwiesen wird, scheint auf github.com/kdart/pycopia/blob/master/core/pycopia/…ConfigHolder
mit einem Diktat von Konfigurationen bestehen, die ich festlegen und zwischen Modulen übergeben möchte?confit
und es unterstützt das Zusammenführen mehrerer Quellen. Es ist Teil eines neuen devtest.config- Moduls.Wie wäre es einfach mit den eingebauten Typen wie folgt:
Sie würden wie folgt auf die Werte zugreifen:
Wenn Sie bereit sind, das Potenzial für die Berechnung von Ausdrücken in Ihrem Konfigurationsbaum zu opfern, können Sie YAML verwenden und eine besser lesbare Konfigurationsdatei wie die folgende erhalten:
Verwenden Sie eine Bibliothek wie PyYAML , um die Konfigurationsdatei bequem zu analysieren und darauf zuzugreifen
quelle
Ich mag diese Lösung für kleine Anwendungen :
Und dann ist die Verwendung:
.. Sie sollten es mögen, weil:
App
,@property
, erfordert jedoch mehr variablen Verarbeitungscode pro Element und ist objektbasiert.--Edit-- : Für große Anwendungen ist es besser, Werte in einer YAML-Datei (dh Eigenschaften) zu speichern und diese als unveränderliche Daten einzulesen (dh die Antwort von blubb / ohaal ). Für kleine Anwendungen ist diese Lösung einfacher.
quelle
Wie wäre es mit Klassen?
quelle
Ähnlich wie bei Blubbs Antwort. Ich schlage vor, sie mit Lambda-Funktionen zu erstellen, um den Code zu reduzieren. So was:
Dies riecht jedoch so, als ob Sie eine Klasse machen möchten.
Oder, wie MarkM feststellte, Sie könnten verwenden
namedtuple
quelle
pass
ist ein unglücklicher Variablenname, da es sich auch um ein Schlüsselwort handelt.mkDict
Lambda in Betracht ziehen . Wenn wir unsere Klasse aufrufenUser
, werden Ihre "config" -Wörterbuchschlüssel so etwas wie initialisiert{'st3v3': User('password','blonde','Steve Booker')}
. Wenn sich Ihr "Benutzer" in eineruser
Variablen befindet, können Sie auf deren Eigenschaften alsuser.hair
usw. zugreifen .User = namedtuple('User', 'passwd hair name'); config = {'st3v3': User('password', 'blonde', 'Steve Booker')}
Eine kleine Variation von Huskys Idee, die ich benutze. Erstellen Sie eine Datei mit dem Namen "Globals" (oder was auch immer Sie möchten) und definieren Sie dann mehrere Klassen darin als solche:
Wenn Sie dann zwei Codedateien c1.py und c2.py haben, können beide oben stehen
Jetzt kann der gesamte Code auf Werte zugreifen und diese als solche festlegen:
Menschen vergessen, dass Klassen existieren, selbst wenn niemals ein Objekt instanziiert wird, das Mitglied dieser Klasse ist. Und Variablen in einer Klasse, denen nicht 'self' vorangestellt ist. werden für alle Instanzen der Klasse gemeinsam genutzt, auch wenn keine vorhanden sind. Sobald 'Debug' durch einen Code geändert wurde, sieht jeder andere Code die Änderung.
Wenn Sie es als gl importieren, können Sie über mehrere solcher Dateien und Variablen verfügen, mit denen Sie auf Codedateien, Funktionen usw. zugreifen und Werte festlegen können, ohne dass die Gefahr einer Namespace-Kollision besteht.
Dies fehlt ein Teil der cleveren Fehlerprüfung anderer Ansätze, ist aber einfach und leicht zu befolgen.
quelle
globals
, da es sich um eine integrierte Funktion handelt, die mit jedem Symbol im aktuellen globalen Bereich ein Diktat zurückgibt. Darüber hinaus empfiehlt PEP8 CamelCase (mit allen Großbuchstaben in Akronymen) für Klassen (dhDBInfo
) und Großbuchstaben mit Unterstrichen für die sogenannten Konstanten (dhDEBUG
).globals
. Der Autor sollte den Namen ändernSeien wir ehrlich, wir sollten wahrscheinlich in Betracht ziehen, eine von Python Software Foundation gepflegte Bibliothek zu verwenden:
https://docs.python.org/3/library/configparser.html
Konfigurationsbeispiel: (INI-Format, aber JSON verfügbar)
Codebeispiel:
Global zugänglich machen:
Nachteile:
quelle
Überprüfen Sie das IPython-Konfigurationssystem, das über Traitlets implementiert wurde, auf die Typdurchsetzung, die Sie manuell durchführen.
Hier ausschneiden und einfügen, um den SO-Richtlinien zu entsprechen, damit nicht nur Links gelöscht werden, wenn sich der Inhalt von Links im Laufe der Zeit ändert.
Dokumentation der Traitlets
Um dies zu erreichen, definieren sie grundsätzlich 3 Objektklassen und ihre Beziehungen zueinander:
1) Konfiguration - im Grunde ein ChainMap / Basic-Diktat mit einigen Verbesserungen für das Zusammenführen.
2) Konfigurierbar - Basisklasse zur Unterklasse aller Dinge, die Sie konfigurieren möchten.
3) Anwendung - Objekt, das instanziiert wird, um eine bestimmte Anwendungsfunktion auszuführen, oder Ihre Hauptanwendung für Einzweck-Software.
In ihren Worten:
quelle