这是一个类似于如何在每次方法调用之后隐式调用方法?的问题,但对于python而言
假设我有一个带有一些属性的爬虫类(例如,self.db)和一个crawl_1(self, *args, **kwargs),另一个save_to_db(self, *args, **kwargs)将爬行结果保存到数据库(self.db) )。
我想让save_to_db在每个crawl_1, crawl_2, etc.调用之后运行。我试着把它作为一个“全局”的util装饰器,但是我不喜欢这样的结果,因为它涉及到将self作为一个参数传递。
发布于 2016-04-21 13:22:15
如果您想在所有crawl_*方法之后隐式运行一个方法,最简单的解决方案可能是设置一个元类,该元类将以编程方式为您包装这些方法。从这个开始,一个简单的包装函数:
import functools
def wrapit(func):
@functools.wraps(func)
def _(self, *args, **kwargs):
func(self, *args, **kwargs)
self.save_to_db()
return _这是一个包装func的基本装饰器,在调用func之后调用self.save_to_db()。现在,我们设置了一个元类,它将以编程方式应用于特定的方法:
class Wrapper (type):
def __new__(mcls, name, bases, nmspc):
for attrname, attrval in nmspc.items():
if callable(attrval) and attrname.startswith('crawl_'):
nmspc[attrname] = wrapit(attrval)
return super(Wrapper, mcls).__new__(mcls, name, bases, nmspc)这将迭代包装类中的方法,查找以crawl_开头的方法名称,并使用我们的装饰器函数包装它们。
最后,包装类本身,它将Wrapper声明为元类:
class Wrapped (object):
__metaclass__ = Wrapper
def crawl_1(self):
print 'this is crawl 1'
def crawl_2(self):
print 'this is crawl 2'
def this_is_not_wrapped(self):
print 'this is not wrapped'
def save_to_db(self):
print 'saving to database'鉴于以上所述,我们得到以下行为:
>>> W = Wrapped()
>>> W.crawl_1()
this is crawl 1
saving to database
>>> W.crawl_2()
this is crawl 2
saving to database
>>> W.this_is_not_wrapped()
this is not wrapped
>>> 您可以看到,我们的save_to_database方法是在crawl_1和crawl_2的每个后面调用的(而不是在this_is_not_wrapped之后)。
以上内容适用于Python 2。在Python 3中,复制以下内容:
class Wrapped (object):
__metaclass__ = Wrapper通过以下方式:
class Wrapped (object, metaclass=Wrapper):发布于 2016-04-21 13:13:58
就像这样:
from functools import wraps
def my_decorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
print 'Calling decorated function'
res = f(*args, **kwargs)
obj = args[0] if len(args) > 0 else None
if obj and hasattr(obj, "bar"):
obj.bar()
return wrapper
class MyClass(object):
@my_decorator
def foo(self, *args, **kwargs):
print "Calling foo"
def bar(self, *args, **kwargs):
print "Calling bar"
@my_decorator
def example():
print 'Called example function'
example()
obj = MyClass()
obj.foo()它将为您提供以下输出:
Calling decorated function
Called example function
Calling decorated function
Calling foo
Calling bar发布于 2016-04-21 13:28:38
Python中的装饰器如下所示,它是一个以单个方法为参数的方法,并返回另一个包装器方法,该方法将被调用,而不是修饰的方法。通常包装器“包装”修饰的方法,即在执行其他一些操作之前/之后调用它。
示例:
# define a decorator method:
def save_db_decorator(fn):
# The wrapper method which will get called instead of the decorated method:
def wrapper(self, *args, **kwargs):
fn(self, *args, **kwargs) # call the decorated method
MyTest.save_to_db(self, *args, **kwargs) # call the additional method
return wrapper # return the wrapper method现在学习如何使用它:
class MyTest:
# The additional method called by the decorator:
def save_to_db(self, *args, **kwargs):
print("Saver")
# The decorated methods:
@save_db_decorator
def crawl_1(self, *args, **kwargs):
print("Crawler 1")
@save_db_decorator
def crawl_2(self, *args, **kwargs):
print("Crawler 2")
# Calling the decorated methods:
my_test = MyTest()
print("Starting Crawler 1")
my_test.crawl_1()
print("Starting Crawler 1")
my_test.crawl_2()这将产生以下结果:
Starting Crawler 1
Crawler 1
Saver
Starting Crawler 1
Crawler 2
Saver看到在ideone.com上运行的代码
https://stackoverflow.com/questions/36770310
复制相似问题