python 装饰器2 常用装饰器【@property,@x.setter,@x.deleter】

  1. @classmethod

加入这个装饰器表示第一个参数永远就是self

在stackoverflow看到的直接贴过来,有时候出现类似:required argument **cls** 可能是这个原因

  1. @property

加入这个装饰器表示把一个方法变成属性

1 class Foo:
 2     @property
 3     def AAA(self):
 4         print('get的时候运行我啊')
 5 
 6     @AAA.setter
 7     def AAA(self,value):
 8         print('set的时候运行我啊')
 9 
10     @AAA.deleter
11     def AAA(self):
12         print('delete的时候运行我啊')
13 
14 #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
15 f1=Foo()
16 f1.AAA
17 f1.AAA='aaa'
18 del f1.AAA


  1. @contextlib.contextmanager 或者@contextmanager

由它修饰的方法会有两部分构成,中间由yield关键字分开。
配合【with】语法,在代码块执行前会先执行yield上面的语句;在代码块执行后会再执行yield下面的语句。

import contextlib
import time

@contextlib.contextmanager
def timeit():
    start = time.time()
    print('before yield ')
    yield start                   # 理解 yield start执行完后返回,如果是 res = yield start ,那么赋值操作不会执行
    print('after yield stating')
    end = time.time()
    usedTime = (end - start) * 1000
    print ('Use time %d ms' % usedTime)
    print('after yield ending')

with timeit() as stattime:   # with timeit()  ,注意可以用as的情况
    print('in with staring')
    time.sleep(1)
    print('in with doing something')
    print('in with ending')

'''
结果:
before yield 
in with staring
in with doing something
in with ending
after yield stating
Use time 1000 ms
after yield ending
'''

unittest 中的源码应用:
case.py中的with outcome.testPartExecutor(self) 会触发调用

'''
case.py
'''
with outcome.testPartExecutor(self):
      self._callSetUp()


'''
@contextlib.contextmanager的代码
'''
class _Outcome(object):
    def __init__(self, result=None):
        self.expecting_failure = False
        self.result = result
        self.result_supports_subtests = hasattr(result, "addSubTest")
        self.success = True
        self.skipped = []
        self.expectedFailure = None
        self.errors = []

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, isTest=False):
        old_success = self.success
        self.success = True
        try:
            yield
        except KeyboardInterrupt:
            raise
        except SkipTest as e:
            self.success = False
            self.skipped.append((test_case, str(e)))
        except _ShouldStop:
            pass
        except:
            exc_info = sys.exc_info()
            if self.expecting_failure:
                self.expectedFailure = exc_info
            else:
                self.success = False
                self.errors.append((test_case, exc_info))
            # explicitly break a reference cycle:
            # exc_info -> frame -> exc_info
            exc_info = None
        else:
            if self.result_supports_subtests and self.success:
                self.errors.append((test_case, None))
        finally:
            self.success = self.success and old_success

  1. @six.add_metaclass(MetaClass)

使用方法

import abc
import six

@six.add_metaclass(abc.ABCMeta)
class PluginBase(object):
     
    @abc.abstractmethod
    def func_a(self,data):
        """
        an abstract method need to be implemented
        """

等价于如下

# 简单的说ABCMeta就是让你的类变成一个纯虚类,子类必须实现某个方法,这个方法在父类中用@abc.abstractmethod修饰
import abc
class Base(object,metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def func_a(self,data):
        """
        an abstract method need to be implemented
        """

  1. @property,@x.setter,@x.deleter 使用

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        print("getter of x called")
        return self._x

    @x.setter
    def x(self, value):
        print("setter of x called")
        self._x = value

    @x.deleter
    def x(self):
        print("deleter of x called")
        del self._x


c = C()
c.x = 'foo'  # setter called
foo = c.x    # getter called
del c.x      # deleter called

  1. 缓存装饰器

# 1. 加快计算
from functools import lru_cache

@lru_cache()  # 不加计算慢很多
def task(x):
    time.sleep(0.01)
    return round(math.log(x**3 / 15), 4)
执行:

for i in range(500):
    task(random.randrange(5, 10))


# 2. 我们缓存了从数据库查询的用户信息,下次再调用这个接口时将直接返回用户信息列表而不需要重新执行一遍数据库查询逻辑,可以有效较少IO次数,加快接口反应速度。
@api.route("/user/info", methods=["GET"])
@functools.lru_cache()
@login_require
def get_userinfo_list():
    userinfos = UserInfo.query.all()
    userinfo_list = [user.to_dict() for user in userinfos]
    return jsonify(userinfo_list)
​ 
原文地址:https://www.cnblogs.com/amize/p/14610811.html