函数是实现一定功能的代码段,传入参数,返回值。
Python 内置函数len
,给它传入一个列表,它会返回列表的长度(返回值);print
函数把传入的对象打印到屏幕上,它没有返回任何值,我们说它返回None
;input
函数的返回值是屏幕输入的字符串。
用def
关键字定义函数,参数写在函数名后的括号内,返回值写在return
后。为了便于理解,下面的例子将自定义一个二次函数f
,传入参数是自变量x
,函数返回计算出的因变量的值
def f(x): # 函数定义 y = x * x return y a = int(input('输入一个整数:')) b = f(a) # 函数调用 print(a, '的平方是', b)
运行结果
输入一个整数:4 4 的平方是 16
函数的使用能提高应用的模块性,和代码的重复利用率。
参数可以有0个,1个或多个,写在变量名后的括号内。定义函数时指定了多少参数,调用时就要传入多少参数。
下面的例子中,定义一个打印三角形的函数和一个打印一行字符串的函数
def print_line(t, symbol): print(symbol * t) def print_triangle(t, symbol): for x in range(1, t + 1): print_line(x, symbol) print_triangle(5, 'O')
运行结果
O OO OOO OOOO OOOOO
如果定义函数时设置了默认参数,则在函数调用时可以不传入对应参数,函数会使用默认参数。下面的例子设置了symbol
的默认值为5
,因此在函数调用时可以不传入该参数
def print_line(t, symbol='#'): print(symbol * t) def print_triangle(t, symbol='#'): for x in range(1, t + 1): print_line(x, symbol) print_triangle(4) # 函数使用默认参数 symbol='#' print() # 空行 print_triangle(5, 'O')
运行结果
# ## ### #### O OO OOO OOOO OOOOO
默认参数都要写在必须参数的后面,不能写成def print_line(symbol='#', t):
return
后的对象叫做返回值。实际编程中,对于返回值非空的函数,常常用一个变量接收返回值。遇到return
时,函数返回返回值,同时会立即退出函数。下面的str_date
函数,把传入的年月日组合成一个时间字符串,然后返回这个时间字符串。
def str_date(year, month, day): date = str(year) + '-' + str(month) + '-' + str(day) if day == 1: date += 'st' return date elif day == 2: date += 'nd' return date elif day == 3: date += 'rd' return date date += 'th' # 当day<=3时,函数不会执行到这里 return date d1 = str_date(2006, 6, 6) d2 = str_date(2003, 8, 1) print(d1, d2)
运行结果
2006-6-6th 2003-8-1st
函数体中没有return
语句的函数,默认返回空值None
。前面的print_triangle
就是一个返回空值的函数。
以function_name(...)
的形式来调用函数,非None
的返回值常用一个变量接收,如b = f(4)
以关键字参数的形式传入参数时,参数传入的顺序可以与定义函数时的顺序不一致,因为 Python 解释器可以用参数名匹配参数值
def str_date(year, month, day): date = str(year) + '-' + str(month) + '-' + str(day) if day == 1: date += 'st' return date elif day == 2: date += 'nd' return date elif day == 3: date += 'rd' return date date += 'th' return date print(str_date(day=1, year=1949, month=10))
运行结果
1949-10-1st
命名空间(namespace)是用字典实现的一个从名字到对象的映射。
简单来说,Python程序启动时,创建了一个全局命名空间。全局命名空间的键值对对应了全局变量和它储存的值(函数名和函数对象 … )。当新定义了一个全局变量时,全局命名空间就会增加一个变量名到变量的值的键值对。当修改变量的值时,全局命名空间中也会修改相应的键值对。globals
函数返回全局命名空间(一个字典)
>>> a = 1 >>> globals() {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'a': 1}
这个字典的键'a'
对应值1
,也就是定义的a = 1
。全局命名空间中还有一些本来就有的键值对,这对应着本来就有的全局变量和它储存的值(对象)。
>>> print(__name__) __main__
函数调用时,会建立一个局部命名空间。在函数内定义的变量,就是这个函数的局部变量。locals
函数返回当前的局部命名空间。
下面的例子定义一个change
函数,尝试在函数内修改全局变量的值,并观察局部命名空间和全局命名空间
>>> def change(): ... a = 2 ... print('Local namespace:', locals()) ... print('Global namespace:', globals()) ... print(a) ... >>> change() Local namespace: {'a': 2} Global namespace: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'a': 1, 'change': <function change at 0x7f8c5c39cd30>} 2 >>> a 1
change
函数没有成功修改全局变量的值,这是因为Python解释器认为a = 2
是在定义局部变量,因此局部命名空间增加了键值对'a': 2
,但全局命名空间的键值对'a': 1
没有改变。当访问一个变量时,Python首先在局部命名空间查找,然后在全局命名空间查找,最后在内置命名空间(内置的函数,变量 … )查找。这解释了为什么函数内的print(a)
打印2
。
在函数内修改全局变量可以使用global
语句,global
语句可以把指定的变量绑定到全局命名空间
>>> def change(): ... global a ... a = 2 ... print('Local namespace:', locals()) ... print('Global namespace:', globals()) ... >>> change() Local namespace: {} Global namespace: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'a': 2, 'change': <function change at 0x7f8c5c39cca0>} >>> a 2
除了使用global
语句,还可以直接修改全局命名空间(字典),来修改全局变量的值
>>> a = 1 >>> def change(): ... globals()['a'] = 2 # 直接修改 ... print('Local namespace:', locals()) ... print('Global namespace:', globals()) ... >>> change() Local namespace: {} Global namespace: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'a': 2, 'change': <function change at 0x7f8c5c39cd30>} >>> a 2
同理,也可以以locals()['name']
的形式修改(创建)局部变量的值。