13 Python 函数进阶

Posted 潘红伟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了13 Python 函数进阶相关的知识,希望对你有一定的参考价值。

代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间

命名空间和作用域

  命名空间的本质:存放名字与值的绑定关系

 1 >>> import this
 2 The Zen of Python, by Tim Peters
 3 
 4 Beautiful is better than ugly.
 5 Explicit is better than implicit.
 6 Simple is better than complex.
 7 Complex is better than complicated.
 8 Flat is better than nested.
 9 Sparse is better than dense.
10 Readability counts.
11 Special cases aren\'t special enough to break the rules.
12 Although practicality beats purity.
13 Errors should never pass silently.
14 Unless explicitly silenced.
15 In the face of ambiguity, refuse the temptation to guess.
16 There should be one-- and preferably only one --obvious way to do it.
17 Although that way may not be obvious at first unless you\'re Dutch.
18 Now is better than never.
19 Although never is often better than *right* now.
20 If the implementation is hard to explain, it\'s a bad idea.
21 If the implementation is easy to explain, it may be a good idea.
22 Namespaces are one honking great idea -- let\'s do more of those!
View Code

在python之禅中提到过:命名空间是一种绝妙的理念,让我们尽情的使用发挥吧!

 

命名空间一共分为三种:

  全局命名空间

  局部命名空间

  内置命名空间

*内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。

三种命名空间之间的加载与取值顺序:

加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)

取值:

  在局部调用:局部命名空间->全局命名空间->内置命名空间

  在局部使用变量取值情况

1 x = 1
2 def f(x):
3     print(x)
4 
5 print(10)
View Code

  在全局调用:全局命名空间->内置命名空间

  在全局引用变量x

1 x = 1
2 def f(x):
3     print(x)
4 
5 f(10)
6 print(x)
View Code

       在全局引用内置max 

1 print(max)
View Code

作用域

  作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。

  全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效

  局部作用域:局部名称空间,只能在局部范围生效

  globals和locals方法

  在全局引用globals和locals

1 print(globals())
2 print(locals())
3 
4 C:\\Users\\panhw\\AppData\\Local\\Programs\\Python\\Python36\\python.exe C:/Users/panhw/Desktop/学习文档/python/day15.py
5 {\'__name__\': \'__main__\', \'__doc__\': None, \'__package__\': None, \'__loader__\': <_frozen_importlib_external.SourceFileLoader object at 0x0000023BB77CA4A8>, \'__spec__\': None, \'__annotations__\': {}, \'__builtins__\': <module \'builtins\' (built-in)>, \'__file__\': \'C:/Users/panhw/Desktop/学习文档/python/day15.py\', \'__cached__\': None, \'sys\': <module \'sys\' (built-in)>, \'li\': [2, 3, 5, 10, 15, 16, 18, 22, 26, 30, 32, 35, 41, 42, 43, 55, 56, 66, 67, 69, 72, 76, 82, 83, 88], \'count\': 1}
6 {\'__name__\': \'__main__\', \'__doc__\': None, \'__package__\': None, \'__loader__\': <_frozen_importlib_external.SourceFileLoader object at 0x0000023BB77CA4A8>, \'__spec__\': None, \'__annotations__\': {}, \'__builtins__\': <module \'builtins\' (built-in)>, \'__file__\': \'C:/Users/panhw/Desktop/学习文档/python/day15.py\', \'__cached__\': None, \'sys\': <module \'sys\' (built-in)>, \'li\': [2, 3, 5, 10, 15, 16, 18, 22, 26, 30, 32, 35, 41, 42, 43, 55, 56, 66, 67, 69, 72, 76, 82, 83, 88], \'count\': 1}
View Code

  在局部引用globals和locals

 1 def func():
 2     a = 12
 3     b = 20
 4     print(locals())
 5     print(globals())
 6 
 7 func()
 8 
 9 
10 C:\\Users\\panhw\\AppData\\Local\\Programs\\Python\\Python36\\python.exe C:/Users/panhw/Desktop/学习文档/python/day15.py
11 {\'b\': 20, \'a\': 12}
12 {\'__name__\': \'__main__\', \'__doc__\': None, \'__package__\': None, \'__loader__\': <_frozen_importlib_external.SourceFileLoader object at 0x000001FEE5D2A4A8>, \'__spec__\': None, \'__annotations__\': {}, \'__builtins__\': <module \'builtins\' (built-in)>, \'__file__\': \'C:/Users/panhw/Desktop/学习文档/python/day15.py\', \'__cached__\': None, \'sys\': <module \'sys\' (built-in)>, \'li\': [2, 3, 5, 10, 15, 16, 18, 22, 26, 30, 32, 35, 41, 42, 43, 55, 56, 66, 67, 69, 72, 76, 82, 83, 88], \'count\': 1, \'func\': <function func at 0x000001FEE4123E18>}
View Code

  global 关键字

1 a = 10
2 def func():
3     global a
4     a = 20
5 
6 print(a)
7 func()
8 print(a)
View Code

函数的嵌套和作用域链

  函数的嵌套调用

 1 def max2(x,y):
 2     m  = x if x>y else y
 3     return m
 4 
 5 def max4(a,b,c,d):
 6     res1 = max2(a,b)
 7     res2 = max2(res1,c)
 8     res3 = max2(res2,d)
 9     return res3
10 
11 # max4(23,-7,31,11)
View Code

  函数的嵌套定义

1 def f1():
2     print("in f1")
3     def f2():
4         print("in f2")
5 
6     f2()
7 f1()
嵌套定义(一)
嵌套定义(二)

  函数的作用域链

1 def f1():
2     a = 1
3     def f2():
4         print(a)
5     f2()
6 
7 f1()
作用域链(一)
1 def f1():
2     a = 1
3     def f2():
4         def f3():
5             print(a)
6         f3()
7     f2()
8 
9 f1()
作用域链(二)
1 def f1():
2     a = 1
3     def f2():
4         a = 2
5     f2()
6     print(\'a in f1 : \',a)
7 
8 f1()
作用域链(三)

  nonlcoal 关键字

    1.外部必须有这个变量
    2.在内部函数声明nonlocal变量之前不能再出现同名变量
    3.内部修改这个变量如果想在外部有这个变量的第一层函数中生效

1 def f1():
2     a = 1
3     def f2():
4         nonlocal a
5         a = 2
6     f2()
7     print(\'a in f1 : \',a)
8 
9 f1()
View Code

函数名的本质

  函数名本质上就是函数的内存地址

  1.可以被引用

1 def func():
2     print(\'in func\')
3 
4 f = func
5 print(f)
函数引用

  2.可以被当作容器类型的元素

 1 def f1():
 2     print(\'f1\')
 3 
 4 
 5 def f2():
 6     print(\'f2\')
 7 
 8 
 9 def f3():
10     print(\'f3\')
11 
12 l = [f1,f2,f3]
13 d = {\'f1\':f1,\'f2\':f2,\'f3\':f3}
14 #调用
15 l[0]()
16 d[\'f2\']()
当做容器

  3.可以当作函数的参数和返回值

1 第一类对象(first-class object)指
2 1.可在运行期创建
3 2.可用作函数参数或返回值
4 3.可存入变量的实体。
View Code

闭包

  闭包函数:

    内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数
    函数内部定义的函数称为内部函数

  在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

1 def func(name):
2     def inner_func(age):
3         print \'name:\', name, \'age:\', age
4     return inner_func
5 
6 bb = func(\'the5fire\')
7 bb(26)  # >>> name: the5fire age: 26
View Code

  闭包函数最常用的用法

1 def func():
2     name = \'eva\'
3     def inner():
4         print(name)
5     return inner
6 
7 f = func()
8 f()
View Code

  判断闭包函数的方法__closure__

 1 #输出的__closure__有cell元素 :是闭包函数
 2 def func():
 3     name = \'eva\'
 4     def inner():
 5         print(name)
 6     print(inner.__closure__)
 7     return inner
 8 
 9 f = func()
10 f()
11 
12 #输出的__closure__为None :不是闭包函数
13 name = \'egon\'
14 def func2():
15     def inner():
16         print(name)
17     print(inner.__closure__)
18     return inner
19 
20 f2 = func2()
21 f2()
View Code

  闭包嵌套

 1 def wrapper():
 2     money = 1000
 3     def func():
 4         name = \'eva\'
 5         def inner():
 6             print(name,money)
 7         return inner
 8     return func
 9 
10 f = wrapper()
11 i = f()
12 i()
View Code

  闭包函数获取网络应用

 1 from urllib.request import urlopen
 2 
 3 def index():
 4     url = "http://www.xiaohua100.cn/index.html"
 5     def get():
 6         return urlopen(url).read()
 7     return get
 8 
 9 xiaohua = index()
10 content = xiaohua()
11 print(content)
View Code

命名空间:

  一共有三种命名空间从大范围到小范围的顺序:内置命名空间、全局命名空间、局部命名空间

作用域(包括函数的作用域链):

小范围的可以用大范围的
但是大范围的不能用小范围的
范围从大到小(图)

在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有就用上上一级的,以此类推。
如果都没有,报错

函数的嵌套:

  嵌套调用

  嵌套定义:定义在内部的函数无法直接在全局被调用

函数名的本质:

  就是一个变量,保存了函数所在的内存地址

闭包:

  内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数

2. 为什么使用闭包

基于上面的介绍,不知道读者有没有感觉这个东西和类有点相似,相似点在于他们都提供了对数据的封装。不同的是闭包本身就是个方法。和类一样,我们在编程时经常会把通用的东西抽象成类,(当然,还有对现实世界——业务的建模),以复用通用的功能。闭包也是一样,当我们需要函数粒度的抽象时,闭包就是一个很好的选择。

在这点上闭包可以被理解为一个只读的对象,你可以给他传递一个属性,但它只能提供给你一个执行的接口。因此在程序中我们经常需要这样的一个函数对象——闭包,来帮我们完成一个通用的功能,比如后面会提到的——装饰器。

3. 使用闭包

第一种场景 ,在python中很重要也很常见的一个使用场景就是装饰器,Python为装饰器提供了一个很友好的“语法糖”——@,让我们可以很方便的使用装饰器,装饰的原理不做过多阐述,简言之你在一个函数func上加上@decorator_func, 就相当于decorator_func(func):

 1 def decorator_func(func):
 2     def wrapper(*args, **kwargs):
 3         return func(*args, **kwargs)
 4     return wrapper
 5 
 6 @decorator_func
 7 def func(name):
 8     print \'my name is\', name
 9 
10 # 等价于
11 decorator_func(func)
View Code

 

以上是关于13 Python 函数进阶的主要内容,如果未能解决你的问题,请参考以下文章

我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情

Python进阶内容--- 函数式编程

13Python之面向对象进阶篇

python进阶第1篇 函数入门

好好学python·函数进阶(递归函数,回调函数,闭包函数,匿名函数,迭代器)

使用 Python 代码片段编写 LaTeX 文档