返回,返回无,根本没有返回?


386

考虑三个功能:

def my_func1():
  print "Hello World"
  return None

def my_func2():
  print "Hello World"
  return

def my_func3():
  print "Hello World"

它们似乎都返回None。这些函数的返回值的行为方式之间有什么区别吗?是否有任何理由偏爱一个?


40
请注意,在风格上有所不同。return None在我看来,该函数有时具有非None返回值,但是在的位置return None,没有这样的返回值。完全不写return对我来说意味着永远不会有一个有趣的返回值,有点像“过程”而不是“函数”。return暗示根据先前的观点从“过程”的早期存在。

Answers:


500

在实际行为上,没有区别。他们都回来了None,就是这样。但是,所有这些都有时间和地点。以下说明基本上是应如何使用不同方法的方法(或至少应告诉我应如何使用它们的方法),但是它们不是绝对规则,因此您可以根据需要将它们混合使用。

使用 return None

这说明该函数确实是要返回一个值供以后使用,在这种情况下,它返回NoneNone然后可以在其他地方使用此值。return None如果该函数没有其他可能的返回值,则永远不要使用。

在下面的例子中,我们返回personmother,如果person给出的一个人。如果不是人类,我们将返回,None因为person它没有mother(假设它不是动物或其他东西)。

def get_mother(person):
    if is_human(person):
        return person.mother
    else:
        return None

使用 return

出于与break循环中相同的原因使用它。返回值无关紧要,您只想退出整个函数。即使您不经常使用它,它在某些地方也非常有用。

我们已经有15个人,prisoners而且我们知道其中一个拥有一把刀。我们prisoner逐个循环检查他们是否有刀。如果我们用小刀打人,则可以退出该功能,因为我们知道只有一把小刀,没有理由检查其余部分prisoners。如果找不到prisoner刀子,则会发出警报。这可以通过许多不同的方式完成,使用return可能甚至不是最好的方式,但这只是说明如何使用return退出函数的一个示例。

def find_prisoner_with_knife(prisoners):
    for prisoner in prisoners:
        if "knife" in prisoner.items:
            prisoner.move_to_inquisition()
            return # no need to check rest of the prisoners nor raise an alert
    raise_alert()

注意:绝对不要这样做var = find_prisoner_with_knife(),因为返回值不是要捕获的。

使用无return可言

这也将返回None,但是该值并不意味着要使用或捕获。这仅表示该功能已成功结束。它基本上与C ++或Java等语言return中的void函数相同。

在下面的示例中,我们设置了人的母亲的名字,然后该函数在成功完成后退出。

def set_mother(person, mother):
    if is_human(person):
        person.mother = mother

注意:绝对不要这样做var = set_mother(my_person, my_mother),因为返回值不是要捕获的。


5
var = get_mother()如果您要传递var给其他可以接受的功能,那就可以了None-“从不”有点极端
joelb

如果var = get_mother()不能使用,应该如何接受返回值?恕我直言,这样做完全可以。您只需要确保在使用前检查非None值即可if var
winklerrr

我认为重要的是要提到,这不仅是一个好的约定,而且是PEP8所要求的。我发布了一个对您的称赞的答案,并为此引用了PEP8。
法比亚诺

29

是的,它们都是一样的。

我们可以查看解释后的机器代码,以确认它们都在做完全相同的事情。

import dis

def f1():
  print "Hello World"
  return None

def f2():
  print "Hello World"
  return

def f3():
  print "Hello World"

dis.dis(f1)
    4   0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE

    5   5 LOAD_CONST    0 (None)
        8 RETURN_VALUE

dis.dis(f2)
    9   0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE

    10  5 LOAD_CONST    0 (None)
        8 RETURN_VALUE

dis.dis(f3)
    14  0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE            
        5 LOAD_CONST    0 (None)
        8 RETURN_VALUE      

4
小心点... dis.dis返回None:-X
mgilson

获得dis作为字符串输出的唯一方法是将stdout重定向到某种IO缓冲区(例如StringIO)。即使那样,直接比较也不可行,因为我相信dis.dis还会报告一些行号……
mgilson

无论它们是否使用完全相同的寄存器都无关紧要,所以我更改了代码,因此我们现在只是盯着机器代码,而不是进行某种愚蠢的字符串比较。感谢您的单挑。
大卫·马克思(Marx)

19

它们每个都返回相同的单例None-功能上没有差异。

我认为,return除非您需要先退出该函数(在这种情况下,裸露return更为常见)或返回除以外的其他值,否则放弃该语句是很习惯的做法None。它也很有意义,并且return None在函数中具有返回除之外的其他值的函数时似乎是惯用的Nonereturn None明确地写出来是读者的视觉提示,还有另一个分支返回更有趣的内容(并且调用代码可能需要处理两种类型的返回值)。

返回的函数通常在Python None中像voidC中的函数一样使用-它们的目的通常是在适当的位置对输入参数进行操作(除非您正在使用全局数据(shudders))。None通常,返回可以使参数更加明确。这使我们更加清楚为什么return从“语言约定”的角度出发不理会该声明。

就是说,如果您正在使用已经针对这些事情设置了预设约定的代码库,那么我肯定会效仿以帮助使代码库保持一致...


1
或更笼统地return说,只要函数在没有命中语句的情况下结束,它就会返回None

如果期望该函数返回值,则省略return语句并不是惯常做法。仅仅通过副作用运行的函数应省略return语句。
分子

@molecule-是的,我认为在我的解释中我可能做得最好。我尝试对其进行更新,而没有使其完全克隆上面(更好)的答案。我对这个帖子仍然不满意...我的一部分想删除它(因为上面的答案好得多),而我的一部分想保留它-到目前为止,有9个人认为这对一个原因或另一个。也许我碰到别人错过的东西?
米尔森

1
@ZAB-我认为不可能。在python中,我可以用任何东西猴子修补任何东西(这是设计使然,如果谨慎使用,则是一个很棒的功能)。具体来说,我可以用猴子修补具有返回值的函数,而没有返回值的函数。所有的“非表达式”检查都在解析时进行,但是由于猴子的修补,只有在运行时才能进行。IOW,完全不同。就个人而言,我认为当前的行为是相当合理的(并且与其他高级语言一致),但是我不是您需要说服的人:-)。
米尔森

1
@ZAB -既RubyJavascript采取同样的方法为蟒蛇。我敢肯定,有一些高级语言的例子在表达式中说“ void”,但我暂时想不起来(也许如果您考虑Java使用高级语言的话)……猴子补丁会如何一个函数(在测试中除其他外对模拟有用)在一个假设的世界中工作,其中python得到了一个void使之成立的关键字,因此该函数不返回任何东西?(此外,正如我之前所说,您不必说服我这是一个糟糕的设计。即使您是对的,我也无法做任何事情)
mgilson

4

正如其他人回答的那样,None在所有情况下都将返回完全相同的结果。

区别是风格上的,但请注意,PEP8要求使用时要保持一致:

在返回语句中保持一致。函数中的所有return语句应返回一个表达式,或者都不返回。如果任何return语句返回一个表达式,则不返回任何值的任何return语句应将其显式声明为return None,并且在函数的末尾(如果可访问)应存在显式return语句。

是:

def foo(x):
    if x >= 0:
        return math.sqrt(x)
    else:
        return None

def bar(x):
    if x < 0:
        return None
    return math.sqrt(x)

没有:

def foo(x):
    if x >= 0:
        return math.sqrt(x)

def bar(x):
    if x < 0:
        return
    return math.sqrt(x)

https://www.python.org/dev/peps/pep-0008/#programming-recommendations


基本上,如果您曾经非None在函数中值,则意味着返回值具有含义,并且被调用方捕获。因此,当您返回时None,它也必须是显式的,以None在这种情况下传达含义,它是可能的返回值之一。

如果您根本不需要返回,则函数基本上是作为过程而不是函数工作的,因此不要包括 return语句。

如果您正在编写类似过程的函数,并且有机会早点返回(即您已经完成了此操作,不需要执行其余的函数),则可以使用empty returns向读者发出信号这只是执行的早期完成,None隐式返回的值没有任何意义,也不意味着被捕获(类似过程的函数始终返回None)。


3

就功能而言,它们都是相同的,它们之间的区别在于代码的可读性和样式(要考虑的重要因素)

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.