Python装饰器abstractmethod、property、classmethod、staticmethod及自定义装饰器

简介: 总览:@abstractmethod:抽象方法,含abstractmethod方法的类不能实例化,继承了含abstractmethod方法的子类必须复写所有abstractmethod装饰的方法,未被装饰的可以不重写@ property:方法伪装属性,方法返回值及属性值,被装饰方法不能有参数,...
+关注继续查看

总览:

@abstractmethod:抽象方法,含abstractmethod方法的类不能实例化,继承了含abstractmethod方法的子类必须复写所有abstractmethod装饰的方法,未被装饰的可以不重写

@ property:方法伪装属性,方法返回值及属性值,被装饰方法不能有参数,必须实例化后调用,类不能调用

@ classmethod:类方法,可以通过实例对象和类对象调用,被该函数修饰的方法第一个参数代表类本身常用cls,被修饰函数内可调用类属性,不能调用实例属性

@staticmethod:静态方法,可以通过实例对象和类对象调用,被装饰函数可无参数,被装饰函数内部通过类名.属性引用类属性或类方法,不能引用实例属性

案例讲解:


@abstractmethod

用于程序接口的控制,正如上面的特性,含有@abstractmethod修饰的父类不能实例化,但是继承的子类必须实现@abstractmethod装饰的方法

 

# -*- coding:utf-8 -*-


from abc import ABC, abstractmethod


class A(ABC):

    @abstractmethod
    def test(self):
        pass


class B(A):

    def test_1(self):
        print("未覆盖父类abstractmethod")


class C(A):

    def test(self):
        print("覆盖父类abstractmethod")


if __name__ == '__main__':
    a = A()
    b = B()
    c = C()
前两个分别报错如下:
    a = A()
TypeError: Can't instantiate abstract class A with abstract methods test

    b = B()
TypeError: Can'
t instantiate abstract class B with abstract methods test
第三个实例化是正确的

 

@ property

将一个方法伪装成属性,被修饰的特性方法,内部可以实现处理逻辑,但对外提供统一的调用方式,实现一个实例属性的get,set,delete三种方法的内部逻辑,具体含义看示例code。

 

# -*- coding:utf-8 -*-


# -*- coding:utf-8 -*-

class Data:
    def __init__(self):
        self.number = 123

    @property
    def operation(self):
        return self.number

    @operation.setter
    def operation(self, number):
        self.number = number

    @operation.deleter
    def operation(self):
        del self.number


2019-03-17-22_10_03.png


@ classmethod,staticmethod

类方法classmethod和静态方法staticmethod是为类操作准备,是将类的实例化和其方法解耦,可以在不实例化的前提下调用某些类方法。两者的区别可以这么理解:类方法是将类本身作为操作对象,而静态方法是独立于类的一个单独函数,只是寄存在一个类名下。类方法可以用过类属性的一些初始化操作。

 

# -*- coding:utf-8 -*-


class Test:
    num = "aaaa"

    def __init__(self):
        self.number = 123

    @classmethod
    def a(cls, n):
        cls.num = n
        print(cls.num)

    @classmethod
    def b(cls, n):
        cls.a(n)

    @classmethod
    def c(cls, n):
        cls.number = n

    @staticmethod
    def d(n):
        Test.b(n)

分别通过类对象、实例化对象来调用

2019-03-17-22_10_03.png

 


装饰器函数机制

谈装饰器的原理就不得不先理解Python的闭包,在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包即内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。

装饰器是建立在闭包的基础上,将被装饰函数传入闭包函数中执行则形成了装饰器。

闭包:

# -*- coding:utf-8 -*-


def test(a):

    def add(a):
        print(a+2)
    return add(a)


if __name__ == '__main__':
    test(2)

2


装饰器原型:

# -*- coding:utf-8 -*-


def B(fn):
    def b():
        return fn()+3
    return b


@B
def add():
    return 3


if __name__ == '__main__':
    str = fn()
    print(str)
----------------
6


当被装饰函数带参数:

# -*- coding:utf-8 -*-


def B(fn):
    def b(*args, **kwargs):
        return str(fn(*args, **kwargs))+"装饰"
    return b


@B
def fn(*args, **kwargs):
    num = 0
    for i in args:
        num +=i
    for i in kwargs.values():
        num += i
    return num


if __name__ == '__main__':
    num = fn(123, a=4, b=5)
    print(num)
----------------
15装饰


当装饰函数带额外参数,应该在装饰函数外再包裹一层函数

# -*- coding:utf-8 -*-


def A(n):
    def B(fn):
        def b(*args, **kwargs):
            return n+str(fn(*args, **kwargs))+"装饰"
        return b
    return B


@A("包裹前缀")
def fn(*args, **kwargs):
    num = 0
    for i in args:
        num +=i
    for i in kwargs.values():
        num += i
    return num


if __name__ == '__main__':
    num = fn(123, a=4, b=5)
    print(num)



----------------
包裹前缀15装饰


当多个装饰函数装饰一个函数时的执行顺序

# -*- coding:utf-8 -*-


def A(fn):

    print(1)

    def run():
        print(2)
        fn()
    print('a')
    return run


def B(fn):
    print(3)

    def run():
        print(4)
        fn()

    print('b')
    return run


def C(fn):
    print(5)

    def run():
        print(6)
        fn()

    print('c')
    return run

@A
@B
@C
def test():
    print(7)


if __name__ == '__main__':
    test()




----------------
5
c
3
b
1
a
2
4
6
7


由此可以得出多装饰情况下的运行情况:初始化运行从下到上,内部执行顺序从内到外。因为开始执行时会按照装饰顺序,组装成一个函数,而这个函数从最外层的return执行到最内层,故有上述顺序,就像剥洋葱一样。


类装饰器

# -*- coding:utf-8 -*-


class Add:

    def __init__(self, fn):
        print("初始化")
        self.num = 44
        self.fn = fn

    def __call__(self, *args, **kwargs):
        print("类装饰器开始工作")
        return self.fn(self.num)


@Add
def test(n):
    return 4+n


if __name__ == '__main__':
    num = test()
    print(num)
----------------
初始化
类装饰器开始工作
48


类装饰器使用地方较少,核心是通过复写类的回调方法__call__.


装饰器应用场景

  1. 引入日志

  2. 函数执行时间统计

  3. 执行函数前预备处理

  4. 执行函数后清理功能

  5. 权限校验等场景

  6. 缓存

相关文章
|
9天前
|
Python
python的模块,包和目录的区别和自定义包的注意点
先插入模块/包是怎么找的 先找当前的包找有没有,没有去安装目录的内置函数中,再没有看看你设置的系统环境变量有没有 一般情况,代码添加的环境变量只存在当前窗口,关闭就没了-
|
1月前
|
Python
59 python - 自定义的异常
59 python - 自定义的异常
15 0
|
2月前
|
数据可视化 Python
【100天精通Python】Day62:Python可视化_Matplotlib绘图基础,绘制折线图、散点图、柱状图、直方图和饼图,以及自定义图标外观和功能,示例+代码
【100天精通Python】Day62:Python可视化_Matplotlib绘图基础,绘制折线图、散点图、柱状图、直方图和饼图,以及自定义图标外观和功能,示例+代码
70 0
|
4月前
|
Python
【从零学习python 】37.Python自定义模块的使用和注意事项
【从零学习python 】37.Python自定义模块的使用和注意事项
26 0
|
4月前
|
JSON 数据挖掘 数据库连接
【100天精通python】Day14:python模块_标准模块,自定义模块
【100天精通python】Day14:python模块_标准模块,自定义模块
47 0
|
6月前
|
Python
python flask自定义404错误页面
python flask自定义404错误页面
125 0
|
7月前
|
Python
Django框架开发004期 Python编程调用自定义Django框架template模板网页
Django框架开发004期 Python编程调用自定义Django框架template模板网页
|
7月前
|
前端开发 Python
Python tkinter库之Canvas自定义直线函数画随机色彩圆盘
Python tkinter库之Canvas自定义直线函数画随机色彩圆盘
83 0
|
7月前
|
Python
python中深化内建类,自定义字符串类
python中深化内建类,自定义字符串类
|
7月前
|
编译器 Python
python中继承内建类, 自定义列表与字典
python中继承内建类, 自定义列表与字典
相关产品
云迁移中心
推荐文章
更多