有效的函数
Python的函数是第一等级
在Python中,函数是被视为“第一等级”对象的。你可以将它们赋值给变量,存储在数据结构中,作为参数传递给其他函数,并且甚至可以将它们作为其他函数返回值来使用。Python中的函数具有很高的灵活性和可操作性,使得它们在编写代码和实现功能时扮演着至关重要的角色。
深入理解这些概念的直觉方式将使你更容易掌握Python中高级特性,如lambda表达式和装饰器。这也将引导你走向函数式编程技术的道路。接下来,我将为你提供一系列示例,帮助你逐步培养这种直觉理解。这些示例会逐个建立在前一个的基础上,因此建议你按照阅读顺序阅读它们,并且在过程中尝试在Python解释器中运行一些示例来加深理解。
理解和掌握我们将讨论的概念可能需要比你预期的更多时间。别担心,这完全正常。我自己也经历过类似的情况。你可能会觉得自己像是撞到了墙,然后突然间一切就绪了,当你准备好时, 我会使用这个“吼叫”函数来演示目标。这是一个简单的玩具示例,具有易于识别的输出:
>>> def yell(text):
... return text.upper() + '!'
>>> yell('hello')
'HELLO!'
函数是对象
在Python程序中,所有数据都由对象或对象之间的关系表示。对象如字符串、列表、模块和函数等都是对象的实例。 Python中的函数虽有特殊性,但从本质上说它们也是对象。
由于"吼叫"函数是Python中的一个对象,因此你可以像操作其他对象一样将它赋值给另一个变量:
>>> bark = yell
这条代码并没有调用函数。它实际上是获取了被引用为"吼叫"的函数对象,并创建了一个新的名称"bark",这个"bark"实际上是指向原始的函数对象。所以你现在也可以通过调用"bark"来执行与原函数相同底层功能的对象:
>>> bark('woof')
'WOOF!'
函数对象和它们的名字确实是两个独立的概念。这里有一个更明确的例子来证明这一点:正如例子所示,即使删除了原始函数名"yell",因为另一个名字"bark"仍然可以调用这个函数。
>>> del yell
>>> yell('hello?')
NameError: name 'yell' is not defined
>>> bark('hey')
'HEY!'
顺便说一下,Python在每个函数创建时都会附加一个字符串标识符,这是出于调试目的。你可以通过name属性来访问这个内部标识:
>>> bark.__name__
'yell'
现在,尽管函数的name仍然是’yell’,但这并不影响你从代码中访问该函数对象的方式。名字标识符只是一个调试辅助工具。一个指向函数的变量和函数本身实际上是两个独立的关注点。
函数可以存储在数据结构中
既然函数是第一类公民,你可以像存储其他对象一样将它们存储在数据结构中。举个例子,你可以在一个列表中添加函数:
>>> funcs = [bark, str.lower, str.capitalize]
>>> funcs
[<function yell at 0x1174676a0>, <method 'lower' of 'str' objects>, <method 'capitalize' of 'str' objects>]
在列表内部存储的函数对象,其访问方式与其他类型的对象并无区别。
>>> for f in funcs:
... print(f, f('hey there'))
<function yell at 0x1174676a0> HEY THERE!
<method 'lower' of 'str' objects> hey there
<method 'capitalize' of 'str' objects> Hey there
你甚至可以在不先将其赋值给变量的情况下,直接调用存储在列表中的函数对象。你可以进行查找操作,然后立即在一个表达式中调用得到的“独立”函数对象
>>> funcs[0]('heyho')
'HEYHO!'