python之路---装饰器

开放---封闭原则:在软件上线后,对修改代码是封闭的(包括修改源代码以及调用方式),对新功能的扩展是开放的

装饰器:在不修改源代码及其调用方式的前提下,为被装饰对象添加新功能

def home():
    print('进入观影模式...')
home()

 对于上述函数,现在需要给他加一个验证功能.

 方式一:

def home():
    uname = input('输入用户名:')
    upwd  = input('输入密码:')
    if uname == 'bob' and upwd == '123456':
        print('进入观影模式...')
    else:
        print('密码错误!')
home()

  但是这改变了源代码,是违背封闭原则的...那么

  方式二:  

def home():
    print('进入观影模式...')
uname = input('输入用户名:')
upwd  = input('输入密码:')
if uname == 'bob' and upwd == '123456':
    home()
else:
    print('密码错误!')

 这个方法虽然没有违背开放---封闭原则, 但是如果是很多地方需要添加认证功能呢,这种方法无疑会造成代码冗余,

 那么任何解决冗余呢,当然是函数啦,而且可读性好,又易于扩展

  方式三: 

def home():
    print('进入观影模式...')
def login(fun):
    uname = input('输入用户名:')
    upwd  = input('输入密码:')
    if uname == 'bob' and upwd == '123456':
        fun()
    else:
        print('密码错误!')
login(home)

 但是问题又来了,这里虽然解决了代码冗余,而且也没有修改源代码,但是以前进入观影模式的接口是home(),现在变成了

login(),这无疑是改变了调用接口的...

#你可以这样...
def home():
    print('进入观影模式...')
def login(fun):
    uname = input('输入用户名:')
    upwd  = input('输入密码:')
    if uname == 'bob' and upwd == '123456':
        return fun
    else:
        print('密码错误!')
home=login(home)
home()

#也可以这样...
def home():
    print('进入观影模式...')
def outter(func):
    def login():
        uname = input('输入用户名:')
        upwd  = input('输入密码:')
        if uname == 'bob' and upwd == '123456':
            return func()
        else:
            print('密码错误!')
    return login
home=outter(home)
home()

  but,玩意home()函数是有参函数呢,第一种方法显然不可能了,so

   

def home(name):
    print('您好%s\n现在开始进入观影模式...'%name)
def outter(func):
    def login(*args,**kwargs):
        uname = input('输入用户名:')
        upwd  = input('输入密码:')
        if uname == 'bob' and upwd == '123456':
            return func(*args,**kwargs)
        else:
            print('密码错误!')
    return login
home=outter(home)
home('bob')

这个方法应用了闭包函数,在调用外部函数outter的时候,home这个变量名是指向内部函数login的内存地址 ,只有当加上(),才会执行login的函数体代码,并且,无论调用home()时实参是什么类型,什么值,*以及**都能原封不动的将其传给login内的func()函数--->实现了在遵循开放---封闭的原则下,又没有代码冗余

 而装饰器正是运用了这一点:

def outter(func):
    def login(*args,**kwargs):
        uname = input('输入用户名:')
        upwd  = input('输入密码:')
        if uname == 'bob' and upwd == '123456':
            return func(*args,**kwargs)
        else:
            print('密码错误!')
    return login
@outter
def home(name):
    print('您好%s\n现在开始进入观影模式...'%name)
    
home('bob')

装饰器语法糖:@代替了home=outter(home),解释器将@下面的函数名作为参数传给@后面的函数,并将返回值赋值给home这个变量名,是其指向home函数体的内存地址

注:装饰器要在被装饰者之上,而且嵌套装饰是有顺序的

有参装饰器:

def wapper(way):
    def outter(func):
        def login(*args,**kwargs):
            uname = input('输入用户名:')
            upwd  = input('输入密码:')
            if uname == 'bob' and upwd == '123456':
                if way == 'QQ':
                    print('QQ登录...')
                return func(*args,**kwargs)
            else:
                print('密码错误!')
        return login
    return outter

@wapper('QQ')
def home(name):
    print('您好%s\n现在开始进入观影模式...'%name)

home('bob')
 

猜你喜欢

转载自blog.csdn.net/ltfdsy/article/details/81283276
今日推荐