python之路——函数进阶
阅读目录
- 楔子
- 命名空间和作用域
- 函数嵌套及作用域链
- 函数名的本质
- 闭包
- 本章小结
楔子
假如有一个函数,实现返回两个数中的较大值:
- def my_max(x,y):
- m = x if x>y else y
- return m
- bigger = my_max(10,20)
- print(bigger)
之前是不是我告诉你们要把结果return回来你们就照做了?可是你们有没有想过,我们为什么要把结果返回?如果我们不返回m,直接在程序中打印,行不行?
来看结果:
- >>> def my_max(x,y):
- ... m = x if x>y else y
- ...
- >>> my_max(10,20)
- >>> print(m)
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- NameError: name 'm' is not defined
报错了!错误是“name 'm' is not defined”。变量m没有被定义。。。为啥?我明明定义了呀!
在这里我们首先回忆一下python代码运行的时候遇到函数是怎么做的。
从python解释器开始执行之后,就在内存中开辟了一个空间
每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。
但是当遇到函数定义的时候解释器只是象征性的将函数名读入内存,表示知道这个函数的存在了,至于函数内部的变量和逻辑解释器根本不关心。
等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会存储在新开辟出来的内存中。函数中的变量只能在函数的内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。
我们给这个“存放名字与值的关系”的空间起了一个名字——叫做命名空间
代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间
命名空间和作用域
命名空间的本质:存放名字与值的绑定关系
- >>> import this
- The Zen of Python, by Tim Peters
- Beautiful is better than ugly.
- Explicit is better than implicit.
- Simple is better than complex.
- Complex is better than complicated.
- Flat is better than nested.
- Sparse is better than dense.
- Readability counts.
- Special cases aren't special enough to break the rules.
- Although practicality beats purity.
- Errors should never pass silently.
- Unless explicitly silenced.
- In the face of ambiguity, refuse the temptation to guess.
- There should be one-- and preferably only one --obvious way to do it.
- Although that way may not be obvious at first unless you're Dutch.
- Now is better than never.
- Although never is often better than *right* now.
- If the implementation is hard to explain, it's a bad idea.
- If the implementation is easy to explain, it may be a good idea.
- Namespaces are one honking great idea -- let's do more of those!
python之禅
在python之禅中提到过:命名空间是一种绝妙的理念,让我们尽情的使用发挥吧!
命名空间一共分为三种:
全局命名空间
局部命名空间
内置命名空间
*内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
取值:
在局部调用:局部命名空间->全局命名空间->内置命名空间
- x = 1
- def f(x):
- print(x)
- print(10)
在局部使用变量取值情况
在全局调用:全局命名空间->内置命名空间
- x = 1
- def f(x):
- print(x)
- f(10)
- print(x)
在全局引用变量x
- print(max)
在全局引用内置max
作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
globals和locals方法
- print(globals())
- print(locals())
在全局调用globals和locals
- def func():
- a = 12
- b = 20
- print(locals())
- print(globals())
- func()
在局部调用globals和locals
global关键字
- a = 10
- def func():
- global a
- a = 20
- print(a)
- func()
- print(a)
global关键字
函数的嵌套和作用域链
函数的嵌套调用
- def max2(x,y):
- m = x if x>y else y
- return m
- def max4(a,b,c,d):
- res1 = max2(a,b)
- res2 = max2(res1,c)
- res3 = max2(res2,d)
- return res3
- # max4(23,-7,31,11)
函数的嵌套调用
函数的嵌套定义
- def f1():
- print("in f1")
- def f2():
- print("in f2")
- f2()
- f1()
函数的嵌套定义(一)
- def f1():
- def f2():
- def f3():
- print("in f3")
- print("in f2")
- f3()
- print("in f1")
- f2()
- f1()
函数的嵌套定义(二)
函数的作用域链
- def f1():
- a = 1
- def f2():
- print(a)
- f2()
- f1()
作用域链(一)
- def f1():
- a = 1
- def f2():
- def f3():
- print(a)
- f3()
- f2()
- f1()
作用域链(二)
- def f1():
- a = 1
- def f2():
- a = 2
- f2()
- print('a in f1 : ',a)
- f1()
作用域链(三)
nonlocal关键字
- # 1.外部必须有这个变量
# 2.在内部函数声明nonlocal变量之前不能再出现同名变量
# 3.内部修改这个变量如果想在外部有这个变量的第一层函数中生效
- def f1():
- a = 1
- def f2():
- nonlocal a
- a = 2
- f2()
- print('a in f1 : ',a)
- f1()
nonlocal关键字
函数名的本质
函数名本质上就是函数的内存地址
1.可以被引用
- def func():
- print('in func')
- f = func
- print(f)
函数被引用
2.可以被当作容器类型的元素
- def f1():
- print('f1')
- def f2():
- print('f2')
- def f3():
- print('f3')
- l = [f1,f2,f3]
- d = {'f1':f1,'f2':f2,'f3':f3}
- #调用
- l[0]()
- d['f2']()
函数被当作容易类型的元素
3.可以当作函数的参数和返回值
*不明白?那就记住一句话,就当普通变量用
- 第一类对象(first-class object)指
- 1.可在运行期创建
- 2.可用作函数参数或返回值
- 3.可存入变量的实体。
第一类对象的概念
闭包
- def func():
- name = 'eva'
- def inner():
- print(name)
闭包函数:
内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数
#函数内部定义的函数称为内部函数
由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回呀!
我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?
是不是直接就把这个函数的名字返回就好了?
这才是闭包函数最常用的用法
- def func():
- name = 'eva'
- def inner():
- print(name)
- return inner
- f = func()
- f()
判断闭包函数的方法__closure__
- #输出的__closure__有cell元素 :是闭包函数
- def func():
- name = 'eva'
- def inner():
- print(name)
- print(inner.__closure__)
- return inner
- f = func()
- f()
- #输出的__closure__为None :不是闭包函数
- name = 'egon'
- def func2():
- def inner():
- print(name)
- print(inner.__closure__)
- return inner
- f2 = func2()
- f2()
- def wrapper():
- money = 1000
- def func():
- name = 'eva'
- def inner():
- print(name,money)
- return inner
- return func
- f = wrapper()
- i = f()
- i()
- from urllib.request import urlopen
- def index():
- url = "http://www.xiaohua100.cn/index.html"
- def get():
- return urlopen(url).read()
- return get
- xiaohua = index()
- content = xiaohua()
- print(content)
闭包函数获取网络应用
本章小结
命名空间:
一共有三种命名空间从大范围到小范围的顺序:内置命名空间、全局命名空间、局部命名空间
作用域(包括函数的作用域链):
- 小范围的可以用大范围的
但是大范围的不能用小范围的
范围从大到小(图)
- 在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有就用上上一级的,以此类推。
如果都没有,报错
函数的嵌套:
嵌套调用
嵌套定义:定义在内部的函数无法直接在全局被调用
函数名的本质:
就是一个变量,保存了函数所在的内存地址
闭包:
内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数
python之路——函数进阶的更多相关文章
- 09-Python之路---函数进阶
Python之路---函数进阶️ 程序员三大美德: 懒惰 因为一直致力于减少工作的总工作量. 缺乏耐性 因为一旦让你去做本该计算机完成的事,你将会怒不可遏. 傲慢 因为被荣誉感冲晕头的你会把程序写得让 ...
- Python全栈之路----函数进阶----装饰器
Python之路,Day4 - Python基础4 (new版) 装饰器 user_status = False #用户登录后改为True def login(func): #传入想调用的函数名 de ...
- 【python 3】 函数 进阶
函数进阶 1.函数命名空间和作用域 命名空间一共分为三种: 全局命名空间 局部命名空间 内置命名空间 *内置命名空间中存放了python解释器为我们提供的名字:input , print , str ...
- python语法基础-函数-进阶-长期维护
############### 函数的命名空间和作用域 ############## """ # 函数进阶 命名空间和作用域 命名空间 全局命名空间——我们自 ...
- python之路:进阶篇
> ) { ; } printf(;} print i >>> >>> == : name == == ...
- Python之路-函数
一.函数是什么: python中函数定义:函数是逻辑结构化和过程化的一种编程方法.定义函数的方法为: def function(): ""The function definiti ...
- python之路:进阶篇 内置函数
li = [11, 22, 33] news = map( li = [100, 2200, 3300] news = map( [13, 24, 35] [11, 11, 11] [22, 4 ...
- Python全栈开发之路 【第五篇】:Python基础之函数进阶(装饰器、生成器&迭代器)
本节内容 一.名称空间 又名name space,就是存放名字的地方.举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方. 名称空间共3种,分别如下 ...
- Python全栈之路----函数进阶----名称空间
又名name space,顾名思义就是存放名字的地方,存什么名字呢?举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的=地方 名称空间共3种,分别如下 ...
随机推荐
- HTTP 请求的组成 方法 已经 请求的状态码
HTTP请求是指从客户端到服务器端的请求消息. 包括:消息首行中,对资源的请求方法.资源的标识符及使用的协议.从客户端到服务器端的请求消息包括,消息首行中,对资源的请求方法.资源的标识符及使用的协议. ...
- 【旧文章搬运】360安全卫士HookPort.sys完美逆向
原文发表于百度空间,2009-11-08 这是第一次逆向一个企业级安全产品的核心代码,并完美替换原驱动正常工作============================================= ...
- 数据库sql互转(oracle转mysql为例子)
转自: https://blog.csdn.net/sinat_32366329/article/details/76402059 在PowerDesinger里找到 File -->> ...
- centos7安装xtrabackup
1.安装percona依赖库: yum install http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-re ...
- git stash和git stash pop(转载)
转自:http://www.cnblogs.com/highriver/archive/2012/01/05/2313808.html zz: http://blog.csdn.net/herbert ...
- E20180408-hm
interaction n. 互动; 一起活动; 合作; 互相影响; interface n. 界面; <计>接口; 交界面; v. (使通过界面或接口) 接合,连接; [计算机] ...
- 更新gitignore
更新: 2017/04/26 修正windows版本下的命令 git rm -r --cached . (Windows 下的版本) 更新: 2017/06/06 mac下的命令也 ...
- 2019 年 Vue 学习路线图!
如果你是 Vue 开发新手,可能已经听过很多行话术语,比如单页面应用程序.异步组件.服务器端渲染,等等.你可能还听说过与 Vue 有关的一些工具和库,比如 Vuex.Webpack.Vue CLI 和 ...
- Hdu 4778 Gems Fight! (状态压缩 + DP)
题目链接: Hdu 4778 Gems Fight! 题目描述: 就是有G种颜色,B个背包,每个背包有n个宝石,颜色分别为c1,c2............两个人轮流取背包放到公共容器里面,容器里面有 ...
- JavaScript-页面打印正方形,各种三角形与菱形
一. 正方形 a) 在第一个for循环中控制,一共输出几行.依靠的是,每次输出一行,就会在后面输出一个换行符<br>; b) 在第二个for循环中控制每行输出几个五角星.这样的 ...