11.1 什么是函数?
函数是对程序逻辑进行结构化或过程化的一种编程方法。能将整块代码巧妙地隔离成易于管理的小块,把重复代码放到函数中而不是进行大量的拷贝——这样既能节省空间,也有助于保持一致性,因为你只需改变单个的拷贝而无须去寻找再修改大量复制代码的拷贝。Python中函数的基础部分与你熟悉的其他的语言没有什么不同。本章开始,我们先回顾一下函数基础,然后将着重介绍Python函数的其他特性。
函数可以以不同的形式出现。下面简单展示了一些创建、使用,或者引用函数的方法。
11.1.1 函数VS过程
我们经常拿函数和过程比较。两者都是可以被调用的实体,但是传统意义上的函数或者“黑盒”,可能不带任何输入参数,经过一定的处理,最后向调用者传回返回值。其中一些函数则是布尔类型的,返回一个“是”或者“否”的回答,更确切地说,一个非零或者零值。而过程是简单、特殊、没有返回值的函数。从后面内容你会看到,python的过程就是函数,因为解释器会隐式地返回默认值None。
11.1.2 返回值与函数类型
函数会向调用者返回一个值,而实际编程中大部分偏函数更接近过程,不显示地返回任何东西。把过程看待成函数的语言通常对于“什么都不返回”的函数设定了特殊的类型或者值的名字。这些函数在C中默认为“void”的返回类型,意思是没有值返回。在python中,对应的返回对象类型是none。
下面hello()函数的行为就像一个过程,没有返回值。如果保存了返回值,该值为None:
另外,与其他大多数的语言一样,Python里的函数可以返回一个值或者对象。只是在返回一个容器对象的时候有点不同,看起来像是能返回多个对象。好比说,你不能拿着大量零散的商品离开百货店,但是你可以将它们放在一个购物袋里,然后带着这个袋子从商店走出去,合理合法。
foo()函数返回一个列表,bar()函数返回一个元组。由于元组语法上不需要一定带上圆括号,所以让人真的以为可以返回多个对象。如果我们要恰当地给这个元组加上括号,bar()的定义看起来会是这样:
从返回值的角度来考虑,可以通过很多方式来存储元组。接下来的3种保存返回值的方式是等价的:
在对x、y、z和a、b、c的赋值中,根据值返回的顺序,每个变量会接收到与之对应的返回值。而aTuple直接获得函数隐式返回的整个元组。回想一下,元组既可以被分解成为单独的变量,也可以直接用单一变量对其进行引用(参见6.18.3小节)。
简而言之,当没有显式地返回元素或者如果返回None时,Python会返回一个None。那么调用者接收的就是Python返回的那个对象,且对象的类型仍然相同。如果函数返回多个对象,Python把他们聚集起来并以一个元组返回。是的,尽管我们声称Python比诸如C那样只允许一个返回值的语言灵活得多,但是老实说,Python也遵循了相同的传统,只是让程序员误以为可以返回多个对象。
表11.1总结了从一个函数中返回的对象的数目,以及Python实际返回的对象。
许多静态类型的语言主张一个函数的类型就是其返回值的类型。在Python中,由于Python是动态地确定类型而且函数能返回不同类型的值,所以没有进行直接的类型关联。因为重载并不是语言特性,程序员需要使用type()这个内建函数作为代理,来处理有着不同参数类型的函数的多重声明以模拟类C语言的函数重载(以参数不同选择函数的多个原型)。