我们有一个config.yaml
这样的文件:
darwin:
installer:
title: "%(product_name)s %(version)s"
filename: "%(brand_name)s-%(version)s"
以及格式化的函数:
def format_context(config):
return {
"company_name": config['company_name'],
"product_name": config['product_name'],
"brand_name": config['brand_name'],
"title": config['darwin']['installer']['title'],
"filename": config['darwin']['installer']['filename'],
}
这里的目标是我们可以将值作为格式化字符串输入。
现在我需要将字典返回format_context
变为变量。
第一次尝试使用locals()
:
context = format_context(config)
for k, v in context.iteritems():
locals()[k] = str(v) % context
但也许由于订单,我有时会遇到KeyError
错误。此外,来自Python doc:
注意不应修改此词典的内容;变化 可能不会影响使用的本地和自由变量的值 解释
所以,我转而使用exec
:
context = format_context(config)
for k, v in context.iteritems():
exec("%s = '%s'" % (k, str(v) % context))
它有效,但我想知道这是一个好方法吗?
请让我澄清为什么我要从该字典创建变量。
我有一个函数来解析这个config.yaml
:
class BrandConfiguration(object):
"""
A brand configuration (directory)
"""
def __init__(self, directory):
self.dirname = directory
@property
def config(self):
"""
return configuration for a single brand
"""
with open(os.path.join(self.dirname, "config.yaml")) as fh:
return yaml.load(fh)
然后在一个班级中,我定义了一些变量:
- brand_config = self.brand_config_instance.config
- binary_name = brand_config['binary_name']
- major_version = brand_config['version']['major']
- minor_version = brand_config['version']['minor']
- patch_version = brand_config['version']['patch']
在另一个类(或另一个Python文件)中,我需要做同样的事情:
- brand_name, binary_name = config['brand_name'], config['binary_name']
- identifiers = [binary_name] + brand_name.split('.')
- identifiers.reverse()
- identifier = '.'.join(identifiers)
- major_version = config['version']['major']
- minor_version = config['version']['minor']
- patch_version = config['version']['patch']
- version = '.'.join(
- (
- str(major_version),
- str(minor_version),
- str(patch_version),
- build_number
- )
- )
由于我不想复制代码,我正在尝试将它全部存储在字典中并将其转换为变量。
您在哪里/如何使用format_context返回的字典中的值?
在config.yaml
中假设你有类似的东西:
version:
major: 1
minor: 0
patch: 0
为Windows添加元数据时,而不是创建一些变量:
- brand_name, binary_name = config['brand_name'], config['binary_name']
- identifiers = [binary_name] + brand_name.split('.')
- identifiers.reverse()
- identifier = '.'.join(identifiers)
- major_version = config['version']['major']
- minor_version = config['version']['minor']
- patch_version = config['version']['patch']
- version = '.'.join(
- (
- str(major_version),
- str(minor_version),
- str(patch_version),
- build_number
- )
- )
现在我可以直接使用它:
json_data['FixedFileInfo']['FileVersion']['Major'] = major_version
json_data['FixedFileInfo']['FileVersion']['Minor'] = minor_version
json_data['FixedFileInfo']['FileVersion']['Patch'] = patch_version
json_data['FixedFileInfo']['FileVersion']['Build'] = build_number
json_data['FixedFileInfo']['ProductVersion'] = \
json_data['FixedFileInfo']['FileVersion']
json_data['StringFileInfo']['CompanyName'] = company_name
json_data['StringFileInfo']['FileDescription'] = service_description
json_data['StringFileInfo']['LegalCopyright'] = legal_copyright
json_data['StringFileInfo']['ProductName'] = product_name
json_data['StringFileInfo']['ProductVersion'] = '.'.join(
(
str(major_version),
str(minor_version),
str(patch_version),
self.target.build_number
)
)
答案 0 :(得分:0)
argparse
用户有时会询问将args
属性转换为全局变量或本地变量,例如。
Python argparse parse_args into global namespace (or a reason this is a bad idea)
python argparse, how to refer args by their name
argparse
将解析后的参数作为Namespace
对象返回,该对象使用以下代码定义:
In [245]: argparse.Namespace??
Init signature: argparse.Namespace(**kwargs)
Source:
class Namespace(_AttributeHolder):
"""Simple object for storing attributes.
Implements equality by attribute names and values, and provides a simple
string representation.
"""
def __init__(self, **kwargs):
for name in kwargs:
setattr(self, name, kwargs[name])
def __eq__(self, other):
if not isinstance(other, Namespace):
return NotImplemented
return vars(self) == vars(other)
def __contains__(self, key):
return key in self.__dict__
File: /usr/lib/python3.5/argparse.py
Type: type
可以使用
从字典创建这样的对象In [247]: adict={'a':1,'b':'aname','c':[1,2,3]}
In [248]: ns=argparse.Namespace(**adict)
In [249]: ns
Out[249]: Namespace(a=1, b='aname', c=[1, 2, 3])
可以通过名称访问属性:
In [250]: ns.a
Out[250]: 1
In [251]: ns.b
Out[251]: 'aname'
In [252]: ns.c
Out[252]: [1, 2, 3]
此语法就像在名为a
的模块中要求变量ns
一样。
可以使用vars
轻松将其重新转换为字典:
In [253]: vars(ns)
Out[253]: {'a': 1, 'b': 'aname', 'c': [1, 2, 3]}
请注意Namespace
使用setattr
设置属性。这比`ns.abc ='123'语法更强大,因为它创建的属性不是有效的变量名:
In [254]: setattr(ns,'123','foo')
In [255]: ns
Out[255]: Namespace(123='foo', a=1, b='aname', c=[1, 2, 3])
In [256]: ns.123
File "<ipython-input-256-f3ac9938f9b1>", line 1
ns.123
^
SyntaxError: invalid syntax
In [257]: getattr(ns,'123')
Out[257]: 'foo'
某些程序(如Ipython
)从config
文件加载参数,然后使用argparse
从命令行读取最后一分钟的参数,为用户提供了几种方法设置选项。将这些选项(无论来源)保存在一个地方(命名空间或字典)而不是合并到globals
或locals
中通常更有用。