看完这个你一定会Python装饰器

看完这个你一定会Python装饰器

我也是一步步学来的,最初看到这个装饰器很不理解,但是通过这个例子后,我就明白了一些。先引入一个例子,里面会牵扯到其它一点基本知识,可能有些表述不准确,但是不影响对python装饰器的理解,望采纳(文中若有纰漏,多多包涵)

account = {'isTrue': False, 'name': 'Alex', 'password': '123'}


def login():
    if not account['isTrue']:
        if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
            account['isTrue'] = True
            print('输入正确,正在登陆......')
        else:
            print('输入错误')
    else:
        print('检验已经登陆过账号,登陆中......')


def content():
    print('=======欢迎进入首页=======')


def net_game():
    print('欢迎进入网络游戏')


def console_game():
    print('欢迎进入单机游戏')


def relax_game():
    print('欢迎进入休闲游戏')


def other_game():
    print('欢迎进入其它游戏')


content()
net_game()
relax_game()

以上类似于进入不同游戏专区的脚本,现在需要增加一个功能,就是需要正确的账号跟密码才能进入特定专区,如:网络游戏专区、休闲游戏。总的来说,要秉承封闭与开放的原则。封闭是指:已实现的的功能代码块不应该被修改。开放是指:对现有功能的扩展开放。先一步步来, 如果不考虑封闭与开放原则,为了满足功能,可以把程序改为:

account = {'isTrue': False, 'name': 'Alex', 'password': '123'}


def login():
    if not account['isTrue']:
        if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
            account['isTrue'] = True
            print('输入正确,正在登陆......')
        else:
            print('输入错误')
    else:
        print('检验已经登陆过账号,登陆中......')


def content():
    print('=======欢迎进入首页=======')


def net_game():
    login()
    print('欢迎进入网络游戏')


def console_game():
    print('欢迎进入单机游戏')


def relax_game():
    login()
    print('欢迎进入休闲游戏')


def other_game():
    print('欢迎进入其它游戏')


content()
net_game()
relax_game()

上面程序满足了要实现的功能,但是,违反了“开放封闭原则”。因此可以采用高阶函数的方法,即把一个函数当做参数传递给另一个函数,如下:

account = {'isTrue': False, 'name': 'Alex', 'password': '123'}


def login(func):
    if not account['isTrue']:
        if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
            account['isTrue'] = True
            print('输入正确,正在登陆......')
            func()
        else:
            print('输入错误')
    else:
        print('检验已经登陆过账号,登陆中......')
        func()


def content():
    print('=======欢迎进入首页=======')


def net_game():
    print('欢迎进入网络游戏')


def console_game():
    print('欢迎进入单机游戏')


def relax_game():
    print('欢迎进入休闲游戏')


def other_game():
    print('欢迎进入其它游戏')


content()
login(net_game)
login(relax_game)

但是,又有一个问题,我们改变了调用方式(就是这里login(net_game))。若是有100个专区,那就要更改100个调用方式。。。。仔细分析login(net_game),这里相当于已经执行完成了(这是一个”过程“)。而这个”过程“相当于完成的就是专区的验证。
此时若进行net_game = login(net_game)。由于login(net_game)只是完成的一个“过程”,没有返回值,此时net_game的类型是None,可以通过print(type(net_game))获知,因此再执行net_game(),就会报错。回想闭包的原理,我们可以吧login(net_game)这一步变成一个“闭包”,即:

def inner():
    if not account['isTrue']:
        if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
            account['isTrue'] = True
            print('输入正确,正在登陆......')
            func()
        else:
            print('输入错误')
    else:
        print('检验已经登陆过账号,登陆中......')
        func()
    return inner

此时,执行完login(net_game)返回的是inner,是一个函数地址,我们把这个地址给net_game。此时再执行net_game(),就顺利执行了login(net_game) 这一“过程”。net_game = login(net_game)又可以简化为:@login。代码如下

account = {'isTrue': False, 'name': 'Alex', 'password': '123'}


def login(func):
    def inner():
        if not account['isTrue']:
            if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
                account['isTrue'] = True
                print('输入正确,正在登陆......')
                func()
            else:
                print('输入错误')
        else:
            print('检验已经登陆过账号,登陆中......')
            func()
    return inner

def content():
    print('=======欢迎进入首页=======')

@login
def net_game():
    print('欢迎进入网络游戏')


def console_game():
    print('欢迎进入单机游戏')

@login
def relax_game():
    print('欢迎进入休闲游戏')


def other_game():
    print('欢迎进入其它游戏')


content()
net_game()# 实际执行的inner()
relax_game()# 实际执行的inner()

以上就实现了装饰函数。但是,此时若要在net_game里面加上参数呢?好比这样:

def net_game(key):
    if key > 3:
        print('欢迎进入网络游戏的高级模式')
    else:
        print('欢迎进入网络游戏')

那此时调用net_game()时可以加参数了,好比net_game(4),但是inner()不识别呀,因此把inner也加上inner(x),下面的func(x)也是如此
但是,问题又来了,此时relax_game()不需要参数啊,因此可以把inner更改为随机数量的参数,即:inner(*args, **kwargs),下面func(*args, **kwargs)。这样就可以代表不限制执行时inner()的参数的数量了。最后程序如下:

account = {'isTrue': False, 'name': 'Alex', 'password': '123'}


def login(func):
    def inner(*args, **kwargs):
        if not account['isTrue']:
            if input('请输入用户名:') == account['name'] and input('请输入密码:') == account['password']:
                account['isTrue'] = True
                print('输入正确,正在登陆......')
                func(*args, **kwargs)
            else:
                print('输入错误')
        else:
            print('检验已经登陆过账号,登陆中......')
            func(*args, **kwargs)
    return inner

def content():
    print('=======欢迎进入首页=======')

# @pay 假如有多个装饰器,则先执行最上面的,依次执行
@login # 装饰器或者叫语法糖
def net_game(key):
    if key > 3:
        print('欢迎进入网络游戏的高级模式')
    else:
        print('欢迎进入网络游戏')


def console_game():
    print('欢迎进入单机游戏')

@login #
def relax_game():
    print('欢迎进入休闲游戏')


def other_game():
    print('欢迎进入其它游戏')


content()
net_game(4)# 实际执行的inner()
relax_game()# 实际执行的inner()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值