多数语言没有的,python特有的内容
一、闭包 closure
什么是闭包:
将内嵌函数的语句和这些语句的执行环境打包在一起后 得到的函数对象称为闭包
闭包必须满足以下三个条件:
1.必须有一个嵌套函数
2.内嵌函数必须引用外部函数中的变量
3.外部函数返回值必须是内嵌函数
示例:
#此程序示意闭包的用法
#1.fn为内嵌函数
#2.fn用到了fn外部的变量y
#3.make_power将fn绑定的函数对象返回给调用者
def make_power(y):
def fn(x):
return x ** y
return fn
pow2 = make_power(2)
print("5的平方是:",pow2 (5))
执行结果:
25
分析上面程序我们不难发现:
make_power函数返回了fn函数的变量,最终pow2绑定的是fn;
y是函数make_power的局部变量,所以make_power(2)函数调用完以后,按理来说局部变量y = 2应该被回收掉了,但是我们发现pow2(5)执行后,结果为25,看起来y= 2并没有被销毁。
这是为什么?
其实这就是闭包。
实际上,make_power函数不仅仅返回了fn的函数对象,而是将局部变量y和函数对象fn一起打包起来返回给了pow2,这个包我们就叫闭包
可以这样理解,我内嵌函数用到了外层函数的变量,这样就将变量的和函数对象捆绑在了一起,整个大的运行环境的引用计数+1,函数对象到哪里,那自然变量也得跟着去哪儿,自然就不会被销毁了。
闭包的好处:就像是个函数工厂
相当于是绑定函数的一个参数,另外一个参数由用户传入
#求一些数的平方
pow2 = make_power(2) #pow2函数专门用来求某个数的平方
print("5的平方是:",pow2 (5))
print("10的平方是:",pow2(10))
print("12的平方是:",pow2(12))
#求一些数的立方
pow3 = make_power(3) #pow3函数专门用来求某个数的立方
print("5的立方是:",pow3 (5))
print("10的立方是:",pow3(10))
print("12的立方是:",pow3(12))
#同理,求一些数的5次方
pow4 = make_power(5)
print("5的5方是:",pow4 (5))
print("10的5方是:",pow4(10))
print("12的5方是:",pow4(12))
执行结果:
5的平方是: 25
10的平方是: 100
12的平方是: 144
5的立方是: 125
10的立方是: 1000
12的立方是: 1728
5的5方是: 3125
10的5方是: 100000
12的5方是: 248832
#pow2等同于
def pow2(x):
return x ** 2
#pow3等同于
def pow3(x):
return x ** 3
#有了闭包就可以很快的创建类似功能的函数
接下来我们通过图来理解整个过程:
所以,内部函数可以放心的使用外部的函数的变量,不用担心被释放。
(如果一个内嵌函数访问了外部嵌套函数的作用域内的变量,则这个内嵌函数就是闭包)
二、装饰器 decorators(专业提高篇)
什么是装饰器:
装饰器是一个函数 , 这个函数的主要作用是包装另一个函数或者类
包装的目的:
在不改变原函数名的情况下改变被包装对象的行为(是在原理函数的基础上装饰)
函数装饰器 function decorators
函数装饰器是指装饰一个函数,传入的是一个函数,返回的也是一个函数
示例1:用新的函数装饰(替换掉)原来的函数
#fn绑定旧的函数(被修饰的函数),返回新的函数
def mydeco(fn):#装饰器函数
def fx ():
print("hello world")
return fx
def hello(): #被装饰函数
print("hello python")
hello() #装饰前
hello = mydeco(hello) #将hello绑定在了mydeco函数返回的函数上
#此种做法可以用装饰器@语法解决
hello() #装饰后
执行结果:
hello python
hello world
示例 1 ** 还有另外一个写法,使用 @ 来代替,与上面的等价 **:即就是@用法的原理
def mydeco(fn):#装饰器函数
def fx ():
print("hello world")
return fx
@mydeco
def hello(): #被装饰函数
print("hello python")
hello() #装饰后
执行结果:
hello world
示例2:装饰器可以在不改变原来函数的调用的情况下,在调用原来函数的前后进行一些操作
def mydeco(fn):#装饰器函数 绑定的是原来被装饰前原来的函数
def fx ():
print("******************")
fn()
print("##################")
return fx
@ mydeco
def hello(): #被装饰函数 原函数
print("hello python")
hello() #装饰后 被装饰的函数
执行结果:
******************
hello python
##################
#此例用意说明:
#我们这里并没有改变原来函数的执行,但是我们可以在原函数调用的基础上做一些装饰,或者其他操作
三、函数的文档字符串:其实就是给开发人员看的函数说明书
语法:
def 函数名(参数列表):
“”“函数的文档字符串”""
函数语句块
说明:
文档字符串通常用来说明本函数的功能和使用方法
在交换模式下,输入help(函数名)
可以查看函数,“文档字符串”
示例1:查看一个内建函数的文档字符串
help(max)
执行结果:
Help on built-in function max in module builtins:
max(...)
max(iterable, *[, default=obj, key=func]) -> value
max(arg1, arg2, *args, *[, key=func]) -> value
With a single iterable argument, return its biggest item. The
default keyword-only argument specifies an object to return if
the provided iterable is empty.
With two or more arguments, return the largest argument.
#max(...)以下的字符,用来描述函数的作用,参数列表,返回值等
实例2:自己写一个函数的文档字符串
def function(a,b):
""""这是一段对function函数的解释,
主要内容包括我的函数名称、参数列表
以及返回值等,我就说这么多,这是我
全部关于该函数的文档字符的"""
print("hello world")
function(1,2)
执行结果:
hello world
#我们甚至可以查看我们自己给自己的function函数的文档字符串
help(function)
执行结果:
Help on function function in module __main__:
function(a, b)
"这是一段对function函数的解释,
主要内容包括我的函数名称、参数列表
以及返回值等,我就说这么多,这是我
全部关于该函数的文档字符的
Process finished with exit code 0
四、函数的_doc_属性:
函数内第一次未赋值给任何变量的字符串是此函数的文档字符串
此字符串会自动赋值给函数的_doc_属性
示例:
def cba():
"这是一个文档字符串" #这是一个表明没有赋值给任何变量的字符串
pass #我们知道函数就是一个对象,对应着函数对象有一个叫_doc_的属性
#会将这个字符串赋值给对象的_doc_属性
print(cba.__doc__) #这是一个文档字符串
执行结果:
这是一个文档字符串
五、函数定义的完整语法:
[@装饰器1]
[@装饰器2]
[…]
def 函数名([位置形参],[*元组形参],[命名关键字形参],[**字典形参]):
“文档字符串”
语句块