We have a config.yaml file like this:
darwin:
installer:
title: "%(product_name)s %(version)s"
filename: "%(brand_name)s-%(version)s"
and a function to format it:
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'],
}
The goal here is we can input the value as a formatted string.
Now I need to turn the dictionary return by format_context into variables.
The first try is use locals():
context = format_context(config)
for k, v in context.iteritems():
locals()[k] = str(v) % context
But maybe due to the order, I sometimes got a KeyError error. And moreover, from the Python doc:
Note The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
So, I switched to use exec:
context = format_context(config)
for k, v in context.iteritems():
exec("%s = '%s'" % (k, str(v) % context))
It works but I'm wondering is this a good way?
Please let me clarify why I'm going to create variables from that dict.
I have a function to parse this 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)
Then in one class, I defined some variables:
- 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']
In another class (or another Python file), I need to do the same thing:
- 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
- )
- )
Since I don't want to duplicate the code, I'm trying store it all in a dictionary and convert it into variables.
Where/how are you trying to use the values from the dictionary returned by format_context?
Assumming that in config.yaml, you have something like this:
version:
major: 1
minor: 0
patch: 0
When adding metadata for Windows, instead of creating some variables:
- 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
- )
- )
now I can use it directly:
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
)
)
argparseusers sometimes ask about converting theargsattributes into a globals or locals, e.g.Python argparse parse_args into global namespace (or a reason this is a bad idea)
python argparse, how to refer args by their name
argparsereturns the parsed arguments as aNamespaceobject, which is defined with this code:Such an object can be created from a dictionary with
And the attributes can be accessed by name:
This syntax is just like asking for variable
ain a module namedns.It can be easily turned back into a dictionary with
vars:Note that
Namespacesets the attributes withsetattr. This is more powerful than the `ns.abc='123' syntax, since it create attributes that aren't valid variable names:Some programs, like
Ipython, load arguments from aconfigfile(s), and then useargparseto read last-minute arguments from the commandline, giving users several ways of setting options. It is usually more useful to keep those options, regardless of source, collected in one place (a namespace or dictionary) rather than merged into theglobalsorlocals.