当我需要返回值

时间:2017-03-15 05:57:06

标签: python python-3.x exec

我之前问了一个问题,但遇到了第二个问题。

我正在编写一个读取文本文件的程序,并执行文件中的所有代码。这是针对课程的,我们必须使用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]

1 个答案:

答案 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']