如何退出if子句


104

有哪些方法可以过早退出if子句?

有时候,我在编写代码时希望将一条break语句放在一个if子句中,只是要记住,这些语句只能用于循环。

让我们以以下代码为例:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   ...
   if condition_b:
       # do something
       # and then exit the outer if block
   # more code here

我可以想到一种方法:假设退出情况发生在嵌套的if语句内,请将其余代码包装在一个大else块中。例:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   else:
       ...
       if condition_b:
           # do something
           # and then exit the outer if block
       else:
           # more code here

问题是更多的退出位置意味着更多的嵌套/缩进代码。

另外,我可以编写我的代码以使if子句尽可能小,并且不需要任何退出。

有人知道退出if子句的好/更好的方法吗?

如果存在任何关联的else-if和else子句,我认为退出将跳过它们。


2
对于您的第二个代码示例-您知道elif吗?
Craig McQueen 2010年

2
“或者,我可以编写我的代码以使if子句尽可能小,并且不需要任何退出。” -当然,这将是最好的做法。:-)
米哈尔Marczyk

2
@克雷格·麦昆(Craig McQueen):是的,但是我想让条件语句之间执行代码吗?例如if a: #stuff; #stuff_inbetween; if b: #stuff;中间代码依赖not a但不依赖b
罗曼(Roman)2010年

你好,请不要忘记elif stackoverflow.com/a/2069680/7045119
kerbrose

Answers:


99

(此方法适用于ifs,多个嵌套循环和您break不易使用的其他构造。)

将代码包装在自己的函数中。代替break使用return

例:

def some_function():
    if condition_a:
        # do something and return early
        ...
        return
    ...
    if condition_b:
        # do something else and return early
        ...
        return
    ...
    return

if outer_condition:
    ...
    some_function()
    ...

4
我很高兴为您添加更多的程序员技巧。以我的经验,这种方法几乎在您每次尝试使用向前移动goto时都有效。(并且它暗示并解决了单个功能太大的情况)
Drew Dormann 2010年

2
理想情况下,您可以同时实现这两者,但是有时必须为了良好的性能而交换良好的代码。那些日子很少见,尤其是当您考虑使用Python时。换句话说:不要太担心函数调用开销。
短暂

17
有一个古老的轶事:“ Dennis Ritchie告诉所有人,杂项鼓励了模块化,在C语言中函数调用确实非常便宜。每个人都开始编写小型函数并进行模块化。多年之后,我们发现在PDP-11上函数调用仍然很昂贵,而VAX代码通常将其时间的50%花费在CALLS指令上。丹尼斯对我们撒谎!但是为时已晚;我们都被钩住了……”
短暂

1
@ephemient:很好笑,这个故事还有更多吗?我想读整本书。
罗曼(Roman)2010年

4
引用来自《 Unix编程的艺术》一书的第4章(在线位于faqs.org/docs/artu)。如果您以前从未读过,那么您真的应该阅读整本书。
短暂

55
goto导入goto,标签

如果有条件:
   ...
   如果condition_a:
       # 做一点事
       #然后退出外部if块
       转到.end
   ...
   如果condition_b:
       # 做一点事
       #然后退出外部if块
       转到.end
   #更多代码在这里

标签.end

(请不要实际使用它。)


35
+1,因为这很有趣。谷歌搜索向我透露这是愚人节的笑话模块。
罗马2010年

2
我也链接了它。单击第一个goto
短暂

1
这让我想起了具有各种分支功能的汇编代码:)
phunehehe 2010年

2
@ephemient:啊,没有注意到链接。认为这是代码突出显示。但现在,我看你的代码,我没有看到任何真正的高亮回事..
罗马

1
当PHP引入goto时,我转向了Python php.net/manual/en/control-structures.goto.php
Marc

25
while some_condition:
   ...
   if condition_a:
       # do something
       break
   ...
   if condition_b:
       # do something
       break
   # more code here
   break

3
哦,嘿,我真的很喜欢这个主意。我认为这完全可以解决我的初衷。但是,我有一个this的感觉,那就是这不是一个好习惯(因此,我将保留当前接受的答案,因为它可以促进良好的编码风格)。
罗马

6
请注意,您可以保留if并将其包装在while True:。只要确保break在末尾声明即可!对于使用do-while构造的语言,它更像是偶合的:do { code that can conditionally break out } while (false);
Thomas Eding 2010年

10

您可以使用以下方法模拟goto的功能:

try:
    # blah, blah ...
    # raise MyFunkyException as soon as you want out
except MyFunkyException:
    pass

免责声明:我只是想提醒您注意以这种方式做事的可能性,而在正常情况下,我绝不认为这样做是合理的。正如我在对该问题的评论中所提到的那样,到目前为止,最好构造代码以便避免拜占庭条件。:-)


哈哈,我喜欢这个创造性的解决方案。虽然我会遵守您的免责声明,但不要使用这种时髦的代码。
罗曼(Roman)2010年

@Roman:很高兴在Shmoopty的基础上再加上一个技巧-即使在比较时我很调皮。;-)
米哈尔Marczyk

8

可能是这个吗?

if some_condition and condition_a:
       # do something
elif some_condition and condition_b:
           # do something
           # and then exit the outer if block
elif some_condition and not condition_b:
           # more code here
else:
     #blah
if

1
是的,那可能有效。我认为elif在撰写本文时,我的头脑有些茫然。尽管我认为这在我希望代码在嵌套的if语句之间执行的情况下不起作用。
罗曼(Roman)2010年

这实际上是正确的答案。为什么我看不到有人推荐这个?:)
kerbrose

6

对于实际提出的要求,我的方法是将这些ifs放入一个单循环的循环中

while (True):
    if (some_condition):
        ...
        if (condition_a):
            # do something
            # and then exit the outer if block
            break
        ...
        if (condition_b):
            # do something
            # and then exit the outer if block
            break
        # more code here
    # make sure it is looped once
    break

测试一下:

conditions = [True,False]
some_condition = True

for condition_a in conditions:
    for condition_b in conditions:
        print("\n")
        print("with condition_a", condition_a)
        print("with condition_b", condition_b)
        while (True):
            if (some_condition):
                print("checkpoint 1")
                if (condition_a):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 2")
                    break
                print ("checkpoint 3")
                if (condition_b):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 4")
                    break
                print ("checkpoint 5")
                # more code here
            # make sure it is looped once
            break

1
老实说,这是最干净的解决方案。很清楚何时退出代码-您不必担心函数内部的函数作用域,并且零性能或逻辑负担。
特伦特

2
可能考虑使用for _ in range(1):而不是while True:。(1)更好地传达您对单个迭代循环的意图,以及(2)没有最后一个break语句退出循环(稍后可能会被意外删除)
Bernhard Kausler,

3

一般来说,不要。如果要嵌套“ if”并从中断开,则说明这样做是错误的。

但是,如果您必须:

if condition_a:
   def condition_a_fun():
       do_stuff()
       if we_wanna_escape:
           return
   condition_a_fun()
if condition_b:
   def condition_b_fun():
       do_more_stuff()
       if we_wanna_get_out_again:
           return
   condition_b_fun()

注意,这些函数不必在if语句中声明,可以提前声明它们;)这将是一个更好的选择,因为它将避免以后再重构一个丑陋的if / then。


感谢你的回答。我不确定“嵌套循环”是什么意思。如果您提到我提到的关键字“ break”,我只是想通过将它与循环退出的存在进行比较来激发我对if-exit的搜索。另外,我不确定你的代码是如何解决这个问题,因为我的例子有if condition_a,并if condition_b嵌套在if some_condition。我希望能够脱颖而出if some_condition
罗马2010年

人们想要嵌套if并破坏它们的原因可能不是因为他们做错了,而是因为他们想编写干净的简单DRY代码。一个简单的情况是,当条件_a和条件_b都满足时,程序需要执行x(),并且仅对条件_a需要执行y(),而对条件_b仅需要执行z()。和编码器拒绝多次写入x()
izzulmakin

1

实际上,您所描述的是goto语句,通常会对其进行大量平移。您的第二个示例更容易理解。

但是,清洁器仍然是:

if some_condition:
   ...
   if condition_a:
       your_function1()
   else:
       your_function2()

...

def your_function2():
   if condition_b:
       # do something
       # and then exit the outer if block
   else:
       # more code here

1

还有另一种方法不依赖于定义函数(因为有时对于小的代码片段而言,其可读性较低),不使用额外的外部while循环(可能需要对注释进行特殊理解,以便乍一看也可以理解) ,不使用goto(...),最重要的是,如果不需要,则让您保持外部的缩进级别。

if some_condition:
   ...
   if condition_a:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if: # if and only if exit_if wasn't set we want to execute the following code
   # keep doing something
   if condition_b:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if:
   # keep doing something

是的,这还需要重新审视其可读性,但是,如果代码段很小,则不需要跟踪任何永远不会重复的while循环,并且在了解了中间if的含义之后,它很容易阅读,所有内容一个位置并具有相同的缩进。

而且它应该非常有效。


0

所以在这里我了解到您正在尝试突破外部if代码块

if some_condition:
    ...
    if condition_a:
       # do something
       # and then exit the outer if block
       ...
    if condition_b:
       # do something
       # and then exit the outer if block
# more code here

一种解决方法是,您可以在外部if块中测试是否存在错误条件,然后隐式退出代码块,然后使用else块嵌套其他ifs以执行某些操作

if test_for_false:
    # Exit the code(which is the outer if code)

else:
    if condition_a:
        # Do something

    if condition_b:
        # Do something

0

无需其他方法即可应用此功能的唯一elif示例是以下示例

a = ['yearly', 'monthly', 'quartly', 'semiannual', 'monthly', 'quartly', 'semiannual', 'yearly']
# start the condition
if 'monthly' in b: 
    print('monthly') 
elif 'quartly' in b: 
    print('quartly') 
elif 'semiannual' in b: 
    print('semiannual') 
elif 'yearly' in b: 
    print('yearly') 
else: 
    print('final') 

-1

这是处理此问题的另一种方法。它使用单个项目进行循环,使您可以仅使用continue。它避免了不必要的不​​必要的额外功能。并且另外消除了潜在的无限while循环。

if something:
    for _ in [0]:
        # Get x
        if not x:
            continue

        # Get y
        if not y:
            continue

        # Get z
        if not z:
            continue

        # Stuff that depends on x, y, and z

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.