2

This is a complex question (at least for me) and I hope there's a book/website/blog someone can point me to to help give me a start. Can someone tell me where I can find info to write a script in python where it reads a bunch of logic statements and applies that logic to a bunch of data being read in? I can do this in a non-declarative manner but that means any time there's a new logic statement, I'd need to write new code to handle it. If I can write some generic script that can interpret the logic statement, then I won't need to keep writing code to keep up with new logic statements.

What I'm trying to do is I have 3 files my script will read. Two files of equal length contain values for two metrics. The third is a file with logic statements. I want the script to read in the logic statements and apply those statements to the numbers and write messages if it fulfills those statements.

For example, file 1 will contain:

1
2
3
4
5
6

file 2 will contain:

2
4
6
8
10
3

file 3, will contain:

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

If I run my script, I want it to output something that says

m1 = 4 and m2 = 8 fulfills condition m1 >= 3 && (m1 + m2) >= 11
m1 = 5 and m2 = 10 fulfills condition m1 >= 3 && (m1 + m2) >= 11
2
  • 1
    Sounds like you'd be better suited to learning SQL and throwing your values in a relational database Commented May 11, 2015 at 23:38
  • @AdamSmith, haha, i wish i could suggest this to the team lead but we're using another db and the calculations are more complicated than what I specified. I think this project might be out of my league but I couldn't say I can't do it w/o trying. I have a general idea of how to attack it but me being able to execute is another question. Commented May 11, 2015 at 23:59

3 Answers 3

4

I would use eval function.

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

Warning eval() executes everything as python code, so if user can input statements, he can run anything. It could be very dangerous on some website. You can always parse statement before evaluation.

Example with safety check:

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)

Use only allowed tags (white list). You propably will need to add samo more tags to the safe_tags

Sign up to request clarification or add additional context in comments.

5 Comments

What does this add to the preexisting answer by Stefan?
It shows that eval can use local variables, without passing them explicitly. He added his answer , when I was editing my, so thats why it's so similiar.
Can, to be sure, but passing a context is safer -- if someone tries to access a variable other than the ones you're trying to let their code operate on, don't you want that to be an error?
@CharlesDuffy you can't make eval safe: that's a horse that's been beaten to death. The answer adds value.
Sure. If the goal is to make eval safe in any kind of absolute way, it fails. If the goal is to make unintentional errors less likely to result in code that runs with an incorrect value rather than failing, on the other hand, it's an enhancement. That is: Safe against unintentional misuse (typoing the name of a different local variable rather than the intended set), rather than intentional misuse (__import__("sys")).
2

Doing it with SQL as suggested by @AdamSmith. The problem is that condition is still prone to SQL injection attacks, so not really any advantage over 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)

1 Comment

I have long ago forgotten how to operate with the sqlite3 library. The SQLAlchemy declarative code I wrote was too ugly to live, but if you like...gist.github.com/NotTheEconomist/52351b173a08930ae42b
2

If you trust the data and can write the logical statements in Python syntax, then you could use eval and give it the expression and the two values:

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

With "if you trust it" I mean it shouldn't possibly contain something like "delete-my-whole-harddisk" function calls. Because eval would run that.


Had to try it for myself...

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.