引言

    在前几章中,我们学会了处理数据和编写逻辑。但随着代码越来越长,我们发现有些代码段在重复出现,维护和修改变得困难。今天,我们将学习编程中最重要的概念之一——函数。它就像现实生活中的工具箱,把常用的工具(代码)整理好,需要时直接取用,让我们的代码更整洁、更高效、更易维护。

一、函数的创建——打造你的第一个工具

  在上一篇的简易通讯录管理系统中,我们多次编写了查找名字信息的代码,这可能会导致几个问题:
1)、代码冗余: 同样功能的代码出现在多个地方。
2)、维护困难: 需要修改查找逻辑时,要改很多处,容易遗漏。
3)、可读性差: 代码冗长,难以理解整体结构。
为了解决这些问题我们就会用到今天所学的函数了,函数的优点有很多例如:
1)、代码复用: 一次定义,多次调用。
2)、模块化: 将复杂问题分解为小问题,各个击破。
3)、易于调试: 错误被局限在函数内部,易于定位和修复。

1、函数的定义与调用

  定义函数就是创建出一个新的函数,其创建的形式是:

python
def 函数名(参数):
      函数体
    return 返回值

  其中def是Python中的关键字,就表示创建一个函数,函数名就是我们要创建函数的名字,参数表示的是该函数可以接受到的数据,函数体里是用于实现函数主要功能的具体代码,return是将数据返回给调用函数。

  这里我们创建一个可以依次输出0-100的函数。

def cc():
    for i in  range(100):
        print(i,end='\t')

  这里运行会发现代码没有被执行因为我们这里只是创建函数,而我们如果使用我们所创建的函数就要调用它,调用函数的方法为:函数名(参数)。

def cc():
    for i in  range(100):
        print(i,end='\t')
cc()

  这里要注意因为代码是自上而下的运行的,所以我们一定要先定义函数再调用函数,否则程序在执行调用函数时将无法找到定义函数的位置从而报错。

2、函数的返回值

  return语句是我们在定义函数时经常用到的语句,他主要的作用是结束函数执行和将结果返回给调用者。

def cc(a, b):
    #计算两个数的和
    c = a + b
    return c
print(cc(5,4))# 输出:9

 带返回值的函数在函数执行完后会将数据返回给调用函数。程序在开始执行后会先跳过def语句,直接执行第5行代码,他会先计算出print(cc(5,4))的参数即调用函数cc(5,4),此时程序转到第一行定义函数,开始按顺序执行函数代码,当程序执行到第四行时会将c的值传递到调用函数处,调用函数接收到数值9时执行结束,此时在打印出结果才会输出9,否则调用函数将会默认接受以个空值即none。

def cc(a, b):
    #计算两个数的和
    c = a + b
print(cc(5,4))# 输出:9

3、函数的复用价值

  定义函数最需要的作用就是当我们需要经常使用某些功能时,将这些功能创建成函数,在使用时直接调用即可不必再重复编写代码,大大增加了我们的编程效率。

  例如我们要计算多个矩形的面积。

def cc(length, width):
    a = length * width
    return a

# 复用同一个函数计算不同矩形
cc1 = cc(4, 5)
cc2 = cc(5, 6)
cc3 = cc(2.5, 4.5)
print(cc1,cc2,cc3)

二、函数的参数——让工具更灵活

1、形参与实参

  定义函数时我们可以设置函数接收多个参数,在函数定义时括号中的变量我们称之为形参,在函数调用时传递给函数的具体值即调用函数里填入的参数我们称之为实参。

def 函数名(形参1,形参2,形参2,...)
  函数代码
  return 返回值
函数名(实参1,实参2,...)

  在我们使用实参和形参是需要注意:

1)、形参都为变量名,因为形参是使用变量名来接受实参传递过来的信息。

2)、在定义函数时需要确定形参的个数。

3)、形参之间要用逗号隔开

4)、调用函数中的实参为实际数据,并且实参里的个数要与形参形同。

5)、调用函数时会按顺序一次将实参的数据复制给形参,所以实参的顺序必须与形参的顺序一致。

def cc1(name):  # name是形参
    print(f'Hello, {name}')
cc1('小王')    # '小王'是实参
def cc2(name, age, city):
    print(f'我叫{name},今年{age}岁,来自{city}')
cc2('小王', 18, '合肥')  # 正确
cc2('合肥', '小王', 18)  # 错误!顺序不对

  最后一行代码虽然能运行(没有语法错误),但语义完全错误:name 参数收到了 "合肥"(城市名)age 参数收到了 "小王"(人名)city 参数收到了 18(年龄)这就导致了荒谬的输出结果:"我叫合肥,今年小王岁,来自18"。

2、关键字参数

  关键字参数是以字典的形式储存接收到的数据(其中键值用等号连接),通过参数名来传递值的方式,调用时可以任意指定参数的顺序,因为Python会根据参数名来匹配对应的值。关键字参数的形参使用**开头,且其必须位于必填参数的右边。

def 函数名(形参1,**形参2):
def cc(a,**b):
    print('姓名',a)
    print(b)
cc('小王',telephone=123321)

3、默认参数

  默认参数就是提前给参数设置一个数据,调用时可省略。但当我们的调用函数传递了参数2的数据,那么我们传递的数据就会覆盖掉原本默认的数据。

def 函数名(形参1,形参2=数据):
    代码
    return语句
def cc(a,b=5):
    c=a*b
    return c
print(cc(1))
print(cc(1,3))

4、可变参数

  当不确定所需要接受参数的个数时就可以使用可变参数。我们只要在形参前加上一个*就可以将其变为可变参数。要注意当有必填参数时,可变参数要位于必填参数的右边让必填参数先接收一个数据再将剩下的数据传递给可变参数,并且可变参数是以元组的形式接收数据的。

def 函数名(形参1,*形参2):
def cc(a,*numbers):
    c = 0
    print(numbers)
    for num in numbers:
        c += num*a
    return c

print(cc(1, 2, 3))
print(cc(2, 2, 3, 4, 5))

三、变量的作用域——理解代码的"可见范围"

1、局部变量与全局变量 

  在我们还未学习函数之前,我们使用变量只需给它赋值就能在后续代码中继续使用,而在函数的内部是不能随意使用主代码中的变量的。根据变量的作用范围我们可以分为全局变量和局部变量。全局变量是整个代码中(包括函数内部)都可以被使用的变量,而局部变量是只能在局部范围内被使用的变量,例如函数中的形参变量和内部代码的变量都是局部变量。

b = '我是全局变量'  # 全局变量

def cc():
    a = '我是局部变量'  # 局部变量
    print(b)  # 可以访问全局变量
    print(a)   # 可以访问局部变量
cc()

  注意当在函数中使用全局变量且对其赋值之后,将会在函数内部创建出一个新的局部变量而不是使用全局变量。

def  cc(b):
    print(a+b)
    a=1
    print(b+a)
a=3
cc(2)
print(a)

  

  报错局部变量a没有信息是因为在函数对a重新赋值时,系统默认在函数中创建了一个局部变量a,a的值为2,因为第二行代码没有a的赋值信息又不能使用全局变量所以会出现报错。

2、关键字global

  如果我们函数内外想要使用同一种变量又不会在函数内部被重新赋值,这里就要用到一个关键字global。

a = 0
def cc():
    global a  # 声明使用全局变量a
    a += 1

cc()
print(a)  # 输出:1


3、函数中的可变数据

  在Python中会根据是否改变内存空间将数据分为可变数据和不可变数据。可变数据在数据发生变化时不会改变内存空间,不可变数据则会改变内存空间。这里我们可以使用id()函数来查看数据的内存空间编号。

a=3
b=[1,2,3]
print(id(a))
print(id(b))
a=4
print(id(a))
b.append(4)
print(id(b))
b=[1,3,4]
print(id(b))

  这里我们对a重新赋值后可以发现其内存空间变化了,而通过方法append()修改可变数据b中的数据则不会改变其内存空间。但当我们对其重新赋值后,b的内存空间也发生了改变。

  对于列表、字典等可变数据类型,在函数内部修改内容时,不需要 global 声明关键字。

a = [1, 2, 3]
def cc(item):
   a.append(item)  # 直接修改全局列表的内容
cc(4)
print(a)  # 输出:[1, 2, 3, 4]

四、导入其他模块的函数——站在巨人的肩膀上

  当开发一个需要多人协同的项目时,往往需要在不同文件里实现不同的函数,最终将代码文件组合成一个完整的项目。我们无法直接调用在其他文件里的函数,就需要我们通过一些方法来实现。

1、导入整个模块

  在Python中,导入整个模块使用import 模块名语法,这是一种基础而实用的模块导入方式。通过这种方式,我们可以访问该模块中的所有函数、类和变量,使用时需以模块名.函数名()格式调用。例如导入math模块后,使用math.sqrt(4)计算平方根。这种方法的优势在于命名空间清晰,能有效避免函数名冲突。

import math
print(math.sqrt(16))  # 输出:4.0

2、导入特定函数

  from 模块名 import 函数名是Python中一种导入方式,它允许从模块中直接导入特定的函数、类或变量。使用这种方法后,在代码中可以直接调用函数名而无需添加模块前缀,使代码更加简洁明了。

from math import sqrt, pow
print(sqrt(25))  
print(pow(2, 3)) 

3、导入所有函数

  当需要导入文件的全部函数时可以使用form 文件名 import *来实现。

from math import *
print(sqrt(25))
print(pow(2, 3))

4、给导入的函数设置别名

  当我们导入的函数名较长时我们可以用as来给它起一个简单的别名。

import 模块名 as 别名
from 模块名 import 函数名 as 别名
import math as ma
print(ma.sqrt(4))

from math import sqrt as sq
print(sq(4))

5、__name__ 属性的妙用

  __name__ 用于获取当前文件的名称,当其位于主文件时就会返回"__main__",如果位于其他文件时就会返回当前的文件名。这常用与调试自己的代码,我们可以在主程序中加入(if __name__ == "__main__":),因为只有位于主文件返回"__main__"时后续代码才会被执行。

def main():
    # 主要逻辑代码
    print("这是主程序")

if __name__ == "__main__":
    main()  # 只有当文件直接运行时才执行

五、进阶概念

1、函数的递归

  函数递归是编程中的重要概念,指的是函数在执行过程中直接或间接调用自身的编程技巧。使用递归时必须设置明确的递归结束条件(基线条件),否则会导致无限递归和栈溢出错误。使用形式为:

def 函数名():
    代码
    函数名()

一个最简单经典的案例就是计算阶乘。

def factorial(n):
    if n == 1:  # 基线条件
        return 1
    else:       # 递归条件
        return n * factorial(n - 1)

print(factorial(7)) 

2、匿名函数 lambda

  Lambda表达式是Python中创建匿名函数的简洁方式,适用于定义简单的、一次性的函数操作。其语法结构为lambda 参数: 表达式,能够快速定义小型函数而无需使用def关键字。lambda函数只能包含单个表达式且不能包含复杂语句。lambda可以作为函数也可以作为函数的参数。

1)、作为函数时

# 普通函数
def cc(x):
    return x * x
# 等价的lambda表达式
cc1 = lambda x: x * x
print(cc(6))
print(cc1(6))  

2)、作为参数时

cc= [23, 15, 47, 82, 36, 91, 54]
# 使用 lambda 按个位数排序
a = sorted(cc, key=lambda x: x % 10)
print("原始列表:", cc)
print("按个位数排序:", a)

  到这我们就学完了函数的基本知识了,让我们用所学的内容将上一篇的简易通讯录管理系统用函数的方法来实现。

# 初始化一个空字典来存储联系人
a = {}

def add_people():   #添加联系人
    name = input("请输入联系人姓名:")
    phone = input("请输入联系人电话:")
    a[name] = phone  # 核心:向字典添加键值对
    print(f"联系人 {name} 添加成功!")


def find_people():   #查找联系人
    name = input("请输入要查找的联系人姓名:")
    if name in a:  # 核心:检查键是否存在
        print(f"{name} 的电话是:{a[name]}")  # 核心:通过键访问值
    else:
        print(f"通讯录中未找到 {name}")


def show_all_people():   #显示所有联系人
    if not a:  # 如果字典为空
        print("通讯录为空!")
        return

    print("\n=== 所有联系人 ===")
    for name, phone in a.items():  # 核心:遍历字典的键值对
        print(f"姓名:{name},电话:{phone}")


def delete_people():   #删除联系人
    name = input("请输入要删除的联系人姓名:")
    if name in a:
        del a[name]  # 核心:删除指定键值对
        print(f"联系人 {name} 已删除")
    else:
        print(f"通讯录中未找到 {name}")


# 主程序循环
while True:
    print("\n=== 简易通讯录 ===")
    print("1. 添加联系人")
    print("2. 查找联系人")
    print("3. 显示所有联系人")
    print("4. 删除联系人")
    print("5. 退出系统")

    choice = input("请选择功能(1-5):")

    if choice == "1":
        add_people()
    elif choice == "2":
        find_people()
    elif choice == "3":
        show_all_people()
    elif choice == "4":
        delete_people()
    elif choice == "5":
        print("再见!")
        break
    else:
        print("输入错误,请重新选择!")

  恭喜你掌握了函数这一强大的代码组织工具。在下一章,我们将学习类与对象的概念。这将是我们从"函数式思维"迈向"对象式思维"的重要一步,也是理解复杂AI框架的基础。

Logo

更多推荐