python解读器_一篇文章看懂Python装饰器(上)

python的装饰器

看文章你必须了解:python函数的知识

python基础操作

刚学python的时候,对装饰器这个概念很是难理解。在百度和知乎上看过很多大佬的文章,但总没有醍醐灌顶的那种感觉。总是觉得好像懂了些什么,其实又不懂。

所以我决定写篇文章,用我的思路来来帮助看到这篇文章的读者理解python中的装饰器,希望能让大家少踩些坑。

名词解释

我觉得要了解装饰器,首先要明白什么是装饰器,装饰器拿来干嘛用,装饰器为什么这么写。这就是看完这篇文章你能知道的全部装饰器:

从字面上的意思来说,装饰器。起到的是装饰的作用,其实说白了就是给函数加一个新的功能。

他一般长成下面这个样子:

def decorator(f):

def wrapper():

f()

return wrapper

@decorator

function():

some code

return ....

其中decorator就是装饰器了。可能看到这边会有点懵,到后边会慢慢讲闭包:

在我们讲装饰器的时候,要先讲一下闭包。闭包是一种奇特的函数

变量的作用域

wr = 1

def foo():

wr = wr+1

return wr

我创建了一个变量wr,和一个函数foo()。大家看一下在foo函数中是不是能取到函数外的wr变量呢?当然是可以的

然后看下一个例子

def foo():

wr =1

def wrapper():

wr = wr+1

return wr

那么问题来了,在这个foo函数中我嵌套了一个wrapper函数,在wrapper函数中能不能取到在foo函数中的wr变量呢,其实也是可以的

wrapper函数使用到wr这个变量的时候,他先在自己函数内部寻找wr变量,发现没找到之后就会在他的上级,也就是这里的foo函数中寻找,然后他找到了wr = 1。如果foo中也没有找到wr变量的话,还会继续向更上一级寻找。

python中的一切都是对象

然后我们这边要讲一句python中很经典的一句话,就是python中的一切都是对象,其实我们实现的每个函数,都是顶级父类object的子类。这句话看不懂没关系,我们来举例子:

def foo():

print("im foo function!")

fun = foo

大家觉得这段代码对吗,看起来我把foo赋值给了fun,那么fun里面到底是什么呢,我们来print一下吧:

print(fun)

在我加上一个print来把fun输来看到下面的提示。没有报错说明我们的程序没有错,那么输出的是什么呢?

function foo at 一串奇怪的东西,这串奇怪的东西其实是一串16进制的值,是函数foo在内存中的地址。原来我们在代码中打fun = foo

的时候其实是把foo函数的内存地址给了fun啊

那我们想想我们之前是怎么调用foo函数的?

def foo():

print("im foo function!")

foo()

是不是这样,用 foo()来调用。那么我们是不是就可以得出:

def foo():

print("im foo function!")

fun = foo

fun()

这样我们就给foo函数改了个名字变成了fun,大家可以把代码放到pycharm里试试,把fun()和foo()的答案是不是一样的

知道这两样之后,我们可以继续来了解闭包了:

我们先不谈闭包到底是干嘛的,到后面会有演示,我们刚才说过,闭包是一种奇特的函数,那么我们就先搞清楚什么样的函数才能称得上叫做闭包这个名字:闭包函数必须有内嵌函数

内嵌函数需要引用该嵌套函数上一级namespace中的变量

闭包函数必须返回内嵌函数

嗯,达成这三样我们就能创建一个闭包了,那大家和我一起来创建一个吧

闭包函数必须有内嵌函数:

先达成第一件,我们要先有个内嵌函数:

直接抄上面的例子

def foo():

def wrapper():

print("i want have a closure!")

好了好了,现在我有个内嵌函数了,在foo中嵌了个wrapper函数。

内嵌函数需要引用该嵌套函数上一级namespace中的变量

然后第二步其实就是说嵌在里面的那个函数要引用外面那个函数里面的一个变量才行。那这个简单啊,我可以

def foo():

a = 1

def wrapper():

a = a+1

print("i want have a closure!")

嵌套在foo函数中的wrapper函数引用了foo函数中的a变量

嘿嘿,先别管这个函数有什么卵用,我们先来实现一个闭包先,然后我们这样也可以完成第二点:

def foo(a):

def wrapper():

print(a)

然后我们来达成第三步

闭包函数必须返回内嵌函数

这个就更简单了嘛,加个return嘛,但是这里要注意了,是闭包函数返回内嵌函数,也就是说,套在外边的那个函数用return返回套在里面的那个函数的内存地址

也就是foo函数return wrapper函数的内存地址

def foo(a):

def wrapper():

print(a)

return wrapper

这样我们就亲手创建了一个闭包,下面我们就要讲讲什么时候我们会用到闭包了:

用途解释

首先我们来假象一个需求,我们要创建两个个函数foo、bar foo函数只要做一件事情,print一个hello

bar函数只要做一件事情,print一个world,这个简单啊对不对,大家都会:

def foo():

print("hello")

def bar():

print("world")

好了,这个函数做得不错,大家都采用了这个方案并在很多代码中调用了这个函数。

有一天产品经理过来说要给所有函数加一个功能,打印这个函数的运行时间(mmp,就输出个hello world还要我打印运行时间)。产品经理的小小要求还是要满足的:

import time

def foo():

startTime = time.time()

print("hello")

stopTime = time.time()

print(stopTime - startTime)

def bar():

startTime = time.time()

print("world")

stopTime = time.time()

print(stopTime - startTime)

但是这样虽然成功了,万一有很多函数到时候都要打印运行时间,那岂不是要完蛋。并且这种代码被同行看见会被笑话的,不行不行不行。改一改:

import time

def timeFUN(fun):

startTime = time.time()

fun()

stopTime = time.time()

print(stopTime - startTime)

def foo():

print("hello")

def bar():

print("world")

timeFUN(foo)

写完之后瞬间觉得自己的智商碾压大众,让他们以后要用某个函数想知道运行时间的时候就用timeFUN()函数。

但是!那foo函数和bar函数可能已经上线了,被做成接口已经在很多地方应用了,改了调用方式相当于说要和所有用了foo和bar这两个函数的人都说一次:“接口改了,把那一万行里面的foo函数全部改成timeFUN(foo)”。这当然不行啊,怕是要被其他人打死。得想想其他办法。这个时候我们想到了闭包的移花接木大法,具体操作:

import time

def timeFUN(fun):

def wrapper()

startTime = time.time()

fun()

stopTime = time.time()

print(stopTime - startTime)

return wrapper

def foo():

print("hello")

def bar():

print("world")

foo = timeFUN(foo)

bar = timeFUN(bar)

foo()

很显然timeFUN是一个标准的闭包吧,timeFun返回了wrapper函数的返回地址,这个时候我们把timeFun返回的wrapper函数的返回地址再赋值回foo,是不是有点绕,多看几遍这句话自己敲下代码

经过这一顿骚操作,瞬间完成了需求。

最后,其实python给了我们一个更方便的方法可以偷懒不用写foo = timeFUN(foo)

这种赋值了

最后完美版代码:

import time

def timeFUN(fun):

def wrapper()

startTime = time.time()

fun()

stopTime = time.time()

print(stopTime - startTime)

return wrapper

@timeFUN

def foo():

print("hello")

@timeFUN

def bar():

print("world")

foo()

bar()

是不是和开头的例子很像呢,这就是python的装饰器的基础运用。其实装饰器就是闭包的一种啦。下篇有时间我来讲讲装饰器的高级运用,如果foo这个函数有参数又该怎么办呢?

最后:

文章本来名字叫做python的装饰器(上),写了有三个半月了,拿到了七个赞,心酸酸。换个标题当个标题党看看会不会点赞激增呢?

因为本人的水平有限可能会有许多地方理解和叙述有出入,希望大家能提出来防止我误人子弟。分享是好事,但是如果因为我理解上有问题,将来报道上有了偏差,我可是要负责任的

基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集中的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展中的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值