Trong nhiệm vụ bất tận của mình về những thứ đơn giản quá phức tạp, tôi đang nghiên cứu cách 'Pythonic' nhất để cung cấp các biến cấu hình toàn cục bên trong ' config.py ' điển hình được tìm thấy trong các gói trứng Python.
Cách truyền thống (aah, good ol ' #define !) Như sau:
MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydb'
MYSQL_DATABASE_TABLES = ['tb_users', 'tb_groups']
Do đó, các biến toàn cục được nhập theo một trong những cách sau:
from config import *
dbname = MYSQL_DATABASE
for table in MYSQL_DATABASE_TABLES:
print table
hoặc là:
import config
dbname = config.MYSQL_DATABASE
assert(isinstance(config.MYSQL_PORT, int))
Nó có ý nghĩa, nhưng đôi khi có thể hơi lộn xộn, đặc biệt là khi bạn đang cố nhớ tên của một số biến nhất định. Bên cạnh đó, việc cung cấp một đối tượng 'cấu hình' , với các biến là thuộc tính , có thể linh hoạt hơn. Vì vậy, dẫn đầu từ tệp bpython config.py, tôi đã nghĩ ra:
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)])
và 'config.py' nhập lớp và đọc như sau:
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'
và được sử dụng theo cách này:
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))
Đây có vẻ là một cách dễ đọc, biểu cảm và linh hoạt hơn để lưu trữ và tìm nạp các biến toàn cục bên trong một gói.
Ý tưởng tuyệt vời nhất bao giờ hết? Phương pháp tốt nhất để đối phó với những tình huống này là gì? Là những gì bạn cách lưu trữ và lấy tên toàn cầu và các biến bên trong gói của bạn?