专栏首页未闻CodePython 装饰器装饰类中的方法

Python 装饰器装饰类中的方法

目前在中文网上能搜索到的绝大部分关于装饰器的教程,都在讲如何装饰一个普通的函数。本文介绍如何使用Python的装饰器装饰一个类的方法,同时在装饰器函数中调用类里面的其他方法。本文以捕获一个方法的异常为例来进行说明。

有一个类Test, 它的结构如下:

class Test(object):
    def __init__(self):
        pass

    def revive(self):
        print('revive from exception.')        # do something to restore

    def read_value(self):
        print('here I will do something.')        # do something.

在类中有一个方法read_value(),这个方法在多个地方被调用。由于某些原因,方法read_value有可能随机抛出Exception导致程序崩溃。所以需要对整个方法做try ... except处理。最丑陋的做法如下面的代码所示:

class Test(object):
    def __init__(self):
        pass

    def revive(self):
        print('revive from exception.')        # do something to restore

    def read_value(self):
        try:
            print('here I will do something.')            # do something.
        except Exception as e:
            print(f'exception {e} raised, parse exception.')            # do other thing.
            self.revive()

这样写虽然可以解决问题,但是代码不Pythonic。

使用装饰器来解决这个问题,装饰器函数应该写在类里面还是类外面呢?答案是,写在类外面。那么既然写在类外面,如何调用这个类的其他方法呢?

首先写出一个最常见的处理异常的装饰器:

def catch_exception(origin_func):
    def wrapper(*args, **kwargs):
        try:
            u = origin_func(*args, **kwargs)            return u        except Exception:            return 'an Exception raised.'
    return wrapperclass Test(object):
    def __init__(self):
        pass

    def revive(self):
        print('revive from exception.')        # do something to restore

    @catch_exception
    def read_value(self):
        print('here I will do something.')        # do something.

这种写法,确实可以捕获到origin_func()的异常,但是如果在发生异常的时候,需要调用类里面的另一个方法来处理异常,这又应该怎么办?答案是给wrapper增加一个参数:self.

代码变为如下形式:

def catch_exception(origin_func):
    def wrapper(self, *args, **kwargs):
        try:
            u = origin_func(self, *args, **kwargs)            return u        except Exception:
            self.revive() #不用顾虑,直接调用原来的类的方法
            return 'an Exception raised.'
    return wrapperclass Test(object):
    def __init__(self):
        pass

    def revive(self):
        print('revive from exception.')        # do something to restore

    @catch_exception
    def read_value(self):
        print('here I will do something.')        # do something.

只需要修改装饰器定义的部分,使用装饰器的地方完全不需要做修改。

下图为正常运行时的运行结果:

下图为发生异常以后捕获并处理异常:

通过添加一个self参数,类外面的装饰器就可以直接使用类里面的各种方法,也可以直接使用类的属性。

本文分享自微信公众号 - 未闻Code(itskingname),作者:kingname

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-04-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一日一技:在Python中,调用对象不存在的方法时自定义提示信息

    现在,我实例化这个类,并调用它的 play方法,由于这个方法不存在,所以现在必定导致报错,如下图所示。

    青南
  • 我为什么要创建一个不能被实例化的类

    Python 由于多继承的原因,可能会出现钻石继承[1]又叫菱形继承。为了保留多继承的优点,但又摒除缺点,于是有了混入这种编程模式。

    青南
  • 一日一技:跟着Kenneth Reitz大神学习读取类属性的三种方法

    在看Kenneth Reitz大神的Records项目时,注意到在Readme中,读取数据有三种写法:

    青南
  • JS魔法堂: Native Promise Only源码剖析

    一, 前言                                深入学习Promise的朋友应该都看过<深入理解Promise五部曲>这一系列的文章,...

    ^_^肥仔John
  • python入门到放弃(三)-基本数据类型之int整数和bool值

    #整数可以进行的操作有:bit_length(),计算整数在内存中占用的二进制码的长度

    guoke-boy
  • python 元类做类型检查

    class NoMixedCaseMeta(type): def new(cls, clsname, bases, clsdict): for name i...

    用户5760343
  • 史上最全 Python 面向对象编程

    在多函数程序中,许多重要的数据被放置在全局数据区,这样它们可以被所有的函数访问。每个函数都可以具有它们自己的局部数据,将某些功能代码封装到函数中,日后便无需重复...

    马哥linux运维
  • 史上最全Python面向对象编程 转

    在多函数程序中,许多重要的数据被放置在全局数据区,这样它们可以被所有的函数访问。每个函数都可以具有它们自己的局部数据,将某些功能代码封装到函数中,日后便无需重复...

    双面人
  • Python:一文读懂如何使用面向对象编程

    在多函数程序中,许多重要的数据被放置在全局数据区,这样它们可以被所有的函数访问。每个函数都可以具有它们自己的局部数据,将某些功能代码封装到函数中,日后便无需重复...

    MySQL轻松学
  • 文本计算器

    超级大猪

扫码关注云+社区

领取腾讯云代金券