5.6 用户自定义函数
函数是组织好的、可重复使用的、用来实现单一或相关联功能的代码段。根据实际工作的需求,用户可以自己创建函数,即用户自定义函数。
5.6.1 定义函数
Python的函数定义方法是使用def关键字,语法格式如下:
def函数名称(参数1,参数2, ...): "文件字符串" <语句>
“文件字符串”是可省略的,用来作为描述此函数的字符串。如果“文件字符串”存在,它必须是函数的第1个语句。
定义一个函数的规则如下。
(1)函数代码块以def关键字开头,后接函数名称和圆括号()。
(2)任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
(3)函数的第1行语句可以选择性地使用文件字符串——用于存放函数说明。
(4)函数内容以冒号起始,并且缩进。
(5)return [表达式]结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回None。
下列是一个简单的函数定义:
>>>def addnumbers(x, y): "x + y" return x + y >>> addnumbers(5,4) 9
可见,定义一个函数,主要是指定函数里包含的参数和代码块。这个函数的基本结构完成以后,用户可以通过另一个函数调用执行,也可以直接从Python命令提示符窗口执行。
如果用户调用的函数没有参数,就必须在函数名称后加上小括号()。举例如下:
>>> def getmyname(): "my name is John" return "John" >>> myname = getmyname() >>> print (myname) John
用户可以将函数名称设置为变量,然后使用该变量来运行函数的功能。例如:
>>>x = abs >>>print (x(-3)) 3
其中abs()函数是Python的内置函数。
如果用户的函数只有一个表达式,就可以使用lambda运算符来定义这个函数。例如:
>>>f = lambda x, y: x + y >>>f(10,5) 15
这里Python使用lambda创建一个匿名函数。所谓匿名,即不再使用def语句这样标准的形式定义一个函数。这个函数可以使用def关键字来做,语句如下:
>>> def f(x, y): return x + y >>> f(10,5) 15
5.6.2 函数的参数传递
Python函数的参数传递都是使用传址调用的方式。所谓传址调用,就是将该参数的内存地址传过去,如果参数在函数内被更改,则会影响到原有的参数。参数的数据类型可以是模块、类、实例(instance),或是其他的函数,用户不必在参数内设置参数的数据类型。
调用函数时,可使用的参数类型包括必需参数、关键字参数、默认参数和不定长参数。下面分别介绍它们的使用方法和技巧。
1.必需参数
必需参数要求用户必须以正确的顺序传入函数。调用时的数量必须和声明时的数量相同,设置函数的参数时须依照它们的位置排列顺序。例如:
>>> def addnumbers(x, y): return x + y >>> addnumbers(2, 5) 7
在上述例子中,调用addnumbers(2, 5)时,x参数等于2, y参数等于5,因为Python会根据参数排列的顺序来取值。
如果调用addnumbers()函数时,没有传入参数或者传入参数和声明不同,则会出现语法错误。例如:
>>> addnumbers() Traceback (most recent call last): File "<pyshell#88>", line 1, in <module> addnumbers() TypeError: addnumbers() missing 2 required positional arguments: 'x' and 'y'
2.关键字参数
用户可以直接设置参数的名称与其默认值,这种类型的参数属于关键字参数。设置函数的参数时可以不依照它们的位置排列顺序,因为Python解释器能够用参数名匹配参数值。
例如:
>>> def addnumbers(x, y): return x + y >>> addnumbers(y = 5, x = 20) 25
用户可以将必需参数与关键字参数混合使用,但是必需参数必须放在关键字参数之前。
例如:
>>> def addnumbers(x, y): return x + y >>> addnumbers(2, y = 4) 6
3.默认参数
调用函数时,如果没有传递参数,则会使用默认参数值。例如:
>>>def printinfo( name, price=65 ): "输出商品报价信息" print ("名称: ", name) print ("价格: ", price) return >>>printinfo( price=80, name="耳机" ) 名称: 耳机 价格: 80 >>>printinfo( name="键盘" ) 名称: 键盘 价格: 65
在本案例中,首先定义一个函数printinfo(name, price=65),这里变量price的默认值为65。当第1次调用该函数时,指定了变量price的值为80,所以输出值也为80;第2次调用该函数时,没有指定变量price的值,结果将会输出变量price的默认值,结果为65。
当使用默认参数时,参数的位置排列顺序可以任意改变。如果每个参数值都定义了默认参数,则调用函数时可以不设置参数,直接使用函数定义时的参数默认值。例如:
>>> def addnumbers(x=10, y=15 ): return x + y >>> addnumbers() 25
4.不定长参数
如果用户在声明参数时不能确定需要使用多少个参数,可以使用不定长参数。不定长参数不用命名。基本语法如下:
def functionname([formal_args, ] *var_args_tuple ): "函数_文档字符串" function_suite return [expression]
加了星号(*)的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数,它就是一个空元组。用户也可以不向函数传递未命名的变量。例如:
>>> def addnumbers(*args): sum = 0 for arg in args: sum += arg return sum >>> addnumbers(1,2,3,4) 10 >>> addnumbers(1,2,3,4,5,6,7,8) 36
当用户无法预计参数的数目时,可以使用*args类型的参数,*args代表一个元组对象。或是使用**args类型的参数,**args代表一个字典对象。
下列案例显示**args类型的参数应用:
>>> def spam(**args): print ("Keys = "), for k in args.keys(): print (k), print ("Values = "), for v in args.values(): print (v), >>> spam(x = 10, y = "python", z = (1,2,3)) Keys = x y z Values = 10 python (1, 2, 3)
5.6.3 return语句
return语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句返回None。下面通过一个案例来学习return语句返回数值的方法:
>>>def sum(count, price ): "输出商品总价格" total = count * price print ("商品总价格: ", total) return total >>>sum( 100, 28 ) 商品总价格: 2800 2800
函数的返回值可以是一个表达式。例如:
>>> def addnumbers(x, y): return x * 10 + y * 20 >>> addnumbers(1, 2) 50
函数的返回值可以是多个,此时返回值以元组对象的类型返回。例如:
>>> def returnxy(x, y): return x, y >>> a, b = returnxy(10, 20) >>> print (a, b) 10 20
如果函数没有返回值,则返回None。例如:
>>> def myfunction(): return >>> ret = myfunction() >>> print (ret) None
5.6.4 变量作用域
在Python中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。变量的作用域决定了程序在哪一部分可以访问哪个特定的变量名称。
最基本的变量包括全局变量和局部变量。其中,定义在函数内部的局部变量拥有一个局部作用域,定义在函数外的全局变量拥有全局作用域。
在函数之外定义的变量属于全局变量,用户可以在函数内使用全局变量。例如:
>>> x = 10 >>> def get(y = x): return y >>> get() 10
在本案例中,x就是一个全局变量。在函数get(y = x)中将变量x的值赋给变量y。
当用户在函数内定义的变量名称与全局变量名称相同时,函数内定义的变量不会改变全局变量的值。因为函数内定义的变量属于局部命名空间,而全局变量则属于全局命名空间。
例如:
>>> x = 10 >>> def changex(): x = 20 return x >>> x 10 >>> changex() 20
如果要在函数内改变全局变量的值,就必须使用关键字global。例如:
>>> x = 10 >>> def changex(): global x x = 20 return x >>> changex() 20 >>> x 20
在本案例中,首先定义一个全局变量x,然后定义函数changex(),该函数通过使用关键字global,将x的值修改为20。
5.6.5 函数的内置属性和命名空间
函数有许多的内置属性,用户可以在Python解释器内输入“dir(函数名称)”命令,即可以显示这些内置属性。代码如下:
>>> def myfunction(): return >>> dir(myfunction) ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
下面挑选一些常见的内置属性进行讲解。
(1)__dict__:该属性包含该函数的命名空间。
(2)__doc__:该属性显示该函数的文件字符串。例如:
>>> def returnxy(x, y): "return x + y" return x + y >>> returnxy.__doc__ 'return x + y'
(3)__name__:该属性显示该函数的名称。例如:
>>> def returnxy(x, y): "return x + y" return x + y >>> returnxy.__name__ 'returnxy'
Python使用动态命名空间,在创建每一个函数、模块与类时,都会定义它自己的命名空间。当用户在Python解释器内输入一个指令或语句时,Python会先搜索局部命名空间,然后搜索全局命名空间。
Python包含的命名空间如下。
●内置命名空间(built-in namespace):int、string、def、print等。
●全局命名空间(global namespace):位于模块的最上层。
●局部命名空间(local namespace):位于函数内。
Python解释器在搜索名称或变量时,首先会在局部命名空间中搜索;如果找不到,再到全局命名空间中搜索,如果还是找不到,则会到内置命名空间中搜索;最后如果还是找不到,Python会输出一个NameError异常。