如何在Python中使用exec() - 您需要知道的一切
#编程 #教程 #python #functions

Python中的exec()函数使我们能够从字符串中执行Python代码块。当我们需要动态生成的Python代码时,Python中的此内置功能可能会派上用场。 >

在本教程中,我们将学习

  • 如何使用Python的exec()函数

  • 如何使用代码示例使用exec()函数执行Python代码

  • 从字符串和Python源文件执行Python代码

  • 使用globalslocals参数

Python的exec()函数

python的exec()函数使我们能够执行任何代码多大或小的代码。此功能有助于我们执行动态生成的代码

想想一个python解释器,该解释器会采用代码,内部处理并执行它,exec()函数也可以做到这一点。就像一个独立的Python解释器。

exec()能够执行简单的Python程序以及完整的Python程序。它可以执行函数调用和定义,类定义和实例,导入等等。

句法

exec(object [ , globals [ , locals]])
  • object-必须是字符串代码对象。如果是字符串,则将其解析为 python语句的套件,除非发生语法错误,否则将执行。如果是代码对象,则只需执行。

  • globalslocals-这使我们能够提供代表全局和本地名称空间的字典。

返回值

exec() 函数的返回值是。这可能是因为每个代码都没有最终结果。

最初的目光

这是对exec()函数的工作的初步观察。

obj = ["apple", "cherry", "melon", "strawberry"]
code = "print([sliced[:4] for sliced in obj if 'a' not in sliced])"

exec(code)

.........
['cher', 'melo']

使用exec()函数的另一个示例

# The code will continuously run and we can run our code as we do in 
# Python interpreter 
while True:
    exec(input(">>> "))
>>> print("Welcome to GeekPython")
Welcome to GeekPython

>>> import numpy as np
>>> print(np.random.randint(16, size=(2, 4)))
[[11 13  3 13]
 [ 7  6 15  5]]

>>> x = ["apple", "banana", "cherry", "mango"]
>>> print([fruit for fruit in x if "a" not in fruit])
['cherry']

它的工作原理完全像python的解释器,使用我们的代码,内部处理,执行并返回正确的结果。

我们正在运行一个无限的循环,在其中,我们从命令行中获取输入并将其包装在exec()函数中以执行它。

从字符串输入执行代码

我们可以使用exec()函数执行字符串格式的代码。我们可以通过多种方式来构建基于字符串的输入:

  • 使用单线代码

  • 使用新系列字符

  • 使用适当格式的三重引用字符串

使用基于单线字符串的输入

在Python中,单线代码,也称为单线代码,是用单行编写的代码,可以同时执行多个任务。

如果我们编写了一行Python代码,则看起来像这样:

obj = ["apple", "cherry", "melon", "strawberry"]

print([sliced[:4] for sliced in obj if 'a' not in sliced])

输出

['cher', 'melo']

但是,如果我们使用exec()运行上述代码,则代码将为

obj = ["apple", "cherry", "melon", "strawberry"]

exec("print([sliced[:4] for sliced in obj if 'a' not in sliced])")
#-----------------------------OR--------------------------------
exec("code = [sliced[:4] for sliced in obj if 'a' not in sliced]")

我们上面编写的其他代码,如果我们执行它,则不会返回,而是将输出存储在code变量中,以供以后访问。

执行多行代码,由新行字符分开

我们可以使用新行字符\n在单线字符串中组合多个语句。

exec("square = int(input('Enter the number: '))\nprint(f'The square of {square}:', square**2)")

输出

Enter the number: 30
The square of 30: 900

定义了一个新的行字符(\n),以使exec()函数理解我们基于单线字符串的代码作为多行式的Python语句。

使用三重引用的字符串

在Python中,我们经常使用三引号来评论或记录我们的代码。但是,在这种情况下,我们将使用它来生成基于字符串的输入,外观和行为与普通Python代码完全一样。

我们在三重引号中编写的代码必须像普通的python代码一样正确缩进和格式。请参阅下面的示例以了解更好的理解。

sample_code = """

integers = [4, 7, 2, 9, 44]

def square(num):
    return num ** 2

def odd_num(num):
    return num % 2 == 1

square_if_even = [square(number) for number in integers if number % 2 == 0]

odd_number = [number for number in integers if odd_num(number)]

print("Original values:", integers)

print("Square of even number:", square_if_even)

print("Odd number:", odd_number)

"""
exec(sample_code)

输出

Original values: [4, 7, 2, 9, 44]
Square of even number: [16, 4, 1936]
Odd number: [7, 9]

上面的代码类似于标准的Python代码,具有适当的凹痕和格式,但它包裹在三引号中,从而在sample_code变量中存储了基于字符串的输入,然后使用exec()函数执行。

从Python文件执行代码

我们可以使用exec()函数通过使用open()函数读取文件的内容来从Python(.py)源文件执行代码。

考虑以下示例,其中包括包含以下代码的sample.py文件:

# sample.py
def anime(name):
    print(f"Favourite anime: {name}")

anime("One Piece")

list_of_anime = input("Enter your favourite anime: ").split(",")
print("Your Favourite anime:", list_of_anime)

代码只需在此处打印动漫的名称,而以下代码块将您喜欢的动漫的输入通过逗号分隔并打印所需的输出。

使用EXEC函数执行Python源文件

with open("sample.py", mode="r") as sample:
    file = sample.read()

exec(file)

输出

Favourite anime: One Piece
Enter your favourite anime: One Piece, Naruto, Demon Slayer, Jujutsu kaisen
Your Favourite anime: ['One Piece', ' Naruto', ' Demon Slayer', ' Jujutsu kaisen']

我们使用open()函数使用with语句将.py文件作为常规文本文件打开exec执行代码。

使用全球和当地人参数

这些参数完全是可选的。我们可以使用globalslocals参数来限制不需要的函数,方法和变量的使用。

由于这些参数是可选的,因此省略它们会导致exec()函数在当前范围中执行输入代码。考虑以下示例以更好地理解它。

code = """
out = str1 + str2
print(out)
"""
# global variables
str1 = "Hel"
str2 = "lo"

exec(code)

输出

Hello

上面的代码成功运行,并产生了将两个全局变量结合在一起的输出。由于未指定globalslocals参数,因此exec()函数执行了当前范围中的代码输入。在这种情况下,当前范围是全局

这是如何在当前代码范围中获取变量值的示例。

code = """
out = str1 + str2
print(out)
"""
# global variables
str1 = "Hel"
str2 = "lo"

print(out)
Traceback (most recent call last):
    .....
NameError: name 'out' is not defined. Did you mean: 'oct'?

在前面的代码中,我们试图在调用exec()之前访问out变量的值并收到错误。

但是,我们可以在调用exec()后访问OUT变量的值,因为代码输入中定义的变量将在拨打exec()之后在当前范围中可用。

exec(code)
print(out)

输出

Hello
Hello

使用 globalslocals参数

code = """
out = str1 + str2
print(out)
"""
# global variables
str1 = "Hel"
str2 = "lo"

exec(code, {"str1": str1})

输出

Traceback (most recent call last):
    ....
NameError: name 'str2' is not defined. Did you mean: 'str1'?

代码返回错误,因为我们没有定义字典中的str2键,因此exec()无法访问它。

code = """
out = str1 + str2
print(out)
"""
# global variables
str1 = "Hel"
str2 = "lo"

exec(code, {"str1": str1, "str2": str2})

print(out)

输出

Hello
Traceback (most recent call last):
     ....
NameError: name 'out' is not defined. Did you mean: 'oct'?

现在,exec()函数可以访问这两个全局变量,并且代码返回输出而不会出错,但是这次我们无法访问拨打exec()之后,因为我们使用自定义字典来提供exec()的执行范围。

以下是将localsglobals一起使用的示例

code = """
out = str1 + str2 + " " + x
print(out)
"""
# global variables
str1 = "Hel"
str2 = "lo"

def local():
    # local variable
    x = "there"
    exec(code, {"str1": str1, "str2": str2}, {"x": x})

local()

输出

Hello there

在上面的代码中,我们从本地函数中调用了exec()。在全局范围中,我们在局部范围(函数级别)中具有全局变量和局部变量。 Globals参数指定变量str1str2,而当地人参数指定变量x

阻止不必要的方法和变量

使用globalslocals params,我们可以控制代码输入中是否限制或使用任何变量或方法。在本节中,我们将限制Python的datetime模块中的一些功能。

from datetime import *

code = """
curr_time = datetime.now()
print(curr_time)
"""
exec(code, {})

输出

Traceback (most recent call last):
     ....
NameError: name 'datetime' is not defined

我们限制了datetime模块的datetime方法的使用,这导致了错误。

使用必要的方法和变量

我们只能使用exec()所需的方法。

from datetime import *

# Allowing only two methods
allowed_param = {'datetime': datetime, 'timedelta': timedelta}

exec("print(datetime.now())", allowed_param)
exec("print(datetime.now() + timedelta(days=2))", allowed_param)

# date() method is not allowed
exec("print(date(2022, 9, 4))", allowed_param)

输出

2022-10-15 18:40:44.290550
2022-10-17 18:40:44.290550

Traceback (most recent call last):
     ....
NameError: name 'date' is not defined

由于不允许使用date方法,因此发生了错误。除两种方法(datetimetimedelta)外,禁止使用datetime模块中的所有方法。

让我们看看globalslocals参数还能完成什么。

from datetime import *

# Setting globals parameter to __builtins__
globals_param = {'__builtins__': __builtins__}

# Setting locals parameter to take only print(), slice() and dir()
locals_param = {'print': print, 'dir': dir, 'slice': slice}

exec('print(slice(2))', globals_param, locals_param)
exec('print(dir())', globals_param, locals_param)

输出

slice(None, 2, None)
['dir', 'print', 'slice']

exec()函数中,只能执行slice()方法和所有内置方法。即使slice()方法不是来自datetime模块,它在这里工作得很完美。

我们还可以通过将其设置为None来限制__builtins__的使用。

from datetime import *

# Setting globals parameter to none
globals_param = {'__builtins__': None}

# Setting locals parameter to take only print(), slice(), sum() and dir()
locals_param = {'print': print, 'dir': dir, 'slice': slice, 'sum': sum}

# Allowed methods directory
exec('print(dir())', globals_param, locals_param)
exec('print(f"Sum of numbers: {sum([4, 6, 7])}")', globals_param, locals_param)

输出

['dir', 'print', 'slice', 'sum']
Sum of numbers: 17

我们限制了__builtins__的使用,因此我们不能使用内置方法,只能执行printsumslicedir方法。

结论

我们已经学会了如何使用内置Python exec()函数从基于字符串的输入中执行代码。它允许您动态生成的Python代码。

我们学到的主题

  • 什么是exec()函数并使用它

  • 从基于字符串的输入和Python源文件执行Python代码

  • 了解globalslocals参数的使用

此外,我们已经编码了一些帮助我们更好地了解exec()功能的示例。


如果您喜欢这个

,您可能会感兴趣的其他文章

How to use assert statements to debug the code in Python

Upload and display images on the frontend using Flask in Python

Building a Flask image recognition webapp using a deep learning model

What is generator and yield keyword in Python

Public, Protected, and Private access modifiers in Python

How to build a CLI command in a few steps using argparse in Python

How to perform high-level file operations using shutil module in Python

How to scrape a webpage's content using BeautifulSoup in Python


这就是目前的全部

保持编码