首先来看下面这个函数。

 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学习——函数进阶的更多相关文章

  1. Python学习day08-python进阶(2)-内置方法

    Python学习day08-python进阶(2)-内置方法 列表数据类型内置方法 作用 描述多个值,比如爱好 定义方法       xxxxxxxxxx 2         1 hobby_list ...

  2. Python学习笔记进阶篇——总览

    Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(Socket编程进阶&多线程.多进程) Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(异常处理) Pyth ...

  3. 【转】Python之函数进阶

    [转]Python之函数进阶 本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函 ...

  4. 《Python》 函数进阶和名称空间作用域

    函数进阶: 一.动态参数:*args  **kwargs *args是元祖形式,接收除去键值对以外的所有参数 # args可以换成任意变量名,约定俗成用args **kwargs接收的只是键值对的参数 ...

  5. 10.Python初窥门径(函数进阶)

    Python(函数进阶) 一.函数的传参(接上期) 形参角度(一共四种,后两种) 动态参数(万能参数)* # 定义一个函数时,*所有的位置参数聚合到一个元组中 def func(*args): # * ...

  6. python学习-函数和lambda表达式(五)

    5.2函数参数 位置参数:根据位置传入参数 关键字参数:根据参数名来传入参数 def girth(width, height): print("width:", width) pr ...

  7. Python之函数进阶

    本节内容 上一篇中介绍了Python中函数的定义.函数的调用.函数的参数以及变量的作用域等内容,现在来说下函数的一些高级特性: 递归函数 嵌套函数与闭包 匿名函数 高阶函数 内置函数 总结 一.递归函 ...

  8. python学习——函数返回值及递归

    返回值 return语句是从python 函数返回一个值,在讲到定义函数的时候有讲过,每个函数都要有一个返回值.Python中的return语句有什么作用,今天小编就依目前所了解的讲解一下.pytho ...

  9. python学习——函数及其参数

    函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.函数能提高应用的模块性,和代码的重复利用率.严格来说python只有函数,没有过程,人们理解的函数都是带有return的,而过程 ...

随机推荐

  1. 《SQL必知必会》总结

    目录   第1章 了解SQL 第2章 检索数据 第3章 排序检索数据 第4章 过滤数据 第5章 高级数据过滤 第6章 用通配符进行过滤 第7章 创建计算字段 第8章 使用数据处理函数 第9章 汇总数据 ...

  2. No module named _sqlite3

    [root@lgj01 opsadmin]# python manage.py startapp accountTraceback (most recent call last):  File &qu ...

  3. 基于IDEA的JavaWeb开发环境搭建

    基于IDEA的JavaWeb开发环境搭建 基于IDEA的JavaWeb开发环境搭建 jdk下载安装配置环境变量 下载 安装 配置环境变量 下载安装激活使用IntelliJ IDEA 下载 安装 激活 ...

  4. Python Django 分页

    Python Django 分页 http://www.360doc.com/content/14/0721/17/16044571_396090985.shtml

  5. Django objects.values

    values(*fields) 返回一个ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象. 每个字典表示一个对象,键对应于模型对象的属性名称. 下面的 ...

  6. The Binder Architecture

    The Binder Architecture is a declarative architecture for iOS development inspired by MVVM and VIPER ...

  7. 牛客网多校训练第一场 E - Removal(线性DP + 重复处理)

    链接: https://www.nowcoder.com/acm/contest/139/E 题意: 给出一个n(1≤n≤1e5)个整数(范围是1至10)的序列,求从中移除m(1≤m≤min(n-1, ...

  8. PHP------数组的遍历

    echo current($attr); //取当前元素的value值 echo key($attr); //取当前元素的key next($attr); //将数组里面的指针指向下一个(向下移)pr ...

  9. 关于webstorm打开项目,文件下方出现了一个小锁的图标,修改文件出现“cannot modify a ready-only directory”的弹窗提示

    今天用webstorm打开项目,文件下方出现了一个小锁的图标,修改文件出现“cannot modify a ready-only directory”的弹窗提示 解决办法:运行 sudo chown ...

  10. 系统剪切板的使用UIPasteboard

    最近发现支付宝和淘宝使用吱口令和淘口令的功能,就一直想怎么实现的,觉得应该是使用了系统的剪切板,然后查阅了资料做下笔记! 系统的剪切板主要是使用了UIPasteboard这个类. UIPasteboa ...