当应用于新类型的代码时 Exec 失败

grz*_*ześ 7 python python-3.x

我有一个multiply.py包含以下内容的文件:

from typing import NamedTuple

class Result(NamedTuple):
    product: int
    desc: str

def multiply(a: int, b: int) -> Result:
    return Result(
        product=a * b,
        desc=f"muliplied {a} and {b}",
    )

x=4
y=5
print(multiply(x, y))

Run Code Online (Sandbox Code Playgroud)

如果我像这样运行它,它当然会产生预期的结果:

$ python multiply.py 
Result(product=20, desc='muliplied 4 and 5')
Run Code Online (Sandbox Code Playgroud)

exec不过我正在尝试使用以下函数运行它main.py

from pathlib import Path

gl, lo = {}, {}
exec(Path("multiply.py").read_text(), gl, lo)
Run Code Online (Sandbox Code Playgroud)

这次的输出令人失望:

$ python main.py 
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    exec(Path("multiply.py").read_text(), gl, lo)
  File "<string>", line 16, in <module>
  File "<string>", line 9, in multiply
NameError: name 'Result' is not defined

Run Code Online (Sandbox Code Playgroud)

这是为什么?我不能在执行的代码中创建新类型吗exec

jua*_*aga 5

由于您要从文档中传递本地变量和全局变量的两个不同的字典:

如果exec获取两个单独的对象作为全局对象和局部对象,则代码将像嵌入类定义中一样执行

类体不是封闭范围,类体中定义的函数无法访问类体中定义的变量。self.这就是在方法定义中必须用来引用另一个方法的原因。

为了详细说明我的意思self,这里有一个实际运行类主体中的代码并查看其行为的示例:

In [1]: class NS:
   ...:     from typing import NamedTuple
   ...:
   ...:     class Result(NamedTuple):
   ...:         product: int
   ...:         desc: str
   ...:
   ...:     def multiply(a: int, b: int) -> Result:
   ...:         return Result(
   ...:             product=a * b,
   ...:             desc=f"muliplied {a} and {b}",
   ...:         )
   ...:
   ...:

In [2]: NS.multiply(1, 2)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [2], line 1
----> 1 NS.multiply(1, 2)

Cell In [1], line 9, in NS.multiply(a, b)
      8 def multiply(a: int, b: int) -> Result:
----> 9     return Result(
     10         product=a * b,
     11         desc=f"muliplied {a} and {b}",
     12     )

NameError: name 'Result' is not defined
Run Code Online (Sandbox Code Playgroud)

无论如何,exec这是一个通常被误用的函数。有时它是完全没问题的,但通常情况是,当人们寻求exec/时eval,有更好的方法可以用 Python 来实现。