Python之函数

函数的定义

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

函数的格式如下:

def 函数名():

    函数封装的代码
    …… 

  1. def 是英文 define 的缩写
  2. 函数名称 应该能够表达 函数封装代码 的功能,方便后续的调用
  3. 函数名称 的命名应该 符合 标识符的命名规则
    • 可以由 字母下划线 和 数字 组成
    • 不能以数字开头
    • 不能与关键字重名

函数调用 

通过 函数名() 调用函数

  • 定义好函数之后,只表示这个函数封装了一段代码而已,如果不主动调用函数,函数是不会主动执行的
# 定义函数
def info_print():
    print('hello world')

# 调用函数
info_print()

函数执行流程

1. 函数先定义后调用,如果先调用会报错

提示 NameError: name 'say_hello' is not defined (名称错误:say_hello 这个名字没有被定义)

2.当调用函数的时候,解释器回到定义函数的地方去执行下方缩进的代码,当这些代码执行完,回到调用函数的地方继续向下执行(定义函数的时候,函数体内部缩进的代码并没有执行)

函数的说明文档

  • 在开发中,如果希望给函数添加注释,应该在 定义函数 的下方,使用 连续的三对引号,在 连续的三对引号 之间编写对函数的说明文字
  • 在 函数调用 位置,使用快捷键 CTRL + Q 可以查看函数的说明信息
  • 使用help函数可以查看说明文档的信息

注:因为 函数体相对比较独立函数定义的上方,应该和其他代码(包括注释)保留 两个空行

def my_max(m, n, *args):

#下面形式的说明文档,先打出3个引号,再将鼠标放中间,敲回车,就可以出现
    """
    返回所有参数的最大值
    :param m:
    :param n:
    :param args:
    :return:
    """
    if m < n:
        m = n
    for i in args:
        if m < i:
            m = i
    return m

PyCharm 的调试工具

  • F8 Step Over 可以单步执行代码,会把函数调用看作是一行代码直接执行
  • F7 Step Into 可以单步执行代码,如果是函数,会进入函数内部

 函数参数的使用

  • 在函数名的后面的小括号内部填写 参数,多个参数之间使用 , 分隔

形参和实参 

  • 形参定义 函数时,小括号中的参数,是用来接收参数用的,在函数内部 作为变量使用
  • 实参调用 函数时,小括号中的参数,是用来把数据传递到 函数内部 用的
# # 函数定义的位置的参数叫形式参数
def say(name):
    print('hello %s'%name)
# 实际调用的时候传入的参数叫实际参数
say('tom')

给形参设置默认值 (缺省参数、默认参数)

# 在定义函数的时候给形参设置默认值,此时设置过默认值的参数可以不传
# 可以设置多个默认值
# 要把没有默认值得参数放在前面,有默认值的参数放在后面
def say(name, age, weight=80):
    print('hello %s'%name)
    print('你今年%d岁了' % age)
    print('你体重%.1f公斤!' % weight)
    return #作用是使函数返回到函数调用的位置
# 在不传参数的时候取默认值
say('jack', 22)
# 在传参的时候,优先取值实际传入的值
say('jack1',22,55)

调用函数的时候传参的两种方式

位置参数

也叫非关键字参数,按照函数定义的时候形式参数的位置来传参的

def say(name, age, weight=80):
    print('hello %s'%name)
    print('你今年%d岁了' % age)
    print('你体重%.1f公斤!' % weight)
say('tom', 22, 82.8)

关键字参数

  • 函数调⽤,通过“键=值”形式加以指定
  • 可以不按照形参的位置的顺序传参
def say(name, age, weight=80):
    print('hello %s'%name)
    print('你今年%d岁了' % age)
    print('你体重%.1f公斤!' % weight)
say(name='tom', age=22, weight=82.8)

同时使用两种传递参数的方式 

位置参数必须写在关键字参数的前面

def say(name, age, weight=80):
    print('hello %s'%name)
    print('你今年%d岁了' % age)
    print('你体重%.1f公斤!' % weight)
say('tom', age=22, weight=82.8)

 典型使用情况,中间的参数使用默认值,最后一个不使用默认值

def say(name, age, weight=80):
    print('hello %s'%name)
    print('你今年%d岁了' % age)
    print('你体重%.1f公斤!' % weight)
say('tom',  weight=82.8)

不可变和可变的参数 

不可变参数

 在函数内部,针对参数使用 赋值语句不会影响调用函数时传递的 实参变量

无论传递的参数是 可变 还是 不可变;只要 针对参数 使用 赋值语句,会在 函数内部 修改 局部变量的引用不会影响到 外部变量的引用

def demo(num, num_list):

    print("函数内部")

    # 赋值语句
    num = 200
    num_list = [1, 2, 3]

    print(num)
    print(num_list)

    print("函数代码完成")


gl_num = 99
gl_list = [4, 5, 6]
demo(gl_num, gl_list)
print(gl_num)
print(gl_list)

可变参数 

如果传递的参数是 可变类型,在函数内部,使用 方法 修改了数据的内容,会影响到外部的数据 

def mutable(num_list):

    # num_list = [1, 2, 3]
    num_list.extend([1, 2, 3])

    print(num_list)

gl_list = [6, 7, 8]
mutable(gl_list)
print(gl_list)

不定长参数(多值参数) 

 不定长参数(多值参数),⽤于不确定调⽤的时候会传递多少个参数(不传参也可以)的场景,Python 中有 两种 多值参数

包裹(packing)位置参数

 定义函数时,*参数名  接受任意多个位置参数
一般将参数名写成*argsargs 是 arguments 的缩写,有变量的含义

参数的类型是元组类型

def foo(*args):
    print(args)

# 不传参,返回空元组
foo()
# 可以传一个参数
foo(1)
# 可以传多个参数,类型也不限制
foo(1, 3, 22, 'hello')

# 也可以在前边添加位置参数,表示有一个必传参数
# 位置参数必须放在前面
def foo1(n,*args):
    print(args)

foo1(1, 3, 4)

包裹关键字参数 

定义函数时,**参数名  接收任意多个关键字参数
默认写成**kwargskw 是 keyword 的缩写,

参数的类型为字典,参数名为字典的键,参数值为字典的值

def user_info(**kwargs):
 print(kwargs)

# {'name': 'TOM', 'age': 18, 'id': 110}
user_info(name='TOM', age=18, id=110)

综上:⽆论是包裹位置传递还是包裹关键字传递,都是⼀个组包的过程(传入零散参数,返回一个完整的元组,字典)。 

实际参数的拆包(元组和字典的拆包)

  • 在调用带有多值参数的函数时,如果希望:
    • 将一个 元组变量,直接传递给 args
    • 将一个 字典变量,直接传递给 kwargs
  • 就可以使用 拆包,简化参数的传递,拆包 的方式是:
    • 在 元组变量前,增加 一个 *
    • 在 字典变量前,增加 两个 *
# 实际参数的拆包
def say(name = 'tom', age = 22, weight=80):
    print('hello %s'%name)
    print('你今年%d岁了' % age)
    print('你体重%.1f公斤!' % weight)

# 在实际参数前面加*,表示将实际参数拆成位置参数的形式传进去
# 序列类型的参数都可以拆
# 要求序列中为元素与函数定义时所需要的参数数量和类型一致
a = ['tom', 23, 66.5]
# say(a[0], a[1], a[2])
say(*a)

# 可以将字典拆成关键字参数的类型
# 在字典的名字前面加上**
b = {'name': 'tom', 'weight': 66.5, 'age': 23}
# say(name='tom', age=23,weight=66.5)
say(**b)
def demo(*args, **kwargs):

    print(args)
    print(kwargs)


# 需要将一个元组变量/字典变量传递给函数对应的参数
gl_nums = (1, 2, 3)
gl_xiaoming = {"name": "小明", "age": 18}

# 会把 num_tuple 和 xiaoming 作为元组传递个 args
# demo(gl_nums, gl_xiaoming)
demo(*gl_nums, **gl_xiaoming)

函数的返回值 

  • 返回值 是函数 完成工作后,最后 给调用者的 一个结果
  • 在函数中使用 return 关键字可以返回结果
  • 调用函数一方,可以 使用变量 来 接收 函数的返回结果

返回一个值 

def sum_2_num(num1, num2):
    """对两个数字的求和"""
    return num1 + num2

# 调用函数,并使用 result 变量接收计算结果
result = sum_2_num(10, 20)
print("计算结果是 %d" % result)

无返回值 

注:如果在 return 后没有跟任何内容,只是表示该函数执行到此就不再执行后续的代码,只是使函数返回到函数调用的位置

def say(name, age, weight):
    print('hello %s'%name)
    print('你今年%d岁了' % age)
    print('你体重%.1f公斤!' % weight)
    return #作用是使函数返回到函数调用的位置
ret = say('tom', 22,88.8)
# # 函数没有返回值得时候打印出none,有返回值打印返回值
print(ret)

返回多个值 

1. return a, b 写法,返回多个数据的时候,默认是元组类型

2. return后⾯可以连接列表、元组或字典,以返回多个值

注:如果函数返回的类型是元组,小括号可以省略

def measure():
    """测量温度和湿度"""

    print("测量开始...")
    temp = 39
    wetness = 50
    print("测量结束...")

    # 元组-可以包含多个数据,因此可以使用元组让函数一次返回多个值
    # 如果函数返回的类型是元组,小括号可以省略
    # return (temp, wetness)
    return temp, wetness


# 元组
result = measure()
print(result)

单独处理数据 

# 需要单独的处理温度或者湿度 - 不方便
print(result[0])
print(result[1])

返回值拆包

元组拆包
  • 如果函数返回的类型是元组,可以使用多个变量,一次接收函数的返回结果
  • 注:使用多个变量接收结果时,变量的个数应该和元组中元素的个数保持一致
gl_temp, gl_wetness = measure()

print(gl_temp)
print(gl_wetness)
def return_num():
 return 100, 200
num1, num2 = return_num()
print(num1) # 100
print(num2) # 200
 字典拆包

对字典进⾏拆包,取出来的是字典的key

dict1 = {'name': 'TOM', 'age': 18}
a, b = dict1

print(a) # name
print(b) # age
print(dict1[a]) # TOM
print(dict1[b]) # 18

 函数的嵌套调用

一个函数里面 又调用 了 另外一个函数,这就是 函数嵌套调用

def print_line(char, times):

    """打印单行分隔线
    :param char: 分隔字符
    :param times: 重复次数
    """
    print(char * times)


def print_lines(char, times):

    """打印多行分隔线
    :param char: 分隔线使用的分隔字符
    :param times: 分隔线重复的次数
    """
    row = 0
    while row < 5:
        print_line(char, times)
        row += 1


print_lines("-", 20)

使用模块中的函数 

  • 模块 就好比是 工具包,要想使用这个工具包中的工具,就需要 导入 import 这个模块,导入之后,就可以使用 模块名.变量 / 模块名.函数 的方式,使用这个模块中定义的变量或者函数
  • 每一个以扩展名 py 结尾的 Python 源代码文件都是一个 模块
  • 在模块中定义的 全局变量 、 函数 都是模块能够提供给外界直接使用的工具

注:如果在给 Python 文件起名时,以数字开头 是无法在 PyCharm 中通过导入这个模块的

示例:

 新建 分隔线模块.py

def print_line(char, times):

    """打印单行分隔线
    :param char: 分隔字符
    :param times: 重复次数
    """
    print(char * times)


def print_lines(char, times):

    """打印多行分隔线
    :param char: 分隔线使用的分隔字符
    :param times: 分隔线重复的次数
    """
    row = 0
    while row < 5:
        print_line(char, times)
        row += 1
name = "tom"

新建 hm_10_体验模块.py 文件,并且编写以下代码:

import hm_10_分隔线模块

分隔线模块.print_line("-", 80)
print(分隔线模块.name)

函数的递归 

一个函数 内部 调用自自己叫递归

代码特点

  1. 函数内部的 代码 是相同的(自己调用自己),只是针对 参数 不同,处理的结果不同
  2. 当 参数满足一个条件 时,函数不再执行
    • 这个非常重要,通常被称为递归的出口,否则 会出现死循环
# 3 + 2 + 1
def sum_numbers(num):
 # 1.如果是1,直接返回1 -- 出⼝
# 递归的出口很重要,否则会出现死循环
 if num == 1:
 return 1
 # 2.如果不是1,重复执⾏累加:
 result = num + sum_numbers(num-1)
 # 3.返回累加结果
 return result

sum_result = sum_numbers(3)
# 输出结果为6
print(sum_result)

变量的作用域

局部变量

局部变量是在函数内部 定义的变量,只能在函数内部使用;不同的函数,可以定义相同的名字的局部变量,但是彼此之间不会产生影响

def demo1():

    num = 10
    print(num)
    num = 20
    print("修改后 %d" % num)


def demo2():

    num = 100
    print(num)

demo1()
demo2()

print("over")

局部变量的生命周期:

  • 所谓生命周期就是变量从被创建到被系统回收的过程;
  • 局部变量 在 函数执行时 才会被创建;
  • 函数执行结束后 局部变量 被系统回

局部变量的作用:

  • 在函数内部使用,临时保存函数内部需要使用的数据

全局变量

全局变量是在函数外部定义 的变量,所有函数内部都可以使用这个变量

注:

函数执行时,需要处理变量时会:

  1. 首先 查找 函数内部 是否存在 指定名称 的局部变量,如果有,直接使用
  2. 如果没有,查找 函数外部 是否存在 指定名称 的全局变量,如果有,直接使用
  3. 如果还没有,程序报错!

不允许直接修改全局变量的引用:

  1. 使用赋值语句修改全局变量的值,只是定义了一个局部变量,不会修改到全局变量,只是变量名相同而已
  2. 如果在函数中需要修改全局变量,需要使用 global 进行声明

全局变量定义的位置:

  • 为了保证所有的函数都能够正确使用到全局变量,应该 将全局变量定义在其他函数的上方
# 全局作用域,定义的变量叫‘全局变量’
# 在任何地方都可以访问全局变量
n = 10
# 函数的入参属于局部变量
def foo(a):
    # 函数内部是一个局部作用域,定义的变量为‘局部变量’
    # 局部变量只能在当前函数内部访问,即在当前局部作用域里面访问
    # 在其他函数内部也不能访问
    m = 11
    # 此时相当于定义了一个局部变量n,并不是对全局变量重新赋值
    # 局部变量中如果有一个和全据变量重名的局部变量,优先使用局部变量,会把全局变量屏蔽掉
    # 在函数内部给全局变量重新赋值,需要声明变量
    # global n
    n = 20
    print('in foo:n=', n)
    print('in foo:m=', m)
    # 返回当前作用域所有的局部变量,不需要传参,返回值是一个字典
    print(locals())

print('n =',n)
# 在函数外不能访问函数里面的变量
# print('m=',m)
foo(3)

多函数程序执⾏流程

共⽤全局变量

# 1. 定义全局变量
glo_num = 0
def test1():
 global glo_num
 # 修改全局变量
 glo_num = 100
def test2():
 # 调⽤test1函数中修改后的全局变量
 print(glo_num)

# 2. 调⽤test1函数,执⾏函数内部代码:声明和修改全局变量
test1()
# 3. 调⽤test2函数,执⾏函数内部代码:打印
test2() # 100

返回值作为参数传递

def test1():
 return 50
def test2(num):
 print(num)
# 1. 保存函数test1的返回值
result = test1()
# 2.将函数返回值所在变量作为参数传递到test2函数
test2(result) # 50

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值