【函数】02、函数进阶
一、函数的返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
In [4]: def add(x, y):
...: return x+y
...:
In [5]: add(1, 2)
Out[5]: 3
In [8]: def add(x, y):
...: return x+y
...: print(x+y)
...:
In [9]: add(1, 2)
Out[9]: 3
In [16]: def add(x, y):
...: return "abc" , x+y
...: return x+y
...:
In [17]: add(1, 2)
Out[17]: ( 'abc' , 3)
In [18]: def add(x, y):
...: return
...:
...:
In [19]: add(1, 2)
In [20]: a = add(1, 2)
In [21]: a
In [22]: type (a)
Out[22]: NoneType
In [25]: def add(x, y):
...: return None
...:
In [26]: add(1, 2)
In [27]: type (add(1, 2))
Out[27]: NoneType
|
关键字:return
return只能出现在函数中,可以返回任何对象,可以作为元祖变相的返回多个值
所有函数都有返回值,如果没定义return则默认返回值None
return语句除了返回值之外还会结束函数
1个函数可以有多个return语句,但只会执行一个
二、作用域
1、函数嵌套
函数可以嵌套定义
1
2
3
4
5
6
7
8
9
10
|
In [28]: def outter():
...: def inner():
...: print( 'inner' )
...: print( 'outter' )
...: inner()
...:
In [29]: outter()
outter
inner
|
2、作用域
作用域是一个变量的可见范围
函数内部是一个局部作用域,外面叫全局作用域
不同作用域变量不可见,但是上级作用域的变量对下级只读可见
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
In [32]: x = 1
In [33]: def inc():
...: x += 1 # x此时是局部变量,不能直接使用全局作用域的变量
...:
In [34]: inc()
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-34-ae671e6b904f> in <module>()
----> 1 inc()
<ipython-input-33-661b9217054c> in inc()
1 def inc():
----> 2 x += 1
3
UnboundLocalError: local variable 'x' referenced before assignment
In [40]: x = 1
In [41]: def fn():
...: print(x)
...:
In [42]: fn() # 为什么这里能打印出来,不抛出错误呢
1
|
变量的作用域为定义此变量的作用域:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
In [43]: def fn():
...: name = "xxj"
...: print(name)
...:
In [44]: fn()
xxj
In [45]: name
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-45-18697449d7c4> in <module>()
----> 1 name
NameError: name 'name' is not defined
|
上级作用域对下级作用域是只读可见的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
In [46]: def fn():
...: xx = 1
...: print(xx)
...: def inner():
...: print(xx)
...: inner()
...:
In [47]: fn()
1
1
In [48]: def fn():
...: xx = 1
...: print(xx)
...: def inner():
...: xx = 2
...: print(xx)
...: inner()
...: print(xx)
...:
In [49]: fn()
1
2
1
|
global关键字能且只能引用全局作用域中的变量;引用后的变量能读写
如果全局作用域有此变量名,则引用,
没有则需要定义,定义后此作用域和全局作用域中可见;不定义则会报错,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
In [53]: xx = 1
In [54]: def fn():
...: global xx # global关键字能显式的提升1个变量的作用域
...: xx += 1
...:
In [55]: fn()
In [56]: xx
Out[56]: 2
In [57]: fn()
In [58]: xx
Out[58]: 3
In [68]: xxj
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-68-bc382da45e82> in <module>()
----> 1 xxj
NameError: name 'xxj' is not defined
In [69]: def fn():
...: global xxj # 如果此变量没有定义,则此提升变量作用域没有意义
...:
...:
In [70]: fn()
In [71]: xxj
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-71-bc382da45e82> in <module>()
----> 1 xxj
NameError: name 'xxj' is not defined
|
除非你清楚的知道global会带来什么,并且明确的知道没有global不行的话,否则不要用global;就是不建议使用global关键字
3、默认参数的作用域
函数也是对象,参数是函数对象的属性,所以函数参数的作用域伴随函数整个生命周期
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
In [92]: def fn(xy=[]):
...: xy.append(1)
...: print(xy)
...:
In [93]: fn()
[1]
In [94]: fn()
[1, 1]
In [95]: fn()
[1, 1, 1]
In [96]: fn.__defaults__ # 函数默认参数的值保存在函数__defaults__属性中
Out[96]: ([1, 1, 1],)
In [98]: fn()
[1, 1, 1, 1]
In [100]: fn.__defaults__
Out[100]: ([1, 1, 1, 1],)
|
当使用可变类型数据作为默认参数默认值时,需要特别注意。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
In [105]: def fn(x=0, y=0):
...: x = 1 # 赋值即定义
...: y = 2
...: print(x)
...: print(y)
...:
In [106]: fn.__defaults__
Out[106]: (0, 0)
In [107]: fn()
1
2
In [108]: fn.__defaults__
Out[108]: (0, 0)
|
解决方案:
使用不可变类型作为默认值
函数体内不改变默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
In [109]: def fn(lst=None): # 如果传入的参数是非None,那么改变了传入参数;
...: if lst is None:
...: lst = []
else :
lst = lst[:]
...: lst.append(3)
...: print(lst)
...:
In [110]: fn.__defaults__
Out[110]: (None,)
In [111]: fn()
[3]
In [112]: fn.__defaults__
Out[112]: (None,)
In [113]: def fn(lst=[]):
...: lst = lst[:] # 浅拷贝
...: lst.append(2) # 无论如何不修改传入参数
...: print(lst)
...:
In [114]: fn.__defaults__
Out[114]: ([],)
In [115]: fn()
[2]
In [116]: fn.__defaults__
Out[116]: ([],)
|
通常如果使用一个可变参数作为默认参数时,会使用None来代替
4、命名空间与LEGB
1)命名空间
理解Python的LEGB原则是理解Python命名空间的关键,而理解Python的命名空间又是理解Python中许多语法规定的关键。所以,Python的LEGB原则就成为Python中一个非常核心的内容
白话一点讲:命名空间是对变量名的分组划分。
不同组的相同名称的变量视为两个独立的变量,因此隶属于不同分组(即命名空间)的变量名可以重复。
命名空间可以存在多个,使用命名空间,表示在该命名空间中查找当前名称。
命名空间表示变量的可见范围,一个变量名可以定义在多个不同的命名空间,相互之间并不冲突,但同一个命名空间中不能有两个相同的变量名。
比如:两个叫“张三”的学生可以同时存在于班级A和班级B中,如果两个张三都是一个班级,那么带来的麻烦复杂很多了,在Python中你不能这么干。
在Python中用字典来表示一个命名空间,命名空间中保存了变量(名字)和对象的映射关系,在Python中命名空间出现在哪些地方呢?有函数范围内的命名空间(local),有模块范围内的命名空间(global),有python内建的命名空间(built-in),还有类对象的所有属性组成的命名空间
Python一切皆对象,所以在Python中变量名是字符串对象
例如:
1
|
In [25]: a=10
|
表示建立字符串对象a
与Number对象10
之间的对应关系。由于这是一种映射关系,所以,可以使用键-值的形式来表示,即{name : object}。
前面已经说过,命名空间是对变量名的分组划分,所以,Python的命名空间就是对许多键-值对的分组划分,即,键值对的集合,因此:
Python的命名空间是一个字典,字典内保存了变量名称与对象之间的映射关系
2)命名空间的生命周期
所有的命名空间都是有生命周期的,对于python内建的命名空间,python解析器启动时创建,一直保留直至直python解析器退出时才消亡。而对于函数的local命名空间是在函数每次被调用的时候创建,调用完成函数返回时消亡,而对于模块的global命名空间是在该模块被import的时候创建,解析器退出时消亡。
3)作用域
一个作用域是指一段程序的正文区域,可以是一个函数或一段代码。
一个变量的作用域是指该变量的有效范围。Python的作用域是静态作用域,因为它是由代码中得位置决定的,而命名空间就是作用域的动态表现。
函数定义了本地作用域,而模块定义了全局作用域:
每个模块都是一个全局作用域,因此,全局作用域的范围仅限于单个程序文件
每次对函数的调用都会创建一个新的本地作用域,赋值的变量除非声明为全局变量,否则均为本地变量
所有的变量名都可以归纳为本地,全局或内置的(由__builtin__模块提供)
4)LEGB原则
LEGB含义解释:
L-Local(function);函数内的名字空间
E-Enclosing function locals;外部嵌套函数的名字空间(例如closure)
G-Global(module);函数定义所在模块(文件)的名字空间
B-Builtin(Python);Python内置模块的名字空间,builtin作用域,对应builtin命名空间,python内部定义的最顶层的作用域,在这个作用域里面定义了各种内建函数:open、range、xrange、list等等
前面讲到,Python的命名空间是一个字典,字典内保存了变量名与对象之间的映射关系,
因此,查找变量名就是在命名空间字典中查找键-值对。
Python有多个命名空间,因此,需要有规则来规定,按照怎样的顺序来查找命名空间,LEGB就是用来规定命名空间查找顺序的规则。
LEGB规定了查找一个名称的顺序为:local-->enclosing function locals-->global-->builtin
三、闭包
当一个函数结束了,函数的内部部分变量引用还存在,这就叫闭包
外层函数主要为内层函数提供环境
定义在外层函数内,却由内层函数引用的变量,在外层函数返回时,如果外层函数返回的值是内层函数,再次调用内层函数时,会记忆下内层函数调用的外层函数的变量。
python的闭包可以使用可变容器实现,这也是python2唯一的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
In [91]: def counter():
...: c = [0]
...: def inc():
...: c[0] += 1
...: return c
...: return inc
...:
In [92]: type (counter)
Out[92]: function
In [93]: type (counter())
Out[93]: function
In [94]: type (counter()())
Out[94]: list
In [95]: f = counter()
In [96]: f()
Out[96]: [1]
In [97]: f()
Out[97]: [2]
In [98]: f()
Out[98]: [3]
|
nonlocal关键字:
nonlocal关键字能且只能引用外部函数作用域中已存在的变量(不能在自己的作用域中定义);引用后的变量能读写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
In [102]: def counter():
...: x = 0
...: def inc():
...: nonlocal x
...: x += 1
...: return x
...: return inc
...:
In [103]: f = counter()
In [104]: f()
Out[104]: 1
In [105]: f()
Out[105]: 2
In [106]: f()
Out[106]: 3
|
四、递归函数
函数体内调用自身的函数
递归函数需要有合适的退出条件,否则就成了死循环; 递归需要边界条件,递归前进段和递归返回段
在python中为了保护解释器,递归深度最大为1000
python中应尽量避免递归,效率低(能转化为迭代尽量转化为迭代)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
In [2]: def fib(n):
...: if n == 0:
...: return 1
...: if n == 1:
...: return 1
...: return fib(n-1) + fib(n-2)
...:
In [3]: fib(5)
Out[3]: 8
In [4]: fib(6)
Out[4]: 13
|
本文转自xiexiaojun51CTO博客,原文链接: http://blog.51cto.com/xiexiaojun/1934142,如需转载请自行联系原作者
【函数】02、函数进阶相关推荐
- jquery-210812-05---jquery函数02
jquery-210812-05-jquery函数02 函数介绍 演示 函数介绍 1. hide$(选择器).hide() :将数组中所有 DOM对象隐藏起来2. show$(选择器).show(): ...
- 视频教程-桫哥-GOlang基础-02函数-Go语言
桫哥-GOlang基础-02函数 多年互联网从业经验: 有丰富的的企业网站.手游.APP开发经验: 曾担任上海益盟软件技术股份有限公司项目经理及产品经理: 参与项目有益盟私募工厂.睿妙影音家庭物联网设 ...
- 浅谈Delphi过程与函数02 - 零基础入门学习Delphi21
浅谈Delphi过程与函数02 让编程改变世界 Change the world by program 传值调用 过程和函数的形参与实参之间既可以通过传值的方式传递,也可以通过传地址的方式传递. 例子 ...
- C语言图形编程(绘图函数部分),C语言图形编程(三、绘图函数-02)12
C语言图形编程(三.绘图函数-02)12 } 84. putimage() 输出图像函数 功能: 函数putimage()将一个先前保存在内存中的图像输出到屏幕上. 用法: 此函数调用方式为void ...
- Python 函数基础与进阶 闭包 聚合与打散
阅读目录 函数基础 基础知识 return 返回值 不可变类型和可变类型的值传递问题 函数的参数 打散和聚合 函数进阶 函数的注释 命名空间 作用域和全局变量 函数的嵌套和作用域链 函数名 闭包 函数 ...
- 第三章 Python函数基础及进阶
第三章 函数基础及进阶 3.1 上章补充内容 3.1.1 Bytes类型 计算机的数据需要存到硬盘上,但是硬盘只能存储二进制的数据. 我们知道将计算机里的数据转换成我们能看懂的数据是将二进制 -> ...
- 【MATLAB】进阶绘图 ( Bar 条形图 | bar 函数 | bar3 函数 | Bar 条形图样式 | 堆叠条形图 | 水平条形图 | barh 函数 )
文章目录 一.Bar 条形图 1.bar 函数 2.矩阵数据表示 3.bar 函数代码示例 二.Bar 条形图样式 1.bar 函数样式 2.堆叠条形图示例 三.水平条形图 1.barh 函数 2.代 ...
- python 魔法函数 __add___PythonI/O进阶学习笔记_2.魔法函数
前言: 本文一切观点和测试代码是在python3的基础上. Content: 1.什么是魔法函数,魔法函数__getitem__在python中应用. 2.python的数据模型和数据模型这种设计对p ...
- Python进阶:函数式编程(高阶函数,map,reduce,filter,sorted,返回函数,匿名函数,偏函数)...啊啊啊...
函数式编程 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计 ...
- Python工程师从菜鸟到大师 之.语法基础之条件语句、循环语句和函数 02
一.条件语句 在讲诉条件语句之前,需要先补充语句块的知识.语句块并非一种语句,它是在条件为真时执行一次或执行多次的一组语句,在代码前放置空格缩进即可创建语句块.它类似于C.C++.Java等语言的大括 ...
最新文章
- 【刷算法】LeetCode- 两数之和
- linux管理用户组,技术|如何在 Linux 系统中通过用户组来管理用户
- Hadoop- Hadoop运维小计
- 开发日记-20190608 关键词 读书笔记《鸟哥的Linux私房菜-基础学习篇》
- 看完这20部电影相当于学了经济学(投资理财必看电影)
- vba 判断文本框内容是否为空_校验数据一旦失败,VBA代码自动控制焦点返回的另一备选方案...
- QT的QStateMachine类的使用
- 使用Java扫描DynamoDB项目
- c语言中申请内存并初始化,c语言中结构体的定义、初始化及内存分配
- idea服务器如何手动加载项目,idea导入本地idea的web项目(服务器用的是tomcat)
- 如何编写一个d.ts文件
- 典型的DIV+CSS布局(左中右)
- 幽冥问答录:兼职阴间判官介绍阴间是什么样子
- maven远程私服发布jar包
- 【学习OpenCV4】聊聊图像格式
- c语言数列求和程序137,C语言循环结构
-C语言数列求和(使用while循环)
- html5 队列展示,设计一个队列研究实例
- Codeforces - Qualification Rounds
- 贴图平移凹凸贴图偏移
- 传统企业数字化转型方案
热门文章
- Spring Cache抽象-缓存管理器
- 某些情况下安卓引入so冲突的解决
- plsql存储过程修改后怎么保存_证件照上传不成功,教你修改分辨率、调整照片大小...
- vscode-git中的U,M和D文件标记含义
- linux定期清理日志文件
- substring、substr以及slice、splice用法和区别
- mysql cluster java_Java学习笔记(十):MySQL集群安装配置
- velodyne显示点云中grid的单位_led显示屏怎么选择点间距
- module 'schedule' has no attribute 'every
- 面试题总结16 对一个整数开根号