阶段学习总结


前言

又一段时间的学习,下面做些总结


一、装饰器与带参数的装饰器

装饰器的作用,在不改变函数内容的前提下丰富函数的功能。

1.闭包

闭包是装饰器的组成部分,其基本的语法要求为:
1、发生函数嵌套
2、外层函数返回内层函数名
3、内层函数使用外层函数参数
闭包还可以提高代码的可重用性,不需要再手动定义额外的功能函数。

def func_out(data):
    def func_in():
        print(data)

    return func_in


fun = func_out(10)
fun()

2.利用@的闭包实现

def fun_out(func):
    def func_in(num):
        print(num)
        func()

    return func_in


@fun_out
def run():
    print("跑步")


run(12)

3.装饰器与带参数的装饰器

装饰器的功能特点:
1、不修改已有函数的源代码
2、不修改已有函数的调用方式
3、给已有函数增加额外的功能
上述@形式名为语法糖,为装饰器的特点:

def load(func):
    def success():
        print("请先登录")
        func()

    return success

@load
def comment():
    print("发表评论!")

comment()

带有参数的装饰器利用不定长参数传递参数

def func(fun):
    def warp(*args, **kwargs):
        print("这是装饰")
        sum = fun(*args, **kwargs)
        return sum
        print("这也是装饰!")

    return warp


@func
def fun():
    print("跑起来")


@func
def add(a, b):
    return a + b


fun()
print(add(1, 2))

实现不同函数异常写入不文件中,即在日志装饰器上层再加一个装饰器,与wsgi中实现动态资源路由表相同。
装饰器文件:

import traceback


def decorate(path):
    def outer(func):
        def inner(*args, **kwargs):
            try:
                result = func(*args, **kwargs)
            except:
                with open(path, 'a', encoding="utf-8") as f:
                    print(traceback.format_exc())
                    f.write(traceback.format_exc())
            else:
                return result

        return inner

    return outer

引用装饰器函数

from log import decorate


@decorate("local.log")
def fun():
    a += 1
    print(a)


@decorate("zero.log")
def chu(a):
    result = a / 0
    return result


fun()
chu(10)

二、正则表达式

1.自定义上下文管理器

with open的语法实现具体操作:

https://blog.youkuaiyun.com/weixin_43790276/article/details/90216525

扩展函数的注解:

https://www.cnblogs.com/keye/p/8572353.html

class File(object):
    def __init__(self, file_name, file_type):
        self.file_name = file_name
        self.file_type = file_type

    def __enter__(self):
        print("进入上文的方法")
        self.file = open(self.file_name, self.file_type)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("进入下文的方法")
        self.file.close()


if __name__ == '__main__':
    with File("test.txt", 'r') as file:
        data = file.read()
        print(data)

2.正则表达式

正则表达式就是记录文本规则的代码
特点:
1、正则表达式的语法很令人头疼,可读性差
1、正则表达式通用行很强,能够适用于很多编程语言
在python中使用正则表达式需要导入re模块

# 导入re模块
import re

# 使用match方法进行匹配操作
result = re.match(正则表达式, 要匹配的字符串)

# 如果上一步匹配到数据的话,可以使用group方法来提取数据
result.group()

3.正则表达式:匹配单字符

导入模块

import re
. 匹配任意1个字符(除了\n)
result = re.match('.', 'dog')
print(result.group())	
# d
[ ] 匹配[ ]中列举的字符
result = re.match("...[do]p", "dppdppo")
print(result.group())		
# dppdp

# 只从第一个字符匹配
result = re.match("[dp]", "depppo")  
print(result.group())		
# d

ret = re.match("[0123456789]Hello Python", "7Hello Python")
print(ret.group())		
# 7Hello Python

# 匹配0到9第二种写法
ret = re.match("[0-9]Hello Python", "7Hello Python")
print(ret.group())		
# 7Hello Python

# 匹配0-3,5-9
ret = re.match("[0-35-9]Hello Python", "7Hello Python")
print(ret.group())		
# 7Hello Python
\d 匹配数字,即0-9
result = re.match('今年\d\d\d\d', '今年2021')
print(result.group())
# 今年2021

ret = re.match("嫦娥\d号", "嫦娥3号发射成功")
print(ret.group())
# 嫦娥3号
\D 匹配非数字,即不是数字
result = re.match('今年\d\d\d1\D\D', '今年2021年!')
print(result.group())
# 今年2021年!
\s 匹配空白,即 空格,tab键
result = re.match('今年[0-9]\d\d[1]年\D\s啊', '今年2021年! 啊')
print(result.group())
# 今年2021年! 啊
\S 匹配非空白
result = re.match('今年[0-9]\d\d[1]年\D\s啊\S\S\D', '今年2021年! 啊。。-')
print(result.group())
# 今年2021年! 啊。。-

\w 匹配非特殊字符,即a-z、A-Z、0-9、_、汉字

result = re.match('今年[0-9]\d\d[1]年\D\s啊\S\D\D\w\w', '今年2021年! 啊。。-_A')
print(result.group())
# 今年2021年! 啊。。-_A

\W 匹配特殊字符,即非字母、非数字、非汉字

result = re.match('今年[0-9]\d\d[1]年\D\s啊\S\D\D\w\w\D\S\W', '今年2021年! 啊。。-_A%$#')
print(result.group())
# 今年2021年! 啊。。-_A%$#

4.正则表达式:匹配多字符

* 匹配前一个字符出现0次或者无限次,即可有可无

需求:匹配出一个字符串第一个字母为大小字符,后面都是小写字母并且这些小写字母可有可无

ret = re.match("[A-Z][a-z]*", "M")
print(ret.group())
# M

ret = re.match("[A-Z][a-z]*", "MnnfM")
print(ret.group())
# Mnnf

ret = re.match("[A-Z][a-z]*", "Aabcdef")
print(ret.group())
# Aabcdef

+ 匹配前一个字符出现1次或者无限次,即至少有1次

需求:匹配一个字符串,第一个字符是t, 最后一个字符串是o, 中间至少有一个字符

match_obj = re.match("t.+o", "tdeo")
if match_obj:
    print(match_obj.group())
else:
    print("匹配失败")
# tdeo

? 匹配前一个字符出现1次或者0次,即要么有1次,要么没有

需求:匹配出这样的数据,但是https 这个s可能有,也可能是http 这个s没有

match_obj = re.match("https?", "http")
if match_obj:
    print(match_obj.group())
else:
    print("匹配失败")
# http

{m} 匹配前一个字符出现m次
{m,n} 匹配前一个字符出现从m到n次

需求:匹配出,8到20位的密码,可以是大小写英文字母、数字、下划线

ret = re.match("[a-zA-Z0-9_]{6}", "12a3g45678")
print(ret.group())
# 12a3g4

ret = re.match("[a-zA-Z0-9_]{8,20}", "1ad12f23s34455ff66sfef")
print(ret.group())
# 1ad12f23s34455ff66sf

5.正则表达式:练习

以()为分组内容,可以用.group(1)获取分组内容

# 分组

match_obj = re.match("[a-zA-Z0-9_]{4,20}@(163|126|qq|sina|yahoo)\.com", "hello@163.com")
if match_obj:
    print(match_obj.group())
    # 获取分组数据
    print(match_obj.group(1))
else:
    print("匹配失败")
# hello@163.com
# 163

^匹配以什么开头,$匹配以什么结尾

# 匹配开头和结尾
try:
    str1 = re.match('^[0-9].*', "345hello")
    content = str1.group()
except:
    print("匹配不成功")
else:
    print(content)
# 345hello

# 需求: 匹配以数字结尾的数据
str1 = re.match('\S*\d$', "dadw345")
print(str1.group())
# dadw345

# 需求: 匹配以数字开头中间内容不管以数字结尾
# .*表示任意字符,任意个数
str1 = re.match('^\d.*\d$', "12hudhw93")
print(str1.group())
# 12hudhw93

[^指定字符]: 表示除了指定字符都匹配

# 需求: 第一个字符除了aeiou的字符都匹配
str1 = re.match('[^aeiou].*', "hdaw")
print(str1.group())
# hdaw
# 1.匹配出163的邮箱地址,且@符号之前有4到20位,例如hello@163.com
str1 = re.match("[a-zA-Z0-9_]{4,20}@163\.com$", "hello@163.com")
print(str1.group())

# 2.匹配出11位手机号码
str1 = re.match('[0-9]{11}', "92345678909")
print(str1.group())

# 3.匹配出微博中的话题, 比如: #幸福是奋斗出来的#
str1 = re.match('^#.*#$', "#幸福是奋斗出来的#")
print(str1.group())

| 匹配其中一个

# 需求:在列表中["apple", "banana", "orange", "pear"],匹配apple和pear
list1 = ["apple", "banana", "orange", "pear"]
for i in list1:
    try:
        str1 = re.match("apple|pear", i)
        result = str1.group()
    except:
        print(f"{i}匹配失败")
    else:
        print(f"{result}是我要的")

. 转译小数点

# 需求:匹配出163、126、qq等邮箱
str1 = re.match('[A-Za-z0-9_]{8,20}@(qq|163|126)\.com', "1065365791@qq.com")
print(str1.group(), str1.group(1))
# 需求: 匹配qq:10567这样的数据,提取出来qq文字和qq号码
str1 = re.match('^(qq):([0-9]{4,10})', "qq:1075365791")
print(str1.group(), str1.group(1), str1.group(2))

# 需求:匹配出<html>hh</html>
str1 = re.match('<[a-zA-Z1-6]+>.*</[a-zA-Z1-6]+>', "<html>hh</html>")
print(str1.group())

利用分组匹配相同内容

# 需求:匹配出<html><h1>www.baidu.com</h1></html>
str1 = re.match('<([a-zA-Z1-6]+)><([a-zA-Z1-6]+)>.*</\\2></\\1>', "<html><h1>www.baidu.com</h1></html>")
print(str1.group())

# 需求:匹配出<html><h1>www.baidu.com</h1></html>
str1 = re.match('<(?P<s1>[a-zA-Z1-6]+)><(?P<s2>[a-zA-Z1-6]+)>.*</(?P=s2)></(?P=s1)>',
                "<html><h1>www.baidu.com</h1></html>")
print(str1.group())

三、web编程框架、深浅拷贝、扩展模块

1.回顾TCP、IP:PORT、HTTP

tcp:传输控制协议,数据传输的规则,主要理解三次握手、四次挥手,其核心封装成socket套接字。编程中只需要使用套接字可完成网络连接。
服务端:
1、创建套接字对象
2、设置端口复用
3、绑定IP和端口,注意bind()里的参数是个元组
4、设置客户端套接字监听数量
5、等待客户端建立连接,接收客户端套接字和ip_port,accept()
6、接收客户端数据,解码
7、发送服务端数据,编码
8、关闭客户端套接字、关闭服务端套接字
客户端:
1、创建套接字对象
2、连接服务端connection()
3、发送数据,编码
4、接收数据,解码
5、关闭套接字对象

IP:PORT:IP即计算机在网络中的地址,分为公网IP,内网IP,域名通常绑定公网IP。IPv4:十进制组成端口,IPv6:16进制。PORT指向当前计算机运行的某一程序,端口有限,1-1023知名端口(22,23),动态端口,默认程序端口(2181,1433)

HTTP:超文本传输协议,规定网络传输内容,超越文本限制。 请求报文 get: 请求行、请求头、空行 post:请求行、请求头、空行、请求体; 响应报文:响应行、响应头、空行、响应体;每日一项之间用\r\n连接。

2.FasTAPI框架

框架:即封装好的功能,可以通过装饰器等方式对其功能进行扩展,完善自己的功能。FastAPI封装了,web编程中网络连接、分析请求、接收发数据等功能,只需对响应资源进行处理返回即可实现web程序。

https://blog.youkuaiyun.com/s_daqing/article/details/108294763
https://www.jianshu.com/p/4bc36027049d

# 导入 FastAPI 类
from fastapi import FastAPI, Query
# 导入 uvicorn
import uvicorn
# 对返回内容进行处理
from fastapi import Response
# 对请求参数进行处理
from enum import Enum
from pydantic import BaseModel, Field

# 创建 FastAPI 对象
app = FastAPI()


# 定义业务处理函数并设置对应的 URL 地址
# get:表示请求方式
# /index:表示请求的 URL 地址
@app.get('/index')
def index():
    # 'Hello World'是响应体的内容
    return 'NOT FOUND!'


# TODO:定义处理函数,访问 / 和 /gdp.html 地址时,返回 gdp.html 内容
@app.get('/')
@app.get('/gdp.html')
def gdp():
    with open("./sources/html/gdp.html", 'rb') as f:
        content = f.read()
    return Response(content, media_type='html')


# TODO:定义处理函数,访问 /render.html 地址时,返回 render.html 内容
@app.get('/render.html')
def render():
    with open("./sources/html/render.html", 'rb') as f:
        content = f.read()
    return Response(content, media_type='html')


# 路径参数设置枚举值类
class GenderNum(str, Enum):
    male = "male"
    female = "female"


# 参数设置枚举值
@app.get("/gender/{gender_name}/")
def gender(gender_name: GenderNum):
    return {"gender_name": gender_name}


# 验证必传, 不传会报错
@app.get("/search/")
def search(q: str = Query(..., max_length=5)):
    return {"msg": "查询参数为{}".format(q)}


# 设置表单请求体参数验证模型
class ArticleModel(BaseModel):
    title: str
    author: str
    content: str = None  # 如果没有传入这个参数,则默认为None
    description: str = Field(max_length=5)  # 限制最大长度


@app.post("/article/")
def add_article(article: ArticleModel):
    print(article)
    return {"article": article}


if __name__ == '__main__':
    # 启动 Web 服务器
    uvicorn.run("05-FastAPI 基本使用-返回html内容:app", host='127.0.0.1', port=8080, reload=True)

FastAPI调试地址:http://127.0.0.1:8000/docs

3.深、浅拷贝

在python中,赋值的操作都是将内存中内容的引用赋予相应的变量。对于可变类型来说,容器中内容的改变并不会改变可变容器的引用地址,即

a=[1,2,3] 
b =a  
a.append(7) 
print(b) # -->[1,2,3,7] b和a还是指向同一个引用地址

对于不可变类型来说,值得的改变即引用地址的边改变
浅拷贝:对于不可变类型来说,浅拷贝不会创建新的引用,因为只拷贝第一层引用,不可变嵌套可变也不会创建新引用。对于可变类型来说,浅拷贝只拷贝可变类型的第一层。
深拷贝:拷贝对象的每一层引用创建新引用。对于不可变来说,第一层为不可变不创建新引用,第二层为可变,会创建新引用。对于可变类型来说,拷贝每一层,创建新引用。
例题:

import copy

a = [[1, 2, 3], [4, 5, 6]]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)

a.append(7)
a[1][2] = 0
print(a, b, c, d)

4.扩展模块

加密模块

import hashlib

list1 = []


def encode_pass(method):
    def decorate(func):
        def inner(*args, **kwargs):
            print(f"开始使用{method}加密:")
            result = func(*args, **kwargs)
            print(f"{method}加密完成")
            return result

        return inner

    return decorate


# md5加密
@encode_pass("md5")
def encode_md5(password):
    md5 = hashlib.md5()
    md5.update(password.encode("utf-8"))
    result = md5.hexdigest()
    return result


# sha1 加密
@encode_pass("sha1")
def encode_sha1(password):
    sha1 = hashlib.sha1()
    sha1.update(password.encode("utf-8"))
    result = sha1.hexdigest()
    return result


# sha256 加密
@encode_pass("sha256")
def encode_sha256(password):
    sha256 = hashlib.sha256()
    sha256.update(password.encode("utf-8"))
    result = sha256.hexdigest()
    return result


# shasha384 加密
@encode_pass("sha384")
def encode_sha384(password):
    sha384 = hashlib.sha384()
    sha384.update(password.encode("utf-8"))
    result = sha384.hexdigest()
    return result

# 注意:hashlib 加密啊的字符串类型为二进制编码,直接加密字符串会报如下错误:


# shaa1 = hashlib.sha1()
# shaa1.update(string.encode('utf-8'))
# res = shaa1.hexdigest()
# print("sha1采用encode转换加密结果:", res)

# 或者使用byte转换为二进制

# shab1 = hashlib.sha1()
# shab1.update(bytes(string, encoding='utf-8'))
# res = shab1.hexdigest()
# print("sha1采用byte转换的结果:", res)

low = hashlib.md5()
low.update('ab'.encode('utf-8'))
res = low.hexdigest()
print("普通加密:", res)

high = hashlib.md5(b'beyondjie')
high.update('ab'.encode('utf-8'))
res = high.hexdigest()
print("采用key加密:", res)

# 输出结果:
# 普通加密: 187ef4436122d1cc2f40dc2b92f0eba0
# 采用key加密: 1b073f6b8cffe609751e4c98537b7653

时间模块

import time

# a、timestamp时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移
# b、struct_time 时间元组,共有九个元素组.
# c、format time 格式化时间,已格式化的结构使时间更具可读性.包括自定义格式和固定格式

# 生成时间戳
print(time.time())

# struct_time to timestamp
print(time.mktime(time.localtime()))

# 生成struct_time
print(time.localtime())
print(time.localtime(time.time()))

# timestamp to struct_time
print(time.gmtime())
print(time.gmtime(time.time()))

# format_time to struct_time
print(time.strptime('2011-05-08 16:37:06', '%Y-%m-%d %X'))

# 生成format_time

# struct_time to format_time
print(time.strftime('%Y-%m-%d %X', time.localtime()))

# 生成固定格式的时间表示格式
print(time.asctime(time.localtime()))
print(time.ctime(time.time()))

import datetime

# datetime模块
# 1 date类 年月日
d1 = datetime.date(2012, 3, 4)
print(d1.year)

# 2 time 时分秒
h1 = datetime.time(15, 30, 46)
print(h1.hour)

# 3 datetime 上述组合

日志模块

# logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;
# 相比print,具备如下优点:
"""
1 可以通过设置不同的日志等级,在release版本中只输出重要信息,而不必显示大量的调试信息;
2 print将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging则可以由开发者决定将信息输出到什么地方,以及怎么输出;
"""
import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s - %(levelname)s - %(filename)s -%(lineno)d - %(message)s',
                    filename='info.txt',
                    filemode='w'
                    )
logging.info("这是一个日志")
logging.warning("这是高一点的日志")
logging.debug("这是测试")
logging.error("这是高级日志")

# 我们将logger的级别改为DEBUG,再观察一下输出结果,控制台输出,可以发现,输出了debug的信息。

# logging.basicConfig函数各参数:
# filename:指定日志文件名;
# datefmt:指定时间格式,同time.strftime();
# level:设置日志级别,默认为logging.WARNNING;
# stream:指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,
# 当stream和filename同时指定时,stream被忽略;
# filemode:和file函数意义相同,指定日志文件的打开模式,'w'或者'a';
# format:指定输出的格式和内容,format可以输出很多有用的信息:
# 参数:作用
# %(levelno)s:打印日志级别的数值
# %(levelname)s:打印日志级别的名称
# %(pathname)s:打印当前执行程序的路径,其实就是sys.argv[0]
# %(filename)s:打印当前执行程序名
# %(funcName)s:打印日志的当前函数
# %(lineno)d:打印日志的当前行号
# %(asctime)s:打印日志的时间
# %(thread)d:打印线程ID
# %(threadName)s:打印线程名称
# %(process)d:打印进程ID
# %(message)s:打印日志信息

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s - %(levelname)s - %(filename)s -%(lineno)d - %(message)s',
                    filename='info.txt',
                    filemode='w'
                    )



# logger中添加StreamHandler,可以将日志输出到屏幕上,


logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(level=logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s -%(lineno)d - %(message)s')
handler.setFormatter(formatter)

console = logging.StreamHandler()
console.setLevel(logging.INFO)

logger.addHandler(handler)
logger.addHandler(console)

# handler名称:位置;作用
#
# StreamHandler:logging.StreamHandler;日志输出到流,可以是sys.stderr,sys.stdout或者文件
# FileHandler:logging.FileHandler;日志输出到文件
# BaseRotatingHandler:logging.handlers.BaseRotatingHandler;基本的日志回滚方式
# RotatingHandler:logging.handlers.RotatingHandler;日志回滚方式,支持日志文件最大数量和日志文件回滚
# TimeRotatingHandler:logging.handlers.TimeRotatingHandler;日志回滚方式,在一定时间区域内回滚日志文件
# SocketHandler:logging.handlers.SocketHandler;远程输出日志到TCP/IP sockets
# DatagramHandler:logging.handlers.DatagramHandler;远程输出日志到UDP sockets
# SMTPHandler:logging.handlers.SMTPHandler;远程输出日志到邮件地址
# SysLogHandler:logging.handlers.SysLogHandler;日志输出到syslog
# NTEventLogHandler:logging.handlers.NTEventLogHandler;远程输出日志到Windows NT/2000/XP的事件日志
# MemoryHandler:logging.handlers.MemoryHandler;日志输出到内存中的指定buffer
# HTTPHandler:logging.handlers.HTTPHandler;通过"GET"或者"POST"远程输出到HTTP服务器

# 日志回滚

from logging.handlers import RotatingFileHandler
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
# 定义一个RotatingFileHandler,最多备份3个日志文件,每个日志文件最大1K
rHandler = RotatingFileHandler("log.txt",maxBytes=1*1023,backupCount=3)
rHandler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s -%(lineno)d - %(message)s')
rHandler.setFormatter(formatter)

console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)

logger.addHandler(rHandler)
logger.addHandler(console)


# 设置消息等级

# 日志等级:使用范围
# FATAL:致命错误
# CRITICAL:特别糟糕的事情,如内存耗尽、磁盘空间为空,一般很少使用
# ERROR:发生错误时,如IO操作失败或者连接问题
# WARNING:发生很重要的事件,但是并不是错误时,如用户登录密码错误
# INFO:处理请求或者状态变化等日常事务
# DEBUG:调试过程中使用DEBUG等级,如算法中每个循环的中间状态

# 也可以使用logger.exception(msg,_args),它等价于logger.error(msg,exc_info = True,_args),
#
# 将     logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)
# 替换为,logger.exception("Failed to open sklearn.txt from logger.exception")

josn日志模块,yaml日志模块

import json
import logging.config
import os


def setup_logging(default_path="log_josn.josn", default_level=logging.INFO, env_key="LOG_CFG"):
    path = default_path
    value = os.getenv(env_key, None)
    if value:
        path = value
    if os.path.exists(path):
        with open(path, "r") as f:
            config = json.load(f)
            logging.config.dictConfig(config)
    else:
        logging.basicConfig(level=default_level)


def func():
    logging.info("start func")

    logging.info("exec func")

    logging.info("end func")


if __name__ == "__main__":
    setup_logging(default_path="log_josn.josn")

import yaml
import logging.config
import os


def setup_logging(default_path="./YAML.yml", default_level=logging.INFO, env_key="LOG_CFG"):
    path = default_path
    value = os.getenv(env_key, None)
    if value:
        path = value
    try:
        with open(path, "r", encoding="utf-8") as f:
            config = yaml.load(f, Loader=yaml.FullLoader)
            logging.config.dictConfig(config)
    except Exception:
        logging.basicConfig(level=default_level)


def func():
    logging.info("start func")

    logging.info("exec func")

    logging.info("end func")


if __name__ == "__main__":
    setup_logging(default_path="./YAML.yml")
    func()

https://www.cnblogs.com/wf-linux/archive/2018/08/01/9400354.html


总结

光阴似水,人生逆旅矣。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值