我之前问了一个问题,但遇到了第二个问题。
我正在编写一个读取文本文件的程序,并执行文件中的所有代码。这是针对课程的,我们必须使用exec()
运行代码时出现此错误,无数次搜索并没有让我找到解决方案。
Traceback (most recent call last):
File "doxecute.py", line 28, in <module>
replace_code(statements, contents)
File "doxecute.py", line 17, in replace_code
contents = contents.replace("{%" + statement + "%}", statement)
TypeError: Can't convert 'NoneType' object to str implicitly
代码是
import sys
import re
def sortecute(data):
funcs = re.findall(r'{%(.*?)%}',data,re.DOTALL)#find executable statements
return funcs
def replace_code(statements, contents):
for statement in statements:
if not statement[5:].startswith("print("):
exec(statement[5:]) #execute code after the (letter)
contents = contents.replace("{%" + statement + "%}", "")
else:
statement = exec(statement[5:])#error is here
contents = contents.replace("{%" + statement + "%}", statement)
print(contents)
f = open(sys.argv[1],"r")
contents = f.read()
f.close()
statements = sortecute(contents) #get data from file
statements = sorted(statements) #sorts by letter
replace_code(statements, contents)
这是我读过的文件。
The number {% (c) print(x) %} is a random number between 1 and 6
inclusive. If we multiply it by 2, we get {% (d) print(2*x) %}.
What's interesting is that the statements may appear out of order in the
document. {% (a) import random %} Thus I might generate the random
number in a location in the document well after referencing it.
{% (b) x = random.randint(1,6) %}
我无法找到如何获取exec语句的值。有人可以通过下面列出的方式向我解释如何正确使用它
You will need to use the exec function in Python. To get the output back, you will need to redirect output to your own stream. Your program should accept a filename as a command-line argument to operate on [8]
答案 0 :(得分:2)
exec
将始终返回None
。来自documentation:
exec( object [,globals [,locals]] )
此函数支持动态 执行Python代码。 object必须是字符串或代码 宾语。如果是字符串,则将字符串解析为一套Python 然后执行的语句(除非发生语法错误)。 [1] 如果它是代码对象,则只执行它。在所有情况下,代码 执行时预计作为文件输入有效(参见本节) 参考手册中的“文件输入”。请注意return
和。{yield
语句甚至不能在函数定义之外使用 在传递给exec()
函数的代码的上下文中。 回归 值为None
。
这是一个相当奇怪的请求。但是可以捕获输出,如下所示:
>>> s = """The number {% (c) print(x) %} is a random number between 1 and 6
... inclusive. If we multiply it by 2, we get {% (d) print(2*x) %}.
...
... What's interesting is that the statements may appear out of order in the
... document. {% (a) import random %} Thus I might generate the random
... number in a location in the document well after referencing it.
... {% (b) x = random.randint(1,6) %}"""
>>> import re
>>> stmts = re.findall(r'{%\s*\((\w*)\)\s*(.*)%}',s)
>>> stmts
[('c', 'print(x) '), ('d', 'print(2*x) '), ('a', 'import random '), ('b', 'x = random.randint(1,6) ')]
现在,您必须将输出重定向到稍后可以操作的某个流:
>>> import io
>>> import sys
>>> stream = io.StringIO()
>>> stdout = sys.stdout # this keeps stdout so we can set it back
>>> sys.stdout = stream
>>> for _, statement in sorted(stmts):
... exec(statement)
...
>>> sys.stdout = stdout # remember to reset stdout!
现在,您可以获得打印的值:
>>> stream.getvalue()
'5\n10\n'
>>> stream.getvalue().split()
['5', '10']
虽然,我认为更简单的方法是将命名空间传递给dict:
>>> namespace = {}
>>> for _, statement in sorted(stmts):
... exec(statement, namespace)
...
5
10
>>> namespace.keys()
dict_keys(['__builtins__', 'random', 'x'])
命名空间将加载普通__builtins__
,除非您自己提供。因此,要在执行的代码中创建每个名称,您可以找到namspace.keys
dictview
与包含字符串"__builtins__"
>>> namespace.keys()
dict_keys(['__builtins__', 'random', 'x'])
>>> vals = namespace.keys() - {'__builtins__'}
>>> vals
{'random', 'x'}
>>> for val in vals:
... print(namespace[val])
...
<module 'random' from '/Users/juan/anaconda3/lib/python3.5/random.py'>
5
>>>
虽然,如果您使用的是python 3.4&gt; =将stdout重定向到某个流更容易:
>>> import contextlib
>>> stream = io.StringIO()
>>> with contextlib.redirect_stdout(stream):
... for _, statement in stmts:
... exec(statement)
...
>>> stream.getvalue()
'5\n10\n'
>>> stream.getvalue().split()
['5', '10']