带路径的嵌套词典
texas的Python项目详细描述
纯Python。路径键。类固醇链式地图。
安装
pip install texas
快速启动
import texas context = texas.Context() environment = context.include("environment") cli = context.include("cli") config = context.include("environment", "cli") environment["src.root"] = "~/pics" cli["src.type"] = "jpg" config["src.root"] # ~/pics config["src.type"] # jpg # Change cli's root cli["src.root"] = "~/other" # Doesn't change the underlying environment root environment["src.root"] # ~/pics # Modifies cli, which is the top context in config del config["src.root"] config["src.root"] # ~/pics # Snapshot the contexts into a single dict for use in modules that # typecheck against dict (instead of collections.abc.Mapping) import pprint pprint.pprint(config.snapshot) # { # "src": { # "root": "~/pics", # "type": "jpg" # } # }
用法
上下文是带有(可配置)路径查找的命名空间python字典:
import texas context = texas.Context() # Single context root = context.include("root") # normal dictionary operations root["foo"] = "bar" assert "bar" == root["foo"] del root["foo"] # paths root["foo.bar"] = "baz" assert "baz" == root["foo.bar"] del root["foo.bar"]
包括
include获取要加载到视图中的上下文名称的可变数目:
bottom = context.include("bottom") top = context.include("top") both = context.include("bottom", "top")
这可用于在查找值时创建优先级。顶部 上下文堆栈将首先检查键,然后检查下一个键,直到上下文 找到给定密钥:
bottom["key"] = "bottom" assert both["key"] == "bottom" top["key"] = "top" assert both["key"] == "top"
结合路径,这对于配置管理来说非常强大:
context = texas.Context() env = context.include("env") cli = context.include("cli") config = context.include("env", "cli") env["src.root"] = "~/pics" cli["src.type"] = "jpg" assert config["src.root"] == "~/pics" assert config["src.type"] == "jpg"
这甚至适用于单独的路径段,因为contextview返回 针对底层映射对象的代理:
config["src"] # <texas.context.ContextView at ... > config["src"]["type"] # "jpg"
设置值仅适用于视图中的顶部上下文,因此 底部仍然相同:
assert bottom["key"] == "bottom"
它用可变的值分解-例如,这将修改列表 在下面的上下文中:
context = texas.Context() bottom = context.include(“bottom”) top = context.include(“top”) both = context.include(“bottom”, “top”)
bottom[“list”] = [] top[“list”].append(“modified!”)
assert bottom[“list”] == [“modified!”]
快照
上下文做了一些繁重的工作来使路径和多个指令一起工作 舒适地。不幸的是,有些库对isinstance进行检查 dict,而不是collections.abc.Mapping。
当将ContextView传递给将执行许多 在一个紧密的循环中查找。因为对深度嵌套的 一组dict为每个级别创建一个代理(即。 {TT4}$为该值创建两个代理 something["foo.bar.baz"] = "blah")它可以显著加速到 “快照”或烘焙ContextView以获得更快的读取速度。
一般来说,合并dict最多是一个复杂的问题,有很多歧义。 为了简化操作,使用以下规则:
(1) For every key in each context, the top-most[0] context that contains that key will determine if the value will be used directly, or merged with other contexts. (2) If that value is a collections.abc.Mapping, the value of that key in each context that contains that key will be merged. (A) If there is a context with that key whose value is NOT a mapping, its value will be ignored. (B) If that value is NOT a collections.abc.Mapping, the value will be used directly and no merging occurs[1]. 3) These rules are applied recursively[2] for any nested mappings.
“包含该键的最上面的上下文”并不总是最上面的上下文。 在下面的示例中,底部上下文是唯一包含键的上下文 “底部”:
{ "bottom": "bottom-value" }, { "top": "top-value" } Snapshot: { "bottom": "bottom-value", "top": "top-value" }
当类型(映射,非映射)发生冲突时,最上面的上下文 确定类型。例如,这将从 底部和顶部,但不是中间(其值不是映射):
{ "key": { "bottom": "bottom-value" } }, { "key": ["middle", "non", "mapping"] }, { "key": { "top": "top-value" } } Snapshot: { "key": { "bottom": "bottom-value", "top": "top-value" } }
当snapshot递归地将其规则应用于映射时,实现是 不是递归的。一个示例文件,它使用 与德克萨斯州相同的规则 here。
上下文工厂
默认情况下,Texas使用简单的dict``s for storage. However, this can be customized with the ``context_factory函数,例如使用 collections.OrderedDict或将值预加载到节点中。
此函数用于创建快照、上下文根、新上下文, 以及按路径设置值时的中间段。
created = 0 def factory(): global created created += 1 return dict() # Root context container context = texas.Context(context_factory=factory) assert created == 1 # Including contexts ctx = context.include("some-context") assert created == 2 # Segments along a path when setting values ctx["foo.bar"] = "value" assert created == 3
内部
在内部,所有数据都存储在python dict中。你可以检查全球 上下文通过其contexts属性的状态:
import texas context = texas.Context() context.include("root.something.or.foo") context.include("bar", "and.yet.another.foo", "finally") print(context._contexts)
路径遍历由traverse函数执行,该函数只处理 遍历collestions.abc.Mapping。因此,当一个非映射值 在路径的末尾,路径应该按如下方式拆分:
full_path = "foo.bar.baz" path, last = full_path.rsplit(".", 1) assert path == "foo.bar" assert last = "baz"
这允许我们遍历一个根并创建中间foo和 bardict而不修改或检查baz:
from texas.traversal import traverse, create_on_missing root = dict() full_path = "foo.bar.baz" path, key = full_path.rsplit(".", 1) node = traverse(root, path, ".", create_on_missing(dict)) node[key] = "value" assert root["foo"]["bar"]["baz"] == "value"