设计思想解读开源框架怎么写,万字深度解析Python装饰器,你学废了吗,阿里+头条+腾讯大厂Python笔试真题

位置错误的代码


让我们直接看示例代码。

def html_tags(tag_name):

print ‘begin outer function.’

def wrapper_(func):

print “begin of inner wrapper function.”

def wrapper(*args, **kwargs):

content = func(*args, **kwargs)

print “<{tag}>{content}</{tag}>”.format(tag=tag_name, content=content) print ‘end of inner wrapper function.’

return wrapper

print ‘end of outer function’

return wrapper_@html_tags(‘b’)

def hello(name=‘Toby’):

return ‘Hello {}!’.format(name)

hello()

hello()

在装饰器中我在各个可能的位置都加上了 print 语句,用于记录被调用的情况。你知道他们最后打印出来的顺序吗?如果你心里没底,那么最好不要在装饰器函数之外添加逻辑功能,否则这个装饰器就不受你控制了。以下是输出结果:

begin outer function.

end of outer function

begin of inner wrapper function.

end of inner wrapper function.

Hello Toby!< /b >

Hello Toby!< /b >

错误的函数签名和文档


装饰器装饰过的函数看上去名字没变,其实已经变了。

def logging(func):

def wrapper(*args, **kwargs):

“”“print log before a function.”“”

print “[DEBUG] {}: enter {}()”.format(datetime.now(), func.name)

return func(*args, **kwargs)

return wrapper

@logging

def say(something):

“”“say something”“”

print “say {}!”.format(something)

print say.name # wrapper

为什么会这样呢?@等同于这样的写法。

say = logging(say)

logging 其实返回的函数名字刚好是 wrapper ,那么上面的这个语句刚好就是把这个结果赋值给 say , say 的 __name__ 自然也就是 wrapper 了,不仅仅是 name ,其他属性也都是来自 wrapper ,比如 doc , source 等等。

使用标准库里的 functools.wraps ,可以基本解决这个问题。

from functools import wrapsdef logging(func):

@wraps(func)

def wrapper(*args, **kwargs):

“”“print log before a function.”“”

print “[DEBUG] {}: enter {}()”.format(datetime.now(), func.name)

return func(*args, **kwargs)

return wrapper

@logging

def say(something):

“”“say something”“”

print “say {}!”.format(something)

print say.name # say

print say.doc # say something

看上去不错!主要问题解决了,但其实还不太完美。因为函数的签名和源码还是拿不到的。

import inspect

print inspect.getargspec(say) # failed

print inspect.getsource(say) # failed

如果要彻底解决这个问题可以借用第三方包,比如 wrapt 。后文有介绍。

不能装饰@staticmethod 或者 @classmethod”


当你想把装饰器用在一个静态方法或者类方法时,不好意思,报错了。

class Car(object):

def init(self, model):

self.model = model

@logging # 装饰实例方法,OK

def run(self):

print “{} is running!”.format(self.model)

@logging # 装饰静态方法,Failed

@staticmethod

def check_model_for(obj):

if isinstance(obj, Car):

print “The model of your car is {}”.format(obj.model)

else:

print “{} is not a car!”.format(obj)

“”"

Traceback (most recent call last):

File “example_4.py”, line 10, in logging

@wraps(func)

File “C:\Python27\lib\functools.py”, line 33, in update_wrapper

setattr(wrapper, attr, getattr(wrapped, attr))

AttributeError: ‘staticmethod’ object has no attribute ‘module

“”"

前面已经解释了 @ staticmethod 这个装饰器,其实它返回的并不是一个 callable 对象,而是一个 staticmethod 对象,那么它是不符合装饰器要求的(比如传入一个 callable 对象),你自然不能在它之上再加别的装饰器。要解决这个问题很简单,只要把你的装饰器放在 @ staticmethod 之前就好了,因为你的装饰器返回的还是一个正常的函数,然后再加上一个 @ staticmethod 是不会出问题的。

class Car(object):

def init(self, model):

self.model = model

@staticmethod

@logging

def check_model_for(obj):

pass

如何优化你的装饰器


嵌套的装饰函数不太直观,我们可以使用第三方包类改进这样的情况,让装饰器函数可读性更好。

decorator.py


decorator.py是一个非常简单的装饰器加强包。你可以很直观的先定义包装函数 wrapper () ,再使用 decorate ( func , wrapper ) 方法就可以完成一个装饰器。

from decorator import decorate

def wrapper(func, *args, **kwargs):

“”“print log before a function.”“”

print “[DEBUG] {}: enter {}()”.format(datetime.now(), func.name)

return func(*args, **kwargs)

def logging(func):

return decorate(func, wrapper) # 用wrapper装饰func

你也可以使用它自带的 @ decorator 装饰器来完成你的装饰器。

from decorator import decorator

@decorator

def logging(func, *args, **kwargs):

print “[DEBUG] {}: enter {}()”.format(datetime.now(), func.name)

return func(*args, **kwargs)

decorator.py 实现的装饰器能完整保留原函数的 name , doc 和 args ,唯一有问题的就是 inspect.getsource ( func ) 返回的还是装饰器的源代码,你需要改成 inspect.getsource ( func.__wrapped__ ) 。

wrapt


wrapt是一个功能非常完善的包,用于实现各种你想到或者你没想到的装饰器。使用 wrapt 实现的装饰器你不需要担心之前 inspect 中遇到的所有问题,因为它都帮你处理了,甚至 inspect.getsource ( func ) 也准确无误。

import wrapt# without argument in decorator

@wrapt.decorator

def logging(wrapped, instance, args, kwargs): # instance is must

print “[DEBUG]: enter {}()”.format(wrapped.name)

return wrapped(*args, **kwargs)

@logging

def say(something): pass

使用 wrapt 你只需要定义一个装饰器函数,但是函数签名是固定的,必须是 ( wrapped , instance, args, kwargs ) ,注意第二个参数 instance 是必须的,就算你不用它。当装饰器装饰在不同位置时它将得到不同的值,比如装饰在类实例方法时你可以拿到这个类实例。根据 instance 的值你能够更加灵活的调整你的装饰器。另外, args 和 kwargs 也是固定的,注意前面没有星号。在装饰器内部调用原函数时才带星号。

如果你需要使用 wrapt 写一个带参数的装饰器,可以这样写。

def logging(level):

@wrapt.decorator

def wrapper(wrapped, instance, args, kwargs):

print “[{}]: enter {}()”.format(level, wrapped.name)

return wrapped(*args, **kwargs)

return wrapper@logging(level=“INFO”)

def do(work): pass

关于 wrapt 的使用,建议查阅官方文档,在此不在赘述。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img



既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Python开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注Python)
img

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

一、Python所有方向的学习路线

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、学习软件

工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。

三、全套PDF电子书

书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。

四、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

五、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

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

dnimg.cn/img_convert/252731a671c1fb70aad5355a2c5eeff0.png)

六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值