基于YAML文件动态更新复杂OrderedDict的技术问询
Hey there! Let's break down how to solve this variable substitution problem for your dynamic configuration system. Based on your description, you're looking to replace placeholders like ${stages.current.variables.item1} with their actual values (e.g., stuff), and you've already figured out copying the current stage's content into an OrderedDict's current entry. Let's focus on the substitution logic.
First, Let's Define Our Example Context
Let's start with a concrete example of your data structures to make this tangible (using Python since you mentioned OrderedDict):
from collections import OrderedDict import re # Your stages structure (with current stage) stages = OrderedDict({ "current": { "variables": { "item1": "stuff", "item2": "another useful thing" } }, "staging": { "variables": { "item1": "staging-stuff" } } }) # Your config object with placeholders updated_config_obj = { "feature_toggle": "${stages.current.variables.item1}", "api_settings": { "endpoint": "https://api.example.com/${stages.current.variables.item2}", "timeout": 30 }, "allowed_users": ["admin", "${stages.current.variables.item1}_user"] }
Step 1: Build a Reusable Substitution Function
The core challenge is recursively traversing your config object, identifying placeholders, and resolving their values from the stage variables. Here's a robust function to handle this:
# Regex pattern to match ${...} placeholders PLACEHOLDER_REGEX = re.compile(r"\$\{([^}]+)\}") def resolve_placeholders(obj, context): """ Recursively replace placeholders in a config object with values from the context. Args: obj: The config object (dict, list, str, etc.) to process context: The root context (e.g., {"stages": stages}) to resolve paths from """ # Handle dictionaries: recurse on each value if isinstance(obj, dict): return {key: resolve_placeholders(value, context) for key, value in obj.items()} # Handle lists: recurse on each item elif isinstance(obj, list): return [resolve_placeholders(item, context) for item in obj] # Handle strings: replace all placeholders elif isinstance(obj, str): def replace_match(match): # Extract the variable path (e.g., "stages.current.variables.item1") var_path = match.group(1) # Split the path into parts to traverse the context path_parts = var_path.split(".") # Traverse the context to find the value current_value = context try: for part in path_parts: current_value = current_value[part] return str(current_value) except (KeyError, TypeError): # If the path doesn't exist, return the original placeholder (or raise an error) return match.group(0) # Apply the replacement to the string return PLACEHOLDER_REGEX.sub(replace_match, obj) # For non-string, non-collection types, return as-is else: return obj
Step 2: Execute the Substitution
Now use the function with your context and config object:
# The root context includes your stages structure root_context = {"stages": stages} # Run the substitution final_config = resolve_placeholders(updated_config_obj, root_context) # Check the result print(final_config)
This will output:
{ "feature_toggle": "stuff", "api_settings": { "endpoint": "https://api.example.com/another useful thing", "timeout": 30 }, "allowed_users": ["admin", "stuff_user"] }
Key Details to Note
- Recursive Traversal: The function handles nested dictionaries and lists, so even deeply nested placeholders get resolved.
- Path Resolution: It parses the full path in the placeholder (like
stages.current.variables.item1) to pull values directly from your context structure. - Error Handling: If a placeholder path doesn't exist, it leaves the placeholder intact (you can modify this to raise an exception if you want strict validation).
- OrderedDict Compatibility: Since we're just accessing dictionary keys,
OrderedDictworks exactly like a regular Python dict here—no extra adjustments needed.
Optional Enhancements
If you want to level this up, consider adding:
- Default Values: Extend the regex to support
${path:-default_value}and handle fallback values when paths don't exist. - Caching: Cache resolved paths if you're processing large configs repeatedly to improve performance.
- Validation: Add checks to ensure all placeholders are resolved successfully before using the final config.
内容的提问来源于stack exchange,提问作者Trondh

