函数
函数是实现一定功能的代码段,传入参数,返回值。
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']
的形式修改(创建)局部变量的值。