Python 在pyparsing中实现属性访问操作符

Python 在pyparsing中实现属性访问操作符,python,pyparsing,Python,Pyparsing,我试图实现一个DSL来编写自定义条件表达式,其中包括特定对象的关键字和这些对象上的属性。例如: user.foo.bar or user.baz user是用当前用户对象替换的关键字。我还实现了或、和以及非操作符,这些操作符基于 我实现了如下属性访问: from pyparsing import infixNotation, opAssoc, Keyword, Word, alphas class User: pass class PropertyAccess: def _

我试图实现一个DSL来编写自定义条件表达式,其中包括特定对象的关键字和这些对象上的属性。例如:

user.foo.bar or user.baz
user
是用当前用户对象替换的关键字。我还实现了
以及
操作符,这些操作符基于

我实现了如下属性访问:

from pyparsing import infixNotation, opAssoc, Keyword, Word, alphas

class User:
    pass

class PropertyAccess:
    def __init__(self, t):
        self.value = reduce(lambda o, p: getattr(o, p, None), t[0][0::2])

user = Keyword('user')
user.setParseAction(User)
identifier = Word(alphas + '_')
property_access_expr = infixNotation(user | identifier, [
    ('.', 2, opAssoc.LEFT, PropertyAccess)
])

虽然这样做有效,但它也允许像
foo.bar
这样的表达式,这是毫无意义的。属性访问必须以受支持的关键字之一(如
user
)开始,否则它们将无效。如何重新实现语法以限制它?

您使用
infixNotation
使任务变得不必要的困难
infixNotation
用于定义具有不同优先级(即操作顺序)的多个不同中缀运算符。但是属性访问只有一个操作符(
),可以通过
一个或多个
轻松实现:

property_access_expr = user + OneOrMore('.' + identifier)
property_access_expr.setParseAction(PropertyAccess)
像这样更改语法需要对
PropertyAccess
类稍作修改。以前输入是嵌套列表,但现在是平面列表。因此,我们必须将
t[0][0::2]
更改为
t[0::2]

class PropertyAccess:
    def __init__(self, t):
        self.value = reduce(lambda o, p: getattr(o, p, None), t[0::2])
现在,语法只正确解析以
user开头的属性访问。

>>> property_access_expr.parseString('user.foo.bar')
([<__main__.PropertyAccess object at 0x0000000002DD4048>], {})
>>> property_access_expr.parseString('foo.bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
pyparsing.ParseException: Expected "user" (at char 0), (line:1, col:1)
>>property\u access\u expr.parseString('user.foo.bar'))
([], {})
>>>属性\u访问\u表达式解析字符串('foo.bar')
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
pyparsing.ParseException:应为“用户”(在字符0处),(行:1,列:1)

我只是根据到目前为止我对pyparsing有限的曝光量来拼凑,而
infixNotation
是我唯一真正了解的锤子非常感谢。如果抑制“.”字符(使用类似于
DOT=suppress(“.”);property\u access\u expr=user+one或more(DOT+identifier)
,那么您就不需要跨步切片了:2
因为点将从解析结果中被抑制。我喜欢使用
reduce
连续调用
getattr