python函数进阶
知识内容:
1.函数即变量
2.嵌套函数
3.lambda表达式与匿名函数
4.递归函数
5.函数式编程简介
6.高阶函数与闭包
一、函数即变量
1.变量的本质
声明一个变量,在python里本质上讲是把变量对应的值和变量名联系起来,变量里保存的不是值,而是值对应的地址;而赋值时从本质上讲是把变量名对应的值的内存地址赋给了另一个变量
- a = 1
- b = a
可以这样理解,变量名相对于酒店里的房牌号,而变量名对应的值就相对于对应的房间
在上图中,刚开始a和b都是指向1对应的内存位置,后来把赋值a为3,赋值其实就算改变了变量名与内存位置的对应关系,也就是赋值后a这个变量名对应的值为3而b这个变量名依然对应的值为1
python是基于值的内存管理体系,当1对应的变量没有了,也就是上面的a和b都赋值为其他值时,系统便会自动清除掉1的内存
2.def的本质
def的本质就是将函数名和函数体联系在一起,放入内存中,也就是函数名相当于上面的变量名,函数体相当于上面的值,定义一个函数就相当于将值赋给变量,也就是将函数体赋给了函数名,因此才可以通过函数名来执行函数体
3.几段代码及其解释
- # (1)
- # def foo():
- # print("in the fool")
- # bar()
- # foo()
- # 运行结果: 输出in the fool然后报错
解释: 定义foo之后函数解释时将foo与函数体相关联,解释到foo(),函数执行函数名foo对应的函数体函数名foo对应的函数体在内存可以找到,于是执行该函数体,但是执行到bar时解释器麻痹了,找不到函数名bar对应的函数体,于是就报错了,如下图所示:
- # (2)
- # def bar():
- # print("in the bar")
- # def foo():
- # print("in the fool")
- # bar()
- # foo()
- # 输出结果:
- # # in the fool
- # # in the bar
- # (3)
- # def foo():
- # print("in the fool")
- # bar()
- # def bar():
- # print("in the bar")
- # foo()
- # # 输出结果:
- # # in the fool
- # # in the bar
解释:
(2)和(3)的输出结果一样,但是从解释的流程来讲并不是一样的,但是与下一段代码有异曲同工之妙
- x = 1
- y = 2
- print(x, y)
- y = 2
- x = 1
- print(x, y)
- # 输出结果都是: 1 2
x和y虽然定义的顺序不一样,当两者都是把变量名与对应变量联系起来,所以只要输出顺序一样自然结果就一定一样同样的道理,函数foo和函数bar虽然定义的顺序不一样,但他们的定义的本质与变量是一样的,是将函数名与函数体联系起来,所以只要调用函数的顺序一样自然它们输出的结果也一样,至于它们的具体解释流程可以参见第一段代码的解释,两者的流程是类似的
二、嵌套函数
1.嵌套函数
python中的函数还可以嵌套定义,即一个函数的定义里还有另一个函数的定义,如下:
- # __author__ = "wyb"
- # date: 2018/3/21
- # 函数嵌套
- name = "zzz"
- def f1():
- name = "wyb"
- def f2():
- name = "wyb666"
- print("第一层打印: ", name)
- f2()
- print("第二层打印: ", name)
- f1()
- print("最外层打印: ", name)
- # 输出结果:
- # 第一层打印: wyb666
- # 第二层打印: wyb
- # 最外层打印: zzz
注: 函数嵌套是在函数体内还有一个函数体,而不是在函数体内调用另一个函数
2.前向引用
函数func体内嵌套某一函数logger的调用,则logger函数的声明定义必须在func函数之前,否则程序会报错!
- # 前向引用
- def logger():
- print("in the logger")
- def func():
- print("in the func")
- logger()
- func()
- # 输出结果:
- # in the func
- # in the logger
3.嵌套函数的定义域
在嵌套函数中要格外注意局部作用域和全局作用域的访问顺序
- x = 0
- def grandpa():
- x = 1
- def dad():
- x = 2
- def son():
- x = 3
- print(x)
- son()
- dad()
- grandpa()
注: son()和dad()和grandpa()这几个函数调用少了任何一个程序都将不会执行
三、lambda表达式与匿名函数
1.匿名函数
python使用 lambda 来创建匿名函数,所谓匿名是指不再使用 def 语句这样标准的形式定义一个函数,lambda的特点:
- python中的匿名函数也叫lambda表达式,lambda只是一个表达式,比def定义的函数简单很多
- 匿名函数的核心:一些简单的需要用函数去解决的问题,匿名函数的函数体只有一行并且参数可以有多个,用逗号隔开
- lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去
- 返回值和正常的函数一样可以是任意的数据类型
- 匿名函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
2.匿名函数示例
- >>> f = lambda x, y, z: x+y+z
- >>> print(f(1,2,3))
- 6
- >>> g = lambda x, y=2, z=3: x+y+z # 含有默认值参数
- >>> print(g(1))
- 6
- >>> print(g(2, z=5, y=6)) # 调用时使用位置参数
- 13
- >>> list(map(lambda x: x+10, [1,2,3,4,5])) # 包含函数调用没有名字的lambda表达式
- [11, 12, 13, 14, 15]
四、递归函数
递归的详细讲解:http://www.cnblogs.com/alex3714/articles/8955091.html
1.递归的定义
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数,所谓递归就是在函数内部调用自身
- def proc(n):
- if n < 0:
- print('-', end = '')
- n = -n
- if n // 10:
- proc(n // 10 )
- print(n % 10, end = '')
- proc(-345)
- # 输出: -345
2.递归特性:
(1)必须有一个明确的结束条件
(2)每次进入更深一层递归时,问题规模相比上次递归都应有所减少
(3)递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
3.递归的要领
(1)找相似性 -> 寻找问题在不同大小规模下的相似性,抽象出共同特征,根据共同特征写出递归的核心方程式或者递推公式
(2)找出口 -> 问题不可能一直递归下去,总要有一个出口,结束递归从而结束循环
4.经典递归算法的python实现
- # __author__ = "wyb"
- # date: 2018/3/30
- # Fibonacci数列递归求解
- # # 普通写法:
- # def fib(n):
- # if n == 0 or n == 1:
- # return n
- # a, b = 0, 1
- # count = 0
- # while count < n:
- # a, b = b, a+b
- # count = count + 1
- # return a
- # 递归写法:
- def fib(n):
- if n == 0 or n == 1:
- return n
- else:
- return fib(n-1)+fib(n-2)
- print(fib(0))
- print(fib(1))
- print(fib(2))
- print(fib(3))
- print(fib(4))
- print(fib(5))
Fibonacci数列递归求解
- # __author__ = "wyb"
- # date: 2018/3/30
- # 汉诺塔问题
- def hanoi(a, b, c, n):
- if n == 1:
- print(a, "->", c)
- else:
- hanoi(a, c, b, n-1)
- print(a, "->", c)
- hanoi(b, a, c, n-1)
- hanoi('a', 'b', 'c', 4)
汉诺塔问题
五、函数式编程简介
1.引言
函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元,在编程中函数是指逻辑结构化和过程化的一种编程方法。在过去的10年间,大家所熟悉的编程方式不是面向对象就是面向过程,两种都是编程的规范或如何编程的方法论。而如今,一种更为古老的编程方式--函数式编程,以其不保存状态、不修改变量等特性重出江湖,重新进入人们的思想中
面向对象 --> 类 --> class
面向过程 --> 过程 --> def
函数式编程 --> 函数 --> def
- # __author__ = "wyb"
- # date: 2018/3/27
- # 函数
- def func1():
- """testing1"""
- print("in the func1")
- return 0
- # 过程 -> 没有返回值的函数
- def func2():
- """testing2"""
- print("int the func2")
- x = func1()
- y = func2()
- print(x, y)
- """
- 输出结果:
- in the func1
- int the func2
- 0 None
- """
函数与过程
2.函数式编程定义
简单说,"函数式编程"是一种编程范式(programming paradigm),也就是如何编写程序的方法论。
函数式编程中的函数这个术语不是指计算机中的函数,而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的。Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言
主要思想是把运算过程尽量写成一系列嵌套的函数调用。举例来说,现在有这样一个数学表达式:
(1 + 2) * 3 - 4
传统的过程式编程,可能这样写:
var a = 1 + 2;
var b = a * 3;
var c = b - 4;
函数式编程要求使用函数,我们可以把运算过程定义为不同的函数,然后写成下面这样:
var result = subtract(multiply(add(1,2), 3), 4);
这段代码再演进以下,可以变成这样
add(1,2).multiply(3).subtract(4)
这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它的意思吧:
merge([1,2],[3,4]).sort().search("2")
因此,函数式编程的代码更容易理解。
3.经典的函数式编程语言
LISP: 长期以来垄断人工智能领域的应用,是为人工智能而设计的语言
Haskell: 是一种标准化的、通用纯函数式编程语言,有非限定性语义和强静态类型
Erlang: 是一种通用的面向并发的编程语言,它支持并发与函数式编程
4.函数式编程的特性
- 闭包和高阶函数
- 惰性计算
- 递归
- 函数是"第一等公民"
- 只用"表达式",不用"语句"
- 没有"副作用"
5.函数式编程的优点
- 代码简洁,开发快速
- 接近自然语言,易于理解
- 更方便的代码管理
- 易于"并发编程"
六、高阶函数与闭包
1.高阶函数定义
变量可以指向函数,函数的参数能接收变量,当然一个函数就可以接收另一个函数作为参数或者返回值中包含函数名,这种函数就称之为高阶函数。
2.高阶函数的要求
满足以下两个条件之一的函数可称为高阶函数:
(1)把一个函数名作为实参传给另一个函数 -> 可以在不修改函数源代码的情况下为函数添加功能
(2)返回值中包含函数名 -> 不修改函数的调用方式
3.高阶函数示例
(1)符合第一个标准的高阶函数
- def bar():
- print("in the bar")
- def test1(func):
- print(func) # 函数名->地址
- func() # run bar
- test1(bar)
- # # 输出结果:
- # <function bar at 0x053E85D0>
- # in the bar
(2)符合第二个标准的高阶函数
- def bar():
- print("in the bar")
- def test2(func):
- print(func)
- return func
- t = test2(bar)
- print(t)
- t() # run bar
- # # 输出结果:
- # <function bar at 0x05938618>
- # <function bar at 0x05938618>
- # in the bar
4.闭包
(1)概念
闭包就是能够读取其他函数内部变量的函数。例如在javascript、python中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁
简单说: 如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数,那么闭包就是在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的函数名(引用)。这样就构成了一个闭包
(2)理解
概念看起来不是很容易理解,我直接举实例解释上述概念
- def func():
- n = 10
- def func2():
- print("func2: ", n)
- return func2
- f = func()
- print(f)
- f()
- # 输出结果:
- # <function func.<locals>.func2 at 0x049294F8>
- # func2: 10
上述代码中的func返回的是func2函数的内存地址,调用func返回func2的内存地址然后调用执行会打印n的值,按照局部变量在函数运行完后就释放不再存在的原则似乎这里有点问题,但是这其实就算闭包。原来调用func2只能在func中进行调用,但是现在有了闭包后只需返回fanc2的地址然后可以在func函数外调用,就相当于在func外面拿到了func2函数,如果此时func2调用了func中的变量比如n,此时n是不会释放内存的
一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束
python函数进阶的更多相关文章
- python函数进阶(函数参数、返回值、递归函数)
函数进阶 目标 函数参数和返回值的作用 函数的返回值 进阶 函数的参数 进阶 递归函数 01. 函数参数和返回值的作用 函数根据 有没有参数 以及 有没有返回值,可以 相互组合,一共有 4 种 组合形 ...
- 第六篇:Python函数进阶篇
在了解完了 Python函数基础篇之后,本篇的存在其实是为了整合知识,由于该篇的知识是否杂乱,故大家可以通过点开点连接直接进入其详细介绍,该篇主要大致的介绍一下几个知识点: 一.Python的迭代器 ...
- python -- 函数进阶
一.函数参数-动态传参 1.形参: * 在形参位置, 表示此参数为不定参数,接受的是位置参数 并且接收到的位置参数的动态传参都是元组 def fu ...
- python 函数进阶与闭包
函数的命名空间和作用域 引言 现在有个问题,函数里面的变量,在函数外面能直接引用么? def func1(): m = 1 print(m) print(m) #这行报的错 报错了: NameErro ...
- 万恶之源 - Python函数进阶
函数参数-动态参数 之前我们说过传参,如果我们在传参数的时候不很清楚有哪些的时候,或者说给一个函数传了很多参数,我们就要写很多,很麻烦怎么办呢,我们可以考虑使用动态参数 形参的第三种:动态参数 动态参 ...
- Python 函数进阶(filter/map/json/zip)
一.函数即变量 def say(name): print(name)ybq = say #可以被赋值给其他变量ybq('Amily') #调用函数 函数名:say 函数体:第1-2行 返回值:retu ...
- 13 Python 函数进阶
代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间 命名空间和作用域 命名空间的本质:存放名字与值的绑定关系 >>> ...
- Python—函数进阶篇
lambda表达式(匿名函数表达式) 作用:创建一个匿名函数对象.同def类似,但不提供函数名. 语法:lambda [形参1,形参2,...] : 表达式 语法说明 lambda 只是一个表达式,它 ...
- Python函数进阶:闭包、装饰器、生成器、协程
返回目录 本篇索引 (1)闭包 (2)装饰器 (3)生成器 (4)协程 (1)闭包 闭包(closure)是很多现代编程语言都有的特点,像C++.Java.JavaScript等都实现或部分实现了闭包 ...
随机推荐
- IoT 通信协议
/********************************************************************************* * IoT 通信协议 * 说明: ...
- 一定要记住这20种PS技术,让你的照片美的不行! - imsoft.cnblogs
照片名称:调出照片柔和的蓝黄色-简单方法, 1.打开原图素材,按Ctrl + J把背景图层复制一层,点通道面板,选择蓝色通道,图像 > 应用图像,图层为背景,混合为正片叠底,不透明度50%,反相 ...
- BZOJ4897: [Thu Summer Camp2016]成绩单【DP of DP】
Description 期末考试结束了,班主任L老师要将成绩单分发到每位同学手中.L老师共有n份成绩单,按照编号从1到n的顺序叠 放在桌子上,其中编号为i的成绩单分数为w_i.成绩单是按照批次发放的. ...
- .NET Core Generic Host Windows服务部署使用Topshelf
此文源于前公司在迁移项目到.NET Core的过程中,希望使用Generic Host来管理定时任务程序时,没法部署到Windows服务的问题,而且官方也没给出解决方案,只能关注一下官方issue # ...
- dfs 与 剪枝
http://blog.csdn.net/u010700335/article/details/44095171
- java8 流操作 好文网址
api 各方法详解(很不错!) http://blog.51cto.com/turnsole/2093185 api 各方法 简介: https://www.cnblogs.com/guguli/p/ ...
- (精)AVL树旋转共8种情况(涵盖所有考研的范围)
- php curl上传文件$_FILES为空问题
php使用curl上传文件,代码如下: 发送的代码(完全是官方的示例) <?php /* http://localhost/upload.php:print_r($_POST);print_r( ...
- 我的主机是win 7 虚拟机是vmware,solaris10连接主机
进入主机Control Panel—Administrative Tool—Services,打开服务Vmware DHCP Servise和Vmware NAT Service,启动后虚拟机上网正常 ...
- Linux Home目录硬盘空间缩减
Linux Home目录硬盘空间缩减 操作 基于centos6.5 x86_64, runlevel 3,命令行模式,测试成功. 1.首先查看磁盘使用情况 [root@localhost ~]# ...