函数

函数

Yiuhang Chan

什么是函数

函数是一段可重复使用的代码块,用于执行特定的任务

函数的作用

  1. 提高代码的可重用性: 使用函数可以将代码块组织成更小的可重用模块,减少代码的冗余。
  2. 提高代码的可读性: 使用函数可以使代码更加简洁和易于理解,也更容易进行调试和维护。
  3. 提高代码的模块化: 使用函数可以将程序分解成更小的模块,每个模块都可以处理特定的任务,这样程序的组织结构更加清晰。
  4. 提高代码的可扩展性: 使用函数可以使程序更易于扩展和修改,因为函数可以独立地编写和测试,而不会影响程序的其他部分。

函数就是设计一个技能需要时自己调用,调用的方法本质上是个函数 。两者的区别是使用的方式不一样。

函数写法

1
2
3
4
5
6
7
# 用def定义一个函数
def User():
内容


# 调用函数 必须顶格
User()

函数的形参和实参

  1. 不传值给函数可以不带形参和实参
  2. 形参名字可以随意定义
  3. 形参和实参数量必须一致
  4. 实参对应形参
  5. 形参可以赋默认参数 没有传就以默认参数 传了就以实参
  6. 实参也可以指定形参
  7. 通过*形参名可以获取所有实参,通过索引获取对应实参
1
2
3
4
5
6
7
# 用def定义一个函数
def User(形参):
内容


# 调用函数 必须顶格
User(实参)

案例

1
2
3
4
5
6
7
8
9
10
11
# 形参的默认参数
# 如果没有传就以默认参数 传了就以实参
def user(x, y):
print(x)
print(y)


user(13, 14)

# 13
# 14
1
2
3
4
5
6
7
8
9
# 通过*形参名可以获取所有实参
def user(*item):
# 通过形参名索引获取对应实参
print(item[0])


user(13, 14, 16, 17)

# 13

内置函数

Python自带的一些函数,我们可以直接拿来使用

1
2
3
4
5
# 打印
print()
# 类型判断
type()
# 字符串、列表、元组、集合 的增删改查的方法

字符串、列表、元组、集合 的增删改查的方法 数值类型,详细内容与调用方法跳转查阅

函数的说明文档

  1. 给函数中的代码做解释说明
  2. 让其他程序员知道函数的作用
  3. 函数里的注释

如何写说明文档

  • 三引号包裹
1
2
3
4
def add(a, b):
'''
内容
'''
1
2
3
4
5
6
7
8
9
def add(a, b):
"""
这个函数用于计算两个数的和。

:param a: 第一个加数
:param b: 第二个加数
:return: 两个数的和
"""
return a + b

函数的嵌套

在函数内部调用其它函数

尽量不要嵌套太多层,不然就是屎山了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1.定义一个函数a
def a():
print('我是函数a')
# 3.在函数a内部调用函数b
b()


# 2.定义一个函数b
def b():
print('我是函数b')


# 4.调用函数a
a()

# 我是函数a
# 我是函数b

函数的作用域

Python 中的函数作用域分为两种: 全局作用域和局部作用域

  1. 全局作用域指的是在模块(文件)中定义的变量和函数,可以在模块的任何地方被访问和使用
  2. 局部作用域指的是在函数内部定义的变量和函数,只能在该函数内部被访问和使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 变量a 全局作用域
a = 100


# 定义一个 函数textA
def textA():
# 变量b 局部作用域
b = 20


# 因为变量a在全局作用域 所以可以访问到
print(a) # 100
# 因为变量b 在局部作用域 变量b 访问不到 所以会报错
print(b) # NameError: name 'b' is not defined

global 关键字

使用 global 关键字 可以在函数内部声明变量为全局变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定义两个变量 textA textB
def textA():
# gLobal 声明 money 为全局变量
global money
money = 100
print(money)


def textB():
print(money)


textA() # 100
textB() # 100

闭包 Closure

内部函数使用了外部函数的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def func(): # 外部函数
# 1. 变量a 是func函数的局部变量
a = 10
print("函数func调用")

def func1(): # 内部函数
# 2. 我们在func1这个内部函数里面 使用了 外部函数的变量a 这种现象就叫闭包,没有用到 变量 就不叫闭包
print(a)

return func1 # 3. 我们需要返回func1函数的本身给外部函数 才能看到闭包的效果 闭包不需要调用只需要返回


demo = func() # 函数func调用
demo() # 10

# 或者func()()

好处

好处: 保存局部变量的状态 我们可以将相关的功能和数据绑定在一起,而不用担心数据被其他代码修改。

应用:想保存数据状态和不被污染 我们就可以使用闭包。很多框架底层 保存数据都是用的闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def func():
a = 0

def func1():
nonlocal a # nonlocal 指向外部函数func的a 不会指向全局作用域 如果外部func没有a就会报错
a += 1 # 累加,主要做逻辑处理,每次调用func1就会累加1
return a # 将累加的结果返回出来给func1

return func1 # 返func1本身传递给func 覆盖原始a=0 我们才能看到闭包的效果

# 目的调用func1 让a累加一次
# 需要调用看结果
demo = func()
# 通过demo来调用里面的func1
print(demo())
# 输出 1
print(demo())
# 输出 2
print(demo())
# 输出 3
  1. 因此可以发现通过闭包,可以使得数据状态得到存储,例如存储累加的结果
  2. 且闭包的数据无法通过全局变量进行修改,保证数据完整性,因为是由子函数进行累加的
  3. 需要保存数据状态的时候就需要使用闭包
  4. 使用场景例如 第三方库 能够保存数据状态

信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
a = "Global"


def fun_out():
a = "external_function"

def fun_in():
print(a)

return fun_in


demo = fun_out()
demo() # external_function

在 Python 中,变量的使用和修改遵循不同的规则,特别是在涉及嵌套函数时。这是因为 Python 对变量的查找(读取)和赋值(修改)有不同的作用域规则。

  1. 读取变量:当代码尝试读取一个变量的值时(如在 print(a) 中),Python 会遵循作用域查找规则。这意味着它会首先在当前函数的局部作用域查找该变量。如果在当前作用域找不到,它会在外围作用域中查找,一直查找到全局作用域,最后是内置作用域。这就是为什么在上面的例子中,即使没有使用 nonlocal 关键字,fun_in 也能访问 fun_out 中定义的 a 变量。
  2. 修改变量:当尝试修改一个变量的值时,Python 的默认行为是在当前作用域创建或更新该变量。如果在一个嵌套的函数中不加声明地修改一个变量,Python 会认为这是一个新的局部变量,而不是一个外围作用域中的变量。
    • 使用 nonlocal 关键字:当想在一个嵌套函数中修改外围函数的局部变量时,需要使用 nonlocal 关键字。这样做可以告诉 Python 想修改的是外围作用域中的变量,而不是创建一个新的局部变量。
    • 全局变量:如果想在一个函数中修改全局变量,而不是创建同名的局部变量,需要使用 global 关键字。

这种区分是为了避免意外修改外围作用域中的变量,这可能会导致难以追踪的错误。通过要求显式声明 nonlocalglobal,Python 增强了代码的可读性和可维护性。

闭包(Closure)和嵌套函数(Nested Functions)的区别

闭包(Closure)

在编程中,闭包是指那些能够访问自己外部作用域中变量的函数。一个闭包至少由两部分组成:一个函数以及该函数引用的外部变量。Python 中闭包的一个关键特征是它保持了对其外部变量的引用,即使在外部函数已经结束执行之后。

在代码中,fun_in 是一个闭包,因为它是在 fun_out 内部定义的,并且引用了 fun_out 作用域内的变量 a。当 fun_out 被调用并返回 fun_in 时,尽管 fun_out 的执行已经结束,fun_in 依然保留了对变量 a 的引用。这样,即使是在 fun_out 执行完毕之后,fun_in 仍然可以访问并打印变量 a 的值。

嵌套函数(Nested Functions)

嵌套函数是在另一个函数内部定义的函数。虽然所有闭包都是嵌套函数,但并非所有嵌套函数都是闭包。一个嵌套函数只有在引用了其外部函数的变量时,它才构成一个闭包。

总结

fun_in 作为一个闭包,即使在其外部函数 fun_out 执行完毕后,仍然可以访问并使用 fun_out 作用域中的变量 a

匿名函数

匿名函数,通常在 Python 中通过 lambda 关键字来定义,是一种没有显式函数名的简短函数。它们在语法上是简洁的,通常用于编写小的、一次性的、不需要单独定义函数名的函数。

匿名函数是一个可以定义并立即使用的简洁函数形式。在 Python 中,匿名函数使用 lambda 关键字创建,其基本语法是:

1
lambda 参数列表: 表达式

这种函数通常用于简单的操作,比如简单的数学运算、字符串操作等。由于它们只是单个表达式,所以不能像普通函数那样执行复杂的操作

1
2
3
4
5
6
7
8
9
10
11
# lambda : 8 创建了一个匿名函数,这个函数没有参数,并且总是返回数字 8

func = lambda : 8 # lambda 关键字 代表匿名函数
print(func()) # 输出: 8


# 匿名函数的一个限制是它只能包含一个表达式,不能包含多个独立的语句或复杂的逻辑。如果函数体较复杂,或者需要重复使用,那么定义一个普通函数会更合适。它与匿名函数执行相同的操作,但是更适合复杂逻辑或多次调用的情况。
def func() :
return 8

print(func())

匿名函数的作用

匿名函数的主要作用是简化代码,尤其是在需要小的函数作为参数时,例如在排序操作、高阶函数(如 map()filter())或任何需要函数对象的地方。由于它们不需要定义传统的函数结构,因此可以在代码中快速定义和使用。

何时使用匿名函数

匿名函数通常在以下情况下使用:

  1. 简单的功能:当函数的功能非常简单,只需要一行代码就可以实现时,使用匿名函数是一个很好的选择。
  2. 一次性使用:当有一个不会在代码的其他地方复用的小函数时,使用匿名函数可以减少不必要的函数定义。
  3. 作为参数传递:当一个函数接受另一个函数作为参数时,如果这个参数函数非常简短,使用匿名函数可以使代码更加清晰。常见的例子包括 map()filter()sorted() 等函数。

QA

问:

函数通过function关键字定义吗?

答:

这个说法是错误的。在Python中,函数是通过 def 关键字来定义的,而不是 function。例如:def my_function():

问:

调用函数使用函数名即可吗?

答:

这个说法是正确的。在Python中,函数通过其名称来调用,可能跟随一对圆括号和必要的参数。例如,如果有一个名为 my_function 的函数,可以通过 my_function() 来调用它。

问:

函数必须要有返回值return

答:

这个说法是错误的。函数不一定需要有 return 语句。如果没有 return 语句,函数默认返回 Nonereturn 语句用于从函数中返回一个值。

问:

函数里面直接定义的变量外部不能访问

答:

这个说法是正确的,但需要一些澄清。在Python中,函数内部定义的变量是局部的,意味着它们只在函数内部可见。外部代码不能直接访问函数内部的局部变量。然而,如果需要在外部访问这些变量的值,可以通过函数返回这些值来实现。

  • 标题: 函数
  • 作者: Yiuhang Chan
  • 创建于 : 2018-08-12 16:43:23
  • 更新于 : 2024-02-28 18:49:04
  • 链接: https://www.yiuhangblog.com/2018/08/12/20180812函数/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论