函数

1. pycharm快捷键

Ctrl + Q 快速查看文档(能快速查看到选择的函数创建者对该函数的注释)

2. 定义

(1) 用于封装一个特定的功能,表示一个功能或者行为。

(2) 函数是可以重复执行的语句块, 可以重复调用。

(3) 设计理念:崇尚小而精,拒绝大而全

"""
    函数设计理念:
        崇尚小而精,拒绝大而全
    返回值
"""

# 需求:定义函数,实现2个数字相加
"""
def add():
    # 获取数据
    one = int(input("请输入第一个数字:"))
    two = int(input("请输入第二个数字:"))
    # 逻辑计算
    result = one + two
    # 显示结果
    print("结果是:%s" % result)

add()
"""

# 函数要细分明确它的功能,
# 如逻辑计算,还是获取数据,抑或显示结果,功能要明确
def add(one, two):
    # 逻辑计算
    result = one + two
    return result  # 返回结果    【发送】


# 接收返回值     【接收】
data = add(2, 5)
print(data)

 

3. 作用

将功能的做法与用法分离

提高代码的可重用性和可维护性(代码层次结构更清晰)。

4. 基础语法

4.1 定义函数

 (1) 语法

def 函数名(形式参数):
    函数体

(2) 说明:

def 关键字:全称是define,意为”定义”。

函数名:对函数体中语句的描述,规则与变量名相同。

形式参数:函数定义者要求调用者提供的信息。

函数体:完成该功能的语句。

"""
    函数-参数
        函数调用者 传递给 函数定义者 传递的信息
"""

# 做法(变化)
def attack(count): # 形式参数:抽象的 
    for i in range(count): # 01234
        print("直拳")
        print("摆拳")
        print("勾拳")

# 调试F8:逐过程执行(跳过函数)
# F7:逐语句执行(进入函数)
# 用法
count = 2
attack(count) # 实际参数:具体的  循环2次
num = 3
attack(num)  # 循环3次
attack(5) # 循环5次

 

(3) 函数的第一行语句建议使用文档字符串描述函数的功能与参数(可在pycharm中按ctrl+q查看)

"""
    练习1:创建计算治愈比例的函数
    confirmed = int(input("请输入确诊人数:"))
    cure = int(input("请输入治愈人数:"))
    cure_rate = cure / confirmed * 100
    print("治愈比例为" + str(cure_rate) + "%")
"""
def calculate_cure_ratio(confirmed, cure):
    """
        计算治愈比例的函数
    :param confirmed: int类型,确诊人数
    :param cure: int类型,治愈人数
    :return: float类型,治愈比例
    """
    cure_rate = cure / confirmed * 100
    return cure_rate

rate = calculate_cure_ratio(58, 57)
print(rate)

num01, num02 = 58, 57
calculate_cure_ratio(num01, num02)
print("治愈比例为%s" % rate)

4.2 调用函数

(1) 语法:函数名(实际参数)

(2) 说明:根据形参传递内容。

4.3 返回值

(1) 定义: 函数定义者告诉调用者的结果。

(2) 语法: return 数据

(3) 说明:

return后没有语句,相当于返回 None。

函数体没有return,相当于返回None。

"""
    函数 - 返回值语法

"""

# 返回结果
def func01():
    print("func01执行了")
    return 100

def func02():
    print("func02执行了") #  函数没有返回值,相当于返回了None
    # return # 函数有返回,但没值

def func03():
    # 正常:3个循环应该有3个break结束
    # while True:
    #     while True:
    #         while True:
    #             break
    #         break
    #     break
    while True:
        while True:
            while True:
                return # 退出函数

# 接收结果
data01 = func01()
print(data01)
# 也可以不接
func01()

data02 = func02() # None
print(data02)

5. 可变/不可变类型在传参时的区别

"""
(1) 不可变类型参数有:
数值型(整数,浮点数)
布尔值bool
None 空值
字符串str
元组tuple
"""


def func01(p1, p2, p3):
    p1 += 1
    p2 += "world"
    p3 += (4, 5)


number01 = 10
str01 = "hello"
tuple01 = (1, 2, 3)

func01(number01, str01, tuple01)
print(number01)  # 10
print(str01)  # "hello"
print(tuple01)  # (1, 2, 3)

"""
(2) 可变类型参数有:
列表 list
字典 dict
"""


def func02(p1, p2):
    p1[0] += 1
    p1[1] += "world"
    p2["num_tuple"] += (4, 5)


list01 = [10, "hello"]
dict01 = {
    "num_tuple": (1, 2, 3)
}

func02(list01, dict01)
print(list01)  # [11, 'helloworld']
print(dict01)  # {'num_tuple': (1, 2, 3, 4, 5)}

"""
(3) 结论:
不可变类型的数据传参时,函数内部不会改变原数据的值。
可变类型的数据传参时,函数内部可以改变原数据。
"""

6. 函数参数

6.1 实参与形参

def func01(p1, p2, p3):  # p1,p2,p3 为形参
    print(p1)
    print(p2)
    print(p3)


data01 = 10
data02 = 20
data03 = 30

# 函数调用时传入的data01,data02,data03为实参
# 按位置顺序与形参一一对应,不能多传或者少传
# data01与p1,data02与p2,data03与p3
func01(data01, data02, data03)  # 依次打印10 20 30

# 关键字实参
# 按照名称与形参对应
func01(p3=300, p1=100, p2=200)  # 依次打印100 200 300


def func02(a1=1, a2="hello world", a3=False):  # 在形参中设置值,为默认形参
    print(a1)
    print(a2)
    print(a3)


# 设置有默认形参可以不传入参数,使用默认数值
func02()  # 依次打印1 hello world False

# 设置有默认形参传入参数,使用传入的数值
func02(2, "HELLO WORLD", True)  # 依次打印2 HELLO WORLD True

# 设置有默认形参的情况下可以域关键字实参配合,跳过前面的参数设置
func02(a2="跳过参数1")  # 依次打印1 跳过参数1 False

6.2 参数类型注释

# python3.6以后增加的类型标注(注释)
# 作用:
# 1. 增加代码可读性(知道了变量类型)
# 2. 增加类型检测
# 语法:
# 1. 参数:         变量:类型
# 2. 返回值:       def 函数名()->类型:
# 3. 选择多种类型:  类型|类型

def func01(p1: int, p2: str, p3: bool):  # 分别为形参p1注释int类型,形参p2注释str类型,形参p3注释bool类型
    print(p1)
    print(p2)
    print(p3)


func01(1, "hello", False)  # 使用参数类型注释,传入实参时编译器会提示类型
func01("hello", 33, 6.666)  # 传入与参数注释类型不同的实参,不会强制报错,在编译器中会高亮显示,提醒类型不符


def func02(a1=3, a2="world"):  # 设置默认形参,也能达到参数注释的效果
    print(a1)
    print(a2)


func02(33, "cool")


def func03() -> int:  # 为返回值添加类型注释
    data01 = 111
    return data01  # 返回的值与注释的类型不同时,,编译器会高亮显示,不会报错


num = func03()  # 有返回值注释,在接收返回值时,编译器会有类型提示

7. 作用域

7.1 定义

变量起作用的范围。

7.2 分类

# Local局部作用域:函数内部。
# Global全局作用域:模块(.py文件)内部。
data01 = 10  # 全局变量在整个文件中都适用


def func01():
    data02 = 20  # 局部变量,只在当前函数的作用域中有效
    print(data01)  # 函数内部能使用全局变量 10


func01()

# print(data02) # 运行会报错,函数作用域外无法使用函数内的局部变量data02

# 变量名的查找规则
# 在访问变量时,先查找局部变量,之后是全局变量。


data03 = 30


def func02():
    data03 = 300
    print(data03)  # 300 变量同名时函数内会优先使用函数内部的局部变量data03


func02()

# 结论
# 局部变量
# (1) 定义在函数内部的变量(形参也是局部变量)
# (2) 只能在函数内部使用
# (3) 调用函数时才被创建,函数结束后自动销毁
# 全局变量
# (1) 定义在函数外部,模块内部的变量。
# (2) 在整个模块(py文件)范围内访问(但函数内不能将其直接赋值)。


# 关键字 global
# (1) 作用:
# 在函数内部修改全局变量。
# 在函数内部定义全局变量(全局声明)。
# (2) 语法:
# global 变量1, 变量2, …
# (3) 说明
# 在函数内直接为全局变量赋值,视为创建新的局部变量。
# 不能先声明局部的变量,再用global声明为全局变量。

data04 = 40
data05 = 50
data06 = 60


def func03():
    global data04, data05  # 使用global将data04和data05标记为全局变量,可以直接在函数内修改它
    data04 += 400
    data05 *= 5
    data06 = 600


func03()

print(data04)  # 440 global标记后在函数中修改
print(data05)  # 250 global标记后在函数中修改
print(data06)  # 60 没有被修改

 

函数的内存分别

程序自上而下运行,会将函数add加载到代码区

将int类型10赋值给num01,num01存储的是10的地址值

调用函数add,传入参数num01和20,则参数p1存储10的地址值,p2存储20的地址值

将p1+p2赋值给result,result存储的是p1+p2结果30的地址值

函数最后返回result被赋值给data,因此data存储的是30的地址值.函数运行完毕其内存被释放.

建立自定义函数Python实现加法运算 python定义一个加法函数_建立自定义函数Python实现加法运算

程序自上而下运行,将函数calculate_iq_level加载到代码区

调用函数calculate_iq_level传入18和15,则ma存储的是18地址值,ca存储的是15的地址值

将ma/ca*100赋值给iq,iq存储的是ma/ca*100结果120的地址值

函数最后返回字符串"超常"赋值给level,level存储的是"超常"的地址值,函数运行结束在内存中被释放

建立自定义函数Python实现加法运算 python定义一个加法函数_建立自定义函数Python实现加法运算_02

程序自上而下运行将函数func01加载到代码区

将int类型10赋值给num,num存储的是10的地址值

将列表[10]赋值给list01,list01存储的是列表[10]的地址值

运行函数func01传入num和list01,则p1存储的是10的地址值,p2存储的是[10]的地址值

将int类型20赋值给p1,p1存储的是20的地址值

将int类型20赋值给p2[0],则p2[0]存储的是20的地址值,函数运行结束在内存中被释放

num在函数中没有被修改,list01在函数中list01[0]存储的地址值被修改为20的地址值

建立自定义函数Python实现加法运算 python定义一个加法函数_建立自定义函数Python实现加法运算_03

程序自上而下的运行,将函数func01加载到代码区

将列表[10]赋值给a,a存储的是[10]的地址值

将列表[20]赋值给b,b存储的是[20]的地址值

运行函数func01传入a[:]和b,则p1存储的是新列表[10](为原先列表复制)的地址值,p2存储的是列表[20]的地址值

将100赋值给p1[0],p1[0]存储的是100的地址值

将[200]赋值给p2[:],p2[0]存储的是200的地址值,函数运行结束,在内存中被释放

a在func01运行过程中没有被修改,存储的还是[10]地址值,b在func01运行过程中被修改,原先存储的地址值不变,b[0]存储的地址值发送改变

建立自定义函数Python实现加法运算 python定义一个加法函数_局部变量_04

将int类型10赋值给data01,data01存储的是10的地址值

将函数func01加载到代码区中

将int类型10赋值给data02,data02存储的是10的地址值

运行函数func01传入data02,p1存储的是10的地址值

使用关键字global标记函数内的data01为全局变量,则data01 += 1,全局变量data01存储的是11的地址值,p += 1存储的是11的地址值

函数运行结束,在内存中被释放,变量p也不存在了,变量data02没有改变,在函数中使用关键字global标记了data01,并做了修改,data01变为存储11的地址值

使用关键字global标记函数内的data01为全局变量,则data01 += 1,全局变量data01存储的是12的地址值,p += 1存储的是11的地址值

函数运行结束,在内存中被释放,变量p也不存在了,变量data02没有改变,在函数中使用关键字global标记了data01,并做了修改,data01变为存储12的地址值

 

建立自定义函数Python实现加法运算 python定义一个加法函数_赋值_05