24_python笔记-装饰器

本文深入浅出地介绍了Python中的闭包概念及其应用场景,包括闭包的条件、闭包的特点等。同时,详细解释了装饰器的概念、工作原理及其实现方式,并通过具体示例展示了如何使用装饰器来增强函数的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


博客cPen_web

知识点1 Python闭包

示例1:闭包

#生命周期
# a=1 定义时开始,执行完结束。生命周期定义了程序的开始与结束
#1、闭包
def func1():
    a = 10
    print(f" test {a}")

func1()     # 注:函数调用完 a就释放了,生命周期是函数调用的时间
# print(a)  # 注:打印不出来
#变量解析原则:LEGB原则

def outer(x):
    a = 278
    def inner():    # 注:inner先在自己里面找x和a
        print(x+a)  # 注:再从上一层函数找
    return inner    # 得到的是inner这个函数对象
    #返回这个函数对象
    # return inner()  # 返回的是函数的返回结果 默认返回None
    # inner() 执行的返回结果是None,return None [有括号表示执行了的函数]

result = outer(10)
result()    # 注:因为返回的是函数,所以result()是执行函数
#结果为 288       # 注:内部定义的变量 没有随着outer函数 结束掉,会被inner函数所引用,这就是闭包
#注:内部定义的变量,因为被内部函数所引用,所以不会被销毁

示例2:闭包满足的条件

#闭包满足的条件
#1、必须要有内嵌函数(外函数和内函数)
#2、内函数必须调用外函数的变量
#2、外函数必须返回内函数

示例3:形成闭包之后,内函数会获得一个非空的__closure__属性

#形成闭包之后,内函数会获得一个非空的__closure__属性
def func1():
    a = 10
    print(f" test {a}")

func1()     # 注:函数调用完 a就释放了,生命周期是函数调用的时间

def outer(x):
    a = 278
    def inner():    # 注:inner先在自己里面找x和a
        print(x+a)  # 注:再从上一层函数找
    return inner    # 得到的是inner这个函数对象
#--------------------------------------------------
result = outer(10)
print(dir(result))
#结果为 […… '__class__', '__closure__',……]
print(result.__closure__)   # 注:这个属性里保存了外部函数的变量。
#结果为 (<cell at 0x000001CD121065B0: int object at 0x000001CD12117910>, <cell at 0x000001CD12106B80: int object at 0x00007FFF2ABC07C0>)

示例4:记住函数的执行时间和加入时间

#注:闭包的坑 注意闭包函数返回的执行时间

#记住函数的执行时间和加入时间
def outer():
    fs = []     # 注:定义列表
    for i in range(5):
        def inner():		# def是创建函数变量
            return i*i      # 注:形成了闭包:i是outer的变量,被inner引用,返回的是inner的变量
        fs.append(inner)    # 存放5次,inner函数没有执行。只是把这个变量加入了5次
	# 注:这个inner是函数对象,并不是执行后的结果
    return fs

fs1, fs2, fs3, fs4 ,fs5 = outer()   # 列表返回 赋值.可以这样写
#注:执行的时候 执行的是i=4  inner里面保存的是4   4*4=16
print(fs1())	# 注:fs1实际是函数inner  fs1()实际是执行inner函数
print(fs2())
print(fs3())
print(fs4())
print(fs5())
#结果为 16
# 16
# 16
# 16
# 16

#注:调用的时候,才开始执行,开始执行的时候,i已经变成4了
#注:print(fs5()) 打印 实际是打印函数执行的输出

示例5:列表里的值赋值

#列表里的值都可以这样复制,元组也是
a, b = [1, 2]
print(a, b)
#结果为 1 2

知识点2 什么是装饰器

#装饰器
#装饰器的本质就是闭包函数,在不修改某一功能函数或类的情况下,为它们添加一些额外的功能,通常就使用装饰器
#把函数作为参数,形成闭包,就是装饰器

示例1:装饰器 函数执行时间

#装饰器
import time
import datetime

def func1(a):
    b = a + 2
    print(b)
    time.sleep(1)   # 注:睡1s

def func2():
    print("this is func2")
    time.sleep(1)

#写法1-------------------------------------------------------------------------------------
start = time.time()    # 注:time.time() 获取时间戳
func1(10)              # 注:时间戳:从1970年到现在经历了多少秒
end = time.time()
print(end - start)
#结果为 1.0001559257507324

#注:func1函数前/后 获取时间,相减获取运行时间
#注:Python里处理时间的模块:time、datetime

#写法2-------------------------------------------------------------------------------------
#注:datetime 模块
t1 = datetime.datetime.now()
func1(10)
t2 = datetime.datetime.now()
print(t2 - t1)
#结果为 0:00:01.000106

#写法3-------------------------------------------------------------------------------------
#闭包
def runtime(func):  # 注:传递函数参数
    # print(id(func)) # 注:参数对象的id是定义好的函数的id 不是后面的inner函数
    def inner(*args):   # 注:接收可变长位置参数,这是func函数的参数
        start = time.time()
        func(*args)  # 注:通过inner接收函数的参数,解包
        end = time.time()
        print(f"函数执行花费时间:{end - start}")
    return inner
#注:runtime(func)函数 传参是函数,里面inner(*args)里,传参和func函数传的参数一样,里面运行了func函数 (func(*args))

result = runtime(func1)
result(10)  # 注:本质inner函数 传递参数进去
#结果为 12
# 函数执行花费时间:1.0000476837158203
result2 = runtime(func2)
result2()
#结果为 this is func2
# 函数执行花费时间:1.0005884170532227

#把函数作为参数去传递,形成1个闭包,就是装饰器
#装饰器只能装饰函数或者类

#为函数添加额外功能 就是装饰器
#装饰器的本质就是闭包,装饰器:把函数作为1个参数传递给闭包函数
#装饰器的本质是闭包
@runtime	  # 注:--> 其实是 执行了runtime(func3)    @ 是语法糖
def func3():
    print("i am func3")
    time.sleep(2)

func3 = runtime(func3)	# 注:相当于执行的这个 func3相当于重新形成的inner函数

func3()
#结果为 i am func3
# 函数执行花费时间:2.0000953674316406

#结果为 2642713760384
#结果为 2642713545168

#注:func3() 相当于新的函数 返回的函数inner()  与原来的func3()函数不一样

示例2:增加log日志的装饰器

#增加log日志的装饰器
#执行某个函数的时候,输出"执行了xxx函数"  #注:相当于为函数增加额外功能
import time
def log_func(func): # 注:接收函数作为参数传入
#注:外函数
    print("this is log_func")
    def _log_func(*args, **kwargs):  # 因为可变长,所以能接收0-n个
    #注:内函数引入了外函数的变量
        print(f"执行了{func.__name__}")		# 注:__name__返回类名
        func(*args, **kwargs)   # 注:执行函数
    return _log_func    # 注:不要加括号
    #注:返回了内函数

@log_func   # 相当于执行了 func1 = log_func(func1)
def func1():
    print("this is func1")
    time.sleep(2)

func1()
#结果为 this is log_func
# 执行了func1
# this is func1

练习3 权限认证装饰器

用装饰器实现权限控制
定义一个全局变量:username
定义add函数,实现两个数相加
实现login_required装饰器,如果username值为root,提示"欢迎" 并计算结果,否则"没有权限"

示例

def login_required(func):
    def judge(*args):
        if username in users.keys():
            print("欢迎")
            func(*args)
        else:
            print("没有权限")
    return judge

@login_required
def add(a,b):
    result = a+b
    print(result)

add(1,2)

知识点4 logging模块 记录日志

###logging 模块
#日志记录
#日志 记录所发生的事情
#作用 可以快速定位故障,做一些用户行为统计分析

#logging模块 记录日志

###日志等级
#debug      # 记录最详细的日志信息  用于调试代码 (可以记录到某个文件里面)
#info       # 详细程度仅次于debug,记录关键节点信息
#warning    # 当某些不期望的事情发生了,但是程序正常运行
#error      # 一个严重的问题,引起某些功能不能正常运行
#critical   # 发生严重错误,程序不能正常运行时记录的信息

#默认日志等级是 warning

#大家约定俗称去使用等级

#-------------------------------------------------------------------------------------------
###logging 模块
#日志记录
#日志 记录所发生的事情
#作用 可以快速定位故障,做一些用户行为统计分析

#logging模块 记录日志

###日志等级
#debug      # 记录最详细的日志信息  用于调试代码 (可以记录到某个文件里面)
#info       # 详细程度仅次于debug,记录关键节点信息
#warning    # 当某些不期望的事情发生了,但是程序正常运行
#error      # 一个严重的问题,引起某些功能不能正常运行
#critical   # 发生严重错误,程序不能正常运行时记录的信息

#默认日志等级是 warning
#logging.basicConfig  进行日志相关设置
#示例1
#-------------------------------------------------------------------------------------------
#第一种
#用于配置简单日志
#示例
import logging
logging.basicConfig(filename = "t.log", level=logging.DEBUG)	#注:修改为输出到屏幕、debug以上输出
logging.debug("this is debug log")
#没有输出,默认情况下 只会输出warning以上等级
#debug、info输出太多了,不显示 不关注
logging.error("this is warning log")
#结果为 ERROR:root:this is warning log
logging.error("this is error log")
#结果为 ERROR:root:this is error log   # 注:打印到屏幕了

# logging.basicConfig(filename = "t.log", level=logging.DEBUG)  #修改为输出到屏幕、debug以上输出
#结果为 (输出到屏幕)
# DEBUG:root:this is debug log
# ERROR:root:this is warning log
# ERROR:root:this is error log
#示例2
#-------------------------------------------------------------------------------------------
#第二种
#logging日志系统的组件
#日志器    Logger		用来记录日志的
#处理器    Handler
#过滤器    Filter
#格式器    Formater

import logging
#获取logger对象
logger = logging.getLogger()    # 注:返回1个日志处理对象

#创建1个handle对象,输出到文件
fh = logging.FileHandler("test.log")    # 输出到test.log文件

#创建1个handler对象,输出到屏幕
ch = logging.StreamHandler()

#创建1个formatter对象,指定日志格式
format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s: %(message)s")

#绑定format到handler上
fh.setFormatter(format) #注:只绑定到 输出到文件里的fh

#绑定handler到logger对象上
logger.addHandler(fh)
logger.addHandler(ch)

logger.setLevel(logging.DEBUG)  # 设置等级 Debug以上都输出
logger.info("this is info log")
logger.error("this is error log")

#结果为(屏幕)
# this is info log
# this is error log
#结果为(test.log文件里)
# 2020-11-27 17:13:45,387 - root - INFO: this is info log
# 2020-11-27 17:13:45,387 - root - ERROR: this is error log

练习5 应用多个装饰器

#1、编写2个装饰器
#2、编写函数func1  实现两数之和相加,接收2个参数传入
#3、装饰器1:输出函数运行时间
#4、装饰器2:记录执行的函数,以及传入的参数,记录到日志文件
#5、装饰器执行的时候,有日志记录
#6、看一下装饰器执行顺序

示例

#1、编写2个装饰器
#2、编写函数func1  实现两数之和相加,接收2个参数传入
#3、装饰器1:输出函数运行时间
#4、装饰器2:记录执行的函数,以及传入的参数,记录到日志文件
#5、装饰器执行的时候,有日志记录
#6、看一下装饰器执行顺序

import time,logging

logger = logging.getLogger()
fh = logging.FileHandler('my.log')	# 注:encoding=指定编码
format = logging.Formatter('%(asctime)s - %(message)s')
fh.setFormatter(format)
logger.addHandler(fh)
logger.setLevel(logging.DEBUG)

def runtime(func):
    logger.info("执行花费事件装饰器")
    def _runtime(*args):
        before_time = time.time()
        func(*args)     # 注:执行的是_log
        after_time = time.time()
        result = after_time - before_time
        logger.info('执行时间:' + str(result))
    return _runtime

def log(func):
    logger.info("执行日志记录装饰器")
    def _log(*args):
        func_name=func.__name__
        func(*args)
        logger.info(f'this is info log:func_name:{func_name},parameter:{args}')
    return _log

@runtime    # func1 = runtime(func1)  此func1是log装饰器返回的内函数
@log        # func1 = log(func1)
def func1(a,b):
    print(f'{a}+{b}={a+b}')

func1(1,2)
#结果为
# 2020-11-28 10:25:19,578 - 执行日志记录装饰器
# 2020-11-28 10:25:19,579 - 执行花费事件装饰器
# 2020-11-28 10:25:19,579 - this is info log:func_name:func1,parameter:(1, 2)
# 2020-11-28 10:25:19,579 - 执行时间:0.0

#第1步:@log     -->执行的是log(func1)  返回的函数 交给runtime装饰
#第2步:@runtime -->runtime(log(func1))
#执行时:先log(func1) --> 返回_log --> runtime(_log) --> _runtime
#执行func(1,2) --> _runtime(1,2)

#封装时:由下而上
#执行时:由上而下

知识点6 编写和使用装饰器

示例1:保留元数据

#1、编写2个装饰器
#2、编写函数func1  实现两数之和相加,接收2个参数传入
#3、装饰器1:输出函数运行时间
#4、装饰器2:记录执行的函数,以及传入的参数,记录到日志文件
#5、装饰器执行的时候,有日志记录
#6、看一下装饰器执行顺序

import time,logging
import functools

logger = logging.getLogger()
fh = logging.FileHandler('my.log')
# fh = logging.FileHandler(path, encoding='utf-8') # 这是指定文件编码win默认gbk
format = logging.Formatter('%(asctime)s - %(message)s')
fh.setFormatter(format)
logger.addHandler(fh)
logger.setLevel(logging.DEBUG)

def runtime(func):
    logger.info("执行花费事件装饰器")
    @functools.wraps(func)  # 把本身func函数的元数据 复制给runtime
    # 保留元数据 元数据里面保存了它的函数名 文档字符串 注解
    def _runtime(*args):
        before_time = time.time()
        func(*args)     # 注:执行的是_log
        after_time = time.time()
        result = after_time - before_time
        logger.info('执行时间:' + str(result))
    return _runtime

def log(func):  # log接收的_runtime已经变成func (即func1)
    logger.info("执行日志记录装饰器")
    def _log(*args):
        func_name=func.__name__
        func(*args)
        time.sleep(2)
        logger.info(f'this is info log:func_name:{func_name},parameter:{args}')
    return _log

@log        # func1 = log(func1)	此func1是runtime装饰器返回的内函数
@runtime    # func1 = runtime(func1)  
def func1(a,b):
    print(f'{a}+{b}={a+b}')
    time.sleep(1)

func1(1,2)
#结果为 my.log文件里
# 2020-11-28 10:44:06,442 - 执行花费事件装饰器
# 2020-11-28 10:44:06,442 - 执行日志记录装饰器
# 2020-11-28 10:44:07,442 - 执行时间:1.0005865097045898
# 2020-11-28 10:44:09,443 - this is info log:func_name:func1,parameter:(1, 2)

#封装时:由下而上
#执行时:由上而下
#函数带参数
#建议闭包函数使用*args,**kwargs传递参数
#无论装饰的函数,需要什么参数,装饰器都可以去装饰,比较通用

示例2:函数带参数

import functools
def runtime(func):
    print("执行花费事件装饰器")
    @functools.wraps(func)  # 把本身func函数的元数据 复制给runtime
    # 保留元数据 元数据里面保存了它的函数名 文档字符串 注解
    def _runtime(*args, **kwargs):
        before_time = time.time()
        func(*args, **kwargs)     # 注:执行的是_log
        after_time = time.time()
        result = after_time - before_time
        print('执行时间:' + str(result))
    return _runtime

@runtime
def func1(num1):
    print("i am func1")
@runtime
def func2():
    print("i am func2")
@runtime
def func3(num1,num2,default = 1):
    print("i am func3")

func1(10)
func2()
func3(10,num2=2,default=10)
#结果为
# 执行花费事件装饰器
# 执行花费事件装饰器
# 执行花费事件装饰器
# i am func1
# 执行时间:0.0
# i am func2
# 执行时间:0.0
# i am func3
# 执行时间:0.0
#装饰器带参数
#@dec(args)
# def func():
#     pass

#自身不传入参数的装饰器 (采用2层函数定义装饰器)
#自身传入参数的装饰器 (采用3层函数定义装饰)

示例3:装饰器带参数

import functools,time
def deco(args):
    print("带参数的装饰器:", args)
    def runtime(func):  # 中间函数
        print("执行花费事件装饰器")
        @functools.wraps(func)  # 保留原数据
        def _runtime(*args, **kwargs):
            before_time = time.time()
            # result1 = func(*args, **kwargs)
            func(*args, **kwargs)
            after_time = time.time()
            result = after_time - before_time
            print('执行时间:' + str(result))
            # return result1
        return _runtime
    return runtime  # 注意把中间函数返回

@deco
def func1(a,b):
    print(" i am func1")
    return a+b
#结果为 带参数的装饰器: <function func1 at 0x000001F9C8DD8D30> # 传入的是func1

@deco(1)
######runtime = deco(1)
######func1 = runtime(func1)
def func1(a,b):
    print(" i am func1")
    return a+b
#结果为
# 带参数的装饰器: 1
# 执行花费事件装饰器

func1(1,2)
#结果为
# 带参数的装饰器: 1
# 执行花费事件装饰器
#  i am func1
# 执行时间:0.0

result = func1(1,2)
print(result)
#结果为 None       # 因为 return _runtime 没有返回值
#-----------------------------------------------
#如何获取返回值
def deco(args):
    print("带参数的装饰器:", args)
    def runtime(func):
        print("执行花费事件装饰器")
        @functools.wraps(func)
        def _runtime(*args, **kwargs):
            before_time = time.time()
            result1 = func(*args, **kwargs) # 修改这里
            after_time = time.time()
            result = after_time - before_time
            print('执行时间:' + str(result))
            return result1  # 修改这里
        return _runtime
    return runtime

result = func1(1,2)
print(result)
#结果为
# ……
# 3

示例4:带参数的装饰器,如果username = root可以执行func1,不等于root 提示没有权限

#带参数的装饰器,如果username = root可以执行func1,不等于root 提示没有权限
#自身不传入参数的装饰器 (采用2层函数定义装饰器)
#自身传入参数的装饰器 (采用3层函数定义装饰)
import functools,time
c = input("请输入你的username:")
def deco(username):
    print("带参数的装饰器",username)
    def runtime(func):
        print("执行花费时间装饰器")
        @functools.wraps(func)
        def _runtime(*args,**kwargs):
            if username == "root":
                before_time = time.time()
                func(*args,**kwargs)
                after_time = time.time()
                result = after_time - before_time
                print("执行时间"+str(result))
            else:
                print("你没有权限这么做")
        return _runtime
    return runtime

@deco(username = c)
def func1(a,b):
    print("i am func1")
    return a+b

result = func1(1,2)
print(result)
#结果为
# 请输入你的username:root
# 带参数的装饰器 root
# 执行花费时间装饰器
# i am func1
# 执行时间0.0
# None

#从最外层含糊开始执行,返回最里面的内函数为止,就不去执行了
#调用函数 实际是执行内函数

示例5:让装饰器更加通用一点

#让装饰器更加通用一点
#1、@deco    2、@deco()   3、@deco(username = c)

#通过默认参数做一些通用化的设置
import functools,time
c = input("请输入你的username:")
def deco(decorated_ = None,username=None):   # 注:使用默认参数,实现@deco()/@deco(username = c)2种装饰方法
    print("带参数的装饰器",username)
    def runtime(func):
        print("执行花费时间装饰器")
        @functools.wraps(func)
        def _runtime(*args,**kwargs):
            if username == "root":
                before_time = time.time()
                func(*args,**kwargs)
                after_time = time.time()
                result = after_time - before_time
                print("执行时间"+str(result))
            else:
                print("你没有权限这么做")
        return _runtime
    if decorated_:
        return runtime(decorated_)
    return runtime

# @deco(username = c)   #decorated_ = None,username = c
# @deco
#  _runtime = deco(func1) 相当于把func1传递给deco 返回_runtime
@deco()                 #decorated_ = None,username = None
#runtime = deco() 返回runtime
#_runtime = runtime(func1)  返回_runtime

@deco #  _runtime=deco(func1)   #decorated_ = func1,username = None
#这种写法,必须用关键字参数
#@deco("root")  # 此类传参不支持
def func1(a,b):
    print("i am func1")
    return a+b

result = func1(1,2)
print(result)

练习7 用类实现装饰器

#注:语法糖接收callable对象,一般是函数或者类

示例:基于类实现装饰器

#基于类实现装饰器
#装饰器需要一个callable对象,并且返回1个callable对象,用类去实现也是可以的
#让类的构造函数接受1个函数,使用__call__方法处理并且返回1个函数

#不带参数的装饰器
class A:
    def __init__(self,func):# 构造函数接受函数
        self.func = func    # func实例化的 时候传

    def __call__(self, *args, **kwargs): # 把要做的事情放到__call__里面
        print("this is A.__CALL__")
        return self.func(*args, **kwargs)

@A  # 类生成了实例化对象,语法糖帮做了
def func1():    # 语法糖调用call方法,返回1个函数,执行里面的语句
    print("i am func1")

func1()
#结果为
# this is A.__CALL__
# i am func1
#注:类必须实现init和call方法,init必须接收1个函数,call接收参数

#带参数的装饰器
class A:
    def __init__(self,name):
        self.name = name

    def __call__(self, func):
        # print("this is A.__CALL__")
        # return self.func(*args, **kwargs)
        def deco(*args, **kwargs):
            print("i am deco")
            print(self.name)
            func(*args, **kwargs)
        return deco

@A("wy")
def func1():
    print("i am func1")

func1()
#结果为
# i am deco
# wy
# i am func1
#函数执行时间
import time

class A:
    def __init__(self,func):
        self.func = func

    def __call__(self, *args, **kwargs):
        start = time.time()
        self.func(*args, **kwargs)
        end = time.time()
        print(f"运行时间:{end - start}")

@A
def func1():
    print("i am func1")
    time.sleep(1)

func1()
#结果为 运行时间:1.0006420612335205

练习8 按照对象创建时间排序

示例

#示例:按照对象创建时间排序
import time

class Sortable():
    def __init__(self,name):
        self.name = name
        self.create_time = time.time()  #获取当前时间

    def __repr__(self): # 官方说明,这行是为了输出
        return self.name+"xxx"

    def __lt__(self, other):    # 小于
        if self.create_time < other.create_time:
            return True # 小于返回Free
        return False    # 大于返回False

first = Sortable("first")
time.sleep(0.2)
second = Sortable("second")
time.sleep(0.2)
third = Sortable("third")

result = [third, first, second] # 对列表进行排序
print(sorted(result))  # sorted函数对列表进行排序
#结果为 [firstxxx, secondxxx, thirdxxx]
#注:print打印对象 调用repr方法
#示例:没有小于号的行为
class Sortable():   # 注:没有小于号的行为
    def __init__(self,name):
        self.name = name

    def __repr__(self):
        return self.name

first = Sortable("first")
time.sleep(0.2)
second = Sortable("second")
time.sleep(0.2)
third = Sortable("third")

result = [third, first, second]
print(sorted(result))
#报错 TypeError: '<' not supported between instances of 'Sortable' and 'Sortable'
#示例:给类添加装饰器
#给类添加装饰器
import functools
import time

def sorted_by_create_time(cls):     # 注:接收类
    original_init = cls.__init__    # 注:保存原来的init(保留原数据)

    #给init函数 添加self.create_time属性
    @functools.wraps(original_init) # 注:保留源数据
    def new_init(self, *args, **kwargs):
        original_init(self, *args, **kwargs) # 注:保留原来属性
        self.create_time = time.time()  # 给类添加create_time属性

    cls.__init__ = new_init # 注:修改cls的init参数(添加了create_time属性)

    #定义小于号的行为
    def lt(self, other):
        if self.create_time < other.create_time:
            return True
        return False

    cls.__lt__ = lt     # 注:修改cls的lt参数
    return cls  #把修改好的类返回

@sorted_by_create_time
class Sortable():
    def __init__(self,name):
        self.name = name

    def __repr__(self):
        return self.name

first = Sortable("first")
time.sleep(0.2)
second = Sortable("second")
time.sleep(0.2)
third = Sortable("third")
result = [third, first, second]
print(sorted(result))
#结果为 [first, second, third]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mycpen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值