首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何获得一个名为“装饰师”的方法?在每个对象方法之后

如何获得一个名为“装饰师”的方法?在每个对象方法之后
EN

Stack Overflow用户
提问于 2016-04-21 12:56:07
回答 3查看 1.8K关注 0票数 1

这是一个类似于如何在每次方法调用之后隐式调用方法?的问题,但对于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作为一个参数传递。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-04-21 13:22:15

如果您想在所有crawl_*方法之后隐式运行一个方法,最简单的解决方案可能是设置一个元类,该元类将以编程方式为您包装这些方法。从这个开始,一个简单的包装函数:

代码语言:javascript
复制
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()。现在,我们设置了一个元类,它将以编程方式应用于特定的方法:

代码语言:javascript
复制
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声明为元类:

代码语言:javascript
复制
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'

鉴于以上所述,我们得到以下行为:

代码语言:javascript
复制
>>> 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_1crawl_2的每个后面调用的(而不是在this_is_not_wrapped之后)。

以上内容适用于Python 2。在Python 3中,复制以下内容:

代码语言:javascript
复制
class Wrapped (object):
    __metaclass__ = Wrapper

通过以下方式:

代码语言:javascript
复制
class Wrapped (object, metaclass=Wrapper):
票数 6
EN

Stack Overflow用户

发布于 2016-04-21 13:13:58

就像这样:

代码语言:javascript
复制
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()

它将为您提供以下输出:

代码语言:javascript
复制
Calling decorated function
Called example function
Calling decorated function
Calling foo
Calling bar
票数 0
EN

Stack Overflow用户

发布于 2016-04-21 13:28:38

Python中的装饰器如下所示,它是一个以单个方法为参数的方法,并返回另一个包装器方法,该方法将被调用,而不是修饰的方法。通常包装器“包装”修饰的方法,即在执行其他一些操作之前/之后调用它。

示例:

代码语言:javascript
复制
# 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

现在学习如何使用它:

代码语言:javascript
复制
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()

这将产生以下结果:

代码语言:javascript
复制
Starting Crawler 1
Crawler 1
Saver
Starting Crawler 1
Crawler 2
Saver

看到在ideone.com上运行的代码

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36770310

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档