这个问题与How to call a method implicitly after every method call?类似,但对于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
作为参数。
答案 0 :(得分:6)
如果要在所有crawl_*
方法之后隐式运行方法,最简单的解决方案可能是设置一个以编程方式为您包装方法的元类。从这开始,一个简单的包装函数:
import functools
def wrapit(func):
@functools.wraps(func)
def _(self, *args, **kwargs):
func(self, *args, **kwargs)
self.save_to_db()
return _
这是一个包装func
,召唤的基本装饰者
致电self.save_to_db()
后func
。现在,我们建立了一个元类
这将以编程方式将其应用于特定方法:
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):
答案 1 :(得分:0)
这样的事情:
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
答案 2 :(得分:0)
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