gpt4 book ai didi

python - 关于我在其他地方找不到答案的 Python 'yield' 关键字的问题,以及它在我正在处理的代码中的具体用途

转载 作者:太空宇宙 更新时间:2023-11-04 01:08:57 28 4
gpt4 key购买 nike

我遇到了一个交给我的有效的 python 脚本。我理解该脚本的目的及其在与其他模块交互的大局中的作用,以及它在大多数地方的内部架构。但是,我必须对该脚本进行大修,主要是删除一些旧类并添加大量新子类,以便它提供我们需要的更多功能。我的问题主要来自于我所看到的某些函数返回包含该对象的列表与 yield 之间存在一些无法解释的差异。将该对象返回到自身。

# These functions are methods that belong to a class. 
# There is a top level script that instantiates that class and calls
# these methods on that class, and depending on the `self.mode` variable located in the instance namespace, it invokes the different subsequent methods,
# which are either generateHybridSim() or generatePureHwSim()
# It is worth pointing out here that HybridSimStep and ShangHWSimStep
# are both classes themselves and that they will be instantiated later on as
# I will describe after this chunk of code

def generateSubTests(self) :
if self.mode == TestStep.HybridSim :
return self.generateHybridSim()
elif self.mode == TestStep.PureHWSim or self.mode == TestStep.AlteraSyn \
or self.mode == TestStep.AlteraNls or self.mode == TestStep.XilinxSyn :
return self.generatePureHWSim()

return []

def generateHybridSim(self) :
return [ HybridSimStep(self) ]

def generatePureHWSim(self) :
yield ShangHWSimStep(self)
num_iter = self.max_scheduling_iterations
if num_iter > 1 :
for i in range(1) :
sim_step = ShangHWSimStep(self)
sim_step.option = self.option.copy()
sim_step.hls_base_dir = os.path.join(sim_step.hls_base_dir, str(i))
sim_step.rtl_output = os.path.join(sim_step.hls_base_dir, sim_step.test_name + ".sv")
sim_step.option['max_scheduling_iterations'] = i + 1
yield sim_step

最终,无论 generateHybridSim() 是否或 generatePureHwSim()方法被调用时,它们都以完全相同的方式在另一个模块中被调用:

# The 'job' that is in front of generateSubTests() is the instance's
# variable name, and you can see that prepareTest() and runTest()
# methods get called on the subtest iterable object, which so happens
# to be class's instance.
# So in short, these two methods are not defined within generateSubTests() method, but
# rather under the classes that the generateHybridSim() and
# generatePureHWSim() methods had returned or yielded respectively.

for subtest in job.generateSubTests() :
subtest.prepareTest()
subtest.runTest()
time.sleep(1)
next_active_jobs.append(subtest)

我现在真的很迷茫,不知道使用yield有什么意义?这里与 return ,我需要弄清楚为什么以前写这个脚本的程序员会那样做。这是因为我将实现新的子类,这些子类本身必须包含自己的 generateSubTests()方法并且必须遵循相同的函数调用。他所做的事实for subtest in job.generateSubTests意味着我只能返回一个包含类的列表,或者生成类本身,否则它不适合 python for 循环迭代协议(protocol)。我尝试通过修改 yield 来测试代码generatePureHWSim() 中的陈述至 returngenerateHybridSim() 中的那些它似乎运行良好,尽管我不确定是否引入了任何细微的错误。但是,我不知道我是否在这里遗漏了什么。以前的程序员是不是想促进并发http://www.dabeaz.com/coroutines/index.html通过使用 yield 将函数转换为生成器?

他已经完全离开了我们的实验室,所以我无法向他寻求帮助。

另外,我已经阅读了 yield来自各种来源,包括帖子: What does the "yield" keyword do in Python? ;尽管他们帮助我理解了 yield 的作用,但我仍然不明白在这里使用它对我们的上下文有何帮助。事实上,我什至不明白为什么以前的程序员要用for subtest in job.generateSubTests() :来实现一个循环。并强制 generatePureHWSim()generateHybridSim()方法本身必须是生成器,这样我们就可以有一个循环来调用 prepareTest() 的其他方法。和 runTest()在实例上。为什么他不能直接返回类并调用那些方法???

这真让我失望。我将非常感谢这里的任何帮助!!!谢谢。

PS:还有一个问题 - 我注意到,一般来说,如果您有一个函数定义为:

def a():
return b
print "Now we return c"
return c

似乎每当执行其中的第一条语句时,b被返回,然后函数完成执行并且c永远不会返回,因为 return b 之后的声明永远不会被触及。尝试添加打印语句,您会发现它永远不会被打印出来。

然而,当谈到yield时:

def x():
yield y
print "Now we yield z"
yield z

我注意到即使在第一个 yield y 之后语句已经执行,后续yield z将被执行。尝试添加 print 语句,您会看到它被打印出来了。这是我在调试上述代码时观察到的,我不理解 yield 之间的这种行为差异。和 return .有人可以启发我吗?

谢谢。

最佳答案

我很高兴地告诉您,这不涉及并发。

之前的程序员希望generateSubTests 返回一组子测试(可能是 0、1 或更多子测试)。然后将在 for subtest in job.generateSubTests(): 循环中相应地处理每个子测试。

实际上,如果您仔细观察,generateHybridSim 会返回一个包含一个子测试的普通 Python 列表,而不是生成器对象。但列表和生成器对象在这种情况下实际上是非常相似的东西 - 一系列子测试。

您必须意识到 generatePureHWSim(self) 几乎等同于以下代码:

def generatePureHWSim(self) :
output_list = []
output_list.append(ShangHWSimStep(self))
num_iter = self.max_scheduling_iterations
if num_iter > 1 :
for i in range(1) :
sim_step = ShangHWSimStep(self)
sim_step.option = self.option.copy()
sim_step.hls_base_dir = os.path.join(sim_step.hls_base_dir, str(i))
sim_step.rtl_output = os.path.join(sim_step.hls_base_dir, sim_step.test_name + ".sv")
sim_step.option['max_scheduling_iterations'] = i + 1
output_list.append(sim_step)
return output_list

但有一个异常(exception)。虽然上面的代码预先进行了所有计算并将所有结果放入内存中的列表中,但带有 yield 的版本将立即产生单个子测试,并且仅在要求下一个结果时才进行以下计算.

这有很多潜在的好处,包括:

  1. 节省内存(数据一次只加载一个,而不是一次加载到列表中)
  2. 节省计算(如果您可以根据返回的内容提前跳出循环)
  3. 以不同的顺序对副作用进行排序(个人不推荐,这会使代码推理变得非常困难)。

关于您的第二个问题,正如您观察到的那样,当您点击 return 语句时,Python 函数中的执行结束。在同一代码块中的 return 语句之后放置更多代码是没有意义的。

yield 做的事情稍微复杂一些,因为它返回一个更接近列表的生成器对象。

下面的代码:

def generator_example():
yield 1
print "x"
yield 2

真的不能与:

def return_example():
return 1
print "x"
return 2

但更接近于:

def list_example():
output_list = []
output_list.append(1)
print "x"
output_list.append(2)
return output_list

generator_examplelist_example 都返回一个可以使用 for 循环迭代的序列。

对代码的无关注释

虽然下面的部分很奇怪。

  if num_iter > 1 :
for i in range(1) :
sim_step = ShangHWSimStep(self)

没有理由使用 for i in range(1),它只循环一次,i 设置为 0。我将删除 for i in range(1) 位,缩进代码并将所有出现的 i 替换为 0,或者更好的是,重命名 i 以提供更多信息并将其明确设置为 0 .

关于python - 关于我在其他地方找不到答案的 Python 'yield' 关键字的问题,以及它在我正在处理的代码中的具体用途,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28846032/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com