Dalam pencarian tanpa akhir saya dalam hal-hal sederhana yang terlalu rumit, saya meneliti cara yang paling 'Pythonic' untuk menyediakan variabel konfigurasi global di dalam ' config.py ' khas yang ditemukan dalam paket telur Python.
Cara tradisional (aah, good ol ' #define !) Adalah sebagai berikut:
MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydb'
MYSQL_DATABASE_TABLES = ['tb_users', 'tb_groups']
Oleh karena itu, variabel global diimpor dengan salah satu cara berikut:
from config import *
dbname = MYSQL_DATABASE
for table in MYSQL_DATABASE_TABLES:
print table
atau:
import config
dbname = config.MYSQL_DATABASE
assert(isinstance(config.MYSQL_PORT, int))
Masuk akal, tetapi terkadang bisa sedikit berantakan, terutama saat Anda mencoba mengingat nama variabel tertentu. Selain itu, menyediakan objek 'konfigurasi' , dengan variabel sebagai atribut , mungkin lebih fleksibel. Jadi, mengambil petunjuk dari file bpython config.py, saya datang dengan:
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)])
dan 'config.py' yang mengimpor kelas dan berbunyi sebagai berikut:
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'
dan digunakan dengan cara ini:
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))
Yang tampaknya merupakan cara yang lebih mudah dibaca, ekspresif, dan fleksibel dalam menyimpan dan mengambil variabel global di dalam sebuah paket.
Ide terlama yang pernah ada? Apa praktik terbaik untuk menghadapi situasi ini? Apa cara Anda menyimpan dan mengambil nama dan variabel global di dalam paket Anda?