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等都实现或部分实现了闭包 ...
随机推荐
- 【error】select timeout问题
使用摄像头的过程中出现这个问题,说明是找不到摄像头了, 有可能是摄像头驱动问题,也有可能是摄像头接口处接触不良等原因造成的. re 1.select-timeout-opencv; End
- Lists.transform的使用
转自:https://blog.csdn.net/weixin_42201566/article/details/81513769 Lists.transform:能够轻松的从一种类型的list转换为 ...
- 《Java程序猿面试笔试宝典》之Java变量命名有哪些规则
在Java语言中,变量名.函数名.数组名统称为标识符,Java语言规定标识符仅仅能由字母(a~z.A~Z).数字(0~9).下划线(_)和$组成,而且标识符的第一个字符必须是字母.下划线或$.此外.标 ...
- EXCEL函数LookUp, VLOOKUP,HLOOKUP应用详解(含中文参数解释)
关于VLOOKUP函数的用法 “Lookup”的汉语意思是“查找”,在Excel中与“Lookup”相关的函数有三个:VLOOKUP.HLOOKUO和LOOKUP.下面介绍VLOOKUP函数的用法. ...
- mysql常用的聚合函数
GROUP BY(聚合)函数本章论述了用于一组数值操作的 group (集合)函数.除非另作说明, group 函数会忽略 NULL 值. 假如你在一个不包含 ROUP BY子句的语句中使用一个 gr ...
- hadoop之 Yarn 调度器Scheduler详解
概述 集群资源是非常有限的,在多用户.多任务环境下,需要有一个协调者,来保证在有限资源或业务约束下有序调度任务,YARN资源调度器就是这个协调者. YARN调度器有多种实现,自带的调度器为Capaci ...
- ORA-10997:another startup/shutdown operation of this instance in progress解决方法
SQL> startup ORA-10997: another startup/shutdown operation of this instance inprogress ORA-09967: ...
- 【python】正则表达式-常用函数
m = re.search(pattern, string) # 搜索整个字符串,直到发现符合的子字符串. m = re.match(pattern, string) # 从头开始检查字符串是否符合正 ...
- java 管道流PipedInputStream,PipedInputStream和随机访问文件 RandomAccessFile
http://blog.csdn.net/zlp1992/article/details/50298195 给个链接自己去看吧.网上资料不是很多,而且自己也不想写了 RandomAccessFil ...
- java 字符串String
在 Java 中,字符串被作为 String 类型的对象处理. String 类位于 java.lang 包中.默认情况下,该包被自动导入所有的程序. 创建 String 对象的方法: 只要是双引号标 ...