如何在Python中编写C的do-while(0)?

时间:2021-04-16 15:05:39

In C there's a clever trick that lets you avoid pyramid-style code by turning:

在C中有一个聪明的技巧,让你通过转向避免金字塔式代码:

if (check1())
  if (check2())
    if (check3())
      do_something();

into:

成:

do {
  if (!check1())
    break;

  if (!check2())
    break;

  if (!check3())
    break;

  do_something();
} while (0);

What's the cleanest way for me to do this in Python, which doesn't have a do-while construct?

在Python中没有do-while构造的最简洁的方法是什么?

Note: I'm not necessarily asking for a way to implement a do-while loop in Python, but a technique to avoid the aforementioned pyramid-style code.

注意:我不一定要求在Python中实现do-while循环的方法,而是一种避免上述金字塔样式代码的技术。

Update: It seems there's some confusion. The only reason I'm using a loop is to be able to break out at any point in the body, which is only supposed to be executed once.

更新:似乎有一些混乱。我使用循环的唯一原因是能够在身体的任何一点突破,这应该只执行一次。

Essentially what I'm doing in Python is this:

基本上我在Python中做的是:

while True:
    if not check1():
        break

    if not check2():
        break

    if not check3():
        break

    do_domething()
    break

I'm just wondering if there's a cleaner way.

我只是想知道是否有更清洁的方式。

8 个解决方案

#1


-3  

In C, the use of the do ... while(0) construct that you have shown is usually used when the C programmer wants something that behaves like a goto, but using an actual goto is out of the question (for various reasons). So, the break out of the do ... while(0) is really a kind of hack. Using the same idiom in Python would be perpetuating that hack.

在C中,当C程序员想要一些行为类似于goto的东西时,通常会使用你所显示的do ... while(0)结构,但使用实际的goto是不可能的(出于各种原因) 。所以,do ... while(0)的突破实际上是一种黑客攻击。在Python中使用相同的习惯用法将使黑客行为永久化。

In C, I would generally avoid using this particular use of do ... while(0), and instead opt for a checking function. In Python, this would be:

在C中,我通常会避免使用do ... while(0),而是选择检查函数。在Python中,这将是:

def do_checks():
    if not check1():
        return False
    if not check2():
        return False
    if not check3():
        return False
    return True

if do_checks():
    do_something()

Probably the most direct translation of C's do ... while(0) construct would be a loop with a single iteration. Don't do this.

可能是C的最直接的转换... while(0)构造将是一个循环,只有一次迭代。不要这样做。

for x in range(1):
    if not check1():
        break
    if not check2():
        break
    if not check3():
        break
    do_something()

#2


7  

The Pythonic way of writing this would be

Pythonic的写作方式是

if check1() and check2() and check3():
    do_something()

In Python we emphasize clarity and simplicity of the code, not using clever programming tricks.

在Python中,我们强调代码的清晰性和简单性,而不是使用聪明的编程技巧。


[Edit] If you need to "create a variable and use it in the first check", then you would use the pyramid-style:

[编辑]如果您需要“创建变量并在第一次检查中使用它”,那么您将使用金字塔样式:

if check1():
    #variables and stuff here
    if check2():
        #variables and stuff here
        if check3():
            doSomething()

Or, as @Blender suggests, refactor it into a separate method. These are all much simpler and clearer ways of communicating your intent than using a loop that's not intended to loop.

或者,正如@Blender建议的那样,将其重构为一个单独的方法。与使用不打算循环的循环相比,这些都是更简单,更清晰的方式来传达您的意图。

#3


5  

Invert your conditions and break out early. If you structure your code well, you won't have to worry about if staircases in the first place:

颠倒你的条件,尽早爆发。如果你很好地构建你的代码,你不必担心第一个阶段是否有阶梯:

def do_bigger_something():
    if not check1():
        return

    if not check2():
        return

    if not check3():
        return

    do_something()

There's a good chance that if one portion of your code does a lot of these checks, it should be turned into a function anyways.

很有可能如果你的代码的一部分做了很多这些检查,那么它应该转变成一个函数。

#4


2  

if (check1() and check2() and check3()):
    do_something()

#5


1  

  if check1() and  check2() and  check3():  
         do_something()

#6


1  

I'd say if the checks are not as trivial as this (which can be done with a simple and), refactor your code and break it out into a function instead of mis-using a loop for things it's not meant to do;

我会说,如果检查不是那么简单(可以用简单的方法完成),重构代码并将其分解为函数,而不是错误地使用循环来处理它本不应该做的事情;

def doSomethingIfConditions():

  if not check1():
    return

  if not check2():
    return

  if not check3():
    return

  doSomething()

...your code...
doSomethingOnConditions()
...your code...

#7


0  

Solution #1 (straightforward):

解决方案#1(直截了当):

while True:
    if not check1():
        break
    if not check2():
        break
    if not check3():
        break
    do_something()
    break

Solution #2 (more pythonic):

解决方案#2(更pythonic):

for check in check1, check2, check3:
    if not check():
        break
else:
    # the else part is only executed
    # if we didn't break out the loop
    do_something()

Solution #3 (even more pythonic):

解决方案#3(更加pythonic):

if all(c() for c in check1,check2, check3):
    # all(seq) will stop at the first false result
    do_something()

#8


0  

I do not see the need for a loop... You break out of it at the end anyways.

我没有看到需要一个循环...你最后还是打破了它。

if all((check1(), check2(), check3())):
    print "Do something"

Or just go with the block-style if it's needed.

或者如果需要,可以选择块式。

#1


-3  

In C, the use of the do ... while(0) construct that you have shown is usually used when the C programmer wants something that behaves like a goto, but using an actual goto is out of the question (for various reasons). So, the break out of the do ... while(0) is really a kind of hack. Using the same idiom in Python would be perpetuating that hack.

在C中,当C程序员想要一些行为类似于goto的东西时,通常会使用你所显示的do ... while(0)结构,但使用实际的goto是不可能的(出于各种原因) 。所以,do ... while(0)的突破实际上是一种黑客攻击。在Python中使用相同的习惯用法将使黑客行为永久化。

In C, I would generally avoid using this particular use of do ... while(0), and instead opt for a checking function. In Python, this would be:

在C中,我通常会避免使用do ... while(0),而是选择检查函数。在Python中,这将是:

def do_checks():
    if not check1():
        return False
    if not check2():
        return False
    if not check3():
        return False
    return True

if do_checks():
    do_something()

Probably the most direct translation of C's do ... while(0) construct would be a loop with a single iteration. Don't do this.

可能是C的最直接的转换... while(0)构造将是一个循环,只有一次迭代。不要这样做。

for x in range(1):
    if not check1():
        break
    if not check2():
        break
    if not check3():
        break
    do_something()

#2


7  

The Pythonic way of writing this would be

Pythonic的写作方式是

if check1() and check2() and check3():
    do_something()

In Python we emphasize clarity and simplicity of the code, not using clever programming tricks.

在Python中,我们强调代码的清晰性和简单性,而不是使用聪明的编程技巧。


[Edit] If you need to "create a variable and use it in the first check", then you would use the pyramid-style:

[编辑]如果您需要“创建变量并在第一次检查中使用它”,那么您将使用金字塔样式:

if check1():
    #variables and stuff here
    if check2():
        #variables and stuff here
        if check3():
            doSomething()

Or, as @Blender suggests, refactor it into a separate method. These are all much simpler and clearer ways of communicating your intent than using a loop that's not intended to loop.

或者,正如@Blender建议的那样,将其重构为一个单独的方法。与使用不打算循环的循环相比,这些都是更简单,更清晰的方式来传达您的意图。

#3


5  

Invert your conditions and break out early. If you structure your code well, you won't have to worry about if staircases in the first place:

颠倒你的条件,尽早爆发。如果你很好地构建你的代码,你不必担心第一个阶段是否有阶梯:

def do_bigger_something():
    if not check1():
        return

    if not check2():
        return

    if not check3():
        return

    do_something()

There's a good chance that if one portion of your code does a lot of these checks, it should be turned into a function anyways.

很有可能如果你的代码的一部分做了很多这些检查,那么它应该转变成一个函数。

#4


2  

if (check1() and check2() and check3()):
    do_something()

#5


1  

  if check1() and  check2() and  check3():  
         do_something()

#6


1  

I'd say if the checks are not as trivial as this (which can be done with a simple and), refactor your code and break it out into a function instead of mis-using a loop for things it's not meant to do;

我会说,如果检查不是那么简单(可以用简单的方法完成),重构代码并将其分解为函数,而不是错误地使用循环来处理它本不应该做的事情;

def doSomethingIfConditions():

  if not check1():
    return

  if not check2():
    return

  if not check3():
    return

  doSomething()

...your code...
doSomethingOnConditions()
...your code...

#7


0  

Solution #1 (straightforward):

解决方案#1(直截了当):

while True:
    if not check1():
        break
    if not check2():
        break
    if not check3():
        break
    do_something()
    break

Solution #2 (more pythonic):

解决方案#2(更pythonic):

for check in check1, check2, check3:
    if not check():
        break
else:
    # the else part is only executed
    # if we didn't break out the loop
    do_something()

Solution #3 (even more pythonic):

解决方案#3(更加pythonic):

if all(c() for c in check1,check2, check3):
    # all(seq) will stop at the first false result
    do_something()

#8


0  

I do not see the need for a loop... You break out of it at the end anyways.

我没有看到需要一个循环...你最后还是打破了它。

if all((check1(), check2(), check3())):
    print "Do something"

Or just go with the block-style if it's needed.

或者如果需要,可以选择块式。