ChatGPT解决这个技术问题 Extra ChatGPT

return,return None,根本不返回?

考虑三个函数:

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

def my_func2():
  print "Hello World"
  return

def my_func3():
  print "Hello World"

他们似乎都返回无。这些函数的返回值的行为方式有什么不同吗?有什么理由更喜欢一个而不是另一个?

请注意,存在风格上的差异。 return None 对我来说意味着该函数有时具有非 None 返回值,但在 return None 的位置,没有这样的返回值。根本不写 return 对我来说意味着从来没有一个有趣的返回值,有点像“过程”而不是“函数”。 return 意味着根据前一点从“程序”中提前存在。

j
jshd

在实际行为上,没有区别。他们都返回 None 就是这样。然而,所有这些都有时间和地点。以下说明基本上是应该如何使用不同的方法(或者至少是我被教导应该如何使用它们),但它们不是绝对的规则,所以如果你觉得有必要可以将它们混合起来。

使用返回无

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

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

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

使用返回

这与循环中的 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(),因为返回值并不意味着被捕获。

完全不使用回报

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

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

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

注意:你不应该做 var = set_mother(my_person, my_mother),因为返回值并不意味着被捕获。


如果您将 var 传递给接受 None 的其他函数,var = get_mother() 是可以的 - “从不”有点极端
如果不能使用 var = get_mother(),应该如何接受返回值?恕我直言,这样做完全没问题。您只需要确保在使用之前使用 if var 检查非 None 值。
我认为值得一提的是,这不仅仅是一个好的约定,它是 PEP8 所要求的。我发布了一个回答来赞美你的回答,并在此引用 PEP8。
为什么 return values 不应该是 caught
如果一个答案在 Stack Overflow 上得到另一个分数,但周围没有人收集它,它算作声誉吗?
D
David Marx

是的,它们都是一样的。

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

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      

在这里小心... dis.dis 返回 None :-X
将 dis 的输出作为字符串获取的唯一方法是将 stdout 重定向到某种 IO 缓冲区(例如 StringIO)。即使那样,像这样直接比较可能也行不通,因为我相信 dis.dis 也会报告一些行号......
不管他们是否使用完全相同的寄存器都无关紧要,所以我改变了我的代码,所以我们现在只看机器代码,而不是进行某种愚蠢的字符串比较。感谢您的高度关注。
@mgilson 现在也可以使用 dis.Bytecode.dis()
m
mgilson

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

我认为放弃 return 语句是合理的习惯用法,除非您需要它提前退出函数(在这种情况下,更常见的是空的 return),或者返回 None 以外的其他内容。当 return None 位于具有返回 None 以外的其他路径的函数中时,编写 return None 也是有意义的并且似乎是惯用的。显式写出 return None 是对读者的视觉提示,即有另一个分支返回更有趣的内容(并且调用代码可能需要处理这两种类型的返回值)。

通常在 Python 中,返回 None 的函数与 C 中的 void 函数一样使用——它们的目的通常是对输入参数就地进行操作(除非您使用全局数据(< em>颤抖))。返回 None 通常会更明确地表明参数已发生变化。这更清楚地说明了为什么从“语言约定”的角度省略 return 语句是有意义的。

也就是说,如果您正在使用已经围绕这些东西预先设定约定的代码库,我肯定会效仿以帮助代码库保持统一......


或者更一般地说,只要函数在没有命中 return 语句的情况下结束,它就会返回 None
@ZAB——我认为这是不可能的。在 python 中,我可以用任何东西修补任何东西(这是设计使然,如果谨慎使用它是一个很棒的功能)。具体来说,我可以对一个没有返回的函数进行猴子修补。所有“非表达式”检查都在解析时发生,但由于猴子补丁,这直到运行时才会发生。 IOW,完全不同。就个人而言,我认为当前的行为是相当合理的(并且与其他高级语言一致),但我不是你需要说服的人:-)。
@ZAB -- RubyJavascript 都采用与 python 相同的方法。我确信有个高级语言的例子在表达式中说“void”,但我现在想不出任何例子(也许如果你认为 Java 是高级语言语言)......猴子修补函数(这对于在测试中进行模拟等有用)如何在python得到一个void关键字的假设世界中工作,所以函数没有返回任何东西? (另外,就像我之前说的,你不需要说服我这是一个糟糕的设计。即使你是对的,我也无能为力)
@GregSchmit 没有。将 None 分配给变量与使其未初始化不同。您可以从变量中读取 None ,您可以检查它并在 if 条件下使用它,但您不能读取和使用未初始化的变量,您会得到一个异常。函数返回值也应该如此。
此外,a = myfunc() 正在初始化 a,因此抛出未初始化的错误将毫无意义。 None 的全部工作就是与任何事物(任何有意义的值)相反,因此当函数不返回任何内容时,这与返回 None 相同。
F
Fabiano

正如其他人回答的那样,结果完全相同,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) No: def foo( x): if x >= 0: 返回 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,你的函数基本上是作为一个过程而不是一个函数工作的,所以不要包含 return 语句。

如果您正在编写一个类似过程的函数并且有机会提前返回(即您已经完成了该点并且不需要执行该函数的剩余部分),您可以使用空的 return 来发出信号对于读者来说,这只是执行的早期完成,隐式返回的 None 值没有任何意义,也不意味着被捕获(类似过程的函数总是返回 None )。


Y
Yehuda Schwartz

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