views:

432

answers:

5

I'm trying to write a very simple Python utility for personal use that counts the number of lines in a text file for which a predicate specified at the command line is true. Here's the code:

import sys

pred = sys.argv[2]
if sys.argv[1] == "stdin" :
    handle = sys.stdin
else :
    handle = open(sys.argv[1])
result = 0
for line in handle :
    eval('result += 1 if ' + pred + ' else 0')
print result

When I run it using python count.py myFile.txt "int(line) == 0", I get the following error:

  File "c:/pycode/count.py", line 10, in <module>
    eval('toAdd = 1 if ' + pred + ' else 0')
  File "<string>", line 1
    toAdd = 1 if int(line) == 0 else 0

This looks like perfectly valid Python code to me (though I've never used Python's eval before, so I don't know what its quirks, if any, are). Please tell me how I can fix this to make it work.

+7  A: 

Try using exec instead of eval. The difference between the 2 is explained here

ennuikiller
Thanks. Simple question, simple answer.
dsimcha
you're very welcome!
ennuikiller
+2  A: 

The python eval() function evaluates expressions, not statements. Try replacing the eval() line with:

result += eval(pred + " else 0")
Uh Clem
`eval('int(line) == 0 else 0')` produces `SyntaxError`.
J.F. Sebastian
+5  A: 

try:

for line in handle:
  result += 1 if eval(pred) else 0
orip
A: 

Really, you are looking for the compile function:

>> a = compile("toAdd = 1 if int('0') == 0 else 0", 'tmp2.py', 'exec')
>>> eval(a)
>>> toAdd
1

eval is intended only for expressions... compile while compile sequence of statements into a codeblock that can then be eval'ed.

jsight
+3  A: 
#!/usr/bin/env python
import fileinput, sys

pred = eval('lambda line: ' + sys.argv[1])
print sum(1 for line in fileinput.input(sys.argv[2:]) if pred(line))

Usage: pywc.py predicate [FILE]...
Print number of lines that satisfy predicate for given FILE(s).
With no FILE, or when FILE is -, read standard input.

J.F. Sebastian
This is excellent, a great improvement over the other versions in simplicity and efficiency.
Kragen Javier Sitaker
Thanks. This is a heck of a lot faster than the other versions, I guess because the interpreter parses and compiles the predicate O(1) instead of O(N) times.
dsimcha