Получение значения True или False для элементов в списке из словаря - PullRequest
0 голосов
/ 30 сентября 2018

Предположим, у нас, например, есть эти переменные:

my_list = ["door_open", "AND", "dog_gone"], 
my_dict ={"door_open" : "false", "dog_gone" : "true", "dog_asleep" : "true"})

(обратите внимание, список и словарь могут быть длиннее или короче, и они все равно должны работать).И мы хотим иметь возможность запустить его через эту функцию:

def and_function(arg1, arg2):
    if arg1=="true" and arg2=="true":
        return "true"
    else:
        return "false"

Как мы напишем функцию, которая сначала проверит, являются ли элементы в списке «истиной» или «ложью», а затем запуститэто через "and_function".Вот как это должно выглядеть:

def interpret(my_list, my_dict):
#DO SOMETHING SO WE GET THE "true" OR "false" VALUE FOR ELEMENTS
.
. 
. 
if "AND" in my_list:
    return and_function(ture_or_false, false_or_true) 


"false"

1 Ответ

0 голосов
/ 30 сентября 2018

Это похоже на рекурсивную структуру (поскольку, скорее всего, операнды также могут быть выражениями).В этом случае хорошей идеей будет написание парсера .Самостоятельное написание парсера обычно, однако, подвержено ошибкам и обременительно.Таким образом, мы не собираемся писать синтаксический анализатор самостоятельно, мы используем инструмент, который можем дать спецификации, а затем генерировать сам синтаксический анализатор.

Одним из этих инструментов является, например, PLY .Простой анализатор (я не буду реализовывать полный анализатор, но идея должна быть ясна) может выглядеть следующим образом.

Лексер

Сначала нам нужно реализоватьлексер, который анализирует токены :

# lexer.py

import ply.lex as lex

tokens = (
    'AND',
    'OR',
    'IDENTIFIER',
)

t_AND = r'AND'
t_OR = r'OR'

def t_IDENTIFIER(t):
    r'[a-z_]+'  
    return t

t_ignore  = ' \t\r\n'

lexer = lex.lex()

Приведенное выше приведёт к лексеру (также известному как tokenizer ; не анализатору).Лексер превращает строку в список токенов.Здесь есть три возможных токена: AND, OR и IDENTIFIER.AND соответствует только 'AND' (в верхнем регистре), OR соответствует 'OR' (в верхнем регистре), а IDENTIFIER соответствует всему, что представляет собой последовательность символов нижнего регистра и подчеркивания.

Так что если мыпроанализировав строку, мы получим:

>>> from lexer import lexer
>>> lexer.input('foo AND bar')
>>> lexer.token()
LexToken(IDENTIFIER,'foo',1,0)
>>> lexer.token()
LexToken(AND,'AND',1,4)
>>> lexer.token()
LexToken(IDENTIFIER,'bar',1,8)
>>> lexer.token()
>>>

Парсер

Теперь мы можем превратить список токенов в «дерево», содержащее листья (идентификаторы) и inodes (операнды):

# parser.py

import ply.yacc as yacc

class Identifier:

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

    def resolve(self, dictionary):
        return dictionary[self.name]

class Node:

    def __init__(self, left, right):
        self.left = left
        self.right = right

    def resolve(self, dictionary):
        return self.func(self.left.resolve(dictionary), self.right.resolve(dictionary))

    def func(self, left, right):
        return None

class AndNode(Node):

    def func(self, left, right):
        return left and right

class OrNode(Node):

    def func(self, left, right):
        return left or right

from lexer import tokens

def p_expression_or(p):
    'expression : and_exp OR expression'
    p[0] = OrNode(p[1], p[3])

def p_expression_or_no(p):
    'expression : and_exp'
    p[0] = p[1]

def p_expression_and(p):
    'and_exp : ident AND and_exp'
    p[0] = AndNode(p[1], p[3])

def p_expression_and_no(p):
    'and_exp : ident'
    p[0] = p[1]

def p_ident(p):
    'ident : IDENTIFIER'
    p[0] = Identifier(p[1])

parser = yacc.yacc()

Здесь мы указываем набор правил производства вместе с логикой для обработки этого правила производства.Мы указываем, что expression - это and_expr, за которым следует OR, за которым следует еще expression (первая функция) или просто and_expr (вторая функция).Таким образом, мы строим грамматику языка.В функциях мы создаем объекты AndNode, OrNode и Identifier в виде дерева.

Оцениваем синтаксическое дерево

Теперь мыможно разобрать строку в такое дерево с помощью:

from parser import parser

tree = parser.parse('foo AND bar')

Теперь со словарем вроде:

data = {'foo': True, 'bar': True}

мы можем вызвать .resolve(..) метод tree и получитьрезультат:

>>> tree.resolve({'foo': True, 'bar': True})
True
>>> tree.resolve({'foo': True, 'bar': False})
False
>>> tree.resolve({'foo': False, 'bar': False})
False 

Расширение синтаксического анализатора

Если вы прочитаете документацию, вы найдете способы включить круглые скобки и другие функции (унарные операторы, бинарные операторы, функции) и т. д. длялексер, анализатор и оцените их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...