一、函数的返回值

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
      
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

表示建立字符串对象aNumber对象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、函数进阶相关推荐

  1. jquery-210812-05---jquery函数02

    jquery-210812-05-jquery函数02 函数介绍 演示 函数介绍 1. hide$(选择器).hide() :将数组中所有 DOM对象隐藏起来2. show$(选择器).show(): ...

  2. 视频教程-桫哥-GOlang基础-02函数-Go语言

    桫哥-GOlang基础-02函数 多年互联网从业经验: 有丰富的的企业网站.手游.APP开发经验: 曾担任上海益盟软件技术股份有限公司项目经理及产品经理: 参与项目有益盟私募工厂.睿妙影音家庭物联网设 ...

  3. 浅谈Delphi过程与函数02 - 零基础入门学习Delphi21

    浅谈Delphi过程与函数02 让编程改变世界 Change the world by program 传值调用 过程和函数的形参与实参之间既可以通过传值的方式传递,也可以通过传地址的方式传递. 例子 ...

  4. C语言图形编程(绘图函数部分),C语言图形编程(三、绘图函数-02)12

    C语言图形编程(三.绘图函数-02)12 } 84. putimage() 输出图像函数 功能: 函数putimage()将一个先前保存在内存中的图像输出到屏幕上. 用法: 此函数调用方式为void ...

  5. Python 函数基础与进阶 闭包 聚合与打散

    阅读目录 函数基础 基础知识 return 返回值 不可变类型和可变类型的值传递问题 函数的参数 打散和聚合 函数进阶 函数的注释 命名空间 作用域和全局变量 函数的嵌套和作用域链 函数名 闭包 函数 ...

  6. 第三章 Python函数基础及进阶

    第三章 函数基础及进阶 3.1 上章补充内容 3.1.1 Bytes类型 计算机的数据需要存到硬盘上,但是硬盘只能存储二进制的数据. 我们知道将计算机里的数据转换成我们能看懂的数据是将二进制 -> ...

  7. 【MATLAB】进阶绘图 ( Bar 条形图 | bar 函数 | bar3 函数 | Bar 条形图样式 | 堆叠条形图 | 水平条形图 | barh 函数 )

    文章目录 一.Bar 条形图 1.bar 函数 2.矩阵数据表示 3.bar 函数代码示例 二.Bar 条形图样式 1.bar 函数样式 2.堆叠条形图示例 三.水平条形图 1.barh 函数 2.代 ...

  8. python 魔法函数 __add___PythonI/O进阶学习笔记_2.魔法函数

    前言: 本文一切观点和测试代码是在python3的基础上. Content: 1.什么是魔法函数,魔法函数__getitem__在python中应用. 2.python的数据模型和数据模型这种设计对p ...

  9. Python进阶:函数式编程(高阶函数,map,reduce,filter,sorted,返回函数,匿名函数,偏函数)...啊啊啊...

    函数式编程 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计 ...

  10. Python工程师从菜鸟到大师 之.语法基础之条件语句、循环语句和函数 02

    一.条件语句 在讲诉条件语句之前,需要先补充语句块的知识.语句块并非一种语句,它是在条件为真时执行一次或执行多次的一组语句,在代码前放置空格缩进即可创建语句块.它类似于C.C++.Java等语言的大括 ...

最新文章

  1. 【刷算法】LeetCode- 两数之和
  2. linux管理用户组,技术|如何在 Linux 系统中通过用户组来管理用户
  3. Hadoop- Hadoop运维小计
  4. 开发日记-20190608 关键词 读书笔记《鸟哥的Linux私房菜-基础学习篇》
  5. 看完这20部电影相当于学了经济学(投资理财必看电影)
  6. vba 判断文本框内容是否为空_校验数据一旦失败,VBA代码自动控制焦点返回的另一备选方案...
  7. QT的QStateMachine类的使用
  8. 使用Java扫描DynamoDB项目
  9. c语言中申请内存并初始化,c语言中结构体的定义、初始化及内存分配
  10. idea服务器如何手动加载项目,idea导入本地idea的web项目(服务器用的是tomcat)
  11. 如何编写一个d.ts文件
  12. 典型的DIV+CSS布局(左中右)
  13. 幽冥问答录:兼职阴间判官介绍阴间是什么样子
  14. maven远程私服发布jar包
  15. 【学习OpenCV4】聊聊图像格式
  16. c语言数列求和程序137,C语言循环结构 -C语言数列求和(使用while循环)
  17. html5 队列展示,设计一个队列研究实例
  18. Codeforces - Qualification Rounds
  19. 贴图平移凹凸贴图偏移
  20. 传统企业数字化转型方案

热门文章

  1. Spring Cache抽象-缓存管理器
  2. 某些情况下安卓引入so冲突的解决
  3. plsql存储过程修改后怎么保存_证件照上传不成功,教你修改分辨率、调整照片大小...
  4. vscode-git中的U,M和D文件标记含义
  5. linux定期清理日志文件
  6. substring、substr以及slice、splice用法和区别
  7. mysql cluster java_Java学习笔记(十):MySQL集群安装配置
  8. velodyne显示点云中grid的单位_led显示屏怎么选择点间距
  9. module 'schedule' has no attribute 'every
  10. 面试题总结16 对一个整数开根号