Python学习
python函数
函数的创建
- 格式:
def 函数名([输入参数]):
函数体
[return xxx]
函数的使用
def calc(a, b):
return a + b
print(calc(10, 20)) # 30
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZEKXqZ9g-1654523798082)( https://imgs3.loukky.com/imgs/2022/06/06/179a58f684f8f585.png )]
函数的参数传递
- 位置实参:根据形参对应的位置进行实参传递
def calc(a, b): # a,b 称为形式参数,简称形参,形参的位置在函数定义处
return a - b
# 10,50 是实际参数的值,简称 实参,实参的位置是函数调用处
print(calc(10, 50)) # -40
- 关键字实参:根据形参名称来实参传递
def calc(a, b): # a,b 称为形式参数,简称形参,形参的位置在函数定义处
return a - b
# 等号左边的变量称为 关键字参数,即b,a都是关键字参数
print(calc(b=10, a=50)) # 40
参数传递的内存分析图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FQ57e2Yb-1654523798084)( https://imgs3.loukky.com/imgs/2022/06/06/36f0b79eafd83e04.png )]
在函数的参数传递的过程中:
-
如果传递的是不可变对象,则在函数体中的操作,不会对不可变对象造成影响,即上述的n1依旧是11
-
如果传递的是可变对象,比如列表、字典、集合等,则函数体中对可变对象的操作会使可变对象发生改变,即完成函数调用后,n2变成了[22,33,44,10]
函数的返回值
- 函数没有返回值,return可以不写
- 函数返回一个值时,直接返回该值,返回类型为该值的类型
- 函数返回多个值时,结果为元组
def calc(a, b):
a = a - b
return a - b, a + b
print(calc(10, 20)) # (-30,10)
print(type(calc(10, 20))) # <class 'tuple'>
函数的参数定义
函数定义形参的默认值
当传递参数时,没有给设置了默认值的形参传递值时,该形参使用设置好的默认值,如果传递了值,则使用传过来的值
def calc(a, b=30):
return a + b
print(calc(10)) # 40
print(calc(10, 50)) # 60
个数可变的位置参数
- 定义函数时,可能无法事先确定传递的 位置实参 的个数时,使用可变的位置参数
- 使用 * 定义 个数可变的位置形参
- 结果为一个元组
- 可变的位置参数只能有一个,如 def func(*args,*a) 这样子定义函数是错误的
def func1(*args):
print(args)
func1(10) # (10,)
func1(10, 20) # (10, 20)
func1(10, 20, 30) # (10, 20, 30)
个数可变的关键字参数
- 定义函数时,无法事先确定传递的 关键字实参 的个数时,使用可变的关键字形参
- 使用 ** 定义 个数可变的关键字形参
- 结果为一个字典
- 可变的关键字参数只能有一个,如 def func(**args,**a) 这样子定义函数是错误的
def func1(**args):
print(args)
func1(a=10) # {'a': 10}
func1(a=10, b=20) # {'a': 10, 'b': 20}
func1(a=10, b=20, c=30) # {'a': 10, 'b': 20, 'c': 30}
个数可变的位置参数和个数可变的关键字参数可以搭配使用,但是个数可变的位置参数需要在个数可变的关键字参数之前,如:def func2(*args1,**args2): 这样子是可行的,但是 def func2(**args1,*args2): 是不可行的
将序列中的每个元素都转换成位置实参
- 使用 *
def func1(a, b, c):
print('a', a)
print('b', b)
print('c', c)
func1(10, 20, 30)
'''
a 10
b 20
c 30
'''
list1 = [11, 22, 33]
# func1(list1) TypeError: func1() missing 2 required positional arguments: 'b' and 'c'
func1(*list1)
'''
a 11
b 22
c 33
'''
将字典中的每个键值对都转换成关键字实参
- 使用 **
def func1(a, b, c):
print('a', a)
print('b', b)
print('c', c)
func1(a=10, b=20, c=30)
'''
a 10
b 20
c 30
'''
dict1 = {'c': 10, 'b': 20, 'a': 30}
# func1(dict1) TypeError: func1() missing 2 required positional arguments: 'b' and 'c'
func1(**dict1)
'''
a 30
b 20
c 10
'''
限制必须使用关键字传递
- 使用 *
def func1(a, *, b, c): # 这里的 * 表示,* 号之后的参数必须采用关键字参数传递,* 之前采用位置或者关键字都行
print('a', a)
print('b', b)
print('c', c)
func1(a=10, b=20, c=30)
'''
a 10
b 20
c 30
'''
# func1(10,20,c=30) TypeError: func1() takes 1 positional argument but 2 positional arguments (and 1 keyword-only argument) were given
func1(10, b=20, c=30)
'''
a 10
b 20
c 30
'''
传递参数时,必须是先位置参数,再关键字参数
比如说:函数定义时: def func1(a,b,c):
函数调用时: func1(10,20,c=30) 这种是正确的
func1(a=10,20,c=30) 这种是错误的
可行的函数定义格式:
- def func(a,b,*,c,d):
- def func(a,b,*,c,d,**args):
- def func(a,b=10,*args1,**args2):
变量的作用域
- 变量的作用域是指 程序能够访问该变量的区域
- 根据变量被访问的范围,可分为:
- 局部变量
- 在函数内定义并使用的变量,只在函数内部有效
- 局部变量使用global声明,这个变量就会就成全局变量
- 全局变量
- 函数体外定义的变量,可作用于函数内外
- 局部变量
name = 'wwj' # 全局变量,程序任意地方都访问得到
def func1():
age = 20 # 局部变量,只有该函数的方法体内才访问的到
global sex
sex = '男'
print(name, '\t', age)
func1() # wwj 20
# print(age) age为局部变量,访问不到
print(sex) # 男 sex 被global声明,变成全局变量
递归函数
- 什么是递归函数
- 如果在一个函数的函数体内调用了该函数本身,这个函数就称为递归函数
- 递归函数的组成部分
- 递归调用与递归终止条件
- 递归的调用过程
- 每递归调用一次函数,都会在栈内存分配一个栈帧,
- 每执行完一次函数,都会释放相应的空间
- 递归的优缺点
- 缺点:占用内存多,效率低下
- 优点:思路和代码简单
练习题:使用递归来计算 n 的阶乘
def func(n):
if n == 1:
return 1
else:
return n * func(n - 1)
print(func(6)) # 720
练习题:斐波拉契数列 1、1、2、3、5、8、13…
def func(n):
if n == 1:
return 1
elif n == 2:
return 1
else:
return func(n-2)+func(n-1)
print(func(6)) # 8
Bug常见类型
- 漏了末尾的冒号,如if语句,循环语句,else子句等
- 缩进错误,该缩进的没缩进,不该缩进的瞎缩进
- 把英文符号写成中文符号,比如说:引号,冒号,括号
- 字符串拼接的时候,把字符串和数字拼在一起
- 没有定义变量,比如说while的循环条件的变量
- “==” 比较运算符和 “=” 赋值运算符的混用
- 索引越界异常 IndexError
- append() 方法添加元素,一次只能添加一个元素
python的异常处理机制
一般,当程序出现异常,程序立刻停止运行,但是也有方法处理异常,保证当异常发生时,捕获异常并对其进行处理,确保了程序的正常运行
try…except…结构
单个except示意图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gcaYMkqU-1654523798085)( https://imgs3.loukky.com/imgs/2022/06/06/2a8fbde6b2ed5bd3.png )]
def func(a, b):
return a / b
try:
print(func(10, 0)) # 除数不能为0!
except ZeroDivisionError:
print('除数不能为0!')
当可能有多个异常存在时,
捕获异常的顺序按照先子类后父亲类的顺序,即先捕获小的比较细节的异常,再捕获大的笼统的异常,为了避免遗漏可能出现的异常,可以在最后增加BaseException
多个except示意图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YgKc4Oy5-1654523798086)( https://imgs3.loukky.com/imgs/2022/06/06/fc2eebd29f56f195.png )]
def func(aa, bb):
return aa / bb
try:
a = int(input("请输入第一个数:\t"))
b = int(input("请输入第二个数:\t"))
print(func(a, b))
except ZeroDivisionError:
print('除数不能为0!')
except ValueError:
print('只能输入数字!')
except BaseException:
print('存在异常,请及时处理')
try…except…else…结构
如果try块中没有抛出异常,则执行else块,如果try中抛出异常,则执行except块
def func(aa, bb):
return aa / bb
try:
a = int(input("请输入第一个数:\t"))
b = int(input("请输入第二个数:\t"))
result = func(a, b)
except ZeroDivisionError:
print('除数不能为0!')
else:
print('结果为:\t', result)
try…except…else…finally…结构
finally块无论是否发生异常都会被执行,能常用来释放try块中申请的资源
def func(aa, bb):
return aa / bb
try:
a = int(input("请输入第一个数:\t"))
b = int(input("请输入第二个数:\t"))
result = func(a, b)
except BaseException as e:
print('有异常产生!')
print(e)
else:
print('结果为:\t', result)
finally:
print('程序结束!')
python常见的异常类型
- ZeroDivisionError 除数为0所触发的异常
- IndexError 索引越界所触发的异常
- KeyError 映射中没有所指定的Key,比如根据字典中不存在的key来取value
- NameError 未声明/初始化对象
- SyntaxError Python语法异常
- ValueError 传入无效的参数/值
traceback模块
- 使用traceback模块打印异常信息
import traceback
try:
print('-----------')
print(10 / 0)
except:
# 可以自行捕获异常,并对其进行处理,也可以这样子简单的输出异常信息,程序不会中断
traceback.print_exc()
print('hello')
pycharm的调试
- 设置断点
- Debug运行