专题10 如何应对面试官的拷问—你了解python的装饰器吗?_python的装饰器面试如何回答

本文详细探讨了Python中的装饰器、闭包概念,以及如何创建带参数的高级装饰器。作者通过实例展示了装饰器如何修改函数的行为,并介绍了如何确保装饰后函数的__name__属性不变。
摘要由CSDN通过智能技术生成
inner()

outer() #输出结果 2


如果我们在外函数里不直接调用内函数,而是通过return inner返回一个内函数的引用 这时会发生什么呢? 你将会得到一个内函数对象,而不是运行结果。



def outer():
x = 1
def inner():
y = x + 1
print(y)
return inner

outer() # 输出<function outer..inner at 0x039248E8>
f1 = outer()
f1() # 输出2


上述这个案例比较简单,因为outer和inner函数都是没有参数的。我们现在对上述代码做点改动,加入参数。你可以看到外函数的参数或变量可以很容易传递到内函数。



def outer(x):
a = x

def inner(y):
    b = y
    print(a+b)

return inner

f1 = outer(1) # 返回inner函数对象
f1(10) # 相当于inner(10)。输出11


如果上例中外函数的变量x换成被装饰函数对象(func),内函数的变量y换成被装饰函数的参数,我们就可以得到一个通用的装饰器啦(如下所示)。你注意到了吗? 我们在没对func本身做任何修改的情况下,添加了其它功能, 从而实现了对函数的装饰。



def decorator(func):
def inner(*args, **kwargs):
add_other_actions()
return func(*args, **kwargs)
return inner


##### 闭包


[专题四:python之作用域和闭包详解]( )


#### 面试中的装饰器


##### 通用的装饰器


面试官往往会给你提一些简单的需求,如返回被装饰函数执行时间,函数的名称等,这时候要学会灵活的转变。



def hint(func):
def wrapper(*args, **kwargs):
print(‘{} is running’.format(func.name))
return func(*args, **kwargs)
return wrapper

@hint
def hello():
print(“Hello!”)



> 
> **执行结果**  
>  **调用:** hello()  
>  hello is running.  
>  Hello!  
>  值得一提的是被装饰器装饰过的函数看上去名字没变,其实已经变了。当你运行**print(hello.**name**)** 后,你会发现它的名字已经悄悄变成了wrapper,这显然不是我们想要的。这一点也不奇怪,因为外函数返回的是由wrapper函数和其外部引用变量组成的闭包。  
>  ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201211095412663.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NTgxOTYx,size_16,color_FFFFFF,t_70)  
>  为了解决这个问题保证装饰过的函数\_\_name\_\_属性不变,我们可以使用functools模块里的wraps方法,先对func变量进行wraps。下面这段代码可以作为编写一个通用装饰器的示范代码,注意收藏哦。
> 
> 
> 



from functools import wraps

def hint(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(‘{} is running’.format(func.name))
return func(*args, **kwargs)
return wrapper

@hint
def hello():
print(“Hello!”)


如果你非常的熟悉上面的这些内容,你就可以轻松的写一个通用的装饰器。


##### 带参的高级装饰器


前面几个装饰器一般是内外两层嵌套函数。如果我们需要编写的装饰器本身是带参数的,我们需要编写三层的嵌套函数,其中最外一层用来传递装饰器的参数。现在我们要对@hint装饰器做点改进,使其能通过@hint(coder=“LeooO”)传递参数。该装饰器在函数运行前给出提示的时候还显示函数编写人员的名字。完整代码如下所示:



from functools import wraps

def hint(coder):
def wrapper(func):
@wraps(func)
def inner_wrapper(*args, **kwargs):
print(‘{} is running’.format(func.name))
print(‘Coder: {}’.format(coder))
return func(*args, **kwargs)
return inner_wrapper
return wrapper

@hint(coder=“LeooO”)
def hello():
print(“Hello!”)


##### 多个装饰器


先看一段代码



def d1(f):
def inner1(*args, **kwargs):
print(1)
f()
print(“我是外边的装饰器”)
return inner1
def d2(f):
def inner2(*args, **kwargs):
print(2)
print(f.name)
f()
print(“我是里边的装饰器”)
return inner2
@d1
@d2
def func():
print(‘哈哈哈’)
func()

执行结果是啥呢?



> 
> 2  
>  1  
>  func  
>  哈哈哈  
>  我是里边的装饰器  
>  我是外边的装饰器
> 
> 
> 


这是咋回事呢?我换种写法你思考一下。



def d1(f):
def inner1(*args, **kwargs):
print(2)
f()
print(“我是外边的装饰器”)

return inner1

def d2(f):
def inner2(*args, **kwargs):
print(1)
print(f.name)
f()
print(“我是里边的装饰器”)

return inner2

def func():
print(‘哈哈哈’)
res = d1(d2(func))


如果你还是不明白,没有关系,再来一段代码



from functools import wraps
def A(funE_decorated_by_C):
@wraps(funE_decorated_by_C)
def redecorated_E(str):
print(“开始执行”, end=“——>”)
return funE_decorated_by_C(str) + ’ > redecorated by A’
return redecorated_E
def C(funE):
@wraps(funE)
def decorated_E(str):
return funE(str) + ’ > decorated by C’
return decorated_E
@A
@C
def E(str):
return str
print(E('A string is '))
print(E.name)


**#开始执行——>A string is > decorated by C > redecorated by A**


**难理解的地方在C和A在装饰过程中执行的调用关系**


* **可以看到,先调用那个装饰器,那个装饰器就先运行**  
 print(“开始执行”, end="——>")
* **继续执行 A装饰的是C(A) 即funE\_decorated\_by\_C**  
 调用 funE\_decorated\_by\_C 执行C
* **C执行 调用E函数 返回的结果作为A funE\_decorated\_by\_C的参数**
* **最终在A中调用E 返回 A**


**案例代码**



def decorator_b(fun):
def inner_b(*args, **kwargs):
print(‘This is inner_b’)
print(“*****”)
# print(fun(*args, **kwargs))
return fun(*args, **kwargs) + 2

return inner_b

def decorator_a(fun):
def inner_a(*args, **kwargs):
print(‘This is inner_a’)
return fun(*args, **kwargs) + 11

最后

🍅 硬核资料:关注即可领取PPT模板、简历模板、行业经典书籍PDF。
🍅 技术互助:技术群大佬指点迷津,你的问题可能不是问题,求资源在群里喊一声。
🍅 面试题库:由技术群里的小伙伴们共同投稿,热乎的大厂面试真题,持续更新中。
🍅 知识体系:含编程语言、算法、大数据生态圈组件(Mysql、Hive、Spark、Flink)、数据仓库、Python、前端等等。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里无偿获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值