Większość Pythonicznych sposobów dostarczania globalnych zmiennych konfiguracyjnych w config.py?
W moim niekończącym się poszukiwaniu skomplikowanych prostych rzeczy, badam najbardziej "Pythoniczny" sposób dostarczenia globalnych zmiennych konfiguracyjnych wewnątrz typowego " config.py ' Znalezione w pakietach Python egg.
Tradycyjny sposób (aah, good ol ' # define !) jest następująca:
MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydb'
MYSQL_DATABASE_TABLES = ['tb_users', 'tb_groups']
Dlatego zmienne globalne są importowane w jeden z następujących sposobów:
from config import *
dbname = MYSQL_DATABASE
for table in MYSQL_DATABASE_TABLES:
print table
Lub:
import config
dbname = config.MYSQL_DATABASE
assert(isinstance(config.MYSQL_PORT, int))
To ma sens, ale czasami może być trochę bałagan, zwłaszcza gdy próbujesz zapamiętać nazwy pewnych zmiennych. Poza tym, zapewnienie ' configuration ' obiektu , ze zmiennymi jako atrybutami , może być bardziej elastyczne. / Align = "center" bgcolor = "# e0ffe0 " / cesarz Chin / / align = center / config.py plik, wymyśliłem:
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)])
I "config.py" importuje klasę i brzmi następująco:
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'
I jest używany w ten sposób:
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))
Który wydaje się bardziej czytelny, ekspresyjny i elastyczny sposób przechowywania i pobierania zmiennych globalnych wewnątrz paczka.
Lamest idea ever? Jaka jest najlepsza praktyka radzenia sobie z takimi sytuacjami? Jaki jest Twój sposób przechowywania i pobierania globalnych nazw i zmiennych wewnątrz Twojego pakietu?7 answers
Zrobiłem to raz. Ostatecznie znalazłem mój uproszczony basicconfig.py adekwatne do moich potrzeb. Możesz przekazać w przestrzeni nazw z innymi obiektami, aby odwoływać się do niej, jeśli zajdzie taka potrzeba. Możesz również przekazać dodatkowe wartości domyślne z kodu. Mapuje również atrybut i składnię stylu mapowania do tego samego obiektu konfiguracyjnego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-12 20:35:48
Może po prostu użyj wbudowanych typów, takich jak ten:
config = {
"mysql": {
"user": "root",
"pass": "secret",
"tables": {
"users": "tb_users"
}
# etc
}
}
Możesz uzyskać dostęp do wartości w następujący sposób:
config["mysql"]["tables"]["users"]
Jeśli chcesz poświęcić potencjał do obliczania wyrażeń wewnątrz drzewa konfiguracyjnego, możesz użyć YAML i skończyć z bardziej czytelnym plikiem konfiguracyjnym, takim jak:
mysql:
- user: root
- pass: secret
- tables:
- users: tb_users
I użyj biblioteki podobnej do PyYAML , aby conventiently parsować i uzyskać dostęp do pliku konfiguracyjnego
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-13 20:41:54
Podobne do odpowiedzi blubba. Proponuję zbudować je za pomocą funkcji lambda, aby zredukować kod. Tak:
User = lambda passwd, hair, name: {'password':passwd, 'hair':hair, 'name':name}
#Col Username Password Hair Color Real Name
config = {'st3v3' : User('password', 'blonde', 'Steve Booker'),
'blubb' : User('12345678', 'black', 'Bubb Ohaal'),
'suprM' : User('kryptonite', 'black', 'Clark Kent'),
#...
}
#...
config['st3v3']['password'] #> password
config['blubb']['hair'] #> black
To śmierdzi, jakbyś chciał zrobić klasę.
Lub, jak zauważył MarkM, możesz użyć namedtuple
from collections import namedtuple
#...
User = namedtuple('User', ['password', 'hair', 'name']}
#Col Username Password Hair Color Real Name
config = {'st3v3' : User('password', 'blonde', 'Steve Booker'),
'blubb' : User('12345678', 'black', 'Bubb Ohaal'),
'suprM' : User('kryptonite', 'black', 'Clark Kent'),
#...
}
#...
config['st3v3'].password #> passwd
config['blubb'].hair #> black
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 17:37:15
Podoba mi się to rozwiązanie do małych aplikacji :
class App:
__conf = {
"username": "",
"password": "",
"MYSQL_PORT": 3306,
"MYSQL_DATABASE": 'mydb',
"MYSQL_DATABASE_TABLES": ['tb_users', 'tb_groups']
}
__setters = ["username", "password"]
@staticmethod
def config(name):
return App.__conf[name]
@staticmethod
def set(name, value):
if name in App.__setters:
App.__conf[name] = value
else:
raise NameError("Name not accepted in set() method")
I wtedy użycie to:
if __name__ == "__main__":
# from config import App
App.config("MYSQL_PORT") # return 3306
App.set("username", "hi") # set new username value
App.config("username") # return "hi"
App.set("MYSQL_PORT", "abc") # this raises NameError
.. powinno ci się spodobać, ponieważ:
- używa zmiennych klasy (nie jest wymagany żaden obiekt/ singleton),
- używa wbudowanych typów i wygląda jak (jest) wywołanie metody na
App
, - ma kontrolę nad indywidualną konfiguracją niezmienność, mutable globals are the worst kind of globals .
- Promuje konwencjonalny i dobrze nazwany dostęp / czytelność w kodzie źródłowym
- jest prostą klasą , ale wymusza dostęp strukturalny , alternatywą jest użycie
@property
, ale wymaga to większej liczby zmiennych obsługujących kod na element i jest oparte na obiektach. - wymaga minimalnych zmian , aby dodać nowe elementy konfiguracji i ustawić jego zmienność.
--Edit -- : Dla dużych aplikacji, Zapisywanie wartości w YAML (tj. właściwości) plik i odczyt, że w jako niezmiennych danych jest lepszym podejściem (tj. blubb/ohaal ' s answer ). W przypadku małych aplikacji powyższe rozwiązanie jest prostsze.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-06 07:46:23
Jak o użyciu klas?
# config.py
class MYSQL:
PORT = 3306
DATABASE = 'mydb'
DATABASE_TABLES = ['tb_users', 'tb_groups']
# main.py
from config import MYSQL
print(MYSQL.PORT) # 3306
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-01 22:41:51
Mała wariacja na temat pomysłu Husky ' ego, którego używam. Utwórz plik o nazwie 'globals' (lub cokolwiek chcesz), a następnie zdefiniuj wiele klas w nim, jako takie:
#globals.py
class dbinfo : # for database globals
username = 'abcd'
password = 'xyz'
class runtime :
debug = False
output = 'stdio'
Wtedy, jeśli masz dwa pliki kodu c1.py oraz c2.py, oba mogą mieć na górze
import globals as gl
Teraz cały kod może mieć dostęp i ustawiać wartości, jako takie:
gl.runtime.debug = False
print(gl.dbinfo.username)
Ludzie zapominają, że klasy istnieją, nawet jeśli nie powstał żaden obiekt, który jest członkiem tej klasy. Oraz zmienne w klasie, które nie są poprzedzone przez ' self."are współdzielone przez wszystkie instancje klasy, nawet jeśli ich nie ma. Gdy' debug ' zostanie zmieniony przez dowolny kod, wszystkie inne kody widzą tę zmianę.
Importując go jako gl, możesz mieć wiele takich plików i zmiennych, które umożliwiają dostęp i ustawianie wartości w plikach kodu, funkcjach itp., ale bez niebezpieczeństwa kolizji przestrzeni nazw.
Brakuje tu sprytnego sprawdzania błędów innych podejść, ale jest to proste i łatwe do naśladowania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-13 00:57:15
Zapoznaj się z systemem konfiguracji IPython, zaimplementowanym za pomocą traitletów dla wymuszania typów, które wykonujesz ręcznie.
Wytnij i wklej tutaj, aby zachować zgodność z wytycznymi dotyczącymi nie tylko porzucania linków, ponieważ zawartość linków zmienia się w czasie.
Oto główne wymagania, które chcieliśmy, aby nasz system konfiguracyjny miał:
Wsparcie dla hierarchicznych informacji konfiguracyjnych.
Full integracja z parserami opcji wiersza poleceń. Często chcesz przeczytać plik konfiguracyjny, ale następnie nadpisać niektóre wartości opcjami wiersza poleceń. Nasz system konfiguracji automatyzuje ten proces i pozwala każdej opcji wiersza poleceń, aby być połączone z określonym atrybutem w hierarchii konfiguracji, który będzie nadpisany.
Pliki konfiguracyjne, które same są poprawnym kodem Pythona. To osiąga wiele rzeczy. Po pierwsze, staje się możliwe, aby umieścić logikę w swoim pliki konfiguracyjne, które ustawiają atrybuty na podstawie systemu operacyjnego, konfiguracji sieci, wersji Pythona itp. Po drugie, Python ma bardzo prostą składnię umożliwiającą dostęp do hierarchicznych struktur danych, a mianowicie regularny dostęp do atrybutów (Foo.Bar.Bam.name). po trzecie, Korzystanie z Pythona ułatwia użytkownikom importowanie atrybutów konfiguracji z jednego pliku konfiguracyjnego do drugiego. Po czwarte, mimo że Python jest pisany dynamicznie, ma typy, które można sprawdzać w czasie wykonywania. Tak więc, 1 w pliku konfiguracyjnym jest liczba całkowita "1", podczas gdy " 1 " jest ciągiem znaków.
W pełni zautomatyzowana metoda pobierania informacji o konfiguracji do klas, które jej potrzebują w czasie wykonywania. Pisanie kodu, który przechodzi przez hierarchię konfiguracji, aby wyodrębnić konkretny atrybut, jest bolesne. Gdy masz złożone informacje konfiguracyjne z setkami atrybutów, to sprawia, że chcesz płakać.
Sprawdzanie i Walidacja typu, które nie wymaga statycznie określenia całej hierarchii konfiguracji przed runtime. Python jest bardzo dynamicznym językiem i nie zawsze wiesz wszystko, co trzeba skonfigurować, gdy program się uruchamia.
Aby to osiągnąć, zasadniczo definiują 3 klasy obiektów i ich relacje ze sobą:
1) Konfiguracja-zasadniczo ChainMap / basic dict z pewnymi ulepszeniami do scalania.
2) konfigurowalny - klasa bazowa do podklasowania wszystkich rzeczy, które chcesz skonfigurować.
3) Aplikacja-obiekt, który jest instancją do wykonania konkretna funkcja aplikacji lub główna aplikacja dla oprogramowania do jednego celu.
W ich słowach:
Application: Application
Aplikacja jest procesem, który wykonuje określone zadanie. Najbardziej oczywistą aplikacją jest program wiersza poleceń ipython. Każda aplikacja odczytuje jeden lub więcej plików konfiguracyjnych i pojedynczy zestaw opcji wiersza poleceń, a następnie tworzy główny obiekt konfiguracyjny dla aplikacji. Ten obiekt konfiguracyjny jest następnie przekazywany do konfigurowalnych obiektów, które aplikacja wytworzy. Te konfigurowalne obiekty implementują rzeczywistą logikę aplikacji i wiedzą, jak skonfigurować się w danym obiekcie konfiguracyjnym.
Aplikacje zawsze mają atrybut log, który jest skonfigurowanym Loggerem. Umożliwia to scentralizowaną konfigurację logowania dla poszczególnych aplikacji. Konfigurowalny: Konfigurowalny
Konfigurowalny jest zwykłą klasą Pythona, która służy jako klasa podstawowa dla wszystkich klas Głównych w podanie. Konfigurowalna klasa podstawowa jest lekka i robi tylko jedną rzecz.
Ten konfigurowalny jest podklasą HasTraits, która wie, jak skonfigurować się. Cechy poziomu klasy z metadanymi config = True stają się wartościami, które można skonfigurować z linii poleceń i plików konfiguracyjnych.
Programiści tworzą konfigurowalne podklasy, które implementują całą logikę w aplikacji. Każda z tych podklas ma swoje własne informacje konfiguracyjne, które sterują sposób tworzenia instancji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-14 15:55:11