ChatGPT解决这个技术问题 Extra ChatGPT

如何打破多个循环?

给定以下代码(不起作用):

while True:
    # Snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok.lower() == "y": break 2 # This doesn't work :(
        if ok.lower() == "n": break

    # Do more processing with menus and stuff

有没有办法使这项工作?或者我是否需要进行一次检查以跳出输入循环,然后进行另一项更有限的检查,以在用户满意的情况下一起跳出外部循环?

为什么 Python 不只有“break(n)”,其中 n 是您想要突破的级别数。
如果您深陷于很多循环中,那么 C++ 与 goto 一起使用很不错
@Nathan 请参阅Why python don't natively allow a keyword like goto for breaking out of n loops nathan 的一个非常好的解释
Ned Batchelder 有一个针对 "How do I break out of two loops?" 的有趣演讲。剧透警报:将双环设为单环。

R
Robert Rossney

我的第一直觉是将嵌套循环重构为一个函数并使用 return 来突破。


这是我的另一个想法,因为 get_input_yn() 函数在其他地方也很有用,我敢肯定。
在这种特定情况下同意,但在“我有嵌套循环,我该怎么做”的一般情况下,重构可能没有意义。
通常可以将内部循环重构为自己的方法,返回 true 以继续,返回 false 以中断外部循环。 while condition1: / if not MyLoop2(params): break.另一种方法是设置一个布尔标志,在两个级别都进行测试。 more = True / while condition1 and more: / while condition2 and more: / if stopCondition: more = False / break / ...
我同意努力使用 return 是正确的方法。其理由是,根据Python 之禅,“扁平优于嵌套”。我们这里有三层嵌套,如果这开始妨碍,是时候减少嵌套或至少将整个嵌套提取到它自己的函数中。
我知道这似乎很明显,但是使用原始代码的示例可以改进这个答案。
C
Ciro Santilli Путлер Капут 六四事

这是另一种简短的方法。缺点是你只能打破外循环,但有时它正是你想要的。

for a in xrange(10):
    for b in xrange(20):
        if something(a, b):
            # Break the inner loop...
            break
    else:
        # Continue if the inner loop wasn't broken.
        continue
    # Inner loop was broken, break the outer.
    break

这使用了在 Why does python use 'else' after for and while loops? 中解释的 for / else 构造

关键见解:似乎外循环似乎总是中断。但是如果内循环没有中断,外循环也不会。

continue 语句在这里很神奇。它在 for-else 子句中。 By definition 如果没有内部中断,就会发生这种情况。在那种情况下,continue 巧妙地绕过了外部中断。


@RishitBansal 虽然这是一个深切:外部循环确实很重要,因为内部中断条件 something(a, b) 也取决于 a。只要 something(a, b) 不是 True,外部循环就可以运行。
这是从 Raymond Hettinger 的视频 youtu.be/OSGv2VnC0go?t=971 中得到的,将附加到 for 循环的“else”语句读为“no_break”,这样就更容易理解了。
这很聪明。 :-) 但是,不是直截了当的。坦率地说,我不相信将标签 break 或 break(n) 保留在 Python 之外的论点。变通办法增加了更多的复杂性。
这是非常有效和高效的。解决了我的问题,没有任何缺陷!
这在以下情况下不起作用。如果内部循环中有两个中断,一个打算只打破内部循环,而另一个打算打破两个循环
J
John Fouhy

PEP 3136 建议标记中断/继续。 Guido rejected it 因为“需要此功能的代码如此复杂非常罕见”。 PEP 确实提到了一些解决方法(例如异常技术),而 Guido 认为在大多数情况下使用 return 重构会更简单。


尽管 refactor/return 通常是要走的路,但我已经看到很多情况,其中一个简单简洁的“break 2”语句就非常有意义。此外,对于 continue,refactor/return 的工作方式不同。在这些情况下,数字 break 和 continue 比重构为一个微小的函数、引发异常或涉及在每个嵌套级别设置一个要中断的标志的复杂逻辑更容易遵循并且不那么混乱。很遗憾Guido拒绝了它。
break; break 会很好。
@Jeyekomon问题是你不需要3个或更多的嵌套循环来解决这个问题。 2个嵌套循环很常见
“如此复杂以至于需要此功能的代码非常罕见”。但是,如果您确实使用过这么复杂的代码,那么缺少标记循环会使它变得更加复杂,因为您必须手动将 break 转发到所有循环。愚蠢的。
显然,我只能编辑一个帖子 5 分钟(已经 6 分钟)。所以,这是我编辑的帖子:我的 2 美分:Perl 标记了 break(但称其为“最后一个”)和“下一个”以直接进行下一次迭代。这一点也不罕见 - 我一直在使用它。我是 Python 的新手,并且已经需要它。此外,编号的中断对于重构来说是可怕的 - 最好标记要中断的循环,然后使用 break
R
Russia Must Remove Putin

首先,普通逻辑是有帮助的。

如果由于某种原因无法确定终止条件,则例外是一种备用计划。

class GetOutOfLoop( Exception ):
    pass

try:
    done= False
    while not done:
        isok= False
        while not (done or isok):
            ok = get_input("Is this ok? (y/n)")
            if ok in ("y", "Y") or ok in ("n", "N") : 
                done= True # probably better
                raise GetOutOfLoop
        # other stuff
except GetOutOfLoop:
    pass

对于此特定示例,可能不需要例外。

另一方面,我们在字符模式应用程序中经常有“Y”、“N”和“Q”选项。对于“Q”选项,我们希望立即退出。那更不寻常。


说真的,异常非常便宜,而且惯用的 python 使用了很多。定义和抛出自定义的也很容易。
有趣的想法。我很纠结是喜欢还是讨厌。
如果该解决方案分别显示两个变体,则该解决方案将更有帮助。 (1) 使用标志 (done)。 (2) 引发异常。将它们合并成一个解决方案只会让它看起来很复杂。对于未来的读者:要么使用涉及 done 的所有行,要么定义 GetOutOfLoop(Exception) 并引发/除此之外。
一般来说,对于除异常之外的任何事情都使用 try-blocks 是非常不受欢迎的。 Try-blocks 是专门为错误处理而设计的,从风格上讲,将它们用于一些奇怪的控制流并不是很好。
@tommy.carstensen 那是胡说八道;定义一个新的异常子类并引发它(如答案所示)以及将自定义消息传递给 Exception 构造函数(例如 raise Exception('bla bla bla'))在 Python 2 和 Python 3 中都是有效的。在这种情况下,前者更可取因为我们不希望我们的 except 块捕获 所有 异常,而只捕获我们用来退出循环的特殊异常。如果我们按照您建议的方式做事,然后代码中的错误导致引发意外异常,则会被错误地视为故意退出循环。
M
Mark Dickinson

我倾向于同意重构为函数通常是这种情况的最佳方法,但是当你真的需要打破嵌套循环时,这里是异常引发方法的一个有趣变体@S.Lott 描述的。它使用 Python 的 with 语句使异常引发看起来更好一些。使用以下命令定义一个新的上下文管理器(您只需执行一次):

from contextlib import contextmanager
@contextmanager
def nested_break():
    class NestedBreakException(Exception):
        pass
    try:
        yield NestedBreakException
    except NestedBreakException:
        pass

现在您可以按如下方式使用此上下文管理器:

with nested_break() as mylabel:
    while True:
        print "current state"
        while True:
            ok = raw_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": raise mylabel
            if ok == "n" or ok == "N": break
        print "more processing"

优点:(1) 它稍微干净一些(没有显式的 try-except 块),以及 (2) 每次使用 nested_break 都会获得一个定制的 Exception 子类;无需每次都声明您自己的 Exception 子类。


k
krvolok

引入一个您将用作“循环断路器”的新变量。首先为它分配一些东西(False,0,等等),然后在外部循环中,在你从中中断之前,将值更改为其他东西(True,1,...)。一旦循环退出,让“父”循环检查该值。让我演示一下:

breaker = False #our mighty loop exiter!
while True:
    while True:
        if conditionMet:
            #insert code here...
            breaker = True 
            break
    if breaker: # the interesting part!
        break   # <--- !

如果你有一个无限循环,这是唯一的出路;对于其他循环的执行确实要快得多。如果您有许多嵌套循环,这也适用。您可以全部退出,也可以只退出一些。无限可能!希望这有帮助!


我认为最简单和最容易阅读的解决方案。感谢分享!
虽然这是最容易应用的,但当您有超过 2 个要退出的循环时,它会变得很麻烦。
这是被要求的[虽然是hacky]解决方案。谢谢你。
M
Matt J

首先,您还可以考虑将获取和验证输入的过程变成一个函数;在该函数中,如果它正确,您可以只返回该值,如果不正确,则继续在 while 循环中旋转。这基本上消除了您解决的问题,并且通常可以应用于更一般的情况(打破多个循环)。如果您绝对必须在代码中保留此结构,并且真的不想处理簿记布尔值...

您还可以通过以下方式使用 goto(使用来自 here 的愚人节模块):

#import the stuff
from goto import goto, label

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": goto .breakall
        if ok == "n" or ok == "N": break
    #do more processing with menus and stuff
label .breakall

我知道,我知道,“你不能使用 goto”等等,但它在像这样的奇怪情况下效果很好。


如果它类似于 INTERCAL 中的 COME FROM 命令,那么什么都没有
我喜欢这个笑话,但堆栈溢出的目的是促进好的代码,所以我不得不投票给你:(
我认为这是一个足够干净和可读的解决方案,可以称得上是好代码,所以我投了赞成票。 :)
@JTHurley 不,这不干净且不可读。我的意思是,在这个例子中它看起来很干净且可读,但在任何现实生活场景中,goto 都会造成一团糟。 (这也太反pythonic了……)
goto 的代表不好,我认为任何专业的编码人员都应该能够正确处理它。
J
Justas

要跳出多个嵌套循环,而不重构为函数,请使用带有内置 StopIteration exception 的“模拟 goto 语句”:

try:
    for outer in range(100):
        for inner in range(100):
            if break_early():
                raise StopIteration

except StopIteration: pass

请参阅 this discussion,了解使用 goto 语句打破嵌套循环。


这看起来比创建自己的类来处理异常要好得多,而且看起来非常干净。有什么理由我不应该这样做吗?
实际上 StopIteration 用于生成器,但我认为通常你没有任何未捕获的 StopIteration 异常。所以这似乎是一个很好的解决方案,但无论如何创建新异常并没有错误。
对我来说最好和最简单的解决方案
P
Peter Mortensen
keeplooping = True
while keeplooping:
    # Do stuff
    while keeplooping:
          # Do some other stuff
          if finisheddoingstuff():
              keeplooping = False

或类似的东西。

您可以在内循环中设置一个变量,并在内循环退出后立即在外循环中检查它,如果合适则中断。我有点喜欢 GOTO 方法,只要你不介意使用愚人节的笑话模块——它不是 Pythonic,但它确实有意义。


这是一种标志设置!
p
peterh

这不是最漂亮的方法,但在我看来,这是最好的方法。

def loop():
    while True:
    #snip: print out current state
        while True:
            ok = get_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": return
            if ok == "n" or ok == "N": break
        #do more processing with menus and stuff

我很确定您也可以在这里使用递归来解决问题,但我不知道这对您来说是否是一个不错的选择。


这对我来说是正确的解决方案。我的用例与 OP 的用例非常不同。我对本质上相同的数据进行了两次循环以查找排列,因此我不想将两个 while 循环分开。
P
Peter Mortensen

如果两个条件为真,则继续循环。

我认为这是一种更 Pythonic 的方式:

dejaVu = True

while dejaVu:
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y" or ok == "n" or ok == "N":
            dejaVu = False
            break

为什么不只是while dejaVu:?无论如何,您将其设置为true。
嘿,这行得通!我在考虑在两个 True 条件下跳过两个循环,但一个就足够了。
@MatthewScharley 我认为这是为了表明这在嵌套循环中有效。
@MauroAspé 这不会完全符合 OP 的要求。它仍将执行整个外循环,但目标是如果您中断其余代码将不会被执行
@yamm 不能用底部的 if not dejaVu: break 解决,从而退出主循环吗?我认为解决方案最接近所要求的。 +1
M
Muhammad Faizan Fareed

没有办法从语言层面做到这一点。有些语言有一个 goto 其他语言有一个带参数的中断,python 没有。最好的选择是:设置一个由外循环检查的标志,或设置外循环条件。将循环放在一个函数中,并使用 return 一次跳出所有循环。重新制定你的逻辑。

Credit goes to Vivek Nagarajan, Programmer since 1987

使用功能

def doMywork(data):
    for i in data:
       for e in i:
         return 

使用标志

is_break = False
for i in data:
   if is_break:
      break # outer loop break
   for e in i:
      is_break = True
      break # inner loop break

M
Matt Billenstein

将您的循环逻辑分解为一个迭代器,该迭代器产生循环变量并在完成后返回——这是一个简单的迭代器,它以行/列的形式排列图像,直到我们没有图像或无法放置它们:

def it(rows, cols, images):
    i = 0
    for r in xrange(rows):
        for c in xrange(cols):
            if i >= len(images):
                return
            yield r, c, images[i]
            i += 1 

for r, c, image in it(rows=4, cols=4, images=['a.jpg', 'b.jpg', 'c.jpg']):
    ... do something with r, c, image ...

这样做的好处是将复杂的循环逻辑和处理...


C
Community

Python while ... else 结构中有一个隐藏的技巧,可用于模拟双中断,而无需太多代码更改/添加。实质上,如果 while 条件为假,则触发 else 块。 continuebreak 都不会触发 else 块。有关详细信息,请参阅“Else clause on Python while statement”或 Python doc on while (v2.7) 的答案。

while True:
    #snip: print out current state
    ok = ""
    while ok != "y" and ok != "n":
        ok = get_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N":
            break    # Breaks out of inner loop, skipping else

    else:
        break        # Breaks out of outer loop

    #do more processing with menus and stuff

唯一的缺点是您需要将双重中断条件移动到 while 条件中(或添加标志变量)。 for 循环也存在这种变化,其中 else 块在循环完成后触发。


这似乎不符合双休的要求。适用于确切给定的问题,但不适用于实际问题。
@Dakkaron您确定您正确理解了代码吗?该代码确实解决了 OPs 问题,并且与请求类似。然而,它不会跳出多个循环,而是使用 else 子句来代替双倍中断的需要。
据我了解,问题是How to break out of multiple loops in Python?,答案应该是“它不起作用,试试别的”。我知道它修复了 OP 的确切给定示例,但没有回答他们的问题。
@Dakkaron,请参阅代码下的问题陈述,我认为它确实回答了 OPs 问题。
o
one_observation

将多个循环变成一个可破坏循环的简单方法是使用 numpy.ndindex

for i in range(n):
  for j in range(n):
    val = x[i, j]
    break # still inside the outer loop!

for i, j in np.ndindex(n, n):
  val = x[i, j]
  break # you left the only loop there was!

您确实必须索引到您的对象,而不是能够显式地遍历这些值,但至少在简单的情况下,它似乎比大多数建议的答案简单 2-20 倍。


L
Loax

在这种情况下,正如其他人所指出的那样,功能分解是要走的路。 Python 3 中的代码:

def user_confirms():
    while True:
        answer = input("Is this OK? (y/n) ").strip().lower()
        if answer in "yn":
            return answer == "y"

def main():
    while True:
        # do stuff
        if user_confirms():
            break

C
Community

另一种将迭代减少到单级循环的方法是使用在 python reference 中指定的生成器

for i, j in ((i, j) for i in A for j in B):
    print(i , j)
    if (some_condition):
        break

您可以将其扩展到循环的任意数量的级别

缺点是你不能再只打破一个级别。要么全有,要么全无。

另一个缺点是它不适用于 while 循环。我最初想在 Python - `break` out of all loops 上发布此答案,但不幸的是,该答案已作为此答案的副本关闭


它也适用于 while 循环,您只需要将生成器编写为 def(带有 yield),而不是理解。
是的,a speaker at a PyCon claims here 即使@RobertRossney 接受的答案也不是真正的 Pythonic,但生成器是打破多个循环的正确方法。 (我建议观看整个视频!)
u
user

我想提醒您,Python 中的函数可以在代码中间创建,并且可以透明地访问周围的变量以进行读取,并使用 nonlocalglobal 声明进行写入。

所以你可以使用一个函数作为一个“可破坏的控制结构”,定义一个你想要返回的地方:

def is_prime(number):

    foo = bar = number

    def return_here():
        nonlocal foo, bar
        init_bar = bar
        while foo > 0:
            bar = init_bar
            while bar >= foo:
                if foo*bar == number:
                    return
                bar -= 1
            foo -= 1

    return_here()

    if foo == 1:
        print(number, 'is prime')
    else:
        print(number, '=', bar, '*', foo)

>>> is_prime(67)
67 is prime
>>> is_prime(117)
117 = 13 * 9
>>> is_prime(16)
16 = 4 * 4

R
Rafiq

通过使用函数:

def myloop():
    for i in range(1,6,1):  # 1st loop
        print('i:',i)
        for j in range(1,11,2):  # 2nd loop
            print('   i, j:' ,i, j)
            for k in range(1,21,4):  # 3rd loop
                print('      i,j,k:', i,j,k)
                if i%3==0 and j%3==0 and k%3==0:
                    return  # getting out of all loops

myloop()

尝试通过注释掉 return 来运行上述代码。

不使用任何功能:

done = False
for i in range(1,6,1):  # 1st loop
    print('i:', i)
    for j in range(1,11,2):  # 2nd loop
        print('   i, j:' ,i, j)
        for k in range(1,21,4):  # 3rd loop
            print('      i,j,k:', i,j,k)
            if i%3==0 and j%3==0 and k%3==0:
                done = True
                break  # breaking from 3rd loop
        if done: break # breaking from 2nd loop
    if done: break     # breaking from 1st loop

现在,首先按原样运行上述代码,然后尝试通过注释掉包含 break 的每一行从底部开始运行。


M
MichaelChirico

尝试使用无限生成器。

from itertools import repeat
inputs = (get_input("Is this ok? (y/n)") for _ in repeat(None))
response = (i.lower()=="y" for i in inputs if i.lower() in ("y", "n"))

while True:
    #snip: print out current state
    if next(response):
        break
    #do more processing with menus and stuff

R
RufusVS
# this version uses a level counter to choose how far to break out

break_levels = 0
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_levels = 1        # how far nested, excluding this break
            break
        if ok == "n" or ok == "N":
            break                   # normal break
    if break_levels:
        break_levels -= 1
        break                       # pop another level
if break_levels:
    break_levels -= 1
    break

# ...and so on

R
RufusVS
# this version breaks up to a certain label

break_label = None
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_label = "outer"   # specify label to break to
            break
        if ok == "n" or ok == "N":
            break
    if break_label:
        if break_label != "inner":
            break                   # propagate up
        break_label = None          # we have arrived!
if break_label:
    if break_label != "outer":
        break                       # propagate up
    break_label = None              # we have arrived!

#do more processing with menus and stuff

F
Fateh

这是一个似乎可行的实现:

break_ = False
for i in range(10):
    if break_:
        break
    for j in range(10):
        if j == 3:
            break_ = True
            break
        else:
            print(i, j)

唯一的缺点是您必须在循环之前定义 break_


k
kcEmenike

我个人会做的是使用一个布尔值,当我准备好打破外循环时切换。例如

while True:
    #snip: print out current state
    quit = False
    while True:
        ok = input("Is this ok? (y/n)")
        if ok.lower() == "y":
            quit = True
            break # this should work now :-)
        if ok.lower() == "n":
            quit = True
            break # This should work too :-)
    if quit:
        break
    #do more processing with menus and stuff

S
Skycc

如果不喜欢重构为函数,可能像下面这样的小技巧会做

添加了 1 个 break_level 变量来控制 while 循环条件

break_level = 0
# while break_level < 3: # if we have another level of nested loop here
while break_level < 2:
    #snip: print out current state
    while break_level < 1:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": break_level = 2 # break 2 level
        if ok == "n" or ok == "N": break_level = 1 # break 1 level

h
helmsdeep

您可以定义一个变量(例如 break_statement ),然后在发生两次中断条件时将其更改为不同的值,并在 if 语句中使用它来中断第二个循环。

while True:
    break_statement=0
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N": 
            break
        if ok == "y" or ok == "Y": 
            break_statement=1
            break
    if break_statement==1:
        break

好点,但是在我们感兴趣的内部级别之上的每个级别中,我们都需要扫描该变量。在性能方面,该语言没有 GoTo 指令,感觉真的很糟糕。
N
Nathan Garabedian

我来这里的原因是我有一个外循环和一个内循环,如下所示:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

  do some other stuff with x

如您所见,它实际上不会转到下一个 x,而是会转到下一个 y。

我发现解决这个问题的方法只是遍历数组两次:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

for x in array:
  do some other stuff with x

我知道这是 OP 问题的一个具体案例,但我发布它是希望它能帮助人们以不同的方式思考他们的问题,同时保持简单。


这可能不是 Python。数组的类型是什么?可能是列表,但它包含什么?即使它包含整数, array.pop(x) 也可能不会做你想要的。
那是个很好的观点。我找不到我引用的代码。对于阅读本文的任何人,array.pop(i) “从数组中删除索引为 i 的项目并返回它。”根据python文档。因此,需要获取数组中项目 x 的索引才能使此代码按预期工作。还有一个 array.remove(x) 函数可以做预期的事情。我将修改上面的答案以修复该错误。这假设第二个数组不包含重复项,因为 array.remove(x) 只会删除找到的第一个 x 实例。
好的,那我明白了。在这种情况下,只需使用 break 而不是 continue 就可以满足您的要求,不是吗? :-)
是的,为了提高效率和清晰度,您可能希望在这些示例中使用 break 而不是 continue 。 :)
P
Peter Mortensen

两种方式的解决方案

举个例子:这两个矩阵是否相等/相同? matrix1 和 matrix2 是相同大小、n 的二维矩阵。

第一个解决方案,没有功能

same_matrices = True
inner_loop_broken_once = False
n = len(matrix1)

for i in range(n):
    for j in range(n):

        if matrix1[i][j] != matrix2[i][j]:
            same_matrices = False
            inner_loop_broken_once = True
            break

    if inner_loop_broken_once:
        break

第二种解决方案,具有功能

这是我的情况的最终解决方案。

def are_two_matrices_the_same (matrix1, matrix2):
    n = len(matrix1)
    for i in range(n):
        for j in range(n):
            if matrix1[i][j] != matrix2[i][j]:
                return False
    return True

t
thanos.a

为了尽量减少对 OP 问题的更改,我只是在中断第一个 for 循环之前添加了一个标志,并检查外循环上的该标志,看看我们是否需要再次制动。

break_2 = False
while True:
    # Snip: print out current state
    if break_2: break
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok.lower() == "y": break_2 = True
        if break_2: break
        if ok.lower() == "n": break
    # Do more processing with menus and stuff

你能描述一下你改变了什么吗?想法/要点是什么?来自 the Help Center“...总是解释为什么你提出的解决方案是合适的以及它是如何工作的”。请通过 editing (changing) your answer 回复,而不是在评论中(没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的)。
C
Charlie Clark

我最近遇到了这个问题,为了避免重复的 return 语句,它可以隐藏逻辑错误,查看了@yak 的想法。这在嵌套的 for 循环中效果很好,但不是很优雅。另一种方法是在下一个循环之前检查条件:

b = None
for a in range(10):
    if something(a, b): # should never = True if b is None
        break
    for b in range(20):
        pass

这可能不适用于任何地方,但具有适应性,并且如果需要,具有允许复制条件而不是潜在结果的优势。