python学习——函数进阶
首先来看下面这个函数。
def func(x,y):
bigger = x if x > y else y
return bigger
ret = func(10,20)
print(ret) #运行结果 : 20
在上面的函数中我们把较大值通过return这个关键字返回回来了,如果我不返回而是直接打印可不可以?如下:
def func(x,y):
bigger = x if x > y else y func(10,20)
print(bigger) #运行结果 : NameError: name 'bigger' is not defined
此时它会说,bigger没有定义,这是为什么,在函数中我明明定义了bigger就是较大的那个数,那问题出在哪儿呢?
在这里我们首先回忆一下python代码运行的时候遇到函数是怎么做的。从python解释器开始执行之后,就在内存中开辟了一个空间,每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。但是当遇到函数定义的时候解释器只是象征性的将函数名读入内存,表示知道这个函数的存在了,至于函数内部的变量和逻辑解释器根本不关心。等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会存储在新开辟出来的内存中。函数中的变量只能在函数的内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被解释器释放了。
我们给这个“存放名字与值的关系”的空间起了一个名字——叫做命名空间
代码在运行的时候,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间
一、命名空间和作用域
首先看一下这张图:
这是python之禅中说的,命名空间非常好!在python中命名空间有以下几种:
内置命名空间
全局命名空间
局部命名空间
内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间 (程序运行前加载 ) -> 全局命名空间 ( 程序运行中:从上到下加载 ) -> 局部命名空间 ( 程序运行中:调用时才加载 )
取值:
在局部调用:局部命名空间 -> 全局命名空间 -> 内置命名空间
a = 1
b = 2
def func():
print(a)
print(b)
func()
print(10) #运行结果 :1,2,10
在局部使用变量取值情况
所以存在这种情况:当调用函数时,函数被执行,但是函数内部(局部)并没有a,b这两个值,只能到函数外面(全局)来找,找到了,就打印。而之后打印的10在全局中就直接找到了。
在全局调用:全局命名空间 -> 内置命名空间
a = 1
b = 2
def func(a,b):
print(a)
print(b) func(10,20)
print(a,b) # 运行结果:10,20,1 2
在全局引用变量
此时对a,b传值了,所以首先打印出来,在全局再次打印a,b的时候,函数内部的a,b在函数执行完毕之后就被释放了,所以只能打印全局a,b的值;还有即使a,b没被释放,在全局也不能打印局部变量的值!
print(max(1,2,3,3)) #结果:3
所以三种命名空间有以下这种关系:
所以他们的关系是这样的,内置命名空间在解释器一打开就被加载到内存中了,在定义函数之前的所有变量都是全局命名空间中的变量,而在函数内部的所有变量都是局部命名空间中的变量,当然只有函数被调用时才被加载到内存中,但随着函数执行完毕就被自动释放了。
二、函数的嵌套和作用链域
函数的嵌套调用
def func1(a,b):
return a if a > b else b def func2(x,y,z):
ret1 = func1(x,y)
ret2 = func1(ret1,z)
return ret2 ret = func2(1,2,3)
print(ret) #运行结果:3
函数的嵌套调用
函数的嵌套定义
# 函数的嵌套定义 一 def func1():
print('in func1 now')
def func2():
print('in func2 now')
func2() func1() # 函数的嵌套定义 二 def func1():
def func2():
def func3():
print('in func3 now')
func3()
print('in func2 now')
func2()
print('in func1 now')
func1()
函数的嵌套定义
函数的作用链域
# 函数的作用链域 一
def func1():
a = 1
def func2():
print(a)
func2()
func1() # 运行结果:1 # 函数的作用链域 二
def func1():
a = 100
def func2():
def func3():
print(a)
func3()
func2() func1() # 运行结果:100 # 函数的作用链域 三
def func1():
a = 1000
def func2():
a = 10000
def func3():
print('a in func1 ',a)
func3()
func2() func1() # 运行结果:a in func1 10000
函数的作用链域
nonlocal 关键字
1.外部必须有这个变量
2.在内部函数声明nonlocal变量之前不能再出现同名变量
3.内部修改这个变量如果想在外部有这个变量的第一层函数中生效
def func1():
a = 1
def func2():
nonlocal a
a = 2
func2()
print(a)
func1() # 运行结果:2
nonlocal 关键字
三、函数名的本质
函数名本质上就是一个函数的内存地址(函数即变量)
1.可以被引用
def func():
print('in func now ') ret = func
print(ret) # 运行结果:<function func at 0x0000023C04CDC730>
函数名可以被引用
当打印函数名的时候返回的是一个内存地址。
2.可以被当作容器类型的元素
def func1():
print('func1') def func2():
print('func2') def func3():
print('func3') l = [func1,func2,func3]
d = {'func1':func1,'func2':func2,'func3':func3}
#调用
l[0]
print(l[0])
l[0]()
print(d['func2'])
d['func2']() #运行结果:<function func1 at 0x000001F345C0C7B8> func1 <function func2 at 0x000001F345C0C840> func2
函数名可以被当作容器类型的元素
当我们不调用时(不在后面加上“()”),返回函数名所在的内存地址,加上之后返回函数值。
3.可以当作函数的参数和返回值(就是把函数名当作普通变量来用)
第一类对象(first-class object)指
1.可在运行期创建
2.可用作函数参数或返回值
3.可存入变量的实体。
四、闭包函数
1、首先说什么是闭包
def func1():
name = 'liulonghai'
def func2():
print(name)
2、闭包函数
内部函数包含对外部作用域而非全局作用域名字的引用,该内部函数称为闭包函数 #函数内部定义的函数称为内部函数。
判断一个函数是否是闭包可以这样写
def func1():
name = 'liulonghai'
def func2():
print(name)
print(func2.__closure__)
print(func1.__closure__)
func2() func1() #运行结果:liulonghai
# (<cell at 0x000001B30E5F0108: function object at 0x000001B31163D7B8>,
# <cell at 0x000001B3103A7378: str object at 0x000001B3103A0370>)
# None
判断一个函数是否是闭包函数
可以通过(__closure__)这个双下方法来查看一个函数名是不是闭包,当打印出"(<cell at 0x000001B30E5F0108: function object at 0x000001B31163D7B8>, <cell at 0x000001B3103A7378: str object at 0x000001B3103A0370>)" 这样就表面此函数是一个闭包,其实就是‘cell’ ,如果不是,则返回None
由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回?我们都知道函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?是不是直接就把这个函数的名字返回就好了?
这才是闭包函数最常用的用法
def func():
name = 'liulonghai'
def inner():
print(name) return inner f = func()
f() #运行结果:liulonghai
闭包函数最常用的形式
闭包函数的嵌套
def wrapper():
name = 'liulonghai'
def outter():
money = 1000000
def inner():
print(name,money)
return inner
return outter w = wrapper()
o = w()
o() #运行结果:liulonghai 1000000
闭包函数的嵌套
闭包函数获取网页
from urllib.request import urlopen def index():
url = "http://www.baidu.com"
def get():
return urlopen(url).read()
return get baidu = index()
content = baidu()
print(content)
闭包函数获取网页信息
五、迭代器
1.迭代
在说迭代器之前,我们来先了解以下python中的for循环,为什么当我们对一个对象进行for循环时,为什么能够取到那个对象里面的所有值。如下:
lst = [i for i in range(10)]
print(lst)
for i in lst:
print(i,end=' ') #输出:0 1 2 3 4 5 6 7 8 9
再来看一下下面这个代码,为什么会这样。
for i in 1234:
print(i) #输出:TypeError: 'int' object is not iterable
当我们这样写的时候,解释器会报错,来看一下这个错误TypeError:'int' object is not iterable "类型错误:int对象是不可迭代的",其实iterable就是for循环的关键,在python中,只要某个对象是可迭代的,那就能进行for循环。
python学习——函数进阶的更多相关文章
- Python学习day08-python进阶(2)-内置方法
Python学习day08-python进阶(2)-内置方法 列表数据类型内置方法 作用 描述多个值,比如爱好 定义方法 xxxxxxxxxx 2 1 hobby_list ...
- Python学习笔记进阶篇——总览
Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(Socket编程进阶&多线程.多进程) Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(异常处理) Pyth ...
- 【转】Python之函数进阶
[转]Python之函数进阶 本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函 ...
- 《Python》 函数进阶和名称空间作用域
函数进阶: 一.动态参数:*args **kwargs *args是元祖形式,接收除去键值对以外的所有参数 # args可以换成任意变量名,约定俗成用args **kwargs接收的只是键值对的参数 ...
- 10.Python初窥门径(函数进阶)
Python(函数进阶) 一.函数的传参(接上期) 形参角度(一共四种,后两种) 动态参数(万能参数)* # 定义一个函数时,*所有的位置参数聚合到一个元组中 def func(*args): # * ...
- python学习-函数和lambda表达式(五)
5.2函数参数 位置参数:根据位置传入参数 关键字参数:根据参数名来传入参数 def girth(width, height): print("width:", width) pr ...
- Python之函数进阶
本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函数 内置函数 总结 一.递归函 ...
- python学习——函数返回值及递归
返回值 return语句是从python 函数返回一个值,在讲到定义函数的时候有讲过,每个函数都要有一个返回值.Python中的return语句有什么作用,今天小编就依目前所了解的讲解一下.pytho ...
- python学习——函数及其参数
函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.函数能提高应用的模块性,和代码的重复利用率.严格来说python只有函数,没有过程,人们理解的函数都是带有return的,而过程 ...
随机推荐
- C++ 构造转换函数和强制转换函数
http://blog.csdn.net/chenyiming_1990/article/details/8862497 1.对于系统的预定义基本类型数据,C++提供了两种类型转换方式:隐式类型转换和 ...
- 捕获Task.WhenALl返回的Task的Exception
如果有一个任务抛出异常,则Task.WhenAll 会出错,并把这个异常放在返回的Task 中.如果多个任务抛出异常,则这些异常都会放在返回的Task 中.但是,如果这个Task 在被await 调用 ...
- 查询SQL Server 版本信息
select SERVERPROPERTY('ProductVersion') as ProductionVersion, SERVERPROPERTY('ProductLevel')as Produ ...
- JDK/bin下工具列表说明
JDK/bin下工具列表说明 appletviewer.exe:一种执行HTML文件上的Java小程序类的Java浏览器 apt.exe:注解处理工具(Annotation Processing To ...
- July 03rd 2017 Week 27th Monday
Even if you are on the right track, you will get run over if you just sit there. 即使你处于正确的轨道上,但如果你只是坐 ...
- AngularJs学习笔记--Understanding the Model Component
原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_model 在angular文档讨论的上下文中,术语“model”可以 ...
- FBKVOController代码阅读
功能:对kvo机制进行封装,简化使用,简化内存管理: 要素:观察者.被观察者.处理函数. 模式:注册表模式: 机制:对象创建.注册管理.内存管理.处理机制转换: 其它:注册去重: kvo的管理机制:
- mysqlslap执行基准测试
查看mysqlslap所支持的主要参数配置及说明如下 -a, --auto-generate-sql 由系统自动生成SQL脚本进行测试 Generate SQL where not supplied ...
- PHP---------Smarty模板
Smarty模板 是做什么用的?? 是将前端的显示和后台的逻辑进行分离,就相当于把前台显示的页面和后台要实现的某些功能的逻辑给分离出来了,分离在两个文件里,也就是说,前端只负责显示,后端只负责逻辑操作 ...
- 最简单的PS渐变导入方法 photoshop渐变插件素材导入教程
photoshop渐变插件素材可以让用户更好更直接,更快速地设计出自己想要的效果作品.网上有多种多样的ps渐变,那么Mac版Ps渐变怎么导入呢?这里我来和大家分享一下photoshop渐变插件素材导入 ...