目录

🙄什么是Python函数(了解函数的概念)

🤔为什么需要它?(背景和痛点)

😮函数的分类(函数有哪些?)

内置函数

标准库函数

第三方库函数

定义函数

🧐核心原理拆解(搞清楚他们是如何工作的?)

函数的定义

函数的调用

函数的参数

        形参和实参的概念

        位置参数

        默认参数

        关键字参数

        不定长参数

        函数的返回值

🤑案例实操

案例一:基础函数(无参+有参)

案例二:默认参数+可变参数

案例三:return 返回值

🤓关联知识(通过函数,了解变量的作用域)

什么是作用域?

全局变量和局部变量

案例——全局和局部变量

🤫 避坑总结

🥳三条学习心法

心法 1:参数 + return > global

心法 2:函数要"专一"

心法 3:默认参数用不可变对象


🙄什么是Python函数(了解函数的概念)

  • Python函数:是一个被命名的、独立的、完成特定功能的代码段,有时候给调用它的程序一个返回值。
  • 💡核心导读:Python函数就是一个个功能明确的小工具,当用到某个工具时直接调用。它不仅能帮我们把复杂的任务分解成简单的步骤,还能提高代码的复用性和可读性。

🤔为什么需要它?(背景和痛点)

  • 没有函数之前,我们可能会在代码中多次重复地编写相同的功能代码,这不仅浪费时间,还会使代码变得冗长且难以维护。
  • 函数带来的核心优势:
    • 提高代码复用性,减少重复代码;
    • 使代码逻辑更加清晰,便于理解和调试;
    • 模块化编程,方便团队协作开发,每个人负责不同的函数模块。

😮函数的分类(函数有哪些?)

内置函数

        在编写代码过程中,可以拿来直接使用的时内置函数(如:print() / input() / min() / max() 等)

函数作用
print()输出内容
len()获取长度
type()查看类型
input()接收输入
sum()求和

标准库函数

        通过import语句导入库,然后使用该库中定义的函数。

模块函数作用
mathsqrt()开平方
randomrandint()随机整数
timesleep()延时

第三方库函数

        Python社区提供了很多高质量的库,通过下载安装这些库后,也可以使用import语句导入,然后使用这些第三方库的函数。

库函数
numpyarray()
pandasread_excel()
requestsget()

定义函数

        用户根据自己的需求自定义的函数,这也是我们需要学习的,根据需求构建合适的函数来实现某个功能。

🧐核心原理拆解(搞清楚他们是如何工作的?)

函数的定义

  • 以 def 关键字开始,告诉Python我要定义一个函数。
  • 函数名是函数的标识,所以要遵循命名规则,通常全小写且单词之间使用下划线连接。
  • 参数是函数运行时需要的输入数据,可以是0个或者多个。
  • 函数体是函数的核心部分,包含了具体的处理逻辑,需要注意的是这部分代码需要缩进,表明下面这部分代码属于该函数。
  • return 语句用于返回函数的处理结果,如果没有 return 语句,函数默认返回 None。
def function_name([参数1,参数2,……]):
    ''' 文档字符串(可选,用于解释函数功能) '''
    函数体(注意必须缩进)
    ……
    return 返回值    # 可选,用于结束函数并返回结果,不写这条语句默认返回None

函数的调用

当我们需要使用函数的功能时,通过函数名加上圆括号来调用它,如果函数有参数,需要在圆括号内传入相应的实参。

函数名([参数1,参数2,……])

函数的参数

主要参数类型:默认参数、关键字参数、位置参数、不定长参数

在了解上面那三种参数类型之前,首先需要认识什么是:形参和实参?

        形参和实参的概念

                形参(形式参数):是函数定义时小括号中的参数,用来接收参数的,并在函数内部作为变量使用。

                实参(实际参数):是函数调用时小括号中的参数,用来把数据传递到函数内部。

# 形参
def two_numbers_sum(a, b):    # 函数的定义,其中的a,b是形参
    return a + b

# 实参
result = two_numbers_sum(3, 4)    # 函数的调用,其中的3, 4是实参

        位置参数

                按位置顺序传递,最为常见

                示例:

def two_numbers_sum(a, b):    # 当调用函数时,按照形参定义的位置顺序,一次传递参数
    return a + b

result = two_numbers_sum(3, 4)    # 位置参数:实参“3”对应形参“a”,实参“4”对应形参“b”

        默认参数

                给参数设置默认值,调用时可以不传参数,如果传参,则会变成和传入参数一样的值。一般默认参数放到形参的最后面。

                示例:

def user_info(user_name, age, gender='男'):
    # 格式化打印用户信息
    print("用户名:{0}, 年龄:{1}, 性别:{2}".format(user_name, age, gender))

user_info("小王", 18)
user_info("小刘", 20, "女")

# 运行结果
# 用户名:小王, 年龄:18, 性别:男
# 用户名:小刘, 年龄:20, 性别:女

               通过上面的示例可知:函数"user_info()"中有默认参数" gender ",其默认值是“男”。当没有传递该参数时,函数中形参“gender”的值就是“男”;如果传递了参数“女”,则函数中的“gender”的值就是“女”。

        关键字参数

                调用时指定参数名,此时就不需要按照位置参数的顺序进行传参了。

def user_info(user_name, age, gender='男'):
    # 格式化打印用户信息
    print("用户名:{0}, 年龄:{1}, 性别:{2}".format(user_name, age, gender))

# 调用函数时,使用关键字参数指定传递的参数值,此时的参数就可以不按照定义函数时的顺序进行传递了
user_info(age=22, user_name="小张")

# 运行结果
# 用户名:小张, 年龄:22, 性别:男

        不定长参数

                不定长参数:接收任意多个参数,包括” *args “ 和" **kwargs "两种。

参数类型说明示例
*args接收任意多个位置参数,变成元组def total(*nums)
**kwargs接收任意多个关键字参数,变成字典def info(**data)

                不定长参数也是放到形参的最后面,如果同时又默认参数和不定长参数,最好的方式就是把不定长参数放到默认参数之后。

                ✅推荐正确顺序:

                普通位置参数 -> 默认参数 -> 不定长参数(*args) -> 不定长参数(**kwargs)

# 按照标准顺序定义函数
def my_func(a, b=10, *args, **kwargs):
    print(f"普通参数 a: {a}")
    print(f"默认参数 b: {b}")
    print(f"不定长参数 args (元组): {args}")
    print(f"不定长关键字参数 kwargs (字典): {kwargs}")

# 调用函数
my_func(1, 2, 3, 4, 5, name="小明", age=18)

# 输出结果
# 普通参数 a: 1
# 默认参数 b: 2
# 不定长参数 args (元组): (3, 4, 5)
# 不定长关键字参数 kwargs (字典): {'name': '小明', 'age': 18}

                ❓可能有人问:

                为什么调用函数的时候使用了“关键字函数(name="小明", age=18)”为什么会变成字典呢?

                因为这不是“关键字函数”,关键字函数确实是在函数调用的括号里定义的,定义方式:形参名=数据。可以看到上面在函数定义的形参列表中没有"name,age"这两个形参,但是有不定长参数“ **kwargs ”,所以这两个参数会被打包进“ **kwargs ”变成字典的形式。【至于他为什么会变成字典涉及到“拆包”的思想,这个在本章节不详细讲解,还请谅解】

        函数的返回值

                return后面可以跟一个值、多个值、或不写

                跟多个值时,Python会自动打包成元组

                函数遇到 return 会立即结束,后面的代码不在执行


🤑案例实操

案例一:基础函数(无参+有参)

# 无参函数:打招呼
def say_hello():
    print("hello world")

say_hello()  # 调用无参函数
# 输出结果:hello world

# 带参函数:求两数之和
def two_numbers(a, b):
    result = a + b
    return result

print(two_numbers(3, 5))  # 调用带参函数并打印结果
# 输出结果:8

案例二:默认参数+可变参数

# 默认参数
def user_info(name, age, gender="男"):
    print(f"姓名:{name},年龄:{age},性别:{gender}")


user_info("小明", 18)  # 输出:姓名:小明,年龄:18,性别:男


# 可变参数 *args:计算任意多个数的总和
# 计算小明的所有考试成绩
def total_sum(name, age, gender="男", *numbers):
    result = 0
    for num in numbers:
        result += num
    print(f"姓名:{name},年龄:{age},性别:{gender},总分:{result}")

total_sum("小明", 18, 80, 90, 88)  # 输出:姓名:小明,年龄:18,性别:80,总分:178

        上述不定长参数“ *args ”接收的参数是,先按照位置参数的顺序将前面的实参接收,最后剩下的内容就是“ *args ”打包的内容。所以上述出现了“性别:80”的情况,所以当参数较多,使用“ *args ”接收参数时,实参尽量和形参的数量和顺序对应,更好的方式是使用关键字参数。

# 使用不定长参数**kwargs定义一个函数,接受任意数量的关键字参数,并打印出这些参数的键和值。
def user_info(name,age,gender='男',**info):
    print('姓名:%s'%name)
    print('年龄:%d'%age)
    print('性别:%s'%gender)
    print('其他信息:')
    for key,value in info.items():
        print('%s:%s'%(key,value))

user_info('李四',age=25,job='程序员',city='上海',hobby='篮球')
print('-'*20)
user_info('张三',gender='女',job='学生',city='北京',age=20,hobby='唱歌')
# 输出结果:
# 姓名:李四
# 年龄:25
# 性别:男
# 其他信息:
# job:程序员
# city:上海
# hobby:篮球
# --------------------
# 姓名:张三
# 年龄:20
# 性别:女
# 其他信息:
# job:学生
# city:北京
# hobby:唱歌

        由此可见,不定长参数“ **kwargs ”会接收任意数量的关键字参数。而当同时使用关键字参数和不定长参数时,不按照形参的位置顺序传参也没关系,函数接收参数是按照形参的顺序依次接受的,当到了“ gender ”参数的时候,会现在函数调用的实参中寻找“ gender ”参数,找到就接收,而其他“ key = value ”形式的参数就会被“ **kwargs ”接收。

案例三:return 返回值

无 return 语句

# 不加return 语句
def user_info(name, age):
    print(f"Name: {name}, Age: {age}")

# 使用一个变量接收函数的返回值
ret = user_info("Tom", 18)
print(ret)

# 输出结果:
# Name: Tom, Age: 18    # 此结果是函数中的print()打印的结果
# None                  # 此结果是打印函数的返回值

        可见,不写 return 语句默认返回值为“ None ”。

使用 return 返回单个值

# 使用 return 语句返回单个值
def add(a, b):
    return a + b
# 使用一个变量接收函数的返回值
ret = add(1, 2)
print(ret)  # 3

使用 return 语句返回多个值

# 使用 return 语句返回多个值
def calculate(a, b):
    sum_result = a + b
    difference = a - b
    return sum_result, difference

# 调用函数并接收返回的多个值
result_sum, result_diff = calculate(10, 5)
print("两数求和:", result_sum)        # 输出: 两数求和: 15
print("两数作差:", result_diff)  # 输出: 两数作差: 5
# 打印函数的返回值
print(calculate(10, 5))  # 输出: (15, 5)

        可见,return 返回多个结果时,是以元组的形式返回的。而接收函数的返回值使用的是“拆包”的思想。

🤓关联知识(通过函数,了解变量的作用域)

变量根据作用域的不同分为:

  • 全局变量
  • 局部变量

什么是作用域?

作用域:实际上就是变量的“活动范围”。

Python 中变量的作用域遵循 LEGB 规则(由内到外查找):

L → E → G → B
局部 → 嵌套 → 全局 → 内置
  • L(Local):函数内部定义的变量

  • E(Enclosing):嵌套函数的外层函数变量

  • G(Global):模块级别定义的变量

  • B(Built-in):Python 内置的变量(如 print、len)

简单说:Python 找变量时,先在本函数里找,找不到再去外层找,一层一层往外翻。

全局变量和局部变量

从名字上看,一个在全局(大范围)使用,一个是在局部(小范围)使用。

全局变量:在函数和类定义之外声明的变量。作用域为定义的模块,从定义位置开始到模块结束。

局部变量:在函数内部声明的变量(包括形参),只能在该函数中使用,外部无法使用。

案例——全局和局部变量

函数内部访问全局变量

# 定义一个全局变量
name = 'Tom'
# 定义一个方法,打印全局变量
def show():
    # 函数内部可以直接访问全局变量
    print(name)

show()  # 输出: Tom

函数外部访问局部变量


# 定义一个函数
def show():
    # 定义一个局部变量
    name = 'Tom'
    print(name)

print(name) # 错误:NameError: name 'name' is not defined

既然函数内部可以访问全局变量,那么我们现在在函数内部修改全局变量【需要使用 global 关键字】

# 定义一个全局变量
name = 'Tom'
# 定义一个方法,打印全局变量
def show():
    # 函数内部修改全局变量
    name = 'Jerry'
    print(name)

show()      # 输出:Jerry
print(name) # 输出: Tom

# 我们发现,在函数外面定义的全局变量并没有因为在函数内部发生改变而改变,仍然是原来的“Tom”
print('-'*30)
# 正确的方式是:
name1 = 'Tom1'
def show1():
    # 函数内部修改全局变量
    global name1
    name1 = 'Jerry1'
    print(name1)

show1()         # 输出:Jerry1
print(name1)    # 输出: Jerry1

🤫 避坑总结

1. 缩进问题:Python中是依靠缩进区分代码块的,函数体内部的代码必须缩进,且缩进量保持一致,否则导致语法错误。

2. 调用顺序和局限:不是只要定义了函数就可以随时随地使用。必须先定义函数,然后才能调用它,并且如果想使用别的文件中的方法,直接在当前文件中调用是不可行的。它是先将含有该方法的文件进行封装(封装成一个类或模块),通过导入模块和实例化类,来调用该方法。

3. return 语句:函数没有 return 语句是不是没有返回值?错,没有 return 语句,也有返回值,默认返回 None 。其实所有的函数都有返回值,只是有的函数不需要返回指定的数据,所以可以不需要写 return 语句,让他默认返回None即可。

4. print 与 return 区别:print 只是将结果输出到控制台,方便人查看;而 return 是将结果返回给调用者,供程序后续使用,一个函数可以没有 print ,但是如果需要返回值处理结果,就必须有 return 。

坑说明
函数定义了不调用写 def 只是“造工具”,必须用 函数名() 才会执行
return 后还写代码return 是重点,后面的代码永远不会执行
默认参数使用 [] 或 {}会导致多次调用共享同一个对象,应该使用 None 代替
函数内直接改全局变量需要先使用 global 声明,否则Python认为是局部变量
参数顺序写错正确顺序:位置参数 -> 默认参数 -> *args -> **kwargs

🥳三条学习心法

心法 1:参数 + return > global

能用参数传进去、用 return 传出来,就绝不用 global。

全局变量是"隐形炸弹"——程序小没问题,项目大了谁改了值根本找不到。参数和 return 让数据流动看得见、管得住。

心法 2:函数要"专一"

一个函数只做一件事,名字就要让人一眼看懂。

❌ def process_data_and_save_and_log()
✅ def save_data() + def log_event()

函数越"专一",复用性越强,调试越轻松。

心法 3:默认参数用不可变对象

def f(lst=None) 永远比 def f(lst=[]) 安全。

Python 的默认参数在函数定义时只创建一次,用可变对象(列表、字典)会导致多次调用共享同一个对象,产生难以察觉的 Bug。

更多推荐