文章目录
一、函数基础
1、基础
- 所谓函数,就是把 具有独立功能的代码块 组织为一个小模块,在需要的时候 调用
- 函数的使用包含两个步骤:
- 定义函数 —— 封装 独立的功能
- 调用函数 —— 享受 封装 的成果
案例:洗衣服
# 早上洗衣服
print("打水")
print("洗衣服")
print("甩干")
# 中午洗衣服
print("打水")
print("洗衣服")
print("甩干")
# 晚上洗衣服
print("打水")
print("洗衣服")
print("甩干")
发现了问题:我们将有独立功能的代码封装成一个函数
def washing_machine(): # 洗衣机可以帮我们完成
print("打水")
print("洗衣服")
print("甩干")
# 优化后代码
# 早上洗衣服
washing_machine() # 打开洗衣机开关
# 中午洗衣服
washing_machine() # 打开洗衣机开关
# 晚上洗衣服
washing_machine() # 打开洗衣机开关
2、函数的创建与调用
(1)创建函数
函数用 def
语句创建,语法如下:
def 函数名(参数列表): # 具体情况具体对待,参数可有可无
"""函数说明文档字符串"""
函数封装的代码
……
标题行由 def
关键字,函数的名字,以及参数的集合(如果有的话)组成
def
子句的剩余部分包括了一个虽然可选但是强烈推荐的文档字串,和必需的函数体
函数名称 的命名应该 符合 标识符的命名规则
- 可以由 字母、下划线 和 数字 组成
- 不能以数字开头
- 不能与关键字重名
def washing_machine(): # 洗衣机可以帮我们完成
print("打水")
print("洗衣服")
print("甩干")
(2)调用函数
使用一对圆括号 () 调用函数,如果没有圆括号,只是对函数的引用
任何输入的参数都必须放置在括号中
图例:
案例:加洗衣粉
def washing_machine(): # 洗衣机可以帮我们完成
print("打水")
print("加洗衣粉!!!")
print("洗衣服")
print("甩干")
# 早上洗衣服
washing_machine()
# 中午洗衣服
washing_machine()
# 晚上洗衣服
washing_machine()
总结
- 定义好函数之后,只表示这个函数封装了一段代码而已
- 如果不主动调用函数,函数是不会主动执行的
思考
-
能否将 函数调用 放在 函数定义 的上方?
- 不能!
- 因为在 使用函数名 调用函数之前,必须要保证
Python
已经知道函数的存在 - 否则控制台会提示
NameError: name 'menu' is not defined
(名称错误:menu 这个名字没有被定义)
3、函数的参数
(1)形参和实参
- 形参:定义 函数时,小括号中的参数,是用来接收参数用的,在函数内部 作为变量使用
- 实参:调用 函数时,小括号中的参数,是用来把数据传递到 函数内部 用的
问题
当我们想洗其他的东西,要手动改方法内部的代码:
def washing_machine(): # 洗衣机可以帮我们完成
print("打水")
print("加洗衣粉!!!")
print("洗床单") # 洗被套
print("甩干")
在函数内部有一定的变化的值:
def washing_machine(): # 洗衣机可以帮我们完成
print("打水")
print("加洗衣粉!!!")
print("洗衣服")
print("甩干")
washing_machine()
def washing_machine(): # 洗衣机可以帮我们完成
print("打水")
print("加洗衣粉!!!")
print("洗床单")
print("甩干")
washing_machine()
......
思考一下存在什么问题
函数只能处理 固定 的数据
如何解决?
- 如果能够把需要处理的数据,在调用函数时,传递到函数内部就好了!
(2)传递参数
- 在函数名的后面的小括号内部填写 参数
- 多个参数之间使用
,
分隔 - 调用函数时,实参的个数需要与形参个数一致,实参将依次传递给形参
def washing_machine(something): # 洗衣机可以帮我们完成
print("打水")
print("加洗衣粉!!!")
print("洗" + something)
print("甩干")
# 洗衣服
washing_machine("衣服")
# 洗床单
washing_machine("床单")
图例
(3)作用
- 函数,把 具有独立功能的代码块 组织为一个小模块,在需要的时候 调用
- 函数的参数,增加函数的 通用性,针对 相同的数据处理逻辑,能够 适应更多的数据
- 在函数 内部,把参数当做 变量 使用,进行需要的数据处理
- 函数调用时,按照函数定义的参数顺序,把 希望在函数内部处理的数据,通过参数 传递
练习 1:定义一个函数,计算两个数的和
4. 位置参数
与 shell
脚本类似,程序名以及参数都以位置参数的方式传递给 python 程序,使用 sys
模块的 argv
列表接收
import sys
print(sys.argv[1], sys.argv[2]) #类比shell: $1 $2
def get_sum(a,b):
print(a+b)
#位置参数
#a=sys.argv[1],b=sys.argv[2]
#通过终端传来的参数都是字符串类型----这里需要类型转换
get_sum(int(sys.argv[1]),int(sys.argv[2]))
图例
5. 默认参数
默认参数就是声明了 默认值 的参数,因为给参数赋予了默认值,所以在函数调用时,不向该参数传入值也是允许的
def get_sum(num1, num2, num3=10):
print(num1 + num2 + num3)
# 默认参数
# 如果没有手动给形参赋值,那么就用默认值
# 定义函数时,有默认值的参数一定放在没有默认值参数的后面
get_sum(1,2,3) # num01=1, num02=2, num03=3 6
get_sum(1,2) # num01=1, num02=2, num03=10 13
def get_sum1(num01=5, num02): 报错
print(num01 + num02)
def get_sum2(num1=10, num2=20, num3=30):
print(num1 + num2 + num3)
get_sum2() # 60
6. 函数的返回值
- 在程序开发中,有时候,会希望 一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理
- 返回值 是函数 完成工作后,最后 给调用者的 一个结果
- 在函数中使用
return
关键字可以返回结果 - 调用函数一方,可以 使用变量 来 接收 函数的返回结果
注意:
return
表示返回,表示方法执行结束,后续的代码都不会被执行
案例:计算任意两个数字的和
洗完衣服后我们需要把衣服需要使用 return
关键字将每一单的价格返回,告诉帐房先生:
def get_sum(num01, num02):
return num01 + num02
图例
没有 return
如果方法内部没有 return
语句,那么会默认返回 None,即 return None
练习 3:斐波那契数列函数
斐波那契数列函数
- 将斐波那契数列代码改为函数
- 数列长度由用户指定
- 要求把结果用 return 返回
版本一:方法内部直接打印
def gen_fib():
fib = [0, 1] # 定义列表,指定斐波那契数列的初始两个值
n = int(input('长度: ')) # 定义变量n, 此变量为用户要看到的列表fib中的元素个数
for i in range(n - 2):
fib.append(fib[-1] + fib[-2])
print(fib) # 打印列表fib
# 调用两次函数gen_fib()
gen_fib()
gen_fib()
版本二:带返回值
def gen_fib():
fib = [0, 1]
n = int(input('长度: '))
for i in range(n - 2):
fib.append(fib[-1] + fib[-2])
return fib # 返回最后生成的列表fib
# 调用函数gen_fib()
print(gen_fib())
版本三:带参数
def gen_fib(n):
fib = [0, 1]
for i in range(n - 2):
fib.append(fib[-1] + fib[-2])
return fib # 返回最后生成的列表fib
# 定义列表nlist, 将要产生的斐波那契数列的长度,作为列表nlist的元素
nlist = [10, 8, 6]
# 使用for循环,传递实参(nlist中的元素)给函数gen_fib(n),得到三组斐波那契数列
for i in nlist:
print(gen_fib(i))
练习4:复制文件函数
- 修改文件练习中的拷贝程序
- 将程序改为函数的形式
- 源文件和目标文件要求通过参数进行传递
- 实参要求来自于命令行
版本1:
# 定义函数copy(),实现指定单个文件拷贝的功能
def copy():
src_name = '/usr/bin/ls'
dst_name = '/tmp/list3'
# 以只读字节的方式打开源文件,赋值给变量src_fobj
# 以写入字节的方式打开源文件,赋值给变量dst_fobj
src_fobj = open(src_name, 'rb')
dst_fobj = open(dst_name, 'wb')
while 1:
data = src_fobj.read(4096)
if len(data) == 0:
break
dst_fobj.write(data)
src_fobj.close()
dst_fobj.close()
copy() # 调用拷贝文件的函数copy()
版本2:
def copy(src_name, dst_name): # 定义函数copy(),实现任意文件的拷贝操作
# 以只读字节的方式打开源文件,赋值给变量src_fobj
# 以写入字节的方式打开源文件,赋值给变量dst_fobj
src_fobj = open(src_name, 'rb')
dst_fobj = open(dst_name, 'wb')
while 1:
data = src_fobj.read(4096)
if len(data) == 0:
break
dst_fobj.write(data)
src_fobj.close()
dst_fobj.close()
copy(源文件路径, 目标文件路径) # 使用sys模块的,argv列表获取位置参数
二、函数进阶
1. 创建函数
def语句
- 标题行由 def 关键字、函数的名字,以及参数的集合(如果有的话)组成
- def 子句的剩余部分包括了一个虽然可选但是强烈推荐的文档字串,和必需的函数体
前向引用
- 函数不允许在函数未声明之前,对其进行引用或者调用
def foo(): # 定义函数foo(),先调用bar()函数,报错,下面定义以后,报错取消
print('in foo')
bar()
def bar(): # 定义函数bar()
print('in bar')
foo() # 函数foo()已经被定义,可以直接调用
注意
- 定义函数时,函数的先后顺序不重要,重要的是 函数在什么位置被调用
调用函数
- 使用一对圆括号() 调用函数,如果没有圆括号,只是对函数的引用
- 任何输入的参数都是必须放置在括号中
>>> def foo(): # 定义函数foo()
... print('in foo')
...
>>> foo # 调用函数时,函数名后必须有小括号,否则返回一个位置对象
>>> foo() # 函数得正确调用方式
关键字参数
- 关键字参数的概念仅仅针对函数的调用
- 这种理念是 让调用者通过函数调用中的参数名字来区分参数
- 这种规范允许参数不按顺序
- 位置参数应写在关键字参数前面
>>> def get_age(name, age): #关键字参数的使用,定义函数get_age(name,age), 形参:name和age
... print('%s is %s years old' % (name, age))
...
>>> get_age('tom', 20) #调用函数get_age(name,age),name为‘tom’,age为20
>>> get_age(20, 'tom') #会按照顺序将实参传递给对应得形参,name=20,age='tom'
>>> get_age(age=20, name='tom') #使用关键字进行传参
>>> get_age(age=20, 'tom') #关键字参数【age=20】要写在位置参数【'tom'】的后面
>>> get_age(20, name='tom') #传递实参时,位置参数name在第一个位置,在这里获取了两个name的值
>>> get_age('tom', age=20) #传递实参时,name值为'tom',age值为20,正确
练习 1:简单的加减法数学游戏
需求
- 随机生成两个100以内的数字
- 随机选择加法或是减法
- 总是使用大的数字减去小的数字
创建新的python文件math_game.py ,构建加减法数学游戏程序的结构
def exam(): #函数exam(), 功能:出题,让用户作答
pass
def main(): #函数main(), 功能:主函数,用户选择继续答题或退出
while 1: #永久循环
exam() #调用函数,让用户作答
#判断是否继续
yn = input('Continue(y/n)?')
if yn in 'nN':
print('\nBye-bye')
break
if __name__ == '__main__':
main()
编写出题函数 exam()
# 导入random模块的randint方法【随机产生一个整数】和choice方法【随机取出一个元素】
from random import randint, choice
def exam():
nums = [randint(1, 100) for i in range(2)] #使用列表解析,产生两个1 ~ 100的随机整数
nums.sort(reverse=True) #让列表nums中的元素,从大到小排序
op = choice('+-') #随机取出运算符'+'或'-'
if op == '+': #当op为'+'或'-'时,得到列表nums中两个元素的正确计算结果
result = nums[0] + nums[1]
else:
result = nums[0] - nums[1]
prompt = '%s %s %s = ' % (nums[0], op, nums[1]) #给用户显示出题信息
answer = int(input(prompt)) #定义变量answer,获取用户输入得答案
if answer == result: #判断用户答案和正确结果是否相等,打印相应信息
print('Very Good!!!')
else:
print('Wrong Answer!!!')
def main(): #函数main(), 功能:主函数,用户选择继续答题或退出
while 1: #永久循环
exam() #调用函数,让用户作答
yn = input('Continue(y/n)?')
if yn in 'nN':
print('\nBye-bye')
break #退出while循环
if __name__ == '__main__':
main()
2. 匿名函数
- python 允许用 lambda 关键字创造匿名函数
- 匿名是因为不需要以标准的 def 方式来声明
- 一个完整的 lambda "语句"代表了一个表达式,这个表达式定义体必须和声明放在同一行
# 使用def定义函数add(x,y)
def add(x, y):
return x + y
if __name__ == '__main__':
print(add(10, 5))
myadd = lambda x, y: x + y # 定义匿名函数,赋值给myadd,x和y作为形参
print(myadd(10, 20))
filter() 函数
- filter(func, seq): 调用一个布尔函数 func 来迭代遍历每个序列中的元素;返回一个使 func 返回值为 true 的元素的序列
- 如果布尔函数比较简单,直接使用 lambda 匿名函数就显得非常方便了
filter(func, seq)函数的使用,如果seq序列中的元素,传入函数func后,返回值为True,则保留下来
from random import randint #导入random模块的randint方法(随机产生一个整数)
def func1(x): #定义函数func1(x),奇数返回True, 偶数返回False
return True if x % 2 == 1 else False
if __name__ == '__main__':
nums = [ randint(1, 100) for i in range(10)] #10个100以内的随机数
print(nums) #打印nums
result = filter(func1, nums) #filter()过滤结果
result2 = filter(lambda x: True if x % 2 == 1 else False, nums)
print(list(result)) #将result转换为列表,打印
print(list(result2))
map() 函数
- map(func, seq): 调用一个函数func 来迭代遍历每个序列中的元素;返回一个经过func处理过的元素序列
map(func, seq)函数的使用,将seq序列中的元素,传入函数func后,经过处理后全部保留下来
from random import randint
def func2(x): # 定义函数func2(x),函数返回结果:(x * 2) + 1
return x * 2 + 1
if __name__ == '__main__':
nums = [ randint(1, 100) for i in range(10)] # 10个100以内的随机数
print(nums) # 打印nums
result3 = map(func2, nums) # 结果为:nums经过函数func2处理后的序列对象
result4 = map(lambda x: x * 2 + 1, nums)
print(list(result3)) # 将result3转换为列表,打印
print(list(result4))
总结