python3xiaobaike_2020/chapter5/5-8 python3小白课:局部函数.md
2025-04-20 23:22:14 +08:00

166 lines
7.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# python3小白课局部函数
### 局部函数定义
前面我们学习的函数都是在全局范围内定义的在整个py脚本中都可以调用到它。如果在函数定义的内部再定义函数呢python也是支持的这时候的函数就称之为`局部函数`
接下来我们把在全局范围定义的函数称为封闭函数,封闭函数内定义的函数称之为局部函数。默认情况下,局部函数对外是隐藏的,仅能在封闭函数内进行调用。但你也可以做出一些变动,让外部也能调用到局部函数来进行计算。
我们来看个小例子:
```python
# coding:utf-8
def fengbi(method, num):
def add_1(num):
return num + 1
def add_2(num):
return num + 2
def add_3(num):
return num + 3
if method == "add_1":
return add_1(num)
elif method == "add_2":
return add_2(num)
elif method == "add_3":
return add_3(num)
else:
return "不支持的方法名"
print(fengbi("add_1", 1))
print(fengbi("add_2", 1))
print(fengbi("add_4", 1))
```
由于直接在内部定义并调用比较简单我们就不举例子了。我们来举一个从外部调用到内部局部函数的方法例子这里我们定义了一个封闭函数支持传入方法名在函数内部首先定义好那几个局部函数方法后续可以通过if结构判断给的是什么方法来调用具体的局部函数返回。
---
### 局部函数访问封闭函数中的局部变量
> [!note]
>
> 本部分知识比较不常用,可以学习也可以跳过。
由于我们这里在函数内部又有函数定义,势必有可能会遇到在局部函数中调用到封闭函数中定义的局部变量的情形。此时还是跟之前学习作用域时讲的一样,可以在局部函数中直接调用在封闭函数中定义的局部函数。(这么听起来比较拗口,我们看个例子吧)
```python
# coding:utf-8
def fengbi():
num = 1
def add_1():
return num + 1
print(add_1())
fengbi()
```
可见,是可以直接访问的。如果我们在局部函数中修改封闭函数中的局部变量呢?
```python
# coding:utf-8
def fengbi():
num = 1
def add_1():
print(num)
num = 2
return num + 1
print(add_1())
fengbi()
```
这次运行又报错了,报错信息为:`UnboundLocalError: local variable 'num' referenced before assignment`,看起来还是我们讲变量作用域时说过的问题。怎么解决呢?此时我们就不用`global`语句了,因为那是对付全局变量的。我们可以使用`nonlocal`语句来解决,用法跟`global`语句是一致的。
```python
# coding:utf-8
def fengbi():
num = 1
def add_1():
nonlocal num
print(num)
num = 2
return num + 1
print(add_1())
print(num)
fengbi()
```
此时我们会发现num在上述代码中就一直指代封闭函数中的`num`局部变量了,不会有报错的情况发生,对于`num`的修改也会造成`num`局部变量的值改变。
如果你对这部分知识感兴趣,可以往下学习我们下面的`函数:前沿`部分。
---
### 函数:前沿
关于函数的知识我们还有一些高级内容但作为入门小白经过审慎考虑我认为像市面上一本百科全书一样把一个东西讲得太多太难太细对大家是没有太大帮助的大家只会学着学着感叹哇呀怎么函数这么难这么多知识这么难记哇呀python太难学了我不学了。
为了避免大家出现这种难过的情绪,我希望大家始终保持必要的学习激情,我们前面讲过的知识,基础运用是非常简单的,如果你对于某一块有兴趣,可以找找网上的资料,进一步自学即可,在入门时不必太过于执着和纠结你听不懂记不住的知识,够用就好。
> [!note]
>
> 关于函数的一些更难的知识我们将会安排在进阶或高级课程中跟大家一起去啃这些硬骨头它们适合python编程已经有一定基础想要进一步突破瓶颈的同学。
这里我们就着前面讲过的内容,再扩展一点点前沿知识,如果你学不会看不懂,请跳过,没有关系的,当你做好了进一步突破瓶颈的准备,比如在一个美好的清晨,你休息得很好,脑袋适合研究点什么,再回过头来听一听你感兴趣的内容。
\*\*\*华丽的分割线\*\*\*
好,给大家随便灌了点鸡汤,我们继续讲课。
函数还有比较高级的定义方法,因为函数本身是一个对象,所以函数本身既可以用于赋值,也可以用于作为调用的参数传进别的函数中,还可以作为其他函数的返回值。
这里我们来讲个小例子,看下函数作为返回值是怎样的。
```python
# coding:utf-8
def createCounter():
n = 0
def counter():
nonlocal n
n += 1
return n
return counter
# 验证计数器
mycounter = createCounter()
for i in range(5):
print(mycounter())
```
这是从网上找到的一个小题目,代码也是参考了下网上的朋友的,做了一些优化修改。
我们的题目是定义一个函数计数器,这个计数器内部可以存档一个计数,每次调用函数的时候,可以实现计数次数的增长。
首先我们可以先跑一下运行结果可以看到每次输出的结果都会自增1分别输出`1, 2, 3, 4, 5`这几个值来。
然后我们来分析一下代码。
首先我们定义了一个`createCounter`创建计数器的函数,这个函数内部呢,定义了一个`n`变量,这个变量就是计数器的值了。接着我们定义了一个`counter`的局部函数,这个函数就使用了我们前面讲到的`nonlocal`语句,申明局部函数用到的`n`变量是用的封闭函数中的那个,这样后续赋值就不会重新定义一个`n`变量了实现了访问变量的目的。接下来在局部函数内将变量的值自增1并返回最新的结果。
需要注意的是,这个`createCounter`函数的return语句返回的是一个函数如果返回函数`counter`,直接写函数名即可,没有括号什么的。
这样返回如何调用呢?首先运行这个`createCounter`函数,将它的返回值赋值给一个变量`mycounter`,此时`mycounter`就有了`counter`函数的功能了。接下来在调用时,只需要调用`mycounter`这个函数即可。
> [!note]
>
> 这是一种闭包的概念如果我们的n是一个全局变量那么这个计数器在每次使用时你还需要在自己的代码中定义它或者需要查看这个函数内部的代码实现。
>
> 当使用闭包后变量n的作用域仅限于封闭函数中这在某些时候就给了使用者一些便利。
在python脚本运行期间每次调用我们会发现`n`的值,是在不断自增的,你可以理解为,我们只访问了`counter`函数,并没有再次访问`createCounter`函数,所以这个`n`不会重新赋值,而`counter`函数又能访问到`n`并自增,这样就实现了一个计数器的效果。
是不是很有意思呢?
> [!note]
>
> 关于函数还有其他知识点,我们在入门课就不跟大家讲那么深那么难了,感兴趣的同学可以关注我们的进阶或高级课程学习或者自行网上查阅资料学习。
### 单词释义
| 单词 | 释义 |
| ------------- | ------------------------------------------------------------ |
| method | 方法 |
| nonlocal | non为否定前缀local为局部的在这里理解为非局部的 |
| createCounter | create创建Counter计数器count计数合起来理解为创建计数器 |
| counter | 计数器 |
| mycounter | my我的理解为我的计数器 |