day047函数之装饰器(闭包的运用),面向对象之单例模式(设计模式)

本节内容:

1、函数之装饰器
2、面向对象之单例模式

一、函数之装饰器(闭包的运用)

装饰器本质上就是一个python函数,一个闭包函数的运用,
他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。

装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。

1、装饰器的形成过程

现在有一个需求,要测试一个函数的执行时间,在不改变这个函数的执行情况下:

fe1:简单版的装饰器

简单版的装饰器

# 增加一个函数 测试其他函数执行效率的功能,但是尽量不要改变原函数的执行方式.

import time

def func():  # 被装饰的函数
    time.sleep(0.2)
    print('10万行代码')

def func1():
    time.sleep(0.2)
    print('11万行代码')
# func = 666
# func()

def timmer(f):  # func函数名 = f
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print('此函数的执行效率为%s' % (end_time - start_time))
    return inner

func = timmer(func)  # inner
func()  # inner()
func1 = timmer(func1)
func1()

# 上个版本不行,每次执行被测试时间的函数时,必须要加一行代码.
# 怎么解决,看下面的语法糖
Python

fe2:装饰器—-语法糖

 装饰器:在不改变原函数的执行(代码机构基础上,给原函数增加一些额外的功能,登录验证,打印日志,测试效率等等.
 语法糖,就是python里面封装好的func = timmer(func),你直接调用就行,不用再自己写了

装饰器的语法糖运用

import time
def timmer(f):  # func函数名 = f
    def inner(x,y):
        start_time = time.time()
        f(x,y)
        end_time = time.time()
        print('此函数的执行效率为%s' % (end_time - start_time))

    return inner

@timmer #  func = timmer(func)
def func(x,y):
    time.sleep(0.2)
    print(x + y)

# 语法糖  @
# @timmer  # func1 = timmer(func1)
# def func1():
#     print(666)
func(10,20)  # inner(10,20)
# func1()
Python

fe3:被装饰函数带参数,这时用无敌传参(*args, **kwargs)

无敌传参解决被装饰函数带参数

import time
def timmer(f):  # func函数名 = f
    def inner(*args, **kwargs):  # 传参,聚合
        # args = (10,20)
        start_time = time.time()
        f(*args,**kwargs)  # 被装饰函数的执行  * 打散 10 , 20  f(10,20)
        end_time = time.time()
        print('此函数的执行效率为%s' % (end_time - start_time))
    return inner

@timmer #  func = timmer(func)  func2 = timmer(func2) 这时的func2已经不是被装饰函数了
def func(x,y):
    time.sleep(0.2)
    print(x + y)

@timmer
def func2(x,y,z,w):
    print(x,y,z,w)
# func(10, 20)  # inner(10,20)

func2(1,2,3,w=4)  # 这里的参数被inner的f接收了,f就是语法糖传参的被装饰函数名
Python

fe4: 标准的装饰器, 被装饰的函数带参数,带返回值

标准的装饰器

import time
def timmer(f):  # func函数名 = f
    def inner(*args, **kwargs):   # 接收被装饰函数的参数
        start_time = time.time()
        ret = f(*args,**kwargs)  # 接收被装饰函数执行之后的返回值
        end_time = time.time()
        print('此函数的执行效率为%s' % (end_time - start_time))
        return ret  # 将返回值,返回给调用者
    return inner

@timmer #  func = timmer(func)
def func(x,y,z,e):
    time.sleep(0.2)
    return x + y + z + e
ret1 = func(10, 30, 3, 4)  # inner(10, 30)
print(ret1)
Python

2、面试题(手写一个装饰器)

def wrapper(f):
    def inner(*args, **kwargs):
        '''被装饰函数执行之前的操作'''
        ret = f(*args, **kwargs)
        """被装饰函数执行之后的操作"""
        return ret
    return inner
Python

3、装饰器的应用: 登录验证.

需求:登陆后可以在各个页面切换

名字

dic_status = {
    'username': None,
    'status': False,
}

def login(f):
    def inner(*args, **kwargs):
        '''被装饰函数执行之前的操作'''
        if dic_status['status'] :
            ret = f(*args, **kwargs)
            return ret
        else:
            username = input('请输入用户名').strip()
            password = input('请输入密码').strip()
            with open('register', encoding='utf-8') as f1:
                for line in f1:
                    user, pwd = line.split('|')
                    if username == user.strip() and password == pwd.strip():
                        dic_status['username'] = username
                        dic_status['status'] = True
                        print('登录成功,正在跳转...')
                        ret = f(*args, **kwargs)
                        return ret
                else:
                    print('登录失败...')
    return inner


@login
def article():
    print('欢迎登录文章页面')
@login
def diary():
    print('欢迎登录日记页面')
@login
def comment():
    print('欢迎登录评论页面')

dic = {
    1: article,
    2: diary,
    3: comment,
}

while 1:
    num = input('欢迎访问博客园,请选择:
1文章页面 
2 日记页面 
 3 评论页面').strip()
    if num.isdigit():
        dic[int(num)]()
    else:
        print('重新输入..')
# 还需写一个register的文件来放用户信息,进行登录验证
Python

4、带参数的装饰器

带参数的装饰器

import time
def timmer(flag):  # 这个函数的作用是,将参数传给装饰器函数
    def wrapper(f):  # 这个函数的作用是:将被装饰函数作为参数传入
        def inner(*args, **kwargs):  # 传入被装饰函数的参数,传参
            if flag:  # 通过这个状态来,控制是否执行装饰器函数
                start_time = time.time()
                ret = f(*args, **kwargs)
                end_time = time.time()
                print('执行时间%s' % (end_time-start_time))
                return ret
            else:
                ret = f(*args, **kwargs)
                return ret
        return inner
    return wrapper

flag1 = False
@timmer(flag1)  # 第一步,将@ 与后面 分开,只是单纯的执行timmer(flag1)函数 第二部 将@ 与 wrapper相结合,形成装饰器
def func1():
    time.sleep(0.3)
    print('in func1')
func1()
Python

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

多个装饰器 装饰一个函数

def wrapper1(func):  # func == f 函数名
    def inner1():
        print('wrapper1 ,before func')  # 2
        func()
        print('wrapper1 ,after func')  # 4
    return inner1

def wrapper2(func):  # func == inner1
    def inner2():
        print('wrapper2 ,before func')  # 1
        func()
        print('wrapper2 ,after func')  # 5
    return inner2

# 就近原则   先将近的传给装饰器函数,多个装饰器的话,逐层上传
@wrapper2  # f = wrapper2(f) 里面f == inner1  外面的f == inner2
@wrapper1  # f = wrapper1(f) 里面的f == 函数名f   外面的f == inner1
def f():
    print('in f')  # 3
f()  # inner2()
Python

二、面向对象之单例模式

就是只能实例化一个对象,不管创建多少个对象,都是指向同一个内存地址

例如:多个py文件在引入同一个模块,如果没有设置

1、单例模式代码示例

class A:
    __instance = None   # 定义一个私有变量,
    def __new__(cls, *args, **kwargs):  # 通过重写父类的__new__方法,来控制指向第一个实例化对象的地址
        if A.__instance is None:     # 通过私有变量来控制指向第一个实例化对象的(同一个)的地址
            obj = object.__new__(cls)  # 如果是第一次实例化对象,就创建对象,
            A.__instance = obj
        return A.__instance   # 如果不是第一次,就直接指向第一次对象的内存地址,不再创建对象

obj1 = A()
obj2 = A()
obj3 = A()
obj4 = A()
print(obj1)  # 都指向同一个内存地址
print(obj2)
print(obj3)
print(obj4)
原文地址:https://www.cnblogs.com/yipianshuying/p/10153645.html