getter setter as function in python class giving “no attribute found” error

风格不统一 提交于 2019-12-13 03:59:53

问题


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")

Above is the code of lexer and parser using ply library. I have just encapsulated all of my code in the class form. Problems which i am facing:

1.) I'm trying to pass a dict_obj to the parser class. I don't know what i am doing wrong and getting an error like :

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

2.) What I'm trying to do?

I want to pass this dict_obj to the parser class and then pass it to the lexer class as well and then make use of it in the lexer one of the tokens methods (t_FUNC) method. In this method my regex will return keys of the this dict obj.

I think i'm doing something wrong and hence failing to implement it. Please help.


回答1:


In your constructor (__init__) for the Parser object, you ask Ply to generate a parser before the Parser object is fully constructed:

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

In order to construct a parser from the object (yacc.yacc(module=self)), Ply needs to iterate over all the object's attributes. For example, it needs to find all the parser functions in order to extract their docstrings in order to determine the grammar.

Ply uses the dir built-in function to make a dictionary of all the object's attributes. Because your Parser object has a custom attribute dict_obj, that key is returned from dir and so Ply tries to cache that attribute with its value. But when it calls gettattr(module, 'dict_obj'), the getter is called, and the getter tries to return self._dict_obj. However, self._dict_obj has not yet been defined, so that ends up throwing an error:

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

Note that this is not the error message you reported in your question; that error says that there is no attribute dict_obj. Perhaps that was a copy-and-paste error.

If you move the call to yacc.yacc to the end of the initialiser, that particular problem goes away:

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

However, there are a number of other problems in the code excerpt which make it difficult to verify this solution. These include:

  1. There is no LexerNmsysSearch. I assumed you meant Lexer.

  2. There is no node_expression. I have no idea what that is supposed to be so I just removed the test.

  3. Your grammar does not match the input you are testing, so the parser immediately throws a syntax error. I changed the input to "(~hello)" in an attempt to produce something parseable.

  4. The parser actions do not set semantic values, so self.parse.parse() doesn't return any value. This causes get_result to throw an error.

At that point, I gave up on trying to produce anything sensible out of the code. For future reference, please ensure that error messages are quoted exactly and that sample code included in the question can be run.



来源:https://stackoverflow.com/questions/54048095/getter-setter-as-function-in-python-class-giving-no-attribute-found-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!