Rig*_*ala 81 python config egg global-variables
在我过于复杂的简单内容的无尽追求中,我正在研究最"Pythonic"的方式,在Python egg包中的典型' config.py '中提供全局配置变量.
传统方式(aah,good ol'#define!)如下:
MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydb'
MYSQL_DATABASE_TABLES = ['tb_users', 'tb_groups']
Run Code Online (Sandbox Code Playgroud)
因此,全局变量以下列方式之一导入:
from config import *
dbname = MYSQL_DATABASE
for table in MYSQL_DATABASE_TABLES:
print table
Run Code Online (Sandbox Code Playgroud)
要么:
import config
dbname = config.MYSQL_DATABASE
assert(isinstance(config.MYSQL_PORT, int))
Run Code Online (Sandbox Code Playgroud)
这是有道理的,但有时可能有点混乱,特别是当你试图记住某些变量的名称时.此外,提供了一个"配置"对象,用变量的属性,可能会更加灵活.所以,从bpython config.py文件中取得领先,我想出了:
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)])
Run Code Online (Sandbox Code Playgroud)
和'config.py'导入类并读取如下:
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'
Run Code Online (Sandbox Code Playgroud)
并以这种方式使用:
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))
Run Code Online (Sandbox Code Playgroud)
这似乎是一种在包中存储和获取全局变量的更具可读性,表达性和灵活性的方法.
Lamest的想法永远?应对这些情况的最佳做法是什么?您在包中存储和获取全局名称和变量的方式是什么?
blu*_*ubb 50
如何使用这样的内置类型:
config = {
"mysql": {
"user": "root",
"pass": "secret",
"tables": {
"users": "tb_users"
}
# etc
}
}
Run Code Online (Sandbox Code Playgroud)
您可以按如下方式访问这些值:
config["mysql"]["tables"]["users"]
Run Code Online (Sandbox Code Playgroud)
如果您愿意牺牲在配置树中计算表达式的潜力,您可以使用YAML并最终得到一个更易读的配置文件,如下所示:
mysql:
- user: root
- pass: secret
- tables:
- users: tb_users
Run Code Online (Sandbox Code Playgroud)
并使用像PyYAML这样的库来方便地解析和访问配置文件
pds*_*pds 11
我喜欢这个小应用程序的解决方案:
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")
Run Code Online (Sandbox Code Playgroud)
然后用法是:
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
Run Code Online (Sandbox Code Playgroud)
..你应该喜欢它因为:
App
,@property
,但这需要每个项目更多的变量处理代码,并且是基于对象的.--Edit--:对于大型应用程序,将值存储在YAML(即属性)文件中并将其作为不可变数据读取是一种更好的方法(即blubb/ohaal的答案).对于小型应用,上述解决方案更简单.
老实说,我们可能应该考虑使用Python 软件基金会维护的库:
https://docs.python.org/3/library/configparser.html
配置示例:(ini 格式,但 JSON 可用)
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
Run Code Online (Sandbox Code Playgroud)
代码示例:
>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.read('example.ini')
>>> config['DEFAULT']['Compression']
'yes'
>>> config['DEFAULT'].getboolean('MyCompression', fallback=True) # get_or_else
Run Code Online (Sandbox Code Playgroud)
使其全球可访问:
import configpaser
class App:
__conf = None
@staticmethod
def config():
if App.__conf is None: # Read only once, lazy.
App.__conf = configparser.ConfigParser()
App.__conf.read('example.ini')
return App.__conf
if __name__ == '__main__':
App.config()['DEFAULT']['MYSQL_PORT']
# or, better:
App.config().get(section='DEFAULT', option='MYSQL_PORT', fallback=3306)
....
Run Code Online (Sandbox Code Playgroud)
缺点:
类似于blubb的回答.我建议使用lambda函数构建它们以减少代码.像这样:
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
Run Code Online (Sandbox Code Playgroud)
不过,这确实就像你想要上课一样.
或者,正如MarkM所说,你可以使用 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
Run Code Online (Sandbox Code Playgroud)
如何使用课程?
# config.py
class MYSQL:
PORT = 3306
DATABASE = 'mydb'
DATABASE_TABLES = ['tb_users', 'tb_groups']
# main.py
from config import MYSQL
print(MYSQL.PORT) # 3306
Run Code Online (Sandbox Code Playgroud)
我使用的赫斯基想法略有不同。创建一个名为“ globals”(或您喜欢的文件)的文件,然后在其中定义多个类,如下所示:
#globals.py
class dbinfo : # for database globals
username = 'abcd'
password = 'xyz'
class runtime :
debug = False
output = 'stdio'
Run Code Online (Sandbox Code Playgroud)
然后,如果您有两个代码文件c1.py和c2.py,则两者都可以位于顶部
import globals as gl
Run Code Online (Sandbox Code Playgroud)
现在,所有代码都可以访问和设置值,如下所示:
gl.runtime.debug = False
print(gl.dbinfo.username)
Run Code Online (Sandbox Code Playgroud)
人们会忘记存在类,即使没有实例化该类成员的对象也是如此。并且类中没有“自我”的变量。在类的所有实例之间共享,即使没有实例也是如此。一旦任何代码更改了“调试”,所有其他代码都将看到更改。
通过将其导入为gl,您可以拥有多个这样的文件和变量,使您可以跨代码文件,函数等访问和设置值,但不会发生名称空间冲突的危险。
这缺少其他方法的一些巧妙的错误检查,但是简单易行。
我做过一次.最终我发现我的简化basicconfig.py足以满足我的需求.如果需要,可以使用其他对象传入名称空间以供引用.您还可以从代码中传递其他默认值.它还将属性和映射样式语法映射到同一配置对象.
小智 5
请查看 IPython 配置系统,该系统通过 Traitlet 实现,以实现您手动执行的类型强制。
\n\n剪切并粘贴到此处是为了遵守 SO 准则,即当链接内容随时间变化时,不只是删除链接。
\n\n\n\n\n\n\n以下是我们希望配置系统具有的主要要求:
\n\n支持分层配置信息。
\n\n与命令行选项解析器完全集成。通常,您想要读取配置文件,然后使用命令行选项覆盖某些值。我们的配置系统自动执行此过程,并允许每个命令行选项链接到它将覆盖的配置层次结构中的特定属性。
\n\n配置文件本身就是有效的 Python 代码。这可以完成很多事情。首先,可以将逻辑放入配置文件中,根据操作系统、网络设置、Python 版本等设置属性。其次,Python 有一个超级简单的语法来访问分层数据结构,即常规属性访问 (Foo.酒吧.Bam.名称)。第三,使用Python可以让用户轻松地将配置属性从一个配置文件导入到另一个配置文件中。\n 第四,尽管 Python 是动态类型的,但它确实具有可以在运行时检查的类型。因此,配置文件中的 1 是整数 \xe2\x80\x981\xe2\x80\x99,而 \'1\' 是字符串。
\n\n一种完全自动化的方法,用于将配置信息获取到运行时需要它的类。编写遍历配置层次结构以提取特定属性的代码非常痛苦。当你有数百个属性的复杂配置信息时,这会让你想哭。
\n\n类型检查和验证不需要在运行时之前静态指定整个配置层次结构。Python 是一种非常动态的语言,您并不总是知道程序启动时需要配置的所有内容。
\n
为了实现这一目标,他们基本上定义了 3 个对象类及其相互关系:
\n\n1) 配置 - 基本上是一个 ChainMap / 基本字典,具有一些合并增强功能。
\n\n2) 可配置 - 基类,用于子类化您希望配置的所有内容。
\n\n3) 应用程序 - 实例化以执行特定应用程序功能的对象,或单一用途软件的主要应用程序。
\n\n用他们的话来说:
\n\n\n\n应用: 应用
\n\n应用程序是执行特定工作的进程。最明显的应用是 ipython 命令行程序。每个应用程序读取一个或多个配置文件和一组命令行选项,然后为应用程序生成一个主配置对象。然后,该配置对象被传递给应用程序创建的可配置对象。这些可配置对象实现应用程序的实际逻辑,并且知道如何在给定配置对象的情况下配置自身。
\n\n应用程序始终具有一个日志属性,即已配置的记录器。这允许对每个应用程序进行集中日志配置。\n 可配置:可配置
\n\n可配置是一个常规的 Python 类,充当应用程序中所有主类的基类。Configurable 基类是轻量级的,只做一件事。
\n\n此 Configurable 是 HasTraits 的子类,它知道如何配置自身。元数据 config=True 的类级别特征成为可以从命令行和配置文件配置的值。
\n\n开发人员创建可配置的子类来实现应用程序中的所有逻辑。每个子类都有自己的配置信息来控制实例的创建方式。
\n
归档时间: |
|
查看次数: |
71446 次 |
最近记录: |