函数的创建与调用
#
# 主题:函数的创建与调用
#
if __name__ == '__main__':
# 创建函数
# 求解 a + b
def calc(a, b):
c = a + b
return c
# 调用函数
result = calc(10, 20)
print(result) # 30
函数的参数传递
-
位置传参
-
关键字传参
#
# 主题:函数的参数传递
#
if __name__ == '__main__':
# 位置传参
# 求解 a + b
def calc(a, b): # a,b 是形式参数,简称形参,形参的位置是在函数的定义处
c = a + b
return c
result = calc(10, 20) # 10,20 是实际参数的值,简称实参,实参的位置是在函数的调用处
print(result) # 30
# 关键字传参
result1 = calc(b = 10, a = 20) # = 左边的变量名称为关键字参数
print(result1) # 30
函数的参数传递对实参的影响
#
# 主题:函数的参数传递对实参的影响
#
def fun(arg1, arg2):
print('arg1 =', arg1)
print('arg2 =', arg2)
arg1 = 100
arg2.append(10)
print('arg1 =', arg1)
print('arg2 =', arg2)
if __name__ == '__main__':
n1 = 11
n2 = [22, 33, 44]
print(n1) # 11
print(n2) # [22, 33, 44]
print('---')
fun(n1, n2) # arg1 = 11
# arg2 = [22, 33, 44]
# arg1 = 100
# arg2 = [22, 33, 44, 10]
print('---')
print(n1) # 11 只是值传递
print(n2) # [22, 33, 44, 10] 相当于C语言中在指针层面上的数据操作
'''在函数调用过程中,进行参数的传递
若是不可变对象,则在函数体中的修改不会影响实参的值
若是可变对象,则在函数体的修改会影响实参的值'''
函数的返回值
#
# 主题:函数的返回值
#
def fun(num):
odd = [] # 存奇数
even = [] # 存偶数
for i in num:
if i % 2 == 1:
odd.append(i)
else:
even.append(i)
return odd, even
if __name__ == '__main__':
print(fun([10, 29, 34, 23, 44, 53, 55])) # ([29, 23, 53, 55], [10, 34, 44])
# 若返回值有多个结果,则返回值的类型是元组
函数定义中的形参 —— 默认值
#
# 主题:函数定义中的形参 —— 默认值
#
def fun(a, b = 10):
print(a, b)
if __name__ == '__main__':
fun(100) # 100 10 b未传参,采取默认值
fun(20, 30) # 20 30 30替换10
# print函数也有默认值参数。在代码中,按住Ctrl不放,鼠标点击print函数名进入函数定义处
print('hello')
print('python') # hello
# python
# print在字符串的末尾默认加'\n'
print('hello', end = '\t')
print('world') # hello world
函数定义中的形参 —— 个数可变的位置形参
#
# 主题:函数定义中的形参 —— 个数可变的位置形参
#
def fun(*args):
print(args)
def fun1(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
if __name__ == '__main__':
# 定义函数时,可能无法事先确定传递的位置实参的个数时,使用个数可变的位置参数
# 使用一个*定义个数可变的位置形参
# 函数的返回值类型是元组
fun(10) # (10,)
fun(10, 'hello', True) # (10, 'hello', True)
''' def fun2(*args, *a):
pass
以上代码,程序会报错,可变的位置参数,只能是1个'''
lst = [11, 22, 33]
fun1(*lst) # 函数调用时,将列表中的每个元素都转换为位置实参传入
# a = 11
# b = 22
# c = 33
函数定义中的形参 —— 个数可变的关键字形参
#
# 主题:函数定义中的形参 —— 个数可变的关键字形参
#
def fun(**args):
print(args)
def fun1(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
if __name__ == '__main__':
# 定义参数时,可能无法事先确定传递的位置实参的个数,这时使用可变的关键字形参
# 函数的返回值是字典
fun(a = 10)
fun(a = 10, b = 'hello', c = True) # {'a': 10}
# {'a': 10, 'b': 'hello', 'c': True}
函数定义中的形参 —— 个数可变的关键字形参
#
# 主题:函数定义中的形参 —— 个数可变的关键字形参
#
def fun(**args):
print(args)
def fun1(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
def fun3(a, b, *, c, d): # * 后面的参数,在函数调用时,只能采用关键字参数传递
print('a =', a)
print('b =', b)
print('c =', c)
print('d =', d)
if __name__ == '__main__':
# 定义参数时,可能无法事先确定传递的位置实参的个数,这时使用可变的关键字形参
# 函数的返回值是字典
fun(a = 10)
fun(a = 10, b = 'hello', c = True) # {'a': 10}
# {'a': 10, 'b': 'hello', 'c': True}
''' def fun2(**args, **argc):
pass
以上代码会报错,个数可变的关键字参数,只能是1个
'''
# 函数定义时,形参的顺序问题
# 在定义函数时,个数可变的位置形参要放在个数可变的关键字形参之前
def fun2(*args1, **arg2):
pass
def fun4(a, b, *, c, d, **args):
pass
def fun5(a, b = 10, *args, **args2):
pass
dic = {'a': 100, 'b': 200, 'c': 300}
fun1(**dic) # 函数调用时,将字典中每个元素都转换为关键字实参传入
# a = 100
# b = 200
# c = 300
fun3(a = 10, b = 20, c = 30, d = 40) # 关键字实参传递
# a = 10
# b = 20
# c = 30
# d = 40
fun3(10, 20, c = 30, d = 40) # 前两个参数采用位置实参传递,后两个参数采用关键字实参传递
# a = 10
# b = 20
# c = 30
# d = 40
变量的作用域
#
# 主题:变量的作用域
#
if __name__ == '__main__':
# 局部变量
# 在函数被定义并使用的变量,只在函数内部有效
# 局部变量使用global声明,这个变量就会成为全局变量
def fun(a, b):
global d # d原先是局部变量,经过global声明后变成全局变量
c = a + b # c是局部变量
# a,b是函数的形参,作用范围是函数内部,相当于局部变量
d = c
print(c)
fun(1, 2) # c
print(d) # c
# 全局变量
# 函数体外定义的变量,可作用与函数内外
递归函数
#
# 主题:递归函数
#
def fac(n):
'''
功能:计算阶乘
参数:n 变量
返回:n! 阶乘结果
'''
if n == 1: # 递归终止条件
return 1 # 1! = 1
else: # 递归调用
return n * fac(n - 1)
def fib(n):
'''
功能:斐波那契数列
参数:n 当前数字在数列中是第几个
返回: 斐波那契数列
'''
if n == 1:
return 1
elif n ==2:
return 1
else:
return fib(n - 1) + fib(n - 2)
if __name__ == '__main__':
# 递归函数在函数体内调用函数自身
# 递归函数的组成部分:递归调用与递归终止条件
# 递归函数的调用过程
# 每递归调用一次函数,就会在占内存分配一个栈帧
# 每执行一次函数,都会释放相应的空间
# 递归的优缺点:
# 优点:思路和代码简单
# 缺点:占用内存多,效率低下
# 计算阶乘
print(fac(6)) # 720
# 计算斐波那契数列中第6位上的数字
print(fib(6)) # 8
# 输出斐波那契数列前6位的数字
for i in range(1, 7):
print(fib(i), end = '\t') # 1 1 2 3 5 8
bug 分类
#
# 主题:bug 分类
#
if __name__ == '__main__':
# TypeError 数据类型错误
# IndexError 索引错误
# ZeroDivisionError 除以零
# KeyError 键错误
# ValueError 值错误
# NameError 标识符错误
# SyntaxError 语法错误
异常处理机制
#
# 主题:异常处理机制
#
if __name__ == '__main__':
# try 结构
# 当异常出现时,即时捕获,从而保证程序继续执行
try: # 可能报错的代码
n1 = int(input('请输入一个整数:'))
n2 = int(input('请输入另一个整数:'))
result = n1 / n2
print('结果为:', result)
except ZeroDivisionError: # except 后面是错误类型。根据错误类型执行对应的代码
print('除数不能为0哦!!!')
except ValueError:
print('请检查输入是否正确')
except BaseException as e: # 提取错误提示
# 正常报错是这样:ValueError: invalid literal for int() with base 10: ''
# 执行词句后,e = invalid literal for int() with base 10: ''
print(e)
print(type(e)) # <class 'ValueError'> ValueError 是错误类型
else:
print('结果为:', result) # 若 try 块没有异常,则执行 else 块,否则执行 except 块
finally: # 无论是否有异常,都会执行这块代码,常用于释放 try 块中申请的资源
print('无论是否有异常,都会执行')
# traceback 模块打印异常信息
# 用于将异常信息存入到日志文件(log日志)里
import traceback
try:
print('---')
num = 10 / 0
except:
traceback.print_exc()