python基础04-函数

函数

一、函数的基本使用

1. 基本概念

  • 所谓函数,就是把 具有独立功能的代码块 组织为一个整体,在需要的时候 调用

  • 函数的使用包含两个步骤:

    1. 定义函数 —— 在函数中编写代码,实现功能
    2. 调用函数 —— 执行编写的代码
  • 函数的作用:

    • 提高代码编写效率, 代码重用
    • 写一次函数代码块,后面使用的时候,只需要调用函数即可,无需重新编写函数代码块
  • 2. 函数的定义和调用

    2.1 函数的定义

    定义函数的格式如下:

    def 函数名():
        函数内部的代码块
        ……
    1. def 是英文 define 的缩写
    2. 函数名称的命名应该符合标识符的命名规则
      • 可以由 字母下划线数字 组成
      • 不能以数字开头
      • 不能与关键字重名
      • 建议不要和类型同名

    2.2 函数的调用

    • 函数只是定义,不调用不会自动执行,用户看不到没有效果

    • 函数调用的格式:

      函数名字()

    2.3 第一个函数演练

    需求

    1. 编写一个打招呼 say_hello 的函数,封装三行打招呼的代码
    2. 在函数下方调用打招呼的代码

    示例代码:

    """
    步骤流程:
    函数定义:
    1. def 函数名字():
        2. 函数体,打印信息
    
    函数调用:函数名字()
    """
    
    

函数定义

def say_hello():
print(“hello 1”)
print(“hello 2”)
print(“hello 3”)

print(‘函数调用前’)

say_hello() # 函数调用

print(‘函数调用后’)


  运行结果:

  ```shell
  函数调用前
  hello 1
  hello 2
  hello 3
  函数调用后

二.函数执行过程、文档注释

1. 函数执行流程

1.1 函数执行流程

  • 如果不主动调用函数,函数是不会主动执行的
  • 函数调用时,默认往前面找函数的定义,如果没有找到函数定义,则报错:
    • NameError: name 'say_hello' is not defined (名称错误:say_hello 这个名字没有被定义)

1.2 Debug 的单步调试

  • F7 Step Into 可以单步执行代码,如果是函数,会进入函数内部

  • F8 Step Over 可以单步执行代码,如果函数,直接执行函数,不会进入函数内部

2. 函数的文档注释

  • 在开发中,如果希望给函数添加文档注释,应该在 定义函数 的下方,使用 连续的一对三引号

  • 连续的一对三引号 之间编写对函数的说明文字

    def func_sum():
        """求和 1+2"""
        add_result = 1 + 2
        print(add_result)
    
    func_sum()
  • 函数调用 位置,使用快捷键 Ctrl + Q 可以查看函数的说明信息

三、函数的参数1:普通参数

1. 函数参数的作用

假如开发一个 func_sum 的函数,函数能够实现 两个数字的求和 功能:

# 函数定义
def func_sum():
    """两个数字的求和"""
    num1 = 10
    num2 = 20
    result = num1 + num2
    print("%d + %d = %d" % (num1, num2, result))


# 函数调用
func_sum()
  • 以上函数只能处理 固定数值 的相加
  • 函数参数,可以解决上面的问题,可以传递数据给函数内部,增加函数的 通用性

2. 带参数函数的使用

2.1 带参数函数的定义和调用

  • 函数定义时的参数叫 形参,函数调用时的参数叫 实参

  • 带参数函数的定义格式:

    def 函数名字(形参1,形参2,……):
        函数体代码块
  • 带参数函数的调用格式:

    函数名字(实参1,实参2,……)

示例代码:

# 带参数函数的函数定义
def func_sum(num1, num2):
    """两个数字的求和"""
    result = num1 + num2
    print("%d + %d = %d" % (num1, num2, result))


# 带参数函数的调用
func_sum(20, 30)

2.2 函数执行流程

  • 函数调用时,按照函数定义的形参顺序,实参 一一对应 传递给形参

2.3 形参的作用域

  • 作用域:变量起作用的范围
  • 形参的作用域:只在定义函数的代码块
# 形参作用域仅在函数内部, 所以不同函数的同名参数,互不影响
def func_sum(num1, num2):
    result = num1 + num2
    print(result)


def func_sub(num1, num2):
    result = num1 - num2
    print(result)


func_sum(1, 3)
func_sub(4, 4)

四、函数的返回值

1. 函数返回值的作用

  • 开发中,有时会希望 一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理
  • 返回值函数给调用方提供的结果

前面接触到返回值的例子:

"""
返回值变量 = input()
返回值变量 = len(容器变量)
"""

# 从键盘输入一个内容,内容返回给name赋值
name = input('请输入你的名字:')
print(name)

my_str = 'hello'
# 获取my_str内容的元素个数,返回给n赋值
n = len(my_str)
print(n)

2. return关键字的使用

2.1 通过return给函数设置返回值

  • return 关键字只能使用在函数中
  • 在函数中使用 return 关键字可以中断函数,同时也返回一个结果
  • 调用函数一方,可以 使用变量接收 函数的返回结果
"""
函数定义格式:
def 函数名():
    return 结果

函数调用格式:
返回值变量 = 函数名()
"""


def func_sum(num1, num2):
    """两个数字的求和"""
    result = num1 + num2
    return result  # 中断函数,同时也返回一个结果


# 函数调用:返回值变量 = 函数名()
ret = func_sum(20, 30)
print(ret)

2.2 函数默认返回值

  • 函数内部没有任何return语句,默认返回None,表示没有任何数据
  • return不设置返回值,默认也返回None
# 函数定义,函数内部没有任何return语句
def normal_func():
    print('^_^')


# 函数定义,return不设置返回值
def return_test():
    return


# 函数调用
ret1 = normal_func()
print(ret1)  # None

ret2 = return_test()
print(ret2)  # None

2.3 return中断函数

  • 函数一旦执行return,函数内return下一句往后的代码不会执行
# 函数定义
def func():
    print('不努力,你来深圳干嘛?')
    return
    print('我想玩游戏')


# 函数调用
func()

运行结果:

不努力,你来深圳干嘛?

五、4种函数的类型

1. 4 种函数类型的分类

  • 函数根据有没有参数,有没有返回值,可以相互组合,一共有4种

    • 无参数,无返回值
    • 无参数,有返回值
    • 有参数,无返回值
    • 有参数,有返回值
  • 定义函数时,是 根据实际的功能需求来设计 的,所以不同开发人员编写的函数类型各不相同

2. 无参数,无返回值的函数

"""无参数,无返回值的格式

函数定义:
def 函数名():
    函数体

函数调用:
函数名()
"""


# 函数定义
def menu():
    """功能菜单"""
    print('='*20)
    print('= 1. 添加学生')
    print('= 2. 删除学生')
    print('= 3. 查询学生')
    print('=' * 20)


# 函数调用
menu()

3. 无参数,有返回值的函数

"""无参数,有返回值的函数

函数定义:
def 函数名字():
    return 返回结果

函数调用:
返回值变量 = 函数名字()
"""


# 函数定义
def get_pi():
    """
    获取圆周率
    :return: 返回圆周率
    """
    return 3.14


# 函数调用
pi = get_pi()
print('圆周率为:%f' % pi)

4. 有参数,无返回值的函数

"""有参数,无返回值的函数
函数定义:
def 函数名字(形参1,形参2,……):
    函数体

函数调用:
函数名(实参1,实参2,……)
"""


# 函数定义
def print_char(num, char):
    """
    功能:打印指定数量的字符
    :param num: 打印字符的个数,整型
    :param char: 打印的字符,字符串格式
    :return: None
    """
    print(num * char)


# 函数调用
print_char(5, '^_^ ')

5. 有参数,有返回值的函数

"""有参数,有返回值的函数
函数定义:
def 函数名字(形参1,形参2,……):
    函数体
    return 返回结果

函数调用:
返回变量 = 函数名字(实参1,实参2,……)
"""


# 函数定义
def func_sum(n):
    """
    功能:实现1~n累加和
    :param n: n 控制累加的范围
    :return: 累加后的最终结果
    """
    # 1. 设置条件变量
    i = 1
    _sum = 0
    # 2. while 条件(i <= n):
    while i <= n:
        # 3. 累加
        _sum += i
        # 4. 条件变量改变
        i += 1

    # 5. 循环外面,返回累加的最终结果
    return _sum


# 函数调用
ret = func_sum(100)
print(ret)

六、函数的嵌套调用

1. 函数的嵌套调用

  • 一个函数里面 又调用另外一个函数,这就是 函数嵌套调用
# 定义fun01函数
def fun01():
    print('开始调用fun01')
    print('结束调用fun01')


# 定义fun02函数,在代码块中间调用fun01
def fun02():
    print('开始调用fun02')
    # 调用fun01
    fun01()
    print('结束调用fun02')


# 函数调用
fun02()
  • 如果函数 func02 中,调用了另外一个函数 func01
    • 那么执行到调用 func01 函数时,会先把函数 func01 中的任务都执行完
    • 才会回到 func02 中调用函数 func01 的位置,继续执行后续的代码

2. 函数嵌套的应用

2.1 打印多行分隔线

需求:

  1. 设计一个函数,打印一行分隔线:可指定数量,可指定分隔线字符的样式 如: 一行分隔线字符的数量为5,字符样式为'^_^ '

     ^_^ ^_^ ^_^ ^_^ ^_^
  2. 设计一个函数,打印n行分隔线,可指定一行分隔线字符的数量,可指定分隔线字符的样式 如:3行分隔线,一行分隔线字符的数量为5,字符样式为'^_^ '

     ^_^ ^_^ ^_^ ^_^ ^_^
     ^_^ ^_^ ^_^ ^_^ ^_^
     ^_^ ^_^ ^_^ ^_^ ^_^

示例代码:

def print_char(num, char):
    """
    功能:打印指定数量字符的分隔线
    :param num: 字符的数量
    :param char: 字符样式
    :return: None
    """
    print(num * char)


def print_lines(n, num, char):
    """
    功能:打印n行分隔线
    :param n: 打印的行数
    :param num: 一行分隔线字符的数量
    :param char: 分隔线的字符样式
    :return: None
    """
    # 1. 设置条件变量 i = 0
    i = 0
    # 2. while 条件:
    while i < n:
        # 3. 打印一行的分隔线
        print_char(num, char)

        # 4. 条件变量的改变
        i += 1

# 函数调用
print_lines(3, '^_^ ', 5)

2.2 求三个数的平均值

需求:

  1. 设计一个函数求三个数的和
  2. 设计一个函数求三个数的平均值

示例代码:

"""
1. 设计一个函数求三个数的和
2. 设计一个函数求三个数的平均值
"""

def sum_3_number(a, b, c):
    """求3个数的和"""
    return a + b + c

def avg_3_number(a, b, c):
    """求3个数的平均值"""

    # 先对3数求和,返回值为求和后的结果
    sum_result = sum_3_number(a, b, c)
    # 接着,再求平均值
    avg_result = sum_result / 3

    # 最终平均值结果作为函数返回值
    return avg_result

# 调用函数,完成对3个数求平均值
result = avg_3_number(11, 2, 55)
print("average is %.2f" % result)

七、局部变量和全局变量

1. 局部变量

  • 局部变量:函数定义的形参,函数内部定义的变量
  • 不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响
  • 局部变量的作用域只在函数内部
  • 局部变量的目的是 存储需要临时保存的数据
# 函数定义
def func(temp):
    a = 10
    print(a)


# 函数调用
func(22)

# NameError: name 'a' is not defined
# print('函数的外部:', a)    # err
# print('函数的外部: ', temp)    # err

2. 全局变量

2.1 全局变量

  • 在函数外部定义的变量叫做 全局变量
  • 全局变量能够在所有的函数中进行访问(不修改)
# 定义全局变量
num = 10


def func():
    print('func num = ', num)


func()  # 函数调用
print('函数的外面 num = ', num)

运行结果:

func num =  10
函数的外面 num =  10

2.2 函数内修改全局变量

2.2.1 默认不能直接修改全局变量
# 定义全局变量
num = 10


def func():
    # 函数内给一个变量赋值时,重新生成一个局部变量num
    # 函数内的num和外面的num没有关系
    num = 250
    print('func num = ', num)  # 获取是函数内的num


func()  # 函数调用

# 函数外获取的是全局变量的值
print('函数的外面 num = ', num)
  • 函数内赋值变量 时,默认为定义并赋值局部变量
  • 函数内获取的是函数内局部变量的值,函数外获取的是全局变量的值

运行结果:

func num =  250
函数的外面 num =  10
2.2.2 通过global声明修改全局变量
  • 如果在函数中修改全局变量,那么就需要先使用global进行声明,再进行修改
# 定义全局变量
num = 10


def func():
    # global num 告诉解释器,函数内部使用的num就是外面的全局变量num
    global num
    num = 250   # 修改全局变量
    print('func num = ', num)


func()  # 函数调用
print('函数的外面 num = ', num)

运行结果:

func num =  250
函数的外面 num =  250

八、函数的参数2:参数详解

1. 位置参数

  • 函数调用时,按形参的位置,从左往右,一一匹配传递参数
  • 位置参数必须一一对应,缺一不可
# 函数定义
def func(num1, num2):
    print('num1 = ', num1)
    print('num2 = ', num2)


# 函数调用
func(1, 2)

2. 关键字参数

  • 函数调用时,通过 形参=值 方式为函数形参传值,不用按照位置为函数形参传值,这种方式叫关键字参数
  • 注意:
    • 关键字参数必须在位置参数的右边
    • 对同一个形参不能重复传值
# 函数定义
def func(num1, num2):
    print('num1 = ', num1)
    print('num2 = ', num2)


# 函数调用
func(num2=1, num1=2)

3. 缺省参数

  • 形参设定默认值,称为缺省参数,也叫默认参数
  • 注意:
    • 调用函数时,如果没有传入默认参数对应的实参,则使用默认值
    • 默认参数必须在普通参数的后边
# 默认参数必须在普通参数的后边
def func(a, b=20, c=10):
    print(a, b, c)


# 函数调用
func(1)  # a=1,b=20,c=10
func(1, 2)  # a=1,b=2,c=10
func(1, 3, 2)  # a=1,b=3,c=2

4. 不定长参数

4.1 元组型不定长参数

  • 函数可以定义 不定长参数用于接收任意数量的位置实参

  • 形参变量名前面加上一个*

    ,这个参数则为元

    组型不定长参数

    • 形参变量名一般叫: args
  • 函数体使用不定长参数,直接使用变量名即可,无需加\*

  • 不定长参数的本质是 将传递的参数包装成了元组

# *args 为不定长参数,可以接收0~多个实参
# 把实参的1,2,3, 包装成元组(1, 2, 3)再传递, 等价于args = (1, 2, 3)
def func(*args):
    # 函数内部使用,无需加*
    print(args, type(args))


# 函数调用
func(1, 2, 3)   # (1, 2, 3) <class 'tuple'>

4.2 字典型不定长参数

  • 不定长参数还有一种形式 可以接收任意数量的关键字实参

  • 定义参数时需要在形参名前添加

    **

    ,则为字典型不定长参数,在函数体使用不定长参数,直接使用变量名即可,无需加

    *

    • 形参变量名一般叫: kwargs
  • 这种不定长参数会将 关键字参数包装成字典

# 把实参包装成 {'city': 'sz', 'age': 18}给kwargs传递
# kwargs = {'city': 'sz', 'age': 18}
def func(name, **kwargs):
    # 存在形参name, name不会被包装到字典中
    print(name)
    print(kwargs)  # 函数内部使用,无需加*


# 实参的写法: 变量=数据,变量=数据
func(name='mike', city='sz', age=18)

注意:

  • 已经存在的形参, 其对应的关键字实参 不会被包装到字典中
  • 字典型可变形参必须在形参列表的最后边