Pyparsing:如何在嵌套parseAction中访问外层ParseResults?
Great question! Let's break this down clearly: by default, pyparsing's parseAction callbacks (whether defined as functions or via a class's __call__ method) don't get a direct reference to outer/parent-level ParseResults—they only receive the current match string, starting index, and the ParseResults for the current level of the parse. But don't worry, there are straightforward ways to work around this without ditching parseActions entirely.
Option 1: Use a Closure to Carry Outer Context
The simplest trick is to wrap your parseAction in a closure that captures the outer context you need. This lets the nested parseAction access variables from the outer scope, like a parent ParseResults object or other contextual data.
Here's how you could adapt your sample code:
from pyparsing import * def make_a_parse_action(outer_context): def parse_action(string, index, t): # Directly access the captured outer context here print(f"Using outer context data: {outer_context}") return f"nested value [{t[0]}] paired with outer info" return parse_action # Define your expression structure expr = Forward() number = Word(nums) expr << operatorPrecedence(number, [ (Literal('A'), 1, opAssoc.RIGHT, make_a_parse_action("outer parse context")), (Literal('B'), 2, opAssoc.LEFT), (Literal('C'), 2, opAssoc.LEFT) ]) # Test it out print(expr.parseString("A1B3")[0]) print(expr.parseString("3B1C2BA1")[0])
Option 2: Update Your Class-Based ParseAction to Store Context
Your AParseActionHolder class can be modified to accept and hold onto outer context when it's initialized, instead of relying on a global or external variable. This makes it reusable and explicit.
Check this revised version:
from pyparsing import * class AParseActionHolder(object): def __init__(self, outer_parse_results): # Store the outer ParseResults as an instance attribute self.outer_pr = outer_parse_results def __call__(self, string, index, t): # Access the saved outer context whenever you need it return f"nested value [{t[0]}] using outer data: {self.outer_pr}" # Example: Create an outer ParseResults (could come from a prior parse step) outer_results = ParseResults(["parent_value_1", "parent_value_2"]) expr = operatorPrecedence(Word(nums),[ (Literal('A'), 1, opAssoc.RIGHT, AParseActionHolder(outer_results)), (Literal('B'), 2, opAssoc.LEFT), (Literal('C'), 2, opAssoc.LEFT) ]) print(expr.parseString("A1B3")[0])
If your outer context changes dynamically during parsing, you can even update the instance's outer_pr attribute mid-parse as needed.
Option 3: Recursively Traverse ParseResults Post-Parse
If you don't need to handle the context during the parse itself, you can wait until the entire parse is done, then recursively walk the final ParseResults to associate nested items with their parent data. This is useful for batch processing:
def process_nested(pr, parent_info=None): if isinstance(pr, ParseResults): # For each item in the current ParseResults, pass along parent info for i, item in enumerate(pr): pr[i] = process_nested(item, parent_info=pr if parent_info is None else parent_info) return pr else: # Process leaf nodes with their parent context return f"processed [{pr}] with parent: {parent_info}" # Run the parse, then process the results parsed_data = expr.parseString("3B1C2BA1")[0] processed = process_nested(parsed_data) print(processed)
Quick Recap
- No direct access: ParseActions don't get outer ParseResults by default—they only see their own level's data.
- Closures/contextual classes: These are the best ways to pass outer context into a nested parseAction during the parse.
- Post-parse recursion: Use this if you can handle context association after the parse is complete.
内容的提问来源于stack exchange,提问作者user2952903

