python中的函数与异常

函数的作用与使用步骤

函数的作用

在python实际开发中,我们使用函数的目的只有一个"让我们的代码可以被重复的使用"

函数的作用:

  1. 代码重复使用
  2. 模块化编程 (模块化编程的核心就是函数,我们把一个系统的功能分化成若干个功能,每个功能就是一个函数)

编程可分为两大类:1.模块化编程 2.面向对象编程

函数的定义

所谓函数就是一个被命名的,独立的,完成特定功能的代码段,并可能给调用它的程序一个返回值

基本语法:

def 函数名称([参数1, 参数2, ...]):
    函数体
    ...
    [return 返回值]
函数的调用

先定义后使用

# 定义函数
def 函数名称([参数1, 参数2, ...]):
    函数体
    ...
    [return 返回值]

# 调用函数
函数名称(参数1, 参数2, ...)

引入函数案例

  1. 使用python,编写一个打招呼啊程序

    # 遇见一个人say hello
    print('hello')
    # 遇见一个人say hello
    print('hello')
    # 遇见一个人say hello
    print('hello')
    

    为了避免程序的重复性,对以上代码进行进一步优化

  2. 编写一个函数,多次利用

    # 定义函数
    def say_hello():
        print('hello')
    
    # 调用函数
    # 遇见一个人say hello
    say_hello()
    # 遇见一个人say hello
    say_hello()
    # 遇见一个人say hello
    say_hello()
    
  3. 再次对函数进行升级,以实现向不同的人打招呼

    # 定义一个函数,同时为其定义一个参数
    def say_hello(name):
        print(f'hello,{name}')
        
    # 调用函数
    # hello Tina
    say_hello('Tina')
    # hello Jack
    say_hello('Jack')
    # hello Rose
    say_hello('Rose')
    
  4. 函数设计原则为’高内聚,低耦合’,函数执行完毕后,应主动把数返回给调用处,而不应该都交由print()等函数直接输出

    # 定义一个函数,拥有name参数,同时函数执行完毕后,拥有一个return返回值
    def say_hello(name):
        # 执行一系列相关操作...
        return 'hello,' + name
    
    # 调用函数
    # hello Tina
    print(say_hello('Tina'))
    # hello Jack
    print(say_hello('Jack'))
    # hello Rose
    print(say_hello('Rose'))
    

return返回值(拓展)

拓展1:

def return_num():
    return 1
	return 2

result = return_num()
print(result) # 1

以上述代码为例,函数在执行时,只执行了第一个return,是因为return可以退出当前函数,导致return下方的代码不执行

拓展2:

def return_num():
    return 1, 2


result = return_num()
print(result) # (1, 2)
print(type(result))  # <class 'tuple'>

案例:求两个数的四则运算结果

def calculation(num1, num2):
    summer = num1 + num2
    diff = num1 - num2
    mult = num1 * num2
    quot = num1 / num2
    return summer, diff, mult, quot


# 调用size方法
print(calculation(20, 5))

函数说明文档(拓展)

更方便的查看函数的作用:

在这里插入图片描述

用三引号, 添加函数注释

必须写到函数内部第一行, 可以增加可阅读性

函数的嵌套

函数的嵌套调用指的是一个函数里面又调用了另一个函数

基本语法:

def fun_b():
    print('fun_b')
    
def fun_a():
    print('fun_a')
    fun_b()
    print('fun_end')
    
fun_a()

"""
嵌套函数的执行流程:
1.代码遵循一个'顺序原则',从下往上,从左往后开始执行.代码执行到fun_b的定义,会在计算机内存中声明了一个fun_b函数,但内部代码并没有执行
2.继续执行到fun_a函数的定义,会在计算机内存中声明有一个fun_a函数,函数没有真正的调用,内部没有执行
3.代码继续向下,发现fun_a(),即代表调用了该函数并执行其内部函数,打印'fun_a'
4.继续执行,发现fun_b(),执行函数fun_b内部代码,打印'fun_b'
5.fun_b函数执行完后,最后打印出'fun_end'
"""

案例:

编写一个程序,求出一个列表中偶数和奇数的和,并以列表返回。

# 1. 定义函数 calculate_sum(),参数为一个数字列表 numbers_list
def calculate_sum():
    # 2. 初始化偶数和为0
    even_sum = 0

    # 3. 初始化奇数和为0
    odd_sum = 0
    
    # 4. 遍历数字列表中的每个数字
    for num in numbers_list:
        # 5. 检查数字是否为偶数
        if num % 2 == 0:
            even_sum += num
        else:
            odd_sum += num
    # 6. 返回一个列表,第一个元素为偶数的和,第二个元素为奇数的和
    return [even_sum, odd_sum]

numbers = [2, 5, 7, 4, 8, 9]
# 调用函数,并获取结果
result = calculate_sum(numbers)
print(f"偶数的和是: {result[0]}, 奇数的和是: {result[1]}")            
变量的作用域(了解)

变量的作用域值得是变量的作用范围(变量在哪里可以用,在哪里不可以用),主要分为两类:全局作用域局部作用域

其作用域的划分也比较简单,在函数内部定义范围就称之为局部作用域,在函数外部(全局)定义范围就是全局作用域

# 全局作用域
def func():
    # 局部作用域
局部变量与全局变量

在python中,定义在函数外部的变量就称之为全局变量;定义在函数内部的变量就称之为局部变量

# 定义在函数外部的变量(全局变量)
num = 10
# 定义一个函数
def func():
    # 函数体代码
    #定义在函数内部的变量(局部变量)
    num = 100
变量的作用范围

全局变量:在整个程序范围内都可以直接使用

num = 10

def func():
    print(f'在局部作用域中调用num变量:{num}')
    
print(f'在全局作用域中调用num变量:{num}')

func()

"""
执行结果:
在全局作用域中调用num变量:10
在局部作用域中调用num变量:10
"""

局部变量:在函数的调用过程中,开始定义,函数运行过程中生效,函数执行完毕后,销毁

def func():
    num = 10
    print(f'在局部作用域中调用num局部变量:{num}')

func()
print(f'在全局作用域中调用num局部变量:{num}')

"""
执行结果:
在局部作用域中调用num变量:10
报错:
NameError: name 'num' is not defined
"""

其报错的根本原因为:计算机的垃圾回收机制

用于识别和回收不再被程序使用的内存,避免内存泄漏并减轻开发者的手动内存管理负担

global关键字

用于在局部作用域中修改全局变量

# 定义全局变量num = 10
num = 10
# 定义一个函数func
def func():
    # 尝试在局部作用域中修改全局变量
    num = 20

# 调用函数func
func()
# 尝试访问全局变量num
print(num) # 10

上例创建了一个新的局部变量 num = 20,但要求修改全局变量,而不是创建新的局部变量.那么就需要使用global关键字.

# 定义全局变量num = 10
num = 10
# 定义一个函数func
def func():
    # 尝试在局部作用域中修改全局变量
    global num
    num = 20

# 调用函数func
func()
# 尝试访问全局变量num
print(num) # 20

:

global关键字只是针对不可变数据类型的变量进行修改操作(数值、字符串、布尔类型、元组类型),可变类型可以不加global关键字。

函数的参数

在函数定义与调用时,可根据自己的需求来实现参数的传递.在python中,函数的参数一共有两种形式:

形参:在函数定义时,所编写的参数就称之为形式参数

实参:在函数调用时,所传递的参数就称之为实际参数

def say_hello(name): # 此name为函数定义时编写的形式参数
    return 'hello,' + name

name = 'Tian'
say_hello(name) # 此name为函数调用时传递的实际参数

注意:虽然我们在函数传递时,喜欢使用相同的名称作为参数名称。但是两者的作用范围是不同的。name = ‘Tian’,代表实参。其是一个全局变量,而say_hello(name)函数中的name实际是在函数定义时才声明的变量,所以其实一个局部变量。

函数的参数类型

不同参数对比

在这里插入图片描述

位置参数

理论上,在函数定义时,我们可以为其定义多个参数。但是在函数调用时,我们也应该传递多个参数,正常情况,其要一一对应。

def describe_pet(animal_type, pet_name):
    print(f'我有一只{animal_type},名字叫{pet_name}')
    
# 调用函数
describe_pet('狗', '美元')# 我有一只狗,名字叫美元

describe_pet('猫', '英镑') # 我有一只猫,名字叫英镑

注意事项:位置参数强调的是参数传递的位置必须一一对应,不能颠倒

关键字参数

函数调用,通过“键=值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。

def describe_pet(animal_type, pet_name):
    print(f'我有一只{animal_type},名字叫{pet_name}')
    
# 调用函数(使用关键词参数)
describe_pet(animal_type='狗', pet_name='美元') # 我有一只狗,名字叫美元

describe_pet(pet_name='英镑', animal_type='猫') # 我有一只猫,名字叫英镑

describe_pet('狗', pet_name='美元') # 我有一只狗,名字叫美元

# describe_pet(pet_name='英镑', '猫') # 错误! 位置参数不能在关键之参数之后!

缺省参数(参数默认值)

缺省参数也叫默认参数,用于定义函数时为参数提供默认值,调用函数时可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前,包括函数定义和调用)。

def describe_pet(pet_name, animal_type='狗'):
    print(f'我有一只{animal_type},名字叫{pet_name}')
 
# 调用函数
describe_pet('美元') # 我有一只狗,名字叫美元

describe_pet('英镑', '猫') # 我有一只猫,名字叫英镑 (覆盖默认值)

describe_pet('人民币', animal_type='兔子') # 我有一只兔子,名字叫人民币  (关键字覆盖)

谨记:我们在定义缺省参数时,一定要把其写在参数列表的最后侧

不定长参数

不定长参数也叫可变参数。用于不确定调用的时候会传递多少个参数(不传参也可以)的场景。此时,可用包裹(packing)位置参数,或者包裹关键字参数,来进行参数传递,会显得非常方便。

不定长元组(位置)参数

def add_all(*args):
    """把传进来的所有数字相加"""
    print(args) # 元组类型数据,对传递参数有顺序要求
    summer = 0
    for num in args:
        summer += num
    return summer
	# or
    # return sum(args) 直接使用sum函数不用遍历元组
	
# 调用函数,传递参数
print(add_all(10)) # 10
print(add_all(10, 20)) # 30
print(add_all(10, 20, 30, 40)) #100

不定长字典(关键字)参数

def add_all(**kwargs):
    """相加所有value值"""
    print(kwargs) # 字典类型数据,对传递参数没有顺序要求,格式要求key = value值
    summer = 0
    for num in kwargs.values():
        summer += num
    return summer
	# or
    # return sum(kwargs.values()) 直接使用sum函数不用遍历列表
	
# 调用函数,传递参数
print(add_all(first=40, second=50, third=60)) # 150

kwargs = keyword + args

总结:无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程。

Python组包:就是把多个数据组成元组或者字典的过程。

二者混用案例

def add_all(*args, **kwargs):
    """求元组和字典值的总和"""
    print(args)
    print(kwargs)
    
    summer = 0
    for num in args:
        summer += num
    for num in kwargs.values():
        summer += num
    return summer
	
    # or
    # return sum(args)+sum(kwargs.values())
    
    
# 定义一个元组(也可以是列表)
tuple1 = (10, 20, 30)
# 定义一个字典
dict1 = {'first': 40, 'second': 50, 'third': 60}

# 如果想把元组传递给*args,必须在tuple1的前面加一个*号
# 如果想把字典传递给**kwargs,必须在dict1的前面加两个**号
print(add_all(*tuple1, **dict1))
lambda函数

在Python中,函数大多数是有名函数 => 普通函数。但是有些情况下,我们为了简化程序代码,也可以定义匿名函数 => lambda表达式

应用场景

如果一个函数有一个返回值,并且只有一句代码,可以使用 lambda简化。

基本语法
变量 = lambda 函数参数:表达式(函数代码 + return返回值)
# 调用变量
变量()

lambda表达式:

def fn1():
    return 100

# 调用fn1函数
print(fn1()) 

用lambda表达式对fn1函数进行简化:

fn2 = lambda : 100

# 调用fn1函数
print(fn2()) 

带参数的lambda表达式

def fn1(num1, num2):
    return num1 + num2

print(fn1(10, 20))

用lambda表达式对fn1函数进行简化:

fn2 = lambda num1, num2: num1 + num2

print(fn2(10, 20))

带默认参数的lambda表达式

fn = lambda a, b, c=100: a + b + c

print(fn(10, 20))

带if判断(三目运算符)的lambda表达式

fn = lambda a, b: a if a > b else b

print(fn(10, 20))

案例:

知识点:列表.sort(key=排序的key索引, reverse=True)

# 列表数据+字典数据排序

students = [
    {'name': 'Tom', 'age': 20},
    {'name': 'Rose', 'age': 19},
    {'name': 'Jack', 'age': 22}
]

# 按name值升序排列
students.sort(key=lambda x: x['name']) 
print(students) 
"""
[{'name': 'Jack', 'age': 22}, {'name': 'Rose', 'age': 19}, {'name': 'Tom', 'age': 20}]
"""

# 按name值降序排列
students.sort(key=lambda x: x['name'], reverse=True)
print(students) 
"""
[{'name': 'Tom', 'age': 20}, {'name': 'Rose', 'age': 19}, {'name': 'Jack', 'age': 22}]
"""

# 按age值升序排列
students.sort(key=lambda x: x['age'])
print(students) 
"""
[{'name': 'Rose', 'age': 19}, {'name': 'Tom', 'age': 20}, {'name': 'Jack', 'age': 22}]
"""

python异常处理

什么是异常

当检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的"异常"。

异常演示
num = int(input('请输入一个正整数'))

# 当程序输入字符串时,程序会就报错

报错:

在这里插入图片描述

异常捕获
try:
    可能发生错误的代码
except:
    如果出现异常执行的代码

try…except主要用于捕获代码运行时异常,如果异常发生,则执行except中的代码

案例:

try:
    num = int(input('请输入一个正整数: '))
except: # 更准确的写法为 except ValueError:
    print('输入无效,请输入正整数')

异常捕获并输出错误信息

无论我们在except后面定义多少个异常类型,实际应用中,也可能会出现无法捕获的未知异常。这个时候,我们考虑使用Exception异常类型捕获可能遇到的所有未知异常:

try:
    可能发生错误的代码
except Exception as e:
    print(e)

案例:

# 打印一个未定义变量

try:
    print(name)
except Exception as e:
    print(e)
    # name 'name' is not defined

异常捕获中else语句

else语句:表示的时如果没有异常要执行的代码

try:
    print('执行函数')
except Exception as e:
    print(e)
else:
    print('恭喜,没有任何异常')

案例:

try:
    num = int(input('请输入一个正整数: '))
except Exception as e:
    print(e)
else:
    print(num)

异常捕获中finally语句

finally语句:表示无论是否异常都要执行的代码

try:
    num = int(input('请输入一个正整数: '))
except Exception as e:
    print(e)
else:
    print(num)
finally:
    print('执行结束') # 无论上述代码是否报错,都会打印'执行结束'

异常案例

升级猜数字游戏,增加程序健壮性,用户在输入过程中可能不会输入数字或者不按照要求输入,程序要能捕获到用户的异常输入。在已有的猜数游戏中加入异常功能。

import random


def guess_number_game():
    # 1. 随机生成1个 1 ~ 100之间的数字, 让用户来猜.
    guess_num = random.randint(1, 100)

    while True:
        try:
            # 2. 键盘录入, 表示: 玩家出拳的编号.
            input_num = int(input('请录入您要猜的整数 (1-100): '))

            # 3. 判断用户是否猜对了, 并提示. 猜对, 猜大, 猜小.
            if input_num == guess_num:
                print('恭喜您, 猜对了, 请找夯老师领取奖品, 练习题一套!')
                break
            elif input_num > guess_num:
                print('哎呀, 您猜大了!')
            else:
                print('哎呀, 您猜小了!')
        except ValueError:
            print('输入无效,请输入一个整数!')


# 调用猜数字游戏函数
guess_number_game()
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐