getter setter作为python类中的函数,给出“未找到属性”错误

时间:2019-01-05 01:11:26

标签: python python-2.7 getter-setter lex ply

import operator
import re
from ply import lex, yacc

class Lexer(object):

    tokens = [
        'COMMA',
        'TILDE',
        'PARAM',
        'LP',
        'RP',
        'FUNC'
    ]

    # Regular expression rules for simple tokens
    t_COMMA = r'\,'
    t_TILDE = r'\~'
    t_PARAM = r'[^\s\(\),&:\"\'~]+'

    def __init__(self, dict_obj):
        self.dict_obj = dict_obj

    def t_LP(self, t):
        r'\('
        return t

    def t_RP(self, t):
        r'\)'
        return t

    def t_FUNC(self, t):
        # I want to generate token for this FUNC from the keys of model map
        # For eg: r'key1|key2'
        r'(?i)FUNC'
        return t

    # Define a rule so we can track line numbers
    def t_newline(self, t):
        r'\n+'
        t.lexer.lineno += len(t.value)

    # A string containing ignored characters (spaces and tabs)
    t_ignore = ' \t'

    # Error handling rule
    def t_error(self, t):
        print("Illegal character '%s' on line %d, column %d" % (t.value[0], t.lexer.lineno, t.lexer.lexpos))
        t.lexer.skip(1)

    # Build the lexer
    def build_lexer(self, **kwargs):
        self.lexer = lex.lex(module=self, **kwargs)
        return self.lexer

class Parser(object):

    tokens = Lexer.tokens

    def __init__(self, **kwargs):
        self.parser = yacc.yacc(module=self, **kwargs)
        self.lexer = None
        self._dict_obj = None
        self.error = ""
        self.result = ""

    @property
    def dict_obj(self):
        return self._dict_obj

    @dict_obj.setter
    def dict_obj(self, dict_obj):
        self._dict_obj = dict_obj
        self.lexer = Lexer(self._dict_obj).build_lexer()

    # Handles LP expression RP
    def p_expression(self, p):
        """
        expression : LP expression RP
        """

    # Handles TILDE PARAM - call search
    def p_tilde_param(self, p):
        """
        expression : TILDE PARAM
        """     
        p[0] = p[2]
        return p[0]

    # Handles ANY LP PARAM RP - call search
    def p_expression_any(self, p):
        """
        expression : FUNC LP PARAM RP
        """
        p[0] = p[3]
        return p[0]

    # Error handling rule
    def p_error(self, p):
        if p:
            stack_state_str = " ".join([symbol.type for symbol in self.parser.symstack[1:]])
            self.error = "Syntax error at %s, type %s, on line %d, Parser state: %s %s . %s" % (
                p.value, p.type, p.lineno, self.parser.state, stack_state_str, p
            )
        else:
            self.error = "SYNTAX ERROR IN INPUT"

    def get_result(self, input_):
        input_ = input_.strip()
        if input_:
            self.result = self.parser.parse(input_, lexer=self.lexer)      
            return self.result
        else:
            raise ValueError("EMPTY EXPRESSION ERROR")

def parser(input_):
    par_obj = Parser()
    par_obj.dict_obj = {
      'key1' : 'value1',
      'key2'   : 'value2'
    }
    return par_obj.get_result(input_)

result = parser("~hello")

上面是使用层库的词法分析器和解析器的代码。我刚刚将所有代码封装为类形式。我面临的问题:

1。)我正在尝试将dict_obj传递给解析器类。我不知道我在做错什么,并得到类似这样的错误:

AttributeError: 'Parser' object has no attribute 'dict_obj'

2。)我要做什么?

我想将此dict_obj传递给解析器类,然后也将其传递给lexer类,然后在Tokener方法(t_FUNC)方法之一的lexer中使用它。在这种方法中,我的正则表达式将返回此dict obj的键。

我认为我做错了什么,因此无法实现。请帮忙。

1 个答案:

答案 0 :(得分:0)

__init__对象的构造函数(Parser中,您要求Ply在完全构造Parser对象之前生成解析器:

def __init__(self, **kwargs):
    self.parser = yacc.yacc(module=self, **kwargs)
    # This is the critical line:
    self._dict_obj = None

为了从对象(yacc.yacc(module=self))构造解析器,Ply需要遍历对象的所有属性。例如,它需要找到所有解析器函数以便提取其文档字符串以确定语法。

Ply使用内置的dir函数来创建一个包含所有对象属性的字典。由于您的Parser对象具有自定义属性dict_obj,因此该键是从dir返回的,因此Ply尝试使用其值缓存该属性。但是,当它调用gettattr(module, 'dict_obj')时,将调用getter,并且getter尝试返回self._dict_obj。但是,self._dict_obj尚未定义,因此最终会引发错误:

AttributeError: 'Parser' object has no attribute '_dict_obj'

请注意,这不是不是您在问题中报告的错误消息;该错误表明没有属性dict_obj。也许那是复制粘贴错误。

如果将呼叫移至yacc.yacc到初始化程序的末尾,则该特定问题将消失:

def __init__(self, **kwargs):
    self.lexer = None
    self._dict_obj = None
    self.error = ""
    self.result = ""
    self.parser = yacc.yacc(module=self, **kwargs)

但是,代码摘录中还有许多其他问题,使得很难验证此解决方案。这些包括:

  1. 没有LexerNmsysSearch。我以为你是说Lexer

  2. 没有node_expression。我不知道那应该是什么,所以我只是删除了测试。

  3. 您的语法与您正在测试的输入不匹配,因此解析器会立即引发语法错误。我将输入更改为"(~hello)",以尝试产生可解析的内容。

  4. 解析器操作未设置语义值,因此self.parse.parse()不返回任何值。这会导致get_result引发错误。

那时候,我放弃了尝试从代码中产生任何有意义的东西。为将来参考,请确保正确引用错误消息,并且可以运行问题中包含的示例代码。