【问题标题】:exec returns a nonetype, when I need the return value当我需要返回值时,exec 返回一个非类型
【发布时间】:2017-08-05 17:42:50
【问题描述】:

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

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

【问题讨论】:

  • print() 函数不返回任何内容。
  • 什么意思?我用它来调试。 @AshwiniChaudhary
  • exec 在 Python 3 中总是返回 None。在 Python 2 中,exec 是一个语句,所以它实际上并没有返回任何东西。

标签: python python-3.x exec


【解决方案1】:

exec 将始终返回 None。来自documentation

exec(object[, globals[, locals]])

该函数支持动态 Python代码的执行。对象必须是字符串或代码 目的。如果是字符串,则将该字符串解析为 Python 套件 然后执行的语句(除非发生语法错误)。 [1] 如果它是一个代码对象,它会被简单地执行。在所有情况下,代码 执行的预期作为文件输入有效(请参阅第 参考手册中的“文件输入”)。请注意returnyield 语句甚至不能在函数定义之外使用 在传递给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']

虽然,我认为更简单的方法是将命名空间传递给字典:

>>> 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 >=,将标准输出重定向到某个流会容易得多:

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

【讨论】:

  • 我得出了这个结论,你知道我可以从执行的语句中获取值的方法吗?这是我的教授明确要求的
  • 它到底说了什么?你不能,AFAIK。
  • 我上去复制问题中的内容,然后意识到我忘了放。我是python新手,所以我不完全理解这个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]的含义
  • @sbowde4 好的,我想我知道你想要什么。这是一个非常奇怪的任务。你应该试着理解我在这里做了什么......
  • 谢谢,我正在阅读并努力理解它。即使我们刚开始学习这门语言,我们与这位教授的所有作业都很奇怪而且通常很复杂。
猜你喜欢
  • 2019-06-14
  • 2016-12-13
  • 2016-11-26
  • 1970-01-01
  • 2021-01-17
  • 2011-06-15
  • 2014-02-11
  • 2020-07-30
  • 2012-08-22
相关资源
最近更新 更多