您的位置:

关于不懂python装饰器的信息

本文目录一览:

不学会装饰器,面试不敢说自己会Python

本文章出自【 码同学软件测试 】

码同学公众号:自动化软件测试

码同学抖音号: 小码哥聊软件测试

装饰器

Python的装饰器 是面试常被问到的问题之一,如果你的简历里描述 会Python .那么大概率会被问到.

那么我们应该怎么回答这个问题呢?

这里我从几个角度来解释装饰器的作用,大家可以挑选符合自己的说法

Python中的装饰器,本质上就是一个高阶 函数 ,这里高阶函数指定就是" 一个返回值是函数的函数 "

在python中使用装饰器,有两个组成部分.

①@符号调用装饰器

②定义被装饰的方法

范例如下:

@装饰器名字

定义被装饰的函数

@logger

def func():

pass

装饰器可以在不修改函数的情况下,增加额外的功能.这是官方给 装饰器 的定义

实际上我们会把一些业务功能之外的,附属需求用装饰器来实现.比如:为我们的函数添加 日志记录 , 性能监控器 , 埋点计数器 .大家也都知道,修改写好的函数是非常麻烦并且容易出错的一件事.所以很适合" 在不修改函数内部代码的前提下,为它包装一些额外的功能 "也就是装饰器

staticmethod 用来修饰类中的方法,使得该方法可以直接用类名访问,如cls.foo()。

classmethod 和staticmehod类似,区别在于staticmethod,classmethod会将class传入被修饰的方法中

class A(object):

a = 1

def __init__ ( self ):

self .a = 2

@staticmethod

def foo1():

print A.a

@classmethod

def foo2(cls):

print "class a is" , cls.a

print "instance a is" , cls().a

免费领取 码同学软件测试 课程笔记+超多学习资料+完整视频+最新面试题,可以 转发文章 + 私信「码同学666」获取资料哦

property 可以将属性的访问和赋值用函数来实现,从而可以在函数里添加参数检查等一些功能,同时外部使用时访问和赋值的方式并不发生变化。注意访问和赋值的方法名是一样的

class A(object):

def __init__( self ):

self .__count = 0

@property

def count( self ):

return self .__count

@count .setter

def count( self , value):

if not isinstance(value, int):

raise ValueError ( 'count must be an integer!' )

self .__count = value

a = A()

print a.count

a.count = 1

print a.count

a.count = "a" # raise ValueError

functools.wraps 用在装饰器的代码里。可以把原始函数的 name 等属性复制到wrapper()函数中,这样就可以获取到真实函数的 name 属性,而不是wrapper

import functools

def log(text):

def decorator(func):

@functools.wraps (func)

def wrapper( * args, ** kw):

print '%s %s():' % (text, func. __name__ )

return func( * args, ** kw)

return wrapper

return decorator

#!/anaconda3/envs/FEALPy/bin python3.7

# -*- coding: utf-8 -*-

# ---

# @File: 装饰器语法.py

# @Author: Bull

# ---

# 定义装饰器函数

# 1.简单装饰器范例

def logger(func):#在python里,一切都是对象

def wrapper(*args,**kw):

print("进入装饰器函数了")

func(*args,**kw)#真正的函数在装饰器重新调用

func(*args, **kw)

print("装饰器功能执行完毕")

return wrapper

@logger#=logger(add)

def add(x,y):

print('进入被修饰的函数')

print(f'{x}+{y}={x+y}')

# add(1,2)

# 2.带参数的装饰器

def say_hello(contry):

def wrapper(func):

def second(*args,**kw):

if contry == 'china':

print("来自装饰器的‘你好’")

elif contry == 'america':

print('来自装饰器的"hello"')

else:

return

func(*args,**kw)

return second

return wrapper

@say_hello('america')

def american():

print("I am from America")

@say_hello('china')

def china():

print('我来自中国')

american()

print('*'*30)

china()

END

本文著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

什么是Python装饰器

装饰器(decorator)是Python中的高级语法。装饰的意思就是动态扩展被装饰对象的功能。装饰器可以用于装饰函数、方法和类。

一 嵌套函数

# 定义一个外层函数def foo(): # 定义了一个内部函数 def bar(): print("hello world")

函数bar是一个定义在foo函数内部的函数。

Python中的函数是支持嵌套的,也就是可以在一个函数内部再定义一个函数。

然后,我们还知道函数是可以当作变量的,于是我们就可以在foo函数中把定义的这个bar函数返回。就像下面这样:

# 定义一个外层函数def foo(): # 定义了一个内层函数 def bar(): print("hello world") return

barfunc = foo()func() # func -- bar,这里执行func其实就相当于执行了在foo函数内部定义的bar函数

二 闭包形态1

# 闭包形态1def foo(): name = "Andy" # 外部函数的局部变量 # 定义了一个内部函数 def bar():

print(name) # 虽然bar函数中没有定义name变量,但是它可以访问外部函数的局部变量name return barfunc =

foo()func() # func -- bar -- 除了是一个函数,还包含一个值(它外层函数的局部变量)的引用

三 闭包形态2

# 闭包形态2def foo(name): # 给一个函数传参也相当于给函数定义了一个局部变量 # 定义了一个内部函数 def bar():

print(name) # 内部函数同样可以获取到传到外部函数的变量(参数) return barfunc = foo("Andy") #

把“Andy”当成参数传入foo函数 -- 其内部定义的bar函数也能拿到这个“Andy”func() # func -- bar --

除了是一个函数,还包含一个值(它外层函数的参数)的引用

四 装饰器形态1

# 还是定义一个外层函数def foo(name): # 我接收的参数是一个函数名 # 定义了一个内部函数 def bar():

print("这是新功能。。。") # 新功能 name() # 函数名加()就相当于执行-- 我传进来原函数的函数名,这里就相当于执行了原函数

return bar# 定义一个被装饰的函数def f1(): print("hello world.") # 用foo函数装饰f1函数f1 =

foo(f1)# 不改变f1的调用方式f1() # -- 此时函数已经扩展了新功能

五 装饰器形态2

# 还是定义一个外层函数def foo(name): # 接收的参数是一个函数名 # 定义了一个内部函数 def bar():

print("这是新功能。。。") # 新功能 name() # 函数名加()就相当于执行-- 传进来原函数的函数名,这里就相当于执行了原函数

return bar# 定义一个被装饰的函数# 用foo函数装饰f1函数@foo # 使用f1 =

foo(f1)语法装饰的话稍显啰嗦,Python就提供了@语法,让装饰过程更简便def f1(): print("hello world.") #

不改变f1的调用方式f1() # -- 此时函数已经扩展了新功能。

python装饰器听了N次也没印象,读完这篇你就懂了

装饰器其实一直是我的一个"老大难"。这个知识点就放在那,但是拖延症。。。

其实在平常写写脚本的过程中,这个知识点你可能用到不多

但在面试的时候,这可是一个高频问题。

所谓的装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改。

这一句话理解起来可能没那么轻松,那先来看一个"傻瓜"函数。

放心,绝对不是"Hello World"!

怎么样,没骗你吧? 哈哈,这个函数不用运行相信大家都知道输出结果: "你好,装饰器" 。

那如果我想让 hello() 函数再实现个其他功能,比如多打印一句话。

那么,可以这样"增强"一下:

运行结果:

很显然,这个"增强"没啥作用,但是可以帮助理解装饰器。

当运行最后的 hello() 函数时,调用过程是这样的:

那上述代码里的 my_decorator() 就是一个装饰器。

它改变了 hello() 的行为,但是并没有去真正的改变 hello()函数 的内部实现。

但是,python一直以"优雅"被人追捧,而上述的代码显然不够优雅。

所以,想让上述装饰器变得优雅,可以这样写:

这里的 @my_decorator 就相当于旧代码的 hello = my_decorator(hello) , @ 符号称为语法糖。

那如果还有其他函数也需要加上类似的装饰,直接在函数的上方加上 @my_decorator 就可以,大大提高函数

的重复利用与可读性。

输出:

上面的只是一个非常简单的装饰器,但是实际场景中,很多函数都是要带有参数的,比如hello(people_name)。

其实也很简单,要什么我们就给什么呗,直接在对应装饰器的 wrapper() 上,加上对应的参数:

输出:

但是还没完,这样虽然简单,但是随之而来另一个问题:因为并不是所有函数参数都是一样的,

当其他要使用装饰器的函数参数不止这个一个肿么办?比如:

没关系,在python里, *args 和 **kwargs 表示接受任意数量和类型的参数,所以我们可以这样

写装饰器里的 wrapper() 函数:

同时运行下 hello("老王") ,和 hello3("张三", "李四") ,看结果:

上面2种,装饰器都是接收外来的参数,其实装饰器还可以接收自己的参数。

比如,我加个参数来控制下装饰器中打印信息的次数:

注意,这里 count 装饰函数中的2个 return .

运行下,应该会出现3次:

现在多做一步 探索 ,我们来打印下下面例子中的hello()函数的元信息:

输出:

这说明了,它不再是以前的那个 hello() 函数,而是被 wrapper() 函数取代了。

如果我们需要用到元函数信息,那怎么保留它呢?这时候可以用内置装饰器 @functools.wrap 。

运行下:

好记性不如烂笔头,写一下理解一下会好很多。

下面还分享类的装饰器,以及装饰器所用场景。

Python笔记:Python装饰器

装饰器是通过装饰器函数修改原函数的一些功能而不需要修改原函数,在很多场景可以用到它,比如① 执行某个测试用例之前,判断是否需要登录或者执行某些特定操作;② 统计某个函数的执行时间;③ 判断输入合法性等。合理使用装饰器可以极大地提高程序的可读性以及运行效率。本文将介绍Python装饰器的使用方法。

python装饰器可以定义如下:

输出:

python解释器将test_decorator函数作为参数传递给my_decorator函数,并指向了内部函数 wrapper(),内部函数 wrapper() 又会调用原函数 test_decorator(),所以decorator()的执行会先打印'this is wrapper',然后打印'hello world', test_decorator()执行完成后,打印 'bye' ,*args和**kwargs,表示接受任意数量和类型的参数。

装饰器 my_decorator() 把真正需要执行的函数 test_decorator() 包裹在其中,并且改变了它的行为,但是原函数 test_decorator() 不变。

一般使用如下形式使用装饰器:

@my_decorator就相当于 decorator = my_decorator(test_decorator) 语句。

内置装饰器@functools.wrap可用于保留原函数的元信息(将原函数的元信息,拷贝到对应的装饰器函数里)。先来看看没有使用functools的情况:

输出:

从上面的输出可以看出test_decorator() 函数被装饰以后元信息被wrapper() 函数取代了,可以使用@functools.wrap装饰器保留原函数的元信息:

输出:

装饰器可以接受自定义参数。比如定义一个参数来设置装饰器内部函数的执行次数:

输出:

Python 支持多个装饰器嵌套:

装饰的过程:

顺序从里到外:

test_decorator('hello world') 执行顺序和装饰的过程相反。

输出:

类也可以作为装饰器,类装饰器主要依赖__call__()方法,是python中所有能被调用的对象具有的内置方法(python魔术方法),每当调用一个类的实例时,__call__()就会被执行一次。

下面的类装饰器实现统计函数执行次数:

输出:

下面介绍两种装饰器使用场景

统计函数执行所花费的时间

输出:

在使用某些web服务时,需要先判断用户是否登录,如果没有登录就跳转到登录页面或者提示用户登录:

--THE END--