前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python基础三

python基础三

作者头像
不断折腾
发布2019-09-23 10:24:40
3450
发布2019-09-23 10:24:40
举报

一、揭开函数名的真实面目

我们创建一个函数给的命名实际是代表一个内存地址,加上括号才会运行函数中的函数体,如果不加括号,可以自己试一下,输出的是一个内存地址,这样看来,他实际上他和一个变量差不多,只不过函数代表了一个功能,因此函数也可以作为参数传入函数,也可以作为返回值返回。

二、函数嵌套(函数中的函数)

def zhangsan():

def lisi():

print("我是lisi")

print("我是zhangsan")

lisi()

zhangsan()

当我们在zhangsan函数中没有调用lisi时,我是lisi是不会输出的。只有在调用的时候才会输出。以上只是2级嵌套,你可以像列表一样,多次嵌套。

注意:在嵌套函数中我们内部需要修改外部的变量时不能使用关键字global,

global影响的是函数外的全局变量。需要使用nonlocal(python3中),例如:

age =111

def zhangsan():

age = 18

def lisi():

nonlocal age

age +=1

print("lisi的年龄为",age)

print("zhangsan的年龄为",age)

lisi()

zhangsan()

print("age:",age)

我们运行一下会发现,age并没有影响到函数(zhangsan外)的age。如果换成global,就会影响到全局变量。

三、闭包

例如一个简单的闭包:

def zhangsan():

age = 18

def lisi():

print(age)

return lisi

闭包的概念:首先它是一个嵌套函数,其次在内部函数中引用了外部函数的变量,我们称这是一个闭包。

其次我们为什么要以返回值的形式返回lisi,我们可以想一下,如果我们只想用到lisi这个函数,如果我们用二中的方法,每次调用zhangsan,那么每次都要走一遍zhangsan,这显然不是我们想要的,因此,我们如果只想调用lisi可以这样写:wangwu = zhangsan()#此时wangwu代表的就是lisi的内存地址,但并没有去执行它。wangwu()#这样就实现调用lisi这个内部函数,并且可以引用到zhangsan中age这个变量。

四、装饰器

4.1普通装饰器

首先,思考一个问题,我们进入一个网页,再点击个人信息,会提醒需要登录才能查看,那么需要我们登录的页面很多,每次都调用很麻烦,所有就有了装饰器。

它需要遵循一个原则:开放封闭原则

开放:就是说要有利于扩展新的功能,比如更新的时候。

封闭:在扩展新功能的时候,不能修改原来的代码。

例如:

def login():

print("登录")

def func():

print("点击个人信息")

A写好登录,B写好个人信息,C想要调用个人信息他不会去想着调用登录,B需要将这两个功能结合起来,但是不能修改原来的功能,于是就有了:

def login(func):

print("登录")

def log():

func()

return log


def func():

print("点击个人信息")

func = login(func)

f()

用闭包的知识可以解决这个问题,func这个方法就叫做装饰器。但是一想要加上func = login(func)这样我们就调用的不是原来的函数名了,于是乎就有了:

def login(func):

print("登录")

def log():

func()

return log

@login

def func():

print("点击个人信息")

func()

利用在该函数上方添加一个@加函数名代替func = login(func)。我们称它为语法糖,嗯,真甜。

现在调用func就相当于调用login了,但是当func函数有返回值的时候,我们按照上述写法就获取不到了,因此修改成:

def login(func):

print("登录")

def log():

ret = func()

return ret

return log

@login

def func():

print("点击个人信息")

return "ok"

print(func())

总结:当我们执行到func()的时候,会跳到@login,@login相当于执行func = login(func),此时就执行login函数了。执行后的结果返回给func,此时func得到的值就是ok的内存地址,再回到func(),便会输出ok。

问题来了:

当我们新添加的功能,也就是func函数需要一个参数时候在装饰器函数中如何添加?下一个功能也可能需要这个装饰器需要二个参数该怎么办?也是就我们的参数是动态的,那就添加动态参数掰,将login函数修改成:

def login(func):

print("登录")

def log(*args,**kwargs):

ret = func(*args,**kwargs)

return ret

return log

此时无论添加几个都不会受到影响。

4.2带参数的装饰器

首先如果我们添加一个参数@login(True),当有参数时,我们将@和login(True)拆开看,login(True)得到返回值log函数的内存地址也就是@log,显然我们的func放在哪里呢?显然会报错,于是我们可以在外再嵌套一层变成:

def log_out(F):

def login(func):

print("登录")

def log(*args,**kwargs):

if F==True:

ret = func(*args,**kwargs)

return ret

else:

return "NO"

return log

return login

@log_out(True)

def func():

print("点击个人信息")

return "ok"

print(func())

这样再按照之前的理解方式就明白了,log_out(True)表示login也就是@login,

我们只是在原来的基础上添加了一个开关,也就是说当装饰器带参数时,就需要三层嵌套了。

4.3 一个函数使用多个装饰器

def zhangsan1(fun1):

def lisi1(*args,**kwargs):

print("执行被装饰函数前111111")

fun1(*args,**kwargs)

print("执行被装饰函数后111111")

return lisi1

def zhangsan2(fun2):

def lisi2(*args,**kwargs):

print("执行被装饰函数前222222")

fun2(*args,**kwargs)

print("执行被装饰函数后222222")

return lisi2

@zhangsan1

@zhangsan2 #zhangsan3 = zhangsan2(zhangsan3 )

def zhangsan3():

print("我是被装饰的函数333333")

zhangsan3()

执行的结果:

执行被装饰函数前111111

执行被装饰函数前222222

我是被装饰的函数333333

执行被装饰函数后222222

执行被装饰函数后111111

执行顺序:首先当调用zhangsan3的时候,先执行@zhangsan2,@zhangsan2等同于zhangsan3 = zhangsan2(zhangsan3)也就是返回了lisi2,然后执行@zhangsan1,@zhangsan1等同于zhangsan3 = zhangsan1(lisi2)注意,带入的函数变成了lisi2,而不是zhangsan3,也就返回lisi1,接下来再加上一个括号执行,也就是执行lisi1中的第一句。#执行被装饰函数前111111,接着fun1()也就是lisi2(),就会输出#执行被装饰函数前222222,回到zhangsan2后,带入的参数又变成了zhangsan3,所以输出了#我是被装饰的函数333333,接着输出执行被装饰函数后222222,然后再回到最初调用的地方输出#执行被装饰函数后111111。。。。

可能也不知道我再说撒,。。。。。。。你也可以暂时记住这个顺序,

你也可以使用pycharm打上断点,看一遍执行顺序就会明白。

写的快吐血,溜了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-09-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 python入门到放弃 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档