python——装饰器

一、名称空间(name space)

  存放名字的地方,存什么名字呢?

如变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方

名称空间共3种:

  • locals: 是函数内的名称空间,包括局部变量和形参
  • globals: 全局变量,函数定义所在模块的名字空间
  • builtins: 内置模块的名字空间

不同变量的作用域不同就是由这个变量所在的命名空间决定的。

作用域即范围

  • 全局范围:全局存活,全局有效
  • 局部范围:临时存活,局部有效

查看作用域方法 globals(),locals()

作用域查找顺序:

 locals -> enclosing function(相邻的) -> globals -> __builtins__LEGB

二、闭包

有一下代码:

def outer():
    name = 'alex'

    def inner():
        print("在inner里打印外层函数的变量",name)

    return inner


f = outer()
f()

输出:
在inner里打印外层函数的变量 alex
View Code

外层函数outer返回了内层函数的函数名inner给变量f,在函数外部执行语句:f()是就相当于调用了内层函数inner,并且inner又引用了外层函数的变量name。

对于这种,外层函数返回子函数的函数名(即子函数内存地址),在函数外调用了子函数,子函数又引用了外层函数的变量,就形成了闭包。

闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。

三、装饰器

  可以理解为一种装饰函数的工具,其本质就是一个函数。

  软件开发的原则之一:开放—封闭原则

开放:对现有功能的扩展开放

封闭:已实现的功能代码块不应该被修改

  所以,装饰器的原则是:

1、不能修改被装饰函数的源码

2、不能修改被装饰函数的调用方式

  高阶函数+嵌套函数=装饰器

高阶函数:1、将函数名作为实参传递给另一个函数(不改变源码)

     2、return返回另一个函数名(不改变函数的调用方式)

装饰器实例

你是一家视频网站的后端开发工程师,你们网站已上线运行了该模块

def home():
    print("---首页----")
    

def america():
    print("----欧美专区----")


def japan():
    print("----日韩专区----")


def henan():
    print("----河南专区----")


home()
america()
japan()
henan()
View Code

现在,你们老板跟你说,现在用户越来越多啦,准备将"america"和"henan"两个板块改为收费才能进入,所以你就要给它们新增一个登陆认证的功能,但是系统已经上线了,你是不可能修改源码的,用户一直也都习惯了这种调用方式去进去各板块,所以你想到了装饰器:

status = False  # 用于判断用户登录状态


def auth(func):  # 将函数作为参数传入  func=america or func = henan
    def inner():
        global status  # 定义全局变量
        _username = "qwe"  # 假设这是数据库用户信息
        _password = "123"
        if status is False:  # 未登录
            username = input("username:")
            password = input("password:")
            if username == _username and password == _password:  # 用户名与密码是否正确
                print("\033[35;1m-----Welcome-----\033[0m")
                status = True  # 修改用户登录状态
            else:
                print("Wrong username or password")
        if status is True:  # 已登录
            print("\033[35;1m-----用户已登录-----\033[0m")
            func()  # 允许进入相关板块  america() or henan()
    return inner  # 返回内层函数名



def home():
    print("---首页----")


@auth  # 给函数加上装饰器,相当于执行:auth(america) ,稍后auth 会将函数inner返回,即america=inner
def america():
    print("----欧美专区----")


def japan():
    print("----日韩专区----")


@auth  # 给函数加上装饰器
def henan():
    print("----河南专区----")


home()
america()  # 此时的america已经被“偷梁换柱”,相当于inner()
japan()
henan()  # inner()

输出:
---首页----
username:qwe
password:123
-----Welcome-----
-----用户已登录-----
----欧美专区----
----日韩专区----
-----用户已登录-----
----河南专区----
View Code

你可以在里面传参数,最好使用非固定参数,因为万一有些函数你要传参,有些不用,方便动态管理:

status = False  # 用于判断用户登录状态


def auth(func):  # 将函数作为参数传入  func=america or func = henan
    def inner(*args, **kwargs):
        global status  # 定义全局变量
        _username = "qwe"  # 假设这是数据库用户信息
        _password = "123"
        if status is False:  # 未登录
            username = input("username:")
            password = input("password:")
            if username == _username and password == _password:  # 用户名与密码是否正确
                print("\033[35;1m-----Welcome-----\033[0m")
                status = True  # 修改用户登录状态
            else:
                print("Wrong username or password")
        if status is True:  # 已登录
            print("\033[35;1m-----用户已登录-----\033[0m")
            func(*args, **kwargs)  # 允许进入相关板块  america() or henan()
    return inner  # 返回内层函数名



def home():
    print("---首页----")


@auth  # 给函数加上装饰器,相当于执行:auth(america) ,稍后auth 会将函数inner返回,即america=inner
def america(n):  # 传递参数
    print(n)
    print("----欧美专区----")


def japan():
    print("----日韩专区----")


@auth  # 给函数加上装饰器
def henan():
    print("----河南专区----")


home()
america("付费啦,可以看美剧啦!!!")  # 此时的america已经被“偷梁换柱”,相当于inner()
japan()
henan()  # inner()

输出:
---首页----
username:qwe
password:123
-----Welcome-----
-----用户已登录-----
付费啦,可以看美剧啦!!!
----欧美专区----
----日韩专区----
-----用户已登录-----
----河南专区----
View Code

但是,老板又提新需求了,要求"america"板块用“QQ”认证,"henan"板块用“WeChat”认证,其实就是在装饰器外面再加一层函数:

status = False  # 用于判断用户登录状态


def outer(auth_login):
    def auth(func):  # 将函数作为参数传入
        def inner(*args, **kwargs):
            if auth_login == "QQ" or auth_login == "WeChat":
                global status  # 定义全局变量
                _username = "qwe"  # 假设这是数据库用户信息
                _password = "123"
                if status is False:  # 未登录
                    username = input("username:")
                    password = input("password:")
                    if username == _username and password == _password:  # 用户名与密码是否正确
                        print("\033[35;1m-----Welcome-----\033[0m")
                        status = True  # 修改用户登录状态
                    else:
                        print("Wrong username or password")
                if status is True:  # 已登录
                    print("\033[35;1m-----用户已登录-----\033[0m")
                    func(*args, **kwargs)  # 允许进入相关板块  america() or henan()
                else:
                    print("Wrong authentication login:", func)  # 认证方式错误提示
        return inner  # 返回内层函数名
    return auth



def home():
    print("---首页----")


@outer("QQ")  # 带参数的装饰器
def america(n):  # 传递参数
    print(n)
    print("----欧美专区----")


def japan():
    print("----日韩专区----")


@outer("WeChat")  # 带参数的装饰器
def henan():
    print("----河南专区----")


home()
america("付费啦,可以看美剧啦!!!")
japan()
henan()  # inner()
View Code

 

转载于:https://www.cnblogs.com/yanlin-10/p/9016084.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中,我们可以使用面向对象编程技术来定义抽象类。在本关的题目中,按揭贷款类被设计成一个抽象类,名为Mortgage。抽象类是无法直接实例化的,而是作为其他类的基类来使用。 在定义抽象类Mortgage时,我们需要定义一个构造函数`__init__`来初始化贷款的本金、年利率和贷款期限。此外,我们还需要定义一个抽象方法`findPayment`来计算每月还款金额,一个方法`makePayment`来进行还款操作,以及一个方法`getTotalPaid`来获取已支付的总金额。 下面是一个示例的代码片段,展示了如何定义抽象类Mortgage和其中的一些方法: ```python import abc class Mortgage(abc.ABC): def __init__(self, loan, annRate, months): self.loan = loan self.rate = annRate / 12 / 100 self.months = months self.payment = self.findPayment(loan, self.rate, months) @abc.abstractmethod def findPayment(self, loan, rate, months): pass def makePayment(self): # 实现还款操作的具体逻辑 pass def getTotalPaid(self): # 实现获取已支付总金额的具体逻辑 pass def __str__(self): return 'The Mortgage is {}, Loan is {}, Months is {}, Rate is {:.2f}, Monthly payment is {:.2f}'.format(self.legend, self.loan, self.months, self.rate, self.payment) ``` 在上述代码中,我们使用了`abc`模块中的`ABC`类和`abstractmethod`装饰器来定义抽象类Mortgage。`findPayment`方法被装饰为抽象方法,需要在子类中进行具体实现。 请注意,上述代码只是一个示例,你还需要根据具体题目的要求来完善抽象类Mortgage的其他方法和属性。同时,你也可以定义其他的子类来表示不同类型的按揭贷款,根据不同的贷款类型来实现具体的计算逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值