函数是执行特定任务的一段代码,程序通过将一段代码定义成函数,并为该函数指定一个函数名,这样即可在需要的时候多次调用这段代码。
一、函数入门
通俗来讲,所谓函数,就是指为一段实现特定功能的代码“取”一个名字,以后即可通过该名字来执行(调用)该函数。
函数可以接收零个或多个参数,也可以返回零个或多个值。
从函数定义者(实现函数的人)的角度来看,至少需要想清楚一下3点:
● 函数需要几个关键的需要动态变化的数据,这些数据应该被定义成函数的参数。
● 函数需要传出几个重要的数据(就是调用该函数的人希望得到的数据),这些数据应该被定义成返回值。
● 函数的内部实现过程。
函数定义语法格式:
def 函数名(形参列表):
# 由零条到多条可执行语句组成的函数
[return [返回值]]
● 函数名:一个合法的标识符。
● 形参列表:用于定义该函数可以接受的参数。由多个形参名组成,之间用英文逗号隔开。——谁调用,谁负责对形参赋值。
在函数体中使用return语句可以显式地返回一个值,return语句返回的值既可是有值的变量,也可是一个表达式。
通过内置的help()函数可以查看函数的帮助文档——只要把一段字符串放在函数声明之后、函数体之前,这段字符串将被作为函数的部分,这个文档就是函数的说明文档。
除了help()函数,也可通过__doc__属性访问函数的说明文档。
在一个函数体内调用它自身,被成为函数递归。函数递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
如:已知有一个数列:f(0) = 1, f(1) = 4, f(n+2) = 2*f(n+1) + f(n),其中n是大于0的整数,求f(10)的值。
def fn(n):
if n == 0:
return 1
elif n == 1:
return 4
else:
# 在函数体中调用它自身,就是函数递归
return 2 * fn(n - 1) + fn(n - 2)
# 输出fn(10)的结果
print("fn(10)的结果是:", fn(10))
※ 递归一定要向已知方向进行。
二、函数的参数
按照形参位置传入的参数被称为位置参数。根据参数名来传入参数值被称为关键字(keyword)参数。
使用位置参数的方式来传入参数值,必须严格按照定义函数时指定的顺序来传入参数值,使用关键字参数调用时,可交换参数的位置。
如果混合使用了关键字参数和位置参数,则关键字参数必须位于位置参数之后。换句话说,关键字参数之后只能是关键字参数。
Python要求将带默认值的参数定义在形参列表的最后。
Python允许在形参前面添加一个星号(*),这样就意味着该参数可接收多个参数值,多个参数值被当成元组传入。
Python允许个数可变的形参处于形参列表的任意位置(不要求是形参列表的最后一个参数),但一个函数最多只能带一个支持“普通”参数收集的形参。
Python还可以收集关键字参数,此时Python会将这种关键字参数收集成字典。为了让Python能收集关键字参数,需要在参数前面添加两个星号。
所谓逆向参数收集,指的是在程序已有列表、元组、字典等对象的前提下,把它们的元素“拆开”后传给函数的参数。逆向参数收集需要在传入的列表、元组参数之前添加一个星号,在字典参数之前添加两个星号。代码如下:
def test(name, message):
print("用户是:", name)
print("欢迎消息:", message)
my_list = ['刘德华', '欢迎来Python世界']
test(*my_list)
即使支持收集的参数,如果需要将一个元组传给该参数,那么同样需要使用逆向收集。如:
def foo(name, *nums):
print("name参数:", name)
print("nums参数:", nums)
my_tuple = (1, 2, 3)
# 使用逆向收集,将my_tuple元组的元素传给nums
foo('fkit', *my_tuple)
这里的*号相当于解包操作符,它会将元组拆分成元素,然后依次赋值给函数的形参。如果通过
foo(*my_tuple)
来调用,则会将1赋值给name,2,3赋值给nums。
如果不使用逆向收集,通过foo(my_tuple)则会将my_tuple整体作为参数值传给name参数。
字典也支持逆向收集,以关键字参数的形式传入函数。
Python中函数的参数传递机制都是“值传递”。就是将实际参数值的副本(复制品)传入函数,而参数本身不会受到影响。
● 不管什么类型的参数,在Python函数中对参数直接使用“=”符号赋值是没用的,直接使用“=”符号赋值并不能改变参数。
● 如果需要让函数修改某些数据,则可以通过把这些数据包装成列表、字典等可变对象,然后把列表、字典等可变对象作为参数传入函数,在函数中通过列表、字典的方法修改它们。
变量分两种:
● 局部变量。在函数中定义的变量,包括参数,都被称为局部变量。
● 全局变量。在函数外面、全局范围内定义的变量,被称为全局变量。
每个函数执行时,系统都会为该函数分配一块“临时内存空间”,所有的局部变量都被保存在这块临时内存空间内,当函数执行完毕,这块内存空间就被释放了,局部变量也就失效了,因此离开函数之后就不能再访问局部变量了。
全局变量可以在所有函数内被访问。
Python提供了三个工具函数来获取指定范围内的“变量字典”
● globals():该函数返回全局范围内所有变量组成的“变量字典”
● locals():该函数返回当前局部范围内所有变量组成的“变量字典”
● vars(object):获取在指定对象范围内所有变量组成的“变量字典”。如果不传入object参数,vars()和locals()的作用完全相同。
● locals()总是获取当前局部范围内所有变量组成的“变量字典”,如果在全局范围内(在函数之外)调用locals()函数,同样会获取全局范围内所有变量组成的“变量字典”;而globals()无论在哪里执行,总是获取全局范围内所有变量组成的“变量字典”
● 使用locals()和globals()获取的“变量字典”只应被访问,不应被修改。
Python语法规定:在函数内部对不存在的变量赋值时,默认就是重新定义新的局部变量。
可以通过globals()函数在函数内部定义全局变量。
为了避免在函数中对全局变量赋值(不是重新定义局部变量),可以使用global语句来声明全局变量。
三、局部函数
Python支持在函数体内定义函数,被成为局部函数。
Python提供了nonlocal关键字,可以声明访问赋值语句只是访问该函数所在的函数内部的局部变量。
global用于声明访问全局变量,而nonlocal用于声明访问当前函数所在函数内的局部变量。
四、函数的高级内容
Python的函数也是一种值:所有函数都是function对象,这意味着可以把函数本身赋值给变量,就像把整数、浮点数、列表、元组赋值给变量一样。
Python支持像使用其他参数一样使用函数参数。
Python还支持使用函数作为其他函数的返回值。
五、局部函数与lambda表达式
lambda表达式是现代编程语言争相引入的一种语法,如果说函数是命名的、方便复用的代码块,那么lambda表达式则是功能更灵活的代码块,它可以在程序中被传递和调用。
Python要求lambda表达式只能是单行表达式。
lambda表达式的语法格式如下:
lambda [parameter_list]: 表达式
● lambda表达式必须使用lambda关键字定义
● 在lambda关键字之后、冒号左边的是参数列表,可以没有参数,也可以有多个参数。如果有多个参数,则需要用逗号隔开,冒号右边是该lambda表达式的返回值。
lambda表达式的本质就是匿名的、单行函数体的函数。
lambda表达式的用途:
● 对于单行函数,使用lambda表达式可以省去定义函数的过程,让代码更简洁。
● 对于不需要多次复用的函数,使用lambda表达式可以在用完之后立即释放,提高了性能。
习题:
1. 定义一个函数,该函数可接收一个list 作为参数,该函数使用直接选择排序对list 排序。
def sort_list(sort_list):
temp_list = []
for i in range(len(sort_list)):
min_var = min(sort_list)
sort_list.remove(min_var)
temp_list.append(min_var)
return temp_list
my_list = [3, 2, 3, 2, 1, 3, 2, 2, 1]
print(sort_list(my_list))
2. 定义一个函数,该函数可接收一个list 作为参数,该函数使用冒泡排序对list 排序。
def sort_list(sort_lst):
lst_len = len(sort_lst)
for i in range(0, lst_len):
sort_flag = True
for j in range(0,lst_len - i - 1):
if sort_lst[j] > sort_lst[j + 1]:
sort_lst[j], sort_lst[j + 1] = sort_lst[j + 1], sort_lst[j]
sort_flag = False
if sort_flag:
break
return sort_lst
my_lst = [5, 9, 3, 1, 2, 8, 4, 7, 6]
print(sort_list(my_lst))
3. 定义一个is_leap(year) 函数,该函数可判断year是否为闰年。若是闰年,则返回True ;否则返回False 。
def is_leap(year):
year = int(year)
if(year % 4 == 0) and (year % 100 != 0):
return True
elif (year % 400 == 0):
return True
else:
return False
while(True):
year = input('请输入一个年份:')
if year == 'exit':
import sys
sys.exit(0)
print('%s是闰年吗?%s' % (year, is_leap(year)))
4. 定义一个count_str_ char( my_ str)函数,该函数返回参数字符串中包含多少个数字、多少个英文字母、多少个空白字符、多少个其他字符。
def count_str_char(my_str):
digit_count = 0
char_count = 0
blank_count = 0
other_count = 0
for ch in my_str:
if ch.isdigit():
digit_count += 1
elif ch.encode('utf-8').isalpha():
char_count += 1
elif ch.isspace():
blank_count += 1
else:
other_count += 1
return digit_count, char_count, blank_count, other_count
while(True):
my_str = input('请输入一个字符串:')
if my_str == 'exit':
import sys
sys.exit(0)
digit_count, char_count, blank_count, other_count = count_str_char(my_str)
print('字母个数:', char_count)
print('数字个数', digit_count)
print('空白个数:', blank_count)
print('其他字符个数:', other_count)
5. 定义一个fn(n)函数,该函数返回1~n的立方和,即求1+2*2*2+3*3*3+…+n*n*n。
def fn(n):
result = 0
for i in range(n + 1):
result += pow(i, 3)
return result
while(True):
n = input('请输入一个整数:')
if n == 'exit':
import sys
sys.exit(0)
if not n.isdigit():
print('您输入的不是一个数字!')
continue
print('1~n的立方和为:', fn(int(n)))
6. 定义一个fn(n)函数,该函数返回n 的阶乘。
def fn(n):
if n == 0:
return 1
if n == 1:
return 1
return n * fn(n-1)
while(True):
n = input('请输入一个整数:')
if n == 'exit':
import sys
sys.exit(0)
if not n.isdigit():
print('您输入的不是一个数字!')
continue
print('%s的阶乘是:%d' % (n, fn(int(n))))
7. 定义一个函数,该函数可接收一个list 作为参数,该函数用于去除list 中重复的元素。
def list_uniq(lst):
temp_lst = set(lst)
return list(temp_lst)
my_lst = [1, 2, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4]
print(list_uniq(my_lst))
8. 定义一个fn(n)函数,该函数返回一个包含n 个不重复的0~ 100 之间整数的元组。
import random
def fn(n):
temp_lst = []
for i in range(n):
while(True):
num = random.randint(0, 100)
if num not in temp_lst:
temp_lst.append(num)
break
return tuple(temp_lst)
print(fn(10))
9. 定义一个fn(n)函数,该函数返回一个包含n 个不重复的大写字母的元组。
import random
def fn(n):
temp_lst = []
for i in range(n):
while(True):
ch = chr(random.randint(65, 91))
if ch not in temp_lst:
temp_lst.append(ch)
break
return tuple(temp_lst)
print(fn(10))
10. 定义一个fn(n)函数,其中n 表示输入n 行n 列的矩阵(数的方阵〉。在输出时,先输出n行n 列的矩阵,再输出该矩阵的转置形式。例如,当参数为3 时,先输出:
1 2 3
4 5 6
7 8 9
再输出:
1 4 7
2 5 8
3 6 9
def fn(n):
# 先输出n行n列的矩阵
for i in range(n):
for j in range(n):
print(i * n + j + 1, end=' ')
print()
# 再输出转置矩阵
for i in range(n):
for j in range(n):
print(j * n + i + 1, end=' ')
print()
fn(3)