如何使用“pass”语句?

432

我正在学习Python,目前已经学到了有关 pass 语句的部分。我的教程定义它是一个空语句,通常被用作占位符。

然而,我仍然不完全理解这意味着什么。在什么简单/基本的情况下需要使用 pass 语句,为什么需要使用它呢?


4
我从未在现实生活中需要过这样做,但是我可以想象在子类中覆盖一个方法并将其设为空操作时,可能会用到 pass 关键字。 - kojiro
3
@kojiro 例如,在进行编程时,有时候会用到https://en.wikipedia.org/wiki/Skeleton_(computer_programming)。 - Franck Dernoncourt
1
处理异常时非常方便。有时,异常意味着正常条件只需要不同类型的处理。在这种情况下,在except块中使用pass非常方便。 - Mad Physicist
18个回答

510

假设您正在设计一个新的类,其中有一些方法您暂时不想实现。

class MyClass(object):
    def meth_a(self):
        pass

    def meth_b(self):
        print "I'm meth_b"
如果省略了 pass ,代码将无法运行。
然后会出现以下错误:
IndentationError: expected an indented block

总之,pass语句并不做任何具体的操作,但可以作为一个占位符,正如此处演示的一样。


25
在这种情况下,也可以使用“return”,尽管会略微降低清晰度。 - user395760
48
我认为这并不能很好地回答问题。仅仅列举某个东西可能的用途,即使它是最常见的用途,也不等同于解释它的作用是什么。 - Schilcote
6
@Schilcote: 我理解你的观点了。我在我的初始回答中添加了另一个简短的解释。然而,我认为一个简单的例子通常有助于理解某个概念。 - sebastian_oe
4
@Anaphory的回答展示了为什么这是一项重要的语言要素。 - John
2
这解释了 pass 的一个用法,但我仍然不太明白它的作用。在生产代码中有用吗?从你的例子中,我会选择在准备好实现它之前不添加该方法,或者只是使用 return - theUtherSide
显示剩余6条评论

256

Python有一个语法要求,即代码块(在ifexceptdefclass等之后)不能是空的。然而,在许多不同的情况下,例如下面的例子中,空的代码块确实很有用。

因此,如果代码块中没有任何操作,就需要使用pass,以避免该块产生IndentationError错误。另外,任何语句(包括只是一个需要计算的术语,例如Ellipsis字面量...或字符串,通常是文档字符串)都可以使用,但pass清楚地表明确实没有任何操作需要执行,并且不需要实际计算和(至少暂时)存储在内存中。

  • 忽略某种类型的Exception(来自xml的示例):

 try:
     self.version = "Expat %d.%d.%d" % expat.version_info
 except AttributeError:
     pass # unknown

注意: 忽略所有类型的异常,如下面来自 pandas 的示例通常被认为是不好的实践,因为它也会捕获应该传递给调用者的异常,例如 KeyboardInterruptSystemExit(甚至是 HardwareIsOnFireError - 你怎么知道你没有在运行具有特定错误定义的自定义盒子上,某些调用应用程序想要了解这些错误?)。

 try:
     os.unlink(filename_larry)
 except:
     pass

相比于except Error:,在这种情况下更好的做法是使用except OSError:。对我安装的所有Python模块进行快速分析后发现,超过10%的except ...: pass语句捕获了所有异常,因此这仍然是Python编程中常见的模式。

定义一个不添加新行为的异常类(例如在SciPy中):

 class CompileError(Exception):
     pass

同样,作为抽象基类的类通常具有显式的空__init__或其他子类应该派生的方法(例如pebl):

 class _BaseSubmittingController(_BaseController):
     def submit(self, tasks): pass
     def retrieve(self, deferred_results): pass
  • 通过几个测试值来测试代码是否正确运行,不关心结果(来自mpmath):

  •  for x, error in MDNewton(mp, f, (1,-2), verbose=0,
                              norm=lambda x: norm(x, inf)):
         pass
    
  • 在类或函数定义中,通常已经有一个文档字符串作为唯一要在该块中执行的强制性语句。在这种情况下,为了表明“确实打算什么也不做”,该块可能包含pass 以补充文档字符串,例如在pebl中:

  •  class ParsingError(Exception):
         """Error encountered while parsing an ill-formed datafile."""
         pass
    
  • 在一些情况下,pass 被用作一个占位符来表示“这个方法/类/条件块还没有被实现,但是这将是实现它的地方”,不过我个人更喜欢用 Ellipsis 字面量 ... 来严格区分这种情况和前面例子中有意的“无操作”。(请注意,只有在 Python 3 中 Ellipsis 字面量才是有效的表达式

    例如,如果我粗略地编写一个模型,我可能会写:

     def update_agent(agent):
         ...
    

    别人可能会

     def update_agent(agent):
         pass
    

    之前

     def time_step(agents):
         for agent in agents:
             update_agent(agent)
    

    作为提醒,稍后填写update_agent函数,但是已经运行一些测试以查看其余代码是否按预期工作。(此情况的第三个选项是raise NotImplementedError。这对于两种情况特别有用:要么“每个子类都应该实现此抽象方法,并且在此基类中定义通用方法的方式不存在”,要么“此函数在此版本中尚未实现,但这是其签名将会是什么”)


  • 关于“省略号”(Ellipsis)的面包屑路径,请参考以下链接:https://mail.python.org/pipermail/python-3000/2008-January/011793.html - T Tse

    25

    除了作为未实现函数的占位符之外,pass 在填充 if-else 语句时也很有用(“显式优于隐式”)。

    def some_silly_transform(n):
        # Even numbers should be divided by 2
        if n % 2 == 0:
            n /= 2
            flag = True
        # Negative odd numbers should return their absolute value
        elif n < 0:
            n = -n
            flag = True
        # Otherwise, number should remain unchanged
        else:
            pass
    

    当然,在这种情况下,人们可能会使用 return 而不是赋值,但在需要修改的情况下,这种方法最有效。

    在此处使用 pass 特别有用,可以警告未来的维护者(包括您自己!)不要在条件语句之外放置冗余步骤。在上面的示例中,flag 在两个特定的情况下设置,但不在 else 语句中设置。如果没有使用 pass,将来的程序员可能会将 flag = True 移到条件之外 - 这样就会在所有情况下设置 flag


    另一种情况是经常看到的文件末尾的样板函数:

    if __name__ == "__main__":
        pass
    
    在某些文件中,保留 pass 可以让日后的编辑更加容易,并明确表明在单独运行该文件时不需要执行任何操作。
    最后提到,当捕获到异常时什么也不做也是有用的:
    try:
        n[i] = 0
    except IndexError:
        pass
    

    3
    我认为前两个例子通常都不是好的实践。关于第一个例子,你应该在if ... elif块之前设置flag = False,以防止后面出现晦涩的“NameError:name'flag'未定义”错误。关于第二个例子,似乎需要为大多数不直接执行任何操作的Python文件添加if __name__ == "__main__": pass有些奇怪(这种情况发生在编写模块化代码时)。在Python >= 3.0中,你应该使用...(省略号)而不是pass来表示“稍后完成”的块。 - ostrokach
    如果所有的else子句都只是通过,即什么也不做,那为什么还要包含它呢? - Junglemath
    @Junglemath 你可能需要明确告诉后来的开发人员,除了列举的条件之外,还有其他需要满足的条件。通常情况下,显式比隐式更好,这是一种明确地表达“我没有列出所有条件;还有其他条件,当前功能是不做任何事情,尽管这并不总是这样”的方式。 - Micah Walter

    21

    pass最好、最准确的理解方式是将其视为显式地告诉解释器什么也不做的方法。同样地,以下代码:

    def foo(x,y):
        return x+y
    

    意思是,如果我调用函数foo(x, y),则将标签x和y表示的两个数字相加并返回结果。

    def bar():
        pass
    

    意思是“如果我调用函数bar(),什么也不做。”

    其他答案都是正确的,但它还可以用于一些不涉及占位符的情况。

    例如,在我最近处理的一段代码中,需要将两个变量相除,而被除数可能为零。

    c = a / b
    

    如果b为零,将明显导致ZeroDivisionError。在这种特定情况下,如果b为零,则将c保留为零是期望的行为,因此我使用了以下代码:

    try:
        c = a / b
    except ZeroDivisionError:
        pass
    

    另一种不太常见的用法是作为调试器断点的方便位置。例如,我想让一段代码在 for...in 语句的第20次迭代时进入调试器。所以:
    for t in range(25):
        do_a_thing(t)
        if t == 20:
            pass
    

    在密码处设置断点。


    def bar(): pass 并不是完全什么都不做。它仍然会隐式地返回 None - chepner
    1
    你提到的调试器问题经常被忽视,但是非常重要。+1 - Wtower

    11
    一个常见的用例是将它“原样”使用,以覆盖类以创建一个类型(否则与超类相同),例如:
    class Error(Exception):
        pass
    

    因此,您可以引发和捕获 Error 异常。这里重要的是异常类型,而不是内容。


    9
    你可以说pass的意思是一个NOP(无操作)操作。在此示例之后,你将会有一个清晰的概念: C程序
    #include<stdio.h>
    
    void main()
    {
        int age = 12;
      
        if( age < 18 )
        {
             printf("You are not adult, so you can't do that task ");
        }
        else if( age >= 18 && age < 60)
        {
            // I will add more code later inside it 
        }
        else
        {
             printf("You are too old to do anything , sorry ");
        }
    }
    

    现在你该如何用 Python 来编写:

    age = 12
    
    if age < 18:
    
        print "You are not adult, so you can't do that task"
    
    elif age >= 18 and age < 60:
    
    else:
    
        print "You are too old to do anything , sorry "
    

    但是您的代码会出现错误,因为它需要在 elif 之后缩进一个块。这里就要用到 pass 关键字了。
    age = 12
    
    if age < 18:
    
        print "You are not adult, so you can't do that task"
    
    elif age >= 18 and age < 60:
        
        pass
    
    else:
    
        print "You are too old to do anything , sorry "
    

    现在我认为对您来说这已经很清晰了。

    8
    在Python中,pass基本上什么也不做,但与注释不同的是,它不会被解释器忽略。因此,您可以将其作为占位符在许多地方使用:

    1:可以在类中使用

    class TestClass:
        pass
    

    2: 可以在循环和条件语句中使用:

    if (something == true):  # used in conditional statement
        pass
    
    while (some condition is true):  # user is not sure about the body of the loop
        pass
    

    3:可在函数中使用:

    def testFunction(args): # The programmer wants to implement the body of the function later
        pass
    

    pass通常用于程序员暂时不想实现某个功能,但仍希望创建一个特定的类/函数/条件语句以便以后使用。由于Python解释器不允许空白或未实现的类、函数或条件语句,因此会出现错误:

    IndentationError: expected an indented block

    在这种情况下可以使用pass


    4

    pass语句不做任何事情。它在需要语法上的语句但程序不需要执行任何操作时使用。


    4
    老实说,我认为官方Python文档描述得很好,并提供了一些示例:

    pass语句不执行任何操作。当需要语法上的语句但程序不需要执行任何操作时,可以使用它。例如:

    >>> while True: ... pass # 等待键盘中断(Ctrl+C) ...

    这通常用于创建最小化的类:

    >>> class MyEmptyClass: ... pass ...

    在编写新代码时,pass还可以用作函数或条件体的占位符,使您能够以更抽象的方式思考。 pass会被静默忽略:

    >>> def initlog(*args): ... pass # 记得要实现它! ...


    1
    如果您想导入一个模块,如果它存在,则导入它,如果该模块不存在,则忽略导入它,您可以使用以下代码:
    try:
        import a_module
    except ImportError:
        pass
    # The rest of your code
    

    如果您避免编写pass语句并继续编写其余代码,则会引发IndentationError,因为在打开except块后的行未缩进。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接