如何从函数中获得结果(输出)?我如何在之后使用这个结果?
如何从函数中获得结果(输出)?我如何在之后使用这个结果?
假设我有一个如下的函数:
def foo(): x = 'hello world'
我要如何使这个函数返回x
,以便我可以将其作为另一个函数的输入,或者在程序的主体中使用这个变量?我尝试使用return
然后在另一个函数中使用x
变量,但是这样会导致NameError
错误。
对于在同一个类的方法之间传递信息的特定情况,最好将信息存储在self
中。详细信息请参见在Python中在方法之间传递变量?。
如何从函数中获取结果(输出)?我可以如何稍后使用结果?这个问题的原因是因为我们在函数中进行了计算,想要将计算结果返回给调用函数的代码,并在之后使用这个结果。解决这个问题的方法有两种:直接方法和间接方法。
直接方法是通过在函数中使用return
关键字返回一个值,并让调用代码使用这个值。这是通常我们想要的方式。从函数中获取信息的自然、简单、直接、明确的方法就是使用return
关键字。函数的目的是计算一个值,return
表示“这就是我们计算的值;我们在这里结束了”。
直接使用return
的方法是,return
返回的是一个值而不是一个变量。所以return x
并不能使调用代码在调用函数后使用x
的值,并且也不能修改调用上下文中x
的现有值(这可能是你遇到NameError
的原因)。
在函数中使用return
后,我们需要编写调用代码来使用返回值:
def example(): x = 'hello world' return x result = example() print(result)
这里的另一个关键点是,函数调用是一个表达式,所以我们可以像使用加法的结果一样使用它。就像我们可能会写result = 'hello ' + 'world'
一样,我们也可以写result = foo()
。之后,result
是我们自己的、局部的名字,我们可以随意使用它。
我们可以使用相同的名字x
,如果我们想要的话。或者我们可以使用一个不同的名字。调用代码不需要知道函数是如何编写的,或者函数使用什么名称来表示事物。
我们可以直接使用这个值调用另一个函数,例如print(foo())
。我们也可以直接return
这个值,只需简单地写return 'hello world'
,而不需要赋值给x
。(再次强调:我们返回的是一个值,而不是一个变量。)
函数每次调用只能return
一次。当return
被执行时,函数终止——我们刚刚确定了计算的结果,所以没有理由再进行计算。因此,如果我们想要返回多个信息,我们需要找到一个单一的对象(在Python中,“值”和“对象”基本上是同义词;这在其他一些语言中可能效果不好)。
我们可以在返回行上创建一个元组,或者我们可以使用字典、namedtuple
(Python 2.6+)、types.simpleNamespace
(Python 3.3+)、dataclass
(Python 3.7+),或者其他类(甚至是我们自己编写的类)来关联返回的值和它们的名称。我们还可以在列表中循环累加值等等。这样的可能性是无限的。
另一方面,函数无论你喜不喜欢,都会return
(除非引发异常)。如果函数到达结尾,它会隐式地return
特殊值None
。你可能会选择显式地进行return
,而不是隐式地进行。
间接方法:
除了直接将结果返回给调用者,我们还可以通过修改调用者知道的一些现有对象来传递结果。有许多方法可以做到这一点,但它们都是同一主题的变体。
如果你想让代码以这种方式传递信息,请只让它返回None
,而不要将返回值用于其他有意义的事情。这是内置功能的工作方式。
为了修改这个对象,被调用的函数当然也必须知道这个对象。这意味着需要一个在当前作用域中可以查找的对象的名称。
本地作用域:修改传入的参数
如果我们的参数之一是可变的,我们可以直接修改它,并依赖于调用者来检查更改。这通常不是一个好主意,因为很难推理出代码。它看起来像这样:
def called(mutable): mutable.append('world') def caller(): my_value = ['hello'] # 一个只包含这个字符串的列表 called(my_value) # 现在它包含两个字符串
如果值是我们自己的类的实例,我们也可以给属性赋值:
class Test: def __init__(self, value): self.value = value def called(mutable): mutable.value = 'world' def caller(): test = Test('hello') called(test) # 现在test.value已经改变了
对于内置类型,包括object
在内,赋值给属性是不起作用的;对于一些明确阻止你这样做的类,也可能不起作用。
本地作用域:在方法中修改self
我们已经在上面的例子中见过这个了:在Test.__init__
代码中设置self.value
。这是修改传入参数的一个特殊情况;但它是Python中类的工作方式的一部分,也是我们期望我们要做的事情。通常情况下,当我们这样做时,调用方实际上不会检查self
的更改——它只会在逻辑的下一步中使用修改后的对象。这就是为什么以这种方式编写代码是合适的原因:我们仍然提供了一个接口,所以调用者不必担心细节。
class Example: def __init__(self): self._words = ['hello'] def add_word(self): self._words.append('world') def display(self): print(*self.words) x = Example() x.add_word() x.display()
在这个例子中,调用add_word
将信息传递给了顶层代码,但是我们没有去寻找它,而是直接调用了display
。
封闭作用域
这是使用嵌套函数时的一个罕见特例。这里没有太多的要说的——它与全局作用域的工作方式相同,只是使用nonlocal
关键字而不是global
关键字。
全局作用域:修改全局变量
一般来说,在一开始设置全局变量后,改变其中的任何东西都是一个不好的主意。这使得代码更难理解,因为除了负责更改的部分之外,使用该全局变量的任何内容现在都有一个“隐藏”的输入来源。
如果你仍然想这样做,语法很简单:
words = ['hello'] def add_global_word(): words.append('world') add_global_word() # `words`被更改了
全局作用域:给新的或现有的全局赋值或修改全局变量
这实际上是修改全局变量的特殊情况。我不是说赋值是一种修改(它不是)。我的意思是,当你赋值给一个全局变量时,Python会自动更新一个表示全局命名空间的字典。你可以用globals()
获取到这个字典,并且你可以修改这个字典,它实际上会影响全局变量的存在(即globals()
的返回值是字典本身,而不是副本)。
但请不要这样做。这比前面的方法更糟糕。如果你真的需要通过将值赋给全局变量来从函数中获取结果,请使用global
关键字告诉Python该名称应该在全局作用域中查找:
words = ['hello'] def replace_global_words(): global words words = ['hello', 'world'] replace_global_words() # `words`是一个包含两个单词的新列表
全局作用域:给函数本身的属性赋值或修改函数本身的属性
这是一个罕见的特例,但是现在你已经看到其他例子了,理论应该是清楚的。在Python中,函数是可变的(即你可以在它们上面设置属性);如果我们在顶层定义一个函数,它就在全局命名空间中。所以这实际上只是修改一个全局的一种方式:
def set_own_words(): set_own_words.words = ['hello', 'world'] set_own_words() print(*set_own_words.words)
我们不应该真的使用这种方式将信息发送给调用者。它具有所有全局变量的常规问题,而且更难理解。但是它可以用于从函数内部设置函数的属性,以便函数在调用之间记住某些东西。例如,functools
标准库就是这样做的,在cache
实现中。
内置作用域
这是行不通的。内置命名空间不包含任何可变对象,并且你不能分配新的内置名称(它们将进入全局命名空间)。
一些在Python中行不通的方法:
只是在函数结束之前计算一些东西
在其他一些编程语言中,有一种隐藏的变量,它会自动获取最后一次计算的结果,每次计算都会自动获取;如果你在函数结束时没有return
任何东西,它会被返回。在Python中,这是行不通的。如果你在结束时没有return
任何东西,你的函数仍然会返回None
。
给函数的名字赋值
在其他一些编程语言中,你可以(或者应该)将一个与函数同名的变量赋值给一个变量;在函数结束时,该值将被返回。这在Python中仍然不起作用。如果你在结束时没有return
任何东西,你的函数仍然会返回None
。
def broken(): broken = 1 broken() print(broken + 1) # 会引发`TypeError`
如果你使用global
关键字,这似乎至少可以使用该值,例如:
def subtly_broken(): global subtly_broken subtly_broken = 1 subtly_broken() print(subtly_broken + 1) # 2
但是,这当然只是全局分配的一个特殊情况。这里有一个很大的问题——同一个名称不能同时引用两个东西。通过这样做,函数“替换了自己的名称”。所以,下一次将失败:
def subtly_broken(): global subtly_broken subtly_broken = 1 subtly_broken() subtly_broken() # 会引发`TypeError`
给参数赋值
有时人们希望能够将值赋给函数的参数之一,并使其影响到用于相应参数的变量。然而,这是行不通的:
def broken(words): words = ['hello', 'world'] data = ['hello'] broken(data) # `data`不会改变
就像Python返回的是值而不是变量,它也传递的是值而不是变量。words
是一个局部名称;根据定义,调用代码对该命名空间一无所知。
我们在前面看到的工作方法之一是修改传入的列表。这是可以的,因为如果列表本身发生了变化,那么它就变了——这与使用的名称或代码的哪个部分无关。然而,将一个新的列表分配给words
不会导致现有列表发生变化。它只是使words
开始成为一个不同的列表的名称。
有关更多信息,请参见如何按引用传递变量?。
一些在Python中不起作用的方法:
只是计算函数结束之前的一些东西。
在其他一些编程语言中,有一种隐藏的变量,它会自动获取最后一次计算的结果,每次计算都会自动获取;如果你在函数结束时没有return
任何东西,它会被返回。在Python中,这是行不通的。如果你在结束时没有return
任何东西,你的函数仍然会返回None
。
给函数的名字赋值。
在其他一些编程语言中,你可以(或者应该)将一个与函数同名的变量赋值给一个变量;在函数结束时,该值将被返回。在Python中,这仍然不起作用。如果你在结束时没有return
任何东西,你的函数仍然会返回None
。
def broken(): broken = 1 broken() print(broken + 1) # 会引发`TypeError`
这可能看起来至少可以使用该值,如果你使用了global
关键字:
def subtly_broken(): global subtly_broken subtly_broken = 1 subtly_broken() print(subtly_broken + 1) # 2
但是,这当然只是全局赋值的一个特殊情况。在这方面有一个很大的问题——同一个名称不能同时引用两个东西。通过这样做,函数“替换了自己的名称”。所以,下一次将失败:
def subtly_broken(): global subtly_broken subtly_broken = 1 subtly_broken() subtly_broken() # 会引发`TypeError`
给参数赋值。
有时人们希望能够将值赋给函数的参数之一,并使其影响到用于相应参数的变量。然而,这是行不通的:
def broken(words): words = ['hello', 'world'] data = ['hello'] broken(data) # `data`不会改变
就像Python返回的是值而不是变量一样,它也传递的是值而不是变量。words
是一个局部名称;根据定义,调用代码对该命名空间一无所知。
以上就是关于如何从函数中获取结果以及如何在之后使用结果的问题的原因和解决方法的总结。通过直接使用return
关键字返回值,或者通过间接方法修改传入的对象,我们可以从函数中获取结果,并在之后使用这个结果。这些方法可以根据具体的需求和代码的结构选择使用。
问题的出现原因是函数中使用了return语句返回一个值,但返回的变量在调用者的作用域中不可用。为了在调用者中使用返回的值,可以直接在语句中使用它,或者将其捕获到一个变量中。
解决方法是使用返回值的关键字return,将值从函数中返回。在调用函数时,可以直接在语句中使用返回的值,或者将其赋值给一个变量。以下是代码示例:
def foo(): x = 'hello world' return x foo() # 这里并不会把返回的值存储在变量中 print(x) # 报错 - x在函数外部未定义 y = foo() # 将返回的值存储在变量y中 print(y) # 这里可以正常使用y的值 x = foo() # 将返回的值存储在变量x中,这个x与函数内部的x完全不同 print(x) # 这里可以正常使用x的值,与函数内部的x不冲突 z = bar(x) # 当然,现在你可以根据需要使用x z = bar(foo()) # 但你不一定要这么做
通过使用return语句返回值,并将其赋值给变量,就能够从函数中获取结果,并在后续的代码中使用该结果。
在上面的代码中,我们定义了一个名为foo的函数,它返回字符串'hello world'。然后,我们将函数foo的结果赋给变量x,并输出变量x的值。这样,我们就可以使用函数的结果,并在以后的代码中进行操作。
出现这个问题的原因是,我们经常需要将函数的结果保存下来,以便在以后的代码中使用。有时候,函数的结果可能是一个计算后的值,我们希望将其传递给其他函数或进行其他操作。因此,我们需要知道如何获取函数的结果,并将其保存下来。
解决这个问题的方法是使用函数的返回值。在Python中,我们可以使用return语句来指定函数的返回值。当函数执行到return语句时,它会立即停止执行,并将return语句后面的表达式作为结果返回给调用者。调用者可以将返回值保存在变量中,并在以后的代码中使用。
在上面的代码中,我们使用return语句返回了字符串'hello world'。然后,我们将函数foo的结果赋给变量x,并输出变量x的值。这样,我们就可以在以后的代码中使用变量x,访问函数的结果。
总结起来,要从函数中获取结果并在以后的代码中使用,我们可以使用return语句指定函数的返回值,并将返回值保存在变量中。这样,我们就可以随时访问函数的结果,并在以后的代码中进行操作。