如何使用声明性逻辑编写python脚本

时间:2015-05-11 23:24:58

标签: python

这是一个复杂的问题(至少对我来说),我希望有人可以指点我帮助我开始一本书/网站/博客。有人能告诉我在哪里可以找到信息在python中编写脚本,它会读取一堆逻辑语句并将该逻辑应用于一堆正在读入的数据中吗?我可以用非声明的方式做到这一点,但这意味着任何时候有一个新的逻辑语句,我需要编写新的代码来处理它。如果我可以编写一些可以解释逻辑语句的通用脚本,那么我就不需要继续编写代码来跟上新的逻辑语句了。

我想要做的是我的脚本会读取3个文件。两个长度相等的文件包含两个度量的值。第三个是带有逻辑语句的文件。我希望脚本读入逻辑语句并将这些语句应用于数字,并在满足这些语句时写入消息。

例如,文件1将包含:

1
2
3
4
5
6

文件2将包含:

2
4
6
8
10
3

文件3,将包含:

m1 >=3 && (m1 + m2) >= 11

如果我运行我的脚本,我希望它输出一些说

的内容
m1 = 4 and m2 = 8 fulfills condition m1 >= 3 && (m1 + m2) >= 11
m1 = 5 and m2 = 10 fulfills condition m1 >= 3 && (m1 + m2) >= 11

3 个答案:

答案 0 :(得分:4)

我会使用eval函数。

>>> m1 = 10
>>> m2 = 30
>>> statement = 'm1 < m2 and m2 == 30'
>>> eval(statement)
True

警告 eval()以python代码的形式执行所有操作,因此如果用户可以输入语句,他可以运行任何内容。在某些网站上可能会非常危险。您总是可以在评估之前解析语句。

安全检查示例:

def parse(statement, m1, m2):
  statement = statement.replace('&&', ' and ')
  statement = statement.replace('||', ' or ')
  if is_safe(statement):
    eval(statement)

def is_safe(to_test):
  safe_tags = ('m1', 'm2','>=', '<=', '>', '<', '==', '+', '-', '*', '/', '(', ')', 'and', 'or', '.')
  max_number_length = 20

  for tag in safe_tags:
    to_test = to_test.replace(tag, ' ')

  for other in to_test.split(' '):
    if other == '':
      continue
    if other.isdigit() == False or len(other) > max_number_length:
      return False
  return True


parse('m1 >=3 && (m1 + m2) >= 11', 10, 20)

仅使用允许的标签(白名单)。您可能需要在safe_tags

中添加更多标签

答案 1 :(得分:2)

如果您信任数据并且可以用Python语法编写逻辑语句,那么您可以使用eval并为其提供表达式和两个值:

>>> eval('m1 >=3 and (m1 + m2) >= 11', {'m1':4, 'm2':8})
True
>>> eval('m1 >=3 and (m1 + m2) >= 11', {'m1':4, 'm2':-8})
False

使用“如果你信任它”我的意思是它不应该包含像“delete-my-whole-harddisk”函数调用这样的东西。因为eval会运行它。

不得不为自己尝试......

with open('m1.txt') as f1, open('m2.txt') as f2:
    m12 = list(zip(map(int, f1), map(int, f2)))
with open('expressions.txt') as expressions:
    for expression in expressions:
        for m1, m2 in m12:
            if eval(expression):
                print('m1 = {} and m2 = {} fulfills condition {}'.
                      format(m1, m2, expression.strip()))

答案 2 :(得分:2)

按照@AdamSmith的建议使用SQL。问题是condition仍然容易受到SQL注入攻击,因此与eval相比没有任何优势

import sqlite3
conn = sqlite3.connect(':memory:')
c = conn.cursor()

file1 = [1, 2, 3, 4, 5, 6]
file2 = [2, 4, 6, 8, 10, 3]

c.execute('''CREATE TABLE m (m1, m2)''')
for m1, m2 in zip(file1, file2):
    c.execute('''INSERT INTO m VALUES(?, ?)''', (m1, m2))

condition = '''m1 >=3 AND (m1 + m2) >= 11'''
c.execute('''SELECT m1, m2 FROM m WHERE ''' + condition)
for m1, m2 in c.fetchall():
    print "m1 = {} and m2 = {} fulfills condition {}".format(m1, m2, condition)