函数
# 古诗:悯农
# 改需求
a = '*'
for i in range(100):
print('锄禾日当午')
print('*********')
print('汗滴禾下土')
print('@@@@@@@@@')
print('谁知盘中餐')
print('+++++++++')
print('粒粒皆辛苦')
print('---------')
- 函数的特点
1. 避免代码冗余
2. 提高代码的可维护性
程序员可控的代码量:2W
3. 提高代码的灵活性
4. 提高代码的可重用性
- 函数的语法
将可重用的逻辑,或者拥有独立功能的代码封装成一起
定义(概念):函数由一组代码构成,完成一个特定的任务
语法:
关键字:def:声明要定义一个函数了
函数的声明:
def 函数名(形式参数):
代码(结构体)
函数的调用:
函数名(实际参数)
调用函数的时候分为函数名+(),但凡在定义之外只要出现括号了,就说明函数被调用了
- 函数定义的位置
定义(创建):
1. 定义在全局位置
在没有缩进的位置定义
2. 定义在任何函数的内部
局部性质
- 函数的运行机制
流程:
1. 编译流程
1. 通过编译器寻找def关键字,创建了一个函数对象
2. 创建函数体(但是不执行)
2. 执行流程
1. 执行函数的调用
2. 根据函数名跳转到函数定义的位置
3. 执行函数体
4. 执行完毕函数体,流程返回到函数调用处继续向下执行
- 函数的结构
1. 函数的声明:
def:define
函数名:一定要好好命名(必须自己能看懂)
形式参数
2. 函数体:
内容,函数的功能要实现的核心内容
3. 函数的返回值:
默认返回None
可以返回任意值
可以返回多个值,返回多个值的时候,打包成元组
- 函数的声明
关键字:def
函数名:全小写
参数:形式参数(可以没有)
函数的参数
1. 形式参数
函数声明的时候,定义的参数
简称:形参
相当于函数的局部变量
2. 实际参数
函数调用过程中,传入的参数
简称:实参
相当于给函数的形式参数赋值
3. 没有定义任何参数
称之为无参
- 位置参数
参数和位置有关
1. 实参和形参的位置必须一一对应
2. 位置参数的数量必须一一匹配
3. 位置参数,一旦设定,必须传值。
def func(a,b):
print(a)
func(1,2)
- 关键字参数
1. 基于形参
2. 不受位置的影响
3. 实参和形参必须一一对应
def func(a,b):
print(a)
func(b=2,a=1)
- 默认参数
1. 基于形参
2. 如果不传递实际参数,则使用默认值作为实参
3. 如果传递实参,则使用传递后的实参
def func(a,b):
print(a)
func(b=2,a=1)
- 可变长参数
可以接收多个参数的形参
1. 基于形参
2. 分类:
1. *args
将接收到的多个参数打包成一个元组
只能通过位置参数来传递
2. **kwargs
将接收的多个参数打包成字典
只能通过关键字参数传值
3. 相同类型的可变长参数,只能有一个
4. 可变长参数可以改名
def func(**kwargs):
print(kwargs)
func(a=1,b=2,c=3,d=4,e=5)
- 混用情况
1. 关键字参数和位置参数混用
关键字参数只能出现在位置参数之后
原因:参数出现等号的形式,之后的所有参数,都被视为等号形式传值
2. 默认参数和未知参数混用
默认参数只能出现在位置参数之后
3. 可变长参数和位置参数混用:
约定俗成:可变长参数要放在最后并且先 *args 再 **kwargs
- 函数的文档注释
1. 必须出现在函数体的第一行
2. 习惯上使用三引号作为文档注释
可以使用单引号或者双引号
3. 函数文档的查看:
可以按着ctrl+鼠标单击该函数查看
查看help(函数名)
函数和过程
- 函数的返回值
return
1. 任何函数必须有返回值
2. 如果函数中不写任何的return,在函数结尾的地方,自动添加一个return None
3. 如果函数中只写了return但是没有携带任何值,自动添加一个None
4. return的作用:
1. 返回流程
2. 返回的时候,可以顺便携带一个值(一定会有返回值)
5. return的值:
1. 任何对象
2. 返回值有且只有一个
3. 如果要返回多个值,打包成元组进行返回
4. 如果返回的是表达式,那么返回的是表达式计算出的值
5. 返回一个函数的调用
函数的返回值就是被调用的函数的返回值(间接获取的返回值)
6. 可以返回一个函数对象
返回形式:return 函数名
注意:被返回的函数并没有执行(没有调用)
注:
pass:是一个关键字,表示不写任何内容
def func(a):
if a=='帅':
return func2
else:
return func3
def func2():
return 'my name is zhangyanhao'
def func3():
return 'my name is yaojiaqi'
print(func(a='更帅')())
- 函数变量的作用域
作用域:作用范围
1. 全局变量
1. 没有缩进的变量
2. 先定义后使用
3. 作用范围:从定义开始到包含他的代码块结束
2. 局部变量
1. 定义在函数内部的变量
2. 先定义后使用
3. 作用范围:从定义开始到包含他的代码块结束
3. 如果函数内部的局部变量和全局变量发生了命名冲突,在局部访问的是局部变量,在全局使用的是是全局变量(相互不干扰)
如果全局变量和局部变量重名,那么会在局部创建一个同名对象
- global关键字
如果函数内部的同名局部变量的修改影响同名的全局变量,应该使用global
1. global 变量名:声明从该行开始,本层代码的所有该变量,都是全局变量
只对本层有效
a = 1
def func():
global a
a = 3
print(a)
func()
print(a)
- nonlocal
影响上一层的同名的局部变量
1. nonlocal影响上一层的同名局部变量
2. 如果上一层没有对应的局部变量,则报错:
SyntaxError: no binding for nonlocal 'b' found
3. nonlocal和global不能同时声明同一个变量
a = 1
def func():
a = 2
def func1():
nonlocal a
print(a)
a = 3
print(a)
print(a)
func1()
func()
print(a)
- 匿名函数
没有函数名的函数对象
1. 临时使用一次
2. 函数只使用一次
可以避免命名冲突
关键字:lambda
语法:
lambda 形参:返回值
1. lambda 用于创建函数对象
2. lambda书写的形式:lambda表达式
3. lambda表达式本身的优先级比较低
lambda的效率比较高
- 补充
函数的构成:1. 函数的声明+返回值2. 函数的函数体(过程)函数和内容是分离的,是两个不同的部分。
- lambda表达式的作用
1. 可以避免使用函数名,使用方便,代码更加简洁,优雅
2. 提高代码的可读性
print((lambda n:('偶数' if n%2==0 else '奇数'))(int(input('请输入一个整数'))))
高级函数
- 函数式编程
1. 也称之为泛函式编程,是一个编程范式:
可以将一个函数对象作为参数传递给另外一个函数,被传入的函数对象的执行过程,在调用函数中执行。
2. 函数式编程最重要的基础是lambda表达式
lambda表达式可以返回一个函数对象
- filter()
python2:函数
Python3:类
filter:过滤
1. filter(function or None, iterable)
fuction or None:第一个参数可以是一个函数或者是None
iterable:可迭代对象
1. 如果给了function,则将可迭代对象中的每一个元素,传递给function作为参数,筛选出所有结果为真的值。
2. 如果function没有给出,必须要给None,直接返回iterable中所有为真的值
真值:任何非零的值
假值:零,所有的空
0,False,所有的空
- map
python2:函数
python3:类
map:映射
1. map(func, *iterables)
func:函数
iterables:
运算iterables多个可迭代对象,将每个可迭代对象相同下表的元素,作为参数传递给func,返回一个map对象
函数嵌套调用和递归
- 函数的嵌套使用
1. 一个函数调用另外一个函数,函数的嵌套使用
两个函数之间有没有关系:没有必然联系
1. 分别隶属于两个不同的函数
2. 内嵌函数
3. 自己搞自己:递归
- 使用函数的必要性
1. 拥有特殊功能的代码,抽取出来,封装为函数
2. 重复使用的代码,抽取出来,封装成函数
只要重复使用>=2次,则封装为函数
判断用户名是否合法:用户登录、用户注册、管理员登录
3. 简化开发流程
- 函数的递归
函数的嵌套使用:一个函数调用另一个函数
递归:一个函数调用自己
1. 注意:避免无穷递归
解决方案:设置好递归的终止条件 return
2. 报错的原因:
执行原理:函数的无穷递归区别于死循环(递归不是循环!)
循环:代码块级别---在同一个代码块中无限的执行,占用的空间不超过一个代码块,仅仅是一个重复的过程
递归:对象级别---一个对象中可以由多个代码块,对象的内存占用量要远大于一个代码块;每次新调用,都会创建一个新的函数对象,内存是无限累加使用的---无限递归最终会导致内存溢出(内存满了不够用)
小结:循环消耗较少而递归消耗较大
报错的直接原因:超过了最大深度
python为了保护系统的内存,设置了递归的层数,如果超过层数则报错,最大层数996次
3. 递归的使用
1. 递归本身效率很低,一般用于解决难题,比如八皇后
2. 尽量不要用递归,能用递归解决的一定能用循环解决。
递归:汉诺塔(Hanoi)、八皇后
- 实验课内容
1. 利用递归攻关汉诺塔和八皇后
2. 将图书管理系统更新为函数版
改需求
图书管理系统 V2.0
如果是第二位和第三位发生改变,则意味着,开发者保证,虽然更新了但是根据当前方法现有的功能依然可以使用。
如果更改了第一位,那么开发者不保证,使用当前方法依然可以使用。
启动系统以后,出现欢迎页面,要求用户登录或者注册。
# 序号,书名,作者,出版社,ISBN,分类,库存,价格
注册:
需要跳转到另外一个页面进行注册
注册需要用户输入用户名
密码、确认密码。
密码需要进行分级
用户名:需要同时包含数字和字母,不允许使用特殊符号,长度8-16位
密码:不允许全是特殊符号,长度最长16位
低级:密码长度在8位以下或者只包含数字或者只包含字母(字母、数字、特殊符号只包含一种类型)
中级:密码长度在8位以上并且包含数字和特殊符号或者数字和字母或者字母和特殊符号(字母、数字、特殊符号包含任意两种)
高级:密码长度在12位以上,并且同时包含数字、字母、大写字母、小写字母、特殊符号
其他任何情况都是低级
用户输入密码以后,需要告知用户,当前的密码等级,如果密码等级为低级,则不允许注册
如果用户在注册的过程中出错,那么要求重新注册。如果注册成功,返回图书管理系统的主页面。
登录:需要分辨是用户登录还是管理员登录
主页面:
1. 查:查看图书
1. 显示所有图书
2. 根据书名查找图书
3. 根据作者查找,思路同上
4. 根据分类查找,思路同上
5. 根据价格查找,用户给阈值
2. 改:管理员
1. 改书名
给用户展示所有图书
让用户选择图书的序号
让用户输入新的书名
更改完成后,再输出所有的图书让用户看一眼
2. 改作者
3. 改出版社
4. 改分类
5. 改价格
3. 增:管理员
添加图书
需要用户输入添加图书的相关信息
有些数据必须有,有些数据可以为空
必须有:书名、库存、价格
4. 删除:管理员
展示给用户所有的图书
用户选择序号,进行删除
5. 用户管理:管理员
1. 增加用户:
1. 增加普通用户
2. 增加管理员用户
2. 删除用户:
1. 删除普通用户
3. 更改用户:
1. 根据当前的用户名更改用户的用户名(改名卡)
2. 更改用户的密码
4. 查看用户:
1. 查看所有用户
2. 根据用户名查看用户
写到一个py文件里
每个功能完成后,询问用户是否继续,输入1继续,输入0退出