博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
装饰器和单例模式
阅读量:6342 次
发布时间:2019-06-22

本文共 6642 字,大约阅读时间需要 22 分钟。

  一、装饰器

  装饰器本质就是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。装饰器的应用场景:插入日志,性能测试,事务处理,缓存等场景

  二、装饰器的形成过程

  现在有个需求,想让你测试这个函数的执行时间,在不改变这个函数的情况下。

  1,简单版装饰器

import timedef fun():    time.sleep(2)    print('你好啊')def test(f):    def inner():        start_time=time.time()        f()        end_time=time.time()        print(end_time-start_time)    return innerfun=test(fun)          #这个版本的虽然可以实现任何功能的测试,但每次函数执行前都得写上这一句很是麻烦fun()

  2,语法糖

import timedef fun():    time.sleep(2)    print('你好啊')def test(f):    def inner():        start_time=time.time()        f()        end_time=time.time()        print(end_time-start_time)    return inner@test           #相当于fun=test(fun),只是里面封装好了的,以后测试函数就不用写fun=test(fun),只需要在定义函数上面写上@test就行fun()

  上面的装饰器装饰的函数都没有参数,下面装饰一个带参数的装饰器。

  3,装饰带参数的函数

import timedef test(f):    def inner(*args,**kwargs):        start_time=time.time()        f(*args,**kwargs)        end_time=time.time()        print(end_time-start_time)    return inner@testdef fun():    time.sleep(2)    print('你好啊')

  4,装饰带参数和有返回值的函数

import timedef test(f):    def inner(*args,**kwargs):        start_time=time.time()        res=f(*args,**kwargs)        end_time=time.time()        print(end_time-start_time)        return res    return inner@testdef fun1(a,s,d,f):    return a+s+d+f

 

   对于上面的装饰器来说,如果我要看函数的信息,比如fun.__doc__查看函数注释的方法,fun.__name__查看函数名,由于加上装饰器后fun=inner,所以结果会有错误。下面解决

  5,可以查看函数信息的装饰器

import timefrom functools import wrapsdef test(f):    @wraps(f)    def inner(*args,**kwargs):        start_time=time.time()        res=f(*args,**kwargs)        end_time=time.time()        print(end_time-start_time)        return res    return inner@testdef fun1(a,s,d,f):    return a+s+d+f

  三、装饰器主要功能和固定结构

  1,固定写法

def timer(func):    def inner(*args,**kwargs):        '''执行函数之前要做的'''        re = func(*args,**kwargs)        '''执行函数之后要做的'''        return re    return inner

  2,可以查看函数信息的

from functools import wrapsdef deco(func):    @wraps(func) #加在最内层函数正上方    def wrapper(*args,**kwargs):        return func(*args,**kwargs)    return wrapper

  四、带参数的装饰器(是装饰器袋参数)

  比如说之前要求你为10个函数加上装饰,你得在每个函数上面写上@;一个月之后,不需要装饰器了,你又要把每个函数上的@给去掉;没过多久又让你加上装饰器;反复添加,反复删除,这可是10万个函数,很庞大的工程。其实现在给装饰器加一个参数,很轻松就解决问题。

import timedef outer(flg):    def test(f):        def inner(*args,**kwargs):            if flg:                start_time=time.time()            res=f(*args,**kwargs)            if flg:                end_time=time.time()                print(end_time-start_time)            return res        return inner    return testflg=True       #flg为True时加上装饰器,为False时不加装饰器@outer(flg)def fun1(a,s,d,f):    return a+s+d+fr=fun1(2,3,4,5)print(r)

  五、多个装饰器装饰一个函数

def wrapper1(func):  func=f    def inner1():        print('wrapper1 ,before func')        func()        print('wrapper1 ,after func')    return inner1def wrapper2(func):  func=inner1    def inner2():        print('wrapper2 ,before func')        func()        print('wrapper2 ,after func')    return inner2@wrapper2     #f=wrapper2(f),现在后面的f已经变为inner1,f=inner2@wrapper1     #f=wrapper1(f),f=inner1def f():    print('in f')f()      #此时f为inner2 所以结果为: wrapper2,before func wrapper1,before func in f wrapper1,after func wrapper2,after func

  六、单例模式

  单例模式就是一个类只能产生一个对象,就算产生多个对象,多个对象都是指向同一地址

  方法一:用__new__

class Person:    __status=None    def __new__(cls, *args, **kwargs):        if not Person.__status:            Person.__status=object.__new__(Person)        return Person.__statusob1=Person()ob2=Person()print(ob1)print(ob2)

   方法二:使用模块

  python的模块就是天然的单例模式,因为模块在第一次导入时,会生成.pyc文件,当第二次导入时,就会直接加载.pyc文件,而不会再次执行模块代码。因此,我们只需要把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以如下:

  mysingleton.py

class Singleton(object):    def foo(self):        passsingleton = Singleton()

  要使用时,直接在其他文件中导入此文件中的对象,这个对象就是一个单例模式的对象

from mysingleton.py import singleton

  方法三:使用装饰器

def Singleton(cls):    _instance = {}    def _singleton(*args, **kargs):        if cls not in _instance:            _instance[cls] = cls(*args, **kargs)        return _instance[cls]    return _singleton@Singletonclass A(object):    a = 1    def __init__(self, x=0):        self.x = xa1 = A(2)a2 = A(3)     #后面不管你给的参数是多少,都不会再执行了,只会把a1对象返回给他

  方法四:使用类

class Singleton(object):    def __init__(self):        pass    @classmethod    def instance(cls, *args, **kwargs):        if not hasattr(Singleton, "_instance"):            Singleton._instance = Singleton(*args, **kwargs)        return Singleton._instance

  这种情况下,含有io的多线程就会有问题,当前面的对象还没创建成功,后面的线程就开始,not hasattr(Singleton,'_instance')也为真,所以,第二个线程也会重新创建一个对象,从而就不是一个对象,就不是单例模式。解决办法是加锁。加锁的部分串行执行,没加锁部分并发执行。

import timeimport threadingclass Singleton(object):    _instance_lock = threading.Lock()    def __init__(self):        time.sleep(1)    @classmethod    def instance(cls, *args, **kwargs):        with Singleton._instance_lock:            if not hasattr(Singleton, "_instance"):                Singleton._instance = Singleton(*args, **kwargs)        return Singleton._instancedef task(arg):    obj = Singleton.instance()    print(obj)for i in range(10):    t = threading.Thread(target=task,args=[i,])    t.start()time.sleep(20)obj = Singleton.instance()print(obj)

  方法五:基于metaclass方式实现

  相关知识:

"""1.类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)2.对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的 __call__ 方法"""class Foo:    def __init__(self):        pass    def __call__(self, *args, **kwargs):        passobj = Foo()# 执行type的 __call__ 方法,调用 Foo类(是type的对象)的 __new__方法,用于创建对象,然后调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。obj()    # 执行Foo的 __call__ 方法

  元类的使用:

class SingletonType(type):    def __init__(self,*args,**kwargs):        super(SingletonType,self).__init__(*args,**kwargs)    def __call__(cls, *args, **kwargs): # 这里的cls,即Foo类        print('cls',cls)        obj = cls.__new__(cls,*args, **kwargs)        cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)        return objclass Foo(metaclass=SingletonType): # 指定创建Foo的type为SingletonType    def __init__(self,name):        self.name = name    def __new__(cls, *args, **kwargs):        return object.__new__(cls)obj = Foo('xx')

  实现单例模式:

import threadingclass SingletonType(type):    _instance_lock = threading.Lock()    def __call__(cls, *args, **kwargs):        if not hasattr(cls, "_instance"):            with SingletonType._instance_lock:                if not hasattr(cls, "_instance"):                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)        return cls._instanceclass Foo(metaclass=SingletonType):    def __init__(self,name):        self.name = nameobj1 = Foo('name')obj2 = Foo('name')print(obj1,obj2)

转载于:https://www.cnblogs.com/12345huangchun/p/10158463.html

你可能感兴趣的文章
基于Windows server 2008 R2和Windows7的企业环境的SSTP(或SSL) ×××构建二
查看>>
Android 文件操作
查看>>
两种常用动态路由协议的综合对比(ospf和eigrp)
查看>>
Lync 2013更新CU2
查看>>
Tomcat7+ 启动慢的问题解决
查看>>
0802收获
查看>>
google 开源项目C++ 编码规范
查看>>
23种设计模式之观察者模式
查看>>
memcached的安装与开启脚本
查看>>
Linux与Window字符集~~伤不起的幽灵空白符
查看>>
zabbix 邮件报警 -- sendmail
查看>>
JavaScript异步编程
查看>>
tcpdump用法小记
查看>>
MySQL基础安全注意细节
查看>>
Oracle随机函数—dbms_random
查看>>
pvr 批量转换
查看>>
linux命令basename使用方法
查看>>
windows下开发库路径解决方案
查看>>
linux迁移mysql数据目录
查看>>
脚本源码安装LNMP
查看>>