Python 自制简单实用的日志装饰器

【Python】日志记录与装饰器应用 在软件开发过程中,日志记录是一个非常重要的功能,可以帮助开发者和运维人员了解软件的运行状态、跟踪错误和分析性能问题。本文将介绍如何使用Python中的logging模块进行日志记录,并通过装饰器实现函数执行的日志注解。 阅读详情

在写代码的时候,往往会漏掉日志这个关键因素,导致功能在使用的时候出错却无法溯源。

其实,只需要写一个非常简单的日志装饰器,我们就能大大提升排查问题的效率。

1.简陋版装饰器

写一个装饰器非常简单,因为本质上装饰器就是一个返回函数的“高阶”函数而已:

1) 函数作为参数传递进装饰器。
2) 装饰器内定义一个函数,处理作为参数传递进来的函数。
3) 返回这个装饰器内定义的函数

用一下试试看:

效果如下:


虽然这样可以实现我们所需要的功能,但其实有很大的优化空间。

2.普通版装饰器

第一版代码中有一个显而易见的问题,装饰器内定义的处理函数不支持kwargs,而在装饰器中支持kwargs仅仅是举手之劳而已。

第二个问题是,生成时间戳的时候采用字符串截取的形式,这种形式过于粗暴。其实可以使用strftime做字符串转换。

修改如下:

似乎优化得差不多了,不过依然存在改进空间。

3.优化版装饰器

在前两版代码中,我们使用print进行日志输出,其实这种处理日志的方式并不标准。

使用logging模块控制日志输出是一个更好地选择。

为了使用logging模块记录日志,我们需要先配置好logging相关的选项。

1) 首先,生成一个日志记录器,并配置日志等级:

2) 配置日志格式、增加handler控制输出流:

此处可以设置handler所需要处理的日志等级,没有设置则默认使用logger自身的Level,即DEBUG等级。

3) 最后,将此handler加入到日志记录器内:

logging 完整配置如下:

使用的时候非常简单,就是把print换成logger.debug即可:


效果如下:


这样,一个比较完善的日志装饰器就完成了。

附常用的日志等级配置:

以上就是本次分享的所有内容,如果你觉得文章还不错,欢迎关注公众号:Python编程学习圈,每日干货分享,发送“J”还可领取大量学习资料,内容覆盖Python电子书、教程、数据库编程、Django,爬虫,云计算等等。或是前往编程学习网,了解更多编程技术知识。

封装,装饰器封装,类成员和静态方法,魔术方法,自制一个名片系统 在Python中,没有真正的私有属性,但可以使用命名约定来标识哪些属性是“私有”的。通常,通过在属性名前面加上单下划线(_)或双下划线(__)来表示它们是“受保护的”或“私有的”。单下划线只是一个约定,表示这个属性不应该被外部直接访问,而双下划线会导致Python名称改写(name mangling),使得属性名更难从外部访问。在Python中,装饰器(decorator)是一种高级功能,它允许你在不修改原有函数或方法定义的情况下,为其添加额外的功能或行为。工具方法(不需要访问类属性和类方法) 阅读详情

相关推荐

python进阶 -- 日志&装饰器详解

日志:记录程序运行的时候,出现的问题,或者说验证流程是否正常在实际工作中,python的脚本命令一般是放在服务器执行的linux系统日志其实就是记录程序运行时出现的问题、或者正常的打印,协助出现问题的时解决排查问题日志模块:会有日志的级别设置级别是自己设置的,可以通过自定义的级别去确定什么东西该被记录,什么东西部该被记录注意:设置日志级别的时候,单词全部需要大写● DEBUG:等级最高,包含debug、info、warning、error的4种全部日志。

weixin_54104072的博客 1095

Python装饰器使用(处理日志)

处理日志

weixin_45246215的博客 762

深入解析Matlab phantom函数:从基础模体到自定义头部仿真

本文深入解析了Matlab中的phantom函数,它是医学图像处理算法测试的核心工具。文章详细介绍了如何使用内置的Shepp-Logan及其改良版头部仿真模体,并重点讲解了通过自定义参数矩阵来构建专属模体的方法。通过从生成模体到模拟投影(正弦图)再到图像重建的完整实战流程,展示了phantom函数在CT等算法开发与验证中的关键作用。

m3n5b7v8c9x的博客 950

python装饰器这一篇就够了

python装饰器这一篇就够了

努力下来就凸头 1万+

antiSMASH安装与使用

antiSMASH本地安装 简要: antiSMASH的本地安装需要安装很多的依赖包,本文章使用conda辅助安装 参考: 官方:https://docs.antismash.secondarymetabolites.org/install/ 文章:http://blog.sciencenet.cn/blog-3416913-1240614.html 依赖包下载 conda install -y diamond=0.8.36 conda install -y fasttree=2.1.9 conda ins

Curry_chenhu的博客 7225

移植 lwip,在 windows 内核构建一个 TCPIP 协议栈

移植 lwip,在 windows 内核构建一个 TCPIP 协议栈 亲,当你点开看这篇文章,就说明你知道我想要干什么事情,或者说,你知道在 Windows 的内核种绕开它的网络协议,再独立构建一个网络协议栈的意义。如果你要问我有 windows 系统的网络协议栈不用,移植 lwip 有什么意义,那么你可以关闭链接走人了,因为这篇文章不适合你,它不是讲 lwip 移植原理的。 经常关注我的博客的朋...

oRbIt 的专栏 3578

【 python 】 实现简单 装饰器

【代码】【 python 】 实现简单 装饰器。

GooO_O的博客 349

施耐德EcoStruxure平台深度体验:IEC 61499在智慧物流中心的真实应用案例解析

本文深度解析施耐德EcoStruxure平台在智慧物流中心的应用,重点探讨IEC 61499标准如何通过分布式控制和功能块技术重构自动化逻辑。通过上海某物流中心的真实案例,展示了该平台在提升系统弹性、降低停机成本方面的显著成效,为工业自动化转型提供实践参考。

weixin_30576827的博客 66

Python:关于装饰器

目的   AOP编程,解耦。 一是为了少写代码,二是为了解耦。 为了把重点放在装饰器上,本文的代码没有引入很多包。大概要引入datetime,math等。     例子 问题提出 比如,需要添加一些通用的动作,又不想在原有的函数里面修改。   e.g. 要在函数执行前打印出执行的时间(相当于写日志)。   def say(): print('hi')    ...

qcyfred的博客 684

ArduPilot + Gazebo + Mavros + QGC + 遥控器:从仿真到实机的自主轨迹控制实践

本文详细介绍了基于ArduPilot、Gazebo、Mavros和QGC的无人机自主轨迹控制全流程实践。从仿真环境搭建、多终端协同配置,到遥控器集成与自主圆形轨迹算法实现,提供了完整的代码示例和实机迁移要点,帮助开发者快速掌握无人机自主控制技术。

corn8的博客 940

Windows下TensorRT+YOLOv11部署避坑指南:从CUDA配置到模型加密全流程

本文详细解析了在Windows平台部署YOLOv11与TensorRT的全流程,重点涵盖从CUDA环境配置、工程编译适配到模型加密保护的实战指南。基于wang-xinyu的tensorrtx仓库,提供了详细的版本选择、编译问题修复方案,并深入探讨了如何对TensorRT引擎进行加密,以实现高效且安全的端到端部署。

vscode5coder的博客 450

[Python公开课]零基础玩转Python基础篇----第七节:Python中的高级函数

[Python公开课]零基础玩转Python基础篇----第七节:Python中的高级函数

拥有百余位万粉技术博主、200余位可合作代发博主,私域技术社群规模达千人,商务合作私信 4243

Keil-C51 与 Keil -ARM 共存的方法

本篇为《嵌入式相关》系列博客的第五篇,该系列博客主要记录单片机开发及硬件设计的相关过程,方便以后查阅。 Keil-C51 与 Keil -ARM 共存的方法状况解决方案1测试解决方案2 状况 今天装完Keil-C51,然后又换装了Keil-ARM之后,可以正常编译STM32 的工程,但是无法编译C51的工程,并且出现了如下错误: *** Error: Project ‘template’ requires ‘C51’ Toolchain which is not installe 这种情况就是Keil-

梁小憨憨的博客 1万+

【Python数据分析300个实用技巧】147.高级技巧与黑科技之元编程进阶:用AST分析和修改代码结构

错误示例:用字符串处理获取函数名print(code[4:code.index('(')]) # 输出'hello',但遇到装饰器就失效这种字符串截取方式遇到多行定义、装饰器等复杂情况就会崩溃。批量修改代码如同操作JSON数据实现IDE都做不到的代码转换深入理解Python的语法机制记住,每个你解决的AST难题,都是在积累"代码炼金术"的经验值。当你能轻松把2000行重复代码变成自动生成的元程序时,那种掌控感,比通关最难的BOSS战还要爽!

1073

uniapp微信小程序 - 解决苹果ios底部输入框被软键盘遮挡的问题,input/textarea底部输入框被弹出的软键盘挡住部分或全部遮住(解决uniApp小程序底部输入框,键盘弹起时页面整体上移

uniapp: IOS微信小程序输入框部分被软键盘遮挡问题,iOS微信小程序键盘弹出时输入框被挡住,uniapp小程序苹果IOS系统软键盘唤起导致底部输入框被遮挡的问题,ios 键盘弹出input输入框被遮挡,uniapp textarea输入框软键盘遮挡问题,苹果手机ios系统,解决uni-app微信小程序底部输入框,键盘弹起时页面整体上移 问题,关于手机端IOS系统微信中虚拟键盘遮挡input输入框问题的解决方案,uniapp使用输入框固定在底部键盘弹起把输入框挡住问题,安卓上没问题就苹果不行,仅ios

🏆 前端领域优质创作者 5597

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Python装饰器全解析:从语法糖到高阶函数与闭包的本质

在Python编程中,高阶函数和闭包是函数式编程的核心概念,它们允许函数作为参数传递、返回函数以及捕获外部状态。这些特性共同构成了装饰器的底层原理,使得开发者能够在不修改原函数代码的情况下,动态地为函数添加日志、计时、权限校验等横切关注点功能。装饰器作为一种强大的元编程工具,其技术价值在于实现了关注点分离,提升了代码的可复用性和可维护性。在实际工程实践中,装饰器广泛应用于Web框架路由注册、性能监控、缓存优化等场景。本文以Python中的@staticmethod和@property等高频搜索关键词为例,深

weixin_30905133的博客 345

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Python的面向切面编程(AOP)(通过故事来学习)

在一个名为“魔法世界”的大陆上,有一群魔法师们,他们都有着各自的魔法力量,可以施展出各种神奇的魔法。然而,他们也有着各自的缺点,例如有些魔法师缺乏耐心,有些魔法师缺乏自制力。最终,魔法师们发现,Python的面向切面编程可以让他们的魔法变得更加高效、更加健壮。他们开始尝试使用Python的装饰器来实现不同的功能,如对函数运行时间进行统计,对函数的参数和返回值进行验证等等。有一天,一位年轻的魔法师,名叫艾米莉,发现了一个新的魔法,可以帮助自己和其他魔法师们改正缺点,并且可以让魔法更加高效。

pcaidong_2的专栏 520

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Python Pytest用于在执行测试用例前生成日志文件

fixture是一种用于提供测试用例所需资源的机制,可以在测试用例执行前或执行后进行一些准备或清理操作。函数来获取日志文件路径了,而不必每次都写一遍生成日志文件和设置日志文件路径的代码。的fixture,用于在执行测试用例前生成日志文件,并将日志文件路径传递给。方法生成当前时间的字符串,用于作为日志文件名的一部分。你可以将这段代码封装成一个函数,以便在其他地方使用。函数来获取日志文件路径,以保证代码的复用性。插件的一个方法,用于设置日志文件路径。拼接日志文件的完整路径,其中。表示日志文件存放的相对路径,

weixin_45471729的博客 504

制定一个30天学习Python的计划

以下是专为设计的,兼顾系统性与实操性,帮助你从入门到初步掌握核心技能。每天建议学习时间约1-2小时(可根据个人节奏调整)。

bsklhao的博客 1538

HAP-python开发教程:一步步打造自定义智能配件(附完整代码)

想让你的树莓派、温湿度传感器或自制灯泡被 iPhone 的"家庭"App 直接控制?**HAP-python** 就是帮你实现这一目标的最佳选择。它是 HomeKit 配件协议(HAP)的纯 Python 实现,只需几行代码,就能把你自己的设备伪装成一个"原生态"的 HomeKit 配件,用 Siri 语音控制、扫码配对、局域网内自动发现,通通不在话下。本教程将带你从零开始,一步步用 HAP-py

gitblog_00150的博客 461

有了PySnooper,不用print、不用debug轻松查找问题所在!

PySnooper是一个非常方便的调试器,它是通过python注解的方式来对函数的执行过程进行监督的。应用起来比较简单,不用一步一步的去走debug来查找问题所在,并且将运行过程中函数的变量值打印出来结果一目了然,相当于替代了print函数的打印过程。可以直接在定义的函数上面加一个pysnooper装饰器,它能自动识别到语句和变量并将其值print出来,并且可以将运行过程中打印的数据直接保存到自定义的日志文件中。

梦在硅谷的博客 912

infinite-canvas 前端渲染优化指南:为 Script 标签正确使用 defer 与 async

在 infinite-canvas 这类面向 AI 创作的开源无限画布项目中,首屏加载性能直接决定用户对创作工具的第一印象。本指南围绕渲染性能领域的一项高影响(HIGH)最佳实践展开:**Script 标签必须显式使用 `defer` 或 `async`,消除渲染阻塞(render-blocking)**。读完本文,你将掌握 `defer` 与 `async` 的语义差异、正确的代码写法、Next

gitblog_01062的博客 382

想学python编程,先学什么,想学python编程要多久

6.Web开发基础Python之Web开发基础学习内容为HTML基础、CSS基础、JavaScript基础、局部变量和全局变量、集合、数组、字典、函数参数、原型、面向对象、作用域、dom编程、jquery介绍、jquery选择器、jquery属性和CSS操作、jquery文档处理、jquery筛选、jquery事件托管、jquery事件、jquery ajax、jquery扩展方法、bootstrap使用、EasyUI介绍和使用等。并会对常见数据结构和相应算法进行学习,注重表格的处理,树结构的处理知识。

神经网络爱好者 300
上一篇: 用 Python 绘制动态可视化图表,太酷了
下一篇: Python 你可能从未听说过的5种隐藏技巧
程序员小六
博客等级 码龄6年 111粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值