我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python——编写类装饰器

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python——编写类装饰器

编写类装饰器

类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例。

-------------------------------------------------------------------------------------------------------------------------------------

单体类
由于类装饰器可以拦截实例创建调用,所以它们可以用来管理一个类的所有实例,或者扩展这些实例的接口。
下面的类装饰器实现了传统的单体编码模式,即最多只有一个类的一个实例存在。

instances = {} # 全局变量,管理实例
def getInstance(aClass, *args):
    if aClass not in instances:
        instances[aClass] = aClass(*args)
    return instances[aClass]     #每一个类只能存在一个实例

def singleton(aClass):
    def onCall(*args):
        return getInstance(aClass,*args)
    return onCall
为了使用它,装饰用来强化单体模型的类:
@singleton        # Person = singleton(Person)
class Person:
    def __init__(self,name,hours,rate):
        self.name = name
        self.hours = hours
        self.rate = rate
    def pay(self):
        return self.hours * self.rate

@singleton        # Spam = singleton(Spam)
class Spam:
    def __init__(self,val):
        self.attr = val
        
bob = Person('Bob',40,10)
print(bob.name,bob.pay())

sue = Person('Sue',50,20)
print(sue.name,sue.pay())

X = Spam(42)
Y = Spam(99)
print(X.attr,Y.attr)
现在,当Person或Spam类稍后用来创建一个实例的时候,装饰器提供的包装逻辑层把实例构建调用指向了onCall,它反过来调用getInstance,以针对每个类管理并分享一个单个实例,而不管进行了多少次构建调用。
程序输出如下:
Bob 400
Bob 400
42 42
在这里,我们使用全局的字典instances来保存实例,还有一个更好的解决方案就是使用Python3中的nonlocal关键字,它可以为每个类提供一个封闭的作用域,如下:
def singleton(aClass):
	instance = None
	def onCall(*args):
		nonlocal instance
		if instance == None:
			instance = aClass(*args)
		return instance
	return onCall
当然,我们也可以用类来编写这个装饰器——如下代码对每个类使用一个实例,而不是使用一个封闭作用域或全局表:
class singleton:
	def __init__(self,aClass):
		self.aClass = aClass
		self.instance = None
	def __call__(self,*args):
		if self.instance == None:
			self.instance = self.aClass(*args)
		return self.instance
-------------------------------------------------------------------------------------------------------------------------------------

跟踪对象接口
类装饰器的另一个常用场景是每个产生实例的接口。类装饰器基本上可以在实例上安装一个包装器逻辑层,来以某种方式管理其对接口的访问。
前面,我们知道可以用__getattr__运算符重载方法作为包装嵌入到实例的整个对象接口的方法,以便实现委托编码模式。__getattr__用于拦截未定义的属性名的访问。如下例子所示:

class Wrapper:
	def __init__(self,obj):
		self.wrapped = obj
	def __getattr__(self,attrname):
		print('Trace:',attrname)
		return getattr(self.wrapped,attrname)

	
>>> x = Wrapper([1,2,3])
>>> x.append(4)
Trace: append
>>> x.wrapped
[1, 2, 3, 4]
>>>
>>> x = Wrapper({'a':1,'b':2})
>>> list(x.keys())
Trace: keys
['b', 'a']
在这段代码中,Wrapper类拦截了对任何包装对象的属性的访问,打印出一条跟踪信息,并且使用内置函数getattr来终止对包装对象的请求。

类装饰器为编写这种__getattr__技术来包装一个完整接口提供了一个替代的、方便的方法。如下:
def Tracer(aClass):
    class Wrapper:
        def __init__(self,*args,**kargs):
            self.fetches = 0
            self.wrapped = aClass(*args,**kargs)
        def __getattr__(self,attrname):
            print('Trace:'+attrname)
            self.fetches += 1
            return getattr(self.wrapped,attrname)
    return Wrapper

@Tracer
class Spam:
    def display(self):
        print('Spam!'*8)

@Tracer
class Person:
    def __init__(self,name,hours,rate):
        self.name = name
        self.hours = hours
        self.rate = rate
    def pay(self):
        return self.hours * self.rate

food = Spam()
food.display()
print([food.fetches])

bob = Person('Bob',40,50)
print(bob.name)
print(bob.pay())

print('')
sue = Person('Sue',rate=100,hours = 60)
print(sue.name)
print(sue.pay())

print(bob.name)
print(bob.pay())
print([bob.fetches,sue.fetches])
通过拦截实例创建调用,这里的类装饰器允许我们跟踪整个对象接口,例如,对其任何属性的访问。

Spam和Person类的实例上的属性获取都会调用Wrapper类中的__getattr__逻辑,由于food和bob确实都是Wrapper的实例,得益于装饰器的实例创建调用重定向,输出如下:
Trace:display
Spam!Spam!Spam!Spam!Spam!Spam!Spam!Spam!
[1]
Trace:name
Bob
Trace:pay
2000

Trace:name
Sue
Trace:pay
6000
Trace:name
Bob
Trace:pay
2000
[4, 2]
========================================================================================

示例:实现私有属性
如下的类装饰器实现了一个用于类实例属性的Private声明,也就是说,属性存储在一个实例上,或者从其一个类继承而来。不接受从装饰的类的外部对这样的属性的获取和修改访问,但是,仍然允许类自身在其方法中自由地访问那些名称。类似于Java中的private属性。

traceMe = False
def trace(*args):
    if traceMe:
        print('['+ ' '.join(map(str,args))+ ']')

def Private(*privates):
    def onDecorator(aClass):
        class onInstance:
            def __init__(self,*args,**kargs):
                self.wrapped = aClass(*args,**kargs)
            def __getattr__(self,attr):
                trace('get:',attr)
                if attr in privates:
                    raise TypeError('private attribute fetch:'+attr)
                else:
                    return getattr(self.wrapped,attr)
            def __setattr__(self,attr,value):
                trace('set:',attr,value)
                if attr == 'wrapped': # 这里捕捉对wrapped的赋值
                    self.__dict__[attr] = value
                elif attr in privates:
                    raise TypeError('private attribute change:'+attr)
                else: # 这里捕捉对wrapped.attr的赋值
                    setattr(self.wrapped,attr,value)
        return onInstance
    return onDecorator

if __name__ == '__main__':
    traceMe = True

    @Private('data','size')
    class Doubler:
        def __init__(self,label,start):
            self.label = label
            self.data = start
        def size(self):
            return len(self.data)
        def double(self):
            for i in range(self.size()):
                self.data[i] = self.data[i] * 2
        def display(self):
            print('%s => %s'%(self.label,self.data))

    X = Doubler('X is',[1,2,3])
    Y = Doubler('Y is',[-10,-20,-30])

    print(X.label)
    X.display()
    X.double()
    X.display()

    print(Y.label)
    Y.display()
    Y.double()
    Y.label = 'Spam'
    Y.display()

    # 这些访问都会引发异常
    """
    print(X.size())
    print(X.data)

    X.data = [1,1,1]
    X.size = lambda S:0
    print(Y.data)
    print(Y.size())
这个示例运用了装饰器参数等语法,稍微有些复杂,运行结果如下:
[set: wrapped <__main__.Doubler object at 0x03421F10>]
[set: wrapped <__main__.Doubler object at 0x031B7470>]
[get: label]
X is
[get: display]
X is => [1, 2, 3]
[get: double]
[get: display]
X is => [2, 4, 6]
[get: label]
Y is
[get: display]
Y is => [-10, -20, -30]
[get: double]
[set: label Spam]
[get: display]
Spam => [-20, -40, -60]

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python——编写类装饰器

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python——编写类装饰器

编写类装饰器类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例。-------------------------------------------------------------
2023-01-31

python装饰器2:类装饰器

装饰器1:函数装饰器装饰器2:类装饰器装饰器3:进阶本文是装饰器相关内容的第二篇,关于类装饰器。"类装饰器"有两种解读方式:用来装饰类的装饰器;类作为装饰器装饰其它东西。你如何认为取决于你,两种说法都有出现在其它的文章中。我的文章中是将"类
2023-01-30

浅析Python编写函数装饰器

编写函数装饰器 本节主要介绍编写函数装饰器的相关内容。跟踪调用 如下代码定义并应用一个函数装饰器,来统计对装饰的函数的调用次数,并且针对每一次调用打印跟踪信息。class tracer: def __init__(self,func): s
2022-06-04

怎么用Python编写一个装饰器

本篇内容主要讲解“怎么用Python编写一个装饰器”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么用Python编写一个装饰器”吧!首先概念,装饰器是闭包的一种应用,需要满足一下规则:1.在不
2023-06-02

怎么用Python写装饰器

这篇文章主要讲解了“怎么用Python写装饰器”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用Python写装饰器”吧!按照题目要求写出对应的函数。要求:写一个函数,传入一个有若干个整数
2023-06-03

Python装饰器与类的装饰器怎么实现

这篇“Python装饰器与类的装饰器怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python装饰器与类的装饰器怎么
2023-06-29

类装饰器

在理解类装饰器之前,先回忆一下有关装饰器的知识。装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象(函数的引用)。 __call__方法  一个对象是否可调用,看其中是否实
2023-01-30

Python装饰器高级版—Python类

本文重点:解决了类里面定义的装饰器,在同一个类里面使用的问题,并实现了装饰器的类属性参数传递目录:一、基本装饰器二、在类里定义装饰器,装饰本类内函数三、类装饰器正文:一、基本装饰器        装饰不带参数的函数def clothes(f
2023-01-31

python装饰器(新年第一写)

祭奠碌碌无为的2018,想想其实也不算碌碌无为,至少我还搞懂了装饰器,写了一堆有用没用的玩意原来觉得装饰器挺难的,直到2018年的最后几天,突然就明白了,难道这就是传说中的开天聪么言归正传,之所以觉得装饰器难,是因为这东西不按套路出牌,希望
2023-01-30

Python装饰器的写法是什么

这篇文章主要讲解了“Python装饰器的写法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python装饰器的写法是什么”吧!Hello,装饰器装饰器本质上是一个Python函数,它可
2023-06-15

python_类装饰器

一.定义装饰器就是一个给对象添加额外功能的函数,其本质是函数。它的基本构造:高阶函数+函数嵌套+闭包。基础知识讲解详见:https://blog.51cto.com/10836356/2095118二.简单类的装饰器我们先看简单的类的装饰器
2023-01-31

python-装饰器

装饰器简介:给被装饰的函数在不更改代码的基础上增加新的功能;多个装饰器的执行顺序:从最靠近原始函数的装饰器开始执行,最后执行原始函数; 直接上个简单的例子就懂了: 一 最简单的装饰器:#!/usr/bin/python def deco(f
2023-01-31

python 装饰器

装饰器本质上是一个Python函数,它可以让其他函数在不雲要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面雲求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳
2023-01-30

Python函数式编程之装饰器

原则:对修改是封闭的,对扩展是开放的,方法:一般不修改函数或者类,而是扩展函数或者类一:装饰器 允许我们将一个提供核心功能的对象和其他可以改变这个功能的对象’包裹‘在一起, 使用装饰对象的任何对象与装饰前后该对象的交互遵循完全相
2023-01-30

python装饰器

什么是装饰器:  装饰器就是python中的一个语法糖。作用就是在不改动之前代码的情况下给某个函数增加相应想要增加的功能。假设需求:  我在几个函数内分别放了一部电影,代码如下:1 def mv1():2 print("高清无码01
2023-01-30

Python怎样手动编写一个自己的LRU缓存装饰器

Python怎样手动编写一个自己的LRU缓存装饰器,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。LRU缓存算法,指的是近期最少使用算法,大体逻辑就是淘汰最长时间没有用的那个缓存
2023-06-22

python装饰器1:函数装饰器详解

装饰器1:函数装饰器装饰器2:类装饰器装饰器3:进阶先混个眼熟谁可以作为装饰器(可以将谁编写成装饰器):函数方法实现了__call__的可调用类装饰器可以去装饰谁(谁可以被装饰):函数方法类基础:函数装饰器的表现方式假如你已经定义了一个函数
2023-01-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录