【python全栈开发】面向对象进阶

一、成员

(一)变量

实例变量:属于对象,每个对象中各自维护自己的数据。
类变量:属于类,可以被所有对象共享,一般用于给对象提供公共数据(类似于全局变量)。

请添加图片描述
类变量和实例变量的区别示例:

class Person:

    country = "中国"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        message = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, Person.country)
        message_ = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, self.country)
        print(message_)
        #country是类变量,但是由于self对象没有country,所以会通过调用实例变量来调用类变量


print(Person.country)
#中国
p1 = Person("高宇星", 18)
p1.show()

类变量和实例变量+继承问题:

请添加图片描述

class Base(object):
    country = "中国"


class Person(Base):

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        message = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, Person.country)
        message_ = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, self.country)
        print(message_)
        # country是类变量,但是由于self对象没有country,所以会通过调用实例变量来调用类变量

p2 = Person("闫曦月", 18)
p2.show()
#我的名字是闫曦月,我的年龄是18,我是中国人
print(p2.name)#闫曦月
print(p2.age)#18
print(p2.country)#中国
print(Person.country)#中国
print(Base.country)#中国

通常来说,调用的变量不是对象变量时,就会去对应的类中找类变量,如果类变量中仍然不存在,就会向上去父类中寻找变量。
请添加图片描述

class Base(object):
    country = "美国"


class Person(Base):

    country = "泰国"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        message = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, Person.country)
        message_ = "我的名字是{},我的年龄是{},我是{}人".format(self.name, self.age, self.country)
        print(message_)
        # country是类变量,但是由于self对象没有country,所以会通过调用实例变量来调用类变量

p2 = Person("闫曦月", 18)
p2.show()
#我的名字是闫曦月,我的年龄是18,我是泰国人
print(p2.name)#闫曦月
print(p2.age)#18
print(p2.country)#泰国
print(Person.country)#泰国
print(Base.country)#美国

当Base父类中的country变成“泰国”、Person类中的country变成“美国”时,调用P2实例对象的country时会找到类变量,答案为“美国”,只有调用Base类的变量country时,才会出现“泰国”。

(二)方法

一共有三种方法:绑定方法、类方法和静态方法

  1. 绑定方法:默认参数为self;
  2. 类方法:@classmethod、默认参数为cls;
  3. 静态方法:@staticmethod,没有默认参数。

python中比较灵活,三种方法均可以通过对象和类进行调用。

class Foo(object):
    def __init__(self, name):
        self.name = name
        
    def f1(self):
        print("绑定方法", self.name)
        
    
    @classmethod
    def f2(cls):
        print("类方法",cls)
        
    @staticmethod
    def f3():
        print("静态方法")

#绑定方法执行方式
obj = Foo("高宇星")
obj.f1()#绑定方法 高宇星
Foo.f1(obj) #非主流的执行方式 绑定方法 高宇星

#类方法执行方式
Foo.f2() #主流方式,直接通过类来实现,其中cls参数代表的就是Foo这个类
#类方法 <class '__main__.Foo'>
obj.f2() #非主流执行方式,通过对象来实现
#类方法 <class '__main__.Foo'>

#静态方法的执行方式
Foo.f3() #主流执行方式,通过类来调用
#静态方法
obj.f3() #主流执行方式,通过类来调用
#静态方法

具体应该使用哪种方法,具体还需要看涉及到哪些内容,如果需要传入对象,那就使用绑定方法,如果需要传入类,那就使用类方法,如果什么都不需要传入,就需要静态方法。

(三)属性

属性是由绑定方法+特殊装饰器组合而成的,主要的区别是:调用方法的时候需要加括号,调用属性的时候不需要加括号。

class Foo():

    def __init__(self, name):
        self.name = name

    def f1(self):
        return print(123)


    @property
    def f2(self):
        return print(123)


obj = Foo("闫曦月")
obj.f1()
#123
obj.f2
#123

在分页显示案例中,同样是在绑定方法基础上加上了@property之后,在调用start和end时可以省略掉括号。

class Pagination():
    def __init__(self, current_page, per_page_num=10):
        self.per_page_num = per_page_num

        if current_page < 1:
            self.current_page = 1
            return

        self.current_page = current_page

    #如果加上@property,在下面调用的时候就可以不加括号了,简洁代码(小小的简洁)
    @property
    def start(self):
        return (self.current_page-1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num


user_list = ["用户-{}".format(i) for i in range(1, 3000)]
#分页现实,每页显示10条
while True:
    page = int(input("请输入页码:"))

    print(type(page))

    page_object = Pagination(page, 20)
    page_object_list = user_list[page_object.start: page_object.end]
    for item in page_object_list:
        print(item)

关于属性的编写方式由两种:

  1. 基于装饰器
class C(object):

    @property
    def nnn(self):
        pass

    @nnn.setter
    def nnn(self, value):
        pass

    @nnn.deleter
    def nnn(self):
        pass


obj = C()
#触发nnn属性
obj.nnn

#触发nnn.setter,给该属性传入参数value=123
obj.nnn = 123

#触发nnn.deleter,删除nnn属性
del obj.nnn

  1. 基于定义变量
class C(object):
    def nnn(self):
        print('666')

    def setnnn(self, value):
        print(value)

    def delnnn(self):
        print('delete')

    x = property(nnn, setnnn, delnnn, "I'm the nnn property")
    #第四个参数是注释,等同于‘’‘I'm the nnn property’‘’
obj = C()
obj.x #666
obj.x = 333 
#333
del obj.x
#delete

也可以将方法定义成属性中的变量,在执行方法时会自动触发可以使用的属性。
补充:为了避免报错,属性和实例名不能相同

以下是错误示例:报错原因是,代码以为我要调用@name.setter装饰方法。

class Foo(object):
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    @property
    def name(self):
        return '{}-{}'.format(self.name, self.age)

obj = Foo("高宇星", 24)

改进,增加一个@name.setter装饰器,增加之后不会因为属性和实例名字相同而报错,但是会因为循环调用自己,一直递归导致层次太深而报错。

下面这个例子就是很好的说明,当实例化对象时,自然会用到name这个参数,由于参数name和属性name名字相同,触发了@name.setter,print一下value后就没了,但是此时就会调用属性name,在属性name中又有self.name, 又一次触发@name.setter,循环往复,不停进行递归运算。

class Foo(object):
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    @property
    def name(self):
        return '{}-{}'.format(self.name, self.age)

    @name.setter
    def name(self, value):
        print(value)

    
obj = Foo("高宇星", 24)

如果想让属性和实例上存在一些关联,就可以按照以下方式改进。在实例变量前面加一个_,这样实例变量就变成了_name,属性名字叫name,这样就不冲突了。

class Foo(object):
    
    def __init__(self, name, age):
        self._name = name
        self.age = age
        
    @property
    def name(self):
        print('{}-{}'.format(self._name, self.age))


obj = Foo("高宇星", 24)
obj.name
#高宇星-24

二、成员修饰符

python成员的修饰指的是:公有or私有

  1. 公有: 在任何地方都可以调用成员
  2. 私有:只有类的内部才可以调用成员(成员是以两个下划线开头,则表示该成员为私有)

1、示例一:私有对象和公有对象

(实例对象)对于私有成员__name来说,只能在内部调用,但是对于共有成员age来说,内部和外部都能调用。对于类对象来说也是同样的!

class Foo(object):

    def __init__(self, name, age):
        self.__name = name
        self.age = age

    def get_data(self):
        return self.__name

    def get_age(self):
        return self.age


obj = Foo("闫曦月", 18)
print(obj.age) #18
#obj.__name  age可以调用查看,但是__name是私有的,无法在类的外部进行调用

name = obj.get_data()
#在调用get_data方法时,由于该方法前面没有双下划线,所以是可以在类的外部进行调用的,在方法里面调用私有成员,这样是可以的
print(name) #闫曦月

age = obj.get_age()
print(age)
#18

2、示例二:私有方法和公有方法

class Foo():

    def get_age(self):
        print("公有的get_age")

    def __get_data(self):
        print("私有的__get_data")

    def proxy(self):
        print("公有的proxy")
        self.__get_data()

obj = Foo() 
obj.get_age() #公有的get_age
obj.proxy() 
'''
公有的proxy
私有的__get_data
'''

3、示例三:私有属性和公有属性

class Foo():
    @property
    def __name(self):
        print("私有的属性__name")

    @property
    def proxy(self):
        self.__name
        return 1

obj = Foo()
print(obj.proxy)
'''
私有的属性__name
1
'''

4、特别提示:如果存在继承关系,那么父类中的私有成员,子类无法继承

class Base():

    def __data(self):
        print("base.__data")

    def num(self):
        print("base.num")


class Foo(Base):

    def func(self):
        self.num()
        self.__name()

obj = Foo()
obj.func()
'''
Traceback (most recent call last):
  File "/Users/gaoyuxing/PycharmProjects/Django_learning/3.2.py", line 311, in <module>
    obj.func()
  File "/Users/gaoyuxing/PycharmProjects/Django_learning/3.2.py", line 308, in func
    self.__name()
AttributeError: 'Foo' object has no attribute '_Foo__name'
'''

总结:成员是否可以作为独立的功能暴露给外部,让外部调用,如果可以,则设置成公有成员,不然则是私有成员。

三、对象嵌套

在基于面向对象进行编程时,对象之间可以存在各种各样的关系,例如:组合、关联、依赖等,下面用示例类学习嵌套情景

(一)示例一

class Classes(object):
    '''班级类'''

    def __init__(self, title):
        self.title = title
        self.student_list = []

    def add_student(self, stu_object):
        self.student_list.append(stu_object)

    def add_students(self, stu_object_list):
        for stu in stu_object_list:
            self.add_student(stu)

    def show_numbers(self):
        for item in self.student_list:
            print(item.message())
            #print(item.name, item.age)
            #print(item.message)

c1 = Classes("三年级二班")
c1.add_student(s1)
c1.add_students([S2, S3])
'''
我是一名学生,我叫高宇星,我今年18岁
我是一名学生,我叫闫文,我今年18岁
我是一名学生,我叫哼哈二将,我今年15岁
'''
c1.show_numbers()

(二)示例二

class Student(object):
    '''学生类'''

    def __init__(self, name, age, class_object):
        self.name = name
        self.age = age
        self.class_object = class_object

    def message(self):
        data = "我是一名学生,我叫{},我今年{}岁".format(self.name, self.age)
        print(data)



class Classes(object):
    '''班级类'''

    def __init__(self, title):
        self.title = title


c1 = Classes("Python全栈开发")
c2 = Classes("Linux云计算")

user_object_list = [
    Student("高宇星", 18, c1),
    Student("闫文", 18, c1),
    Student("哼哈二将", 15, c2)
]

for obj in user_object_list:
    print(obj.name, obj.age, obj.class_object.title)

'''
高宇星 18 Python全栈开发
闫文 18 Python全栈开发
哼哈二将 15 Linux云计算
'''

请添加图片描述

(三)示例三

class Student(object):
    '''学生类'''

    def __init__(self, name, age, class_object):
        self.name = name
        self.age = age
        self.class_object = class_object

    def message(self):
        data = "我是一名学生,我叫{},我今年{}岁".format(self.name, self.age)
        print(data)



class Classes(object):
    '''班级类'''

    def __init__(self, title, school_object):
        self.title = title
        self.school_object = school_object


class School(object):
    '''学校类'''

    def __init__(self, name):
        self.name = name


s1 = School("北京海淀")
s2 = School("湖北黄冈")

c1 = Classes("Python全栈开发", s1)
c2 = Classes("Linux云计算", s2)

user_object_list = [
    Student("高宇星", 18, c1),
    Student("闫文", 18, c1),
    Student("哼哈二将", 15, c2)
]

for obj in user_object_list:
    print(obj.name, obj.age, obj.class_object.title, obj.class_object.school_object.name)

'''
高宇星 18 Python全栈开发 北京海淀
闫文 18 Python全栈开发 北京海淀
哼哈二将 15 Linux云计算 湖北黄冈
'''

请添加图片描述

四、特殊成员

在python中存在一些特殊我的方法,这些方法就是:__方法__格式,这种方法在内部均有特殊的含义。

(一)__init__初始化方法

class Foo():

    def __init__(self, name):
        self.name = name

obj = Foo("高宇星")
print(obj.name) #高宇星

(二)__new__构造方法

__new__方法相当于是在创建实例对象,它在__init__初始化方法之前先被触发。

class Foo():
    def __init__(self, name):
        print("第二步:初始化对象,在空对象中创建数据")
        self.name = name

    def __new__(cls, *args, **kwargs):
        print("第一步:先创建空对象并反回")


obj = Foo("高宇星")

(三) __call__构造方法

根据上述介绍,我们可以知道,在类名称后面加扩后可以调用__init__方法和__new__方法,在对象后面加括号,可以调用__call__方法。

class Foo(object):
    def __call__(self, *args, **kwargs):
        print("执行CALL方法")

obj = Foo()
obj()
#执行CALL方法

(四) __str__构造方法

class Student(object):
    '''学生类'''

    def __init__(self, name, age):
        self.name = name
        self.age = age

a = Student("高宇星", 18)
print(a)
#<__main__.Student object at 0x00000178A11A4550>
#当没有__str__方法时,在打印实例对象的时候,输出的是一个封装好的数据

#当我们加上__str__方法时,则可以很好得展示数据
class Student(object):
    '''学生类'''

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return '{}-{}'.format(self.name, self.age)


a = Student("高宇星", 18)
print(a)
#高宇星-18
#a = str(a)
#print(a)
#高宇星-18

(五) __dict__构造方法

class Student(object):
    '''学生类'''

    def __init__(self, name, age):
        self.name = name
        self.age = age

obj = Student("闫雯", 10)
print(obj.name) #闫雯
print(obj.age)#10

#我们可以通过调用对象的属性来查看年龄和姓名,此外,我们还可以调用__dict__方法来让它返回实例对象的所有变量
print(obj.__dict__)
#{'name': '闫雯', 'age': 10}

(六) getitemsetitem、_delitem

正常来说,我们想要实现字典的方式,给某个对象变量属性赋值是不可能实现的。

class Foo(object):
    def __init__(self):
        pass

obj = Foo()
obj["xxx"] = 123
print(obj["xxx"])
'''
Traceback (most recent call last):
  File "D:\test_supplier\develop_learning\123.py", line 222, in <module>
    obj["xxx"] = 123
TypeError: 'Foo' object does not support item assignment
'''

但是,只要我们使用__setitem__函数,就会自动触发,将等号左边的值数赋值给第一个参数,将等号右边的值赋值给第二个参数。实现字典功能。

class Foo():

    def __setitem__(self, key, value):
        print(key, value)

obj = Foo()
obj["xxx"] = 123
#xxx 123

一般来说,setitem只允许等号左右两边均有内容的情况存在,不支持单独调用某一个参数

class Foo():

    def __setitem__(self, key, value):
        print(key, value)

obj = Foo()
obj["xxx"] = 123
#xxx 123

obj["xxx"]
#本来也是不支持的
'''
Traceback (most recent call last):
  File "D:\test_supplier\develop_learning\123.py", line 229, in <module>
    obj["xxx"]
TypeError: 'Foo' object is not subscriptable
'''

但是只要加一个getitem方法就可以解决,实现了字典中调取值的功能。

class Foo():

    def __setitem__(self, key, value):
        print(key, value)


    def __getitem__(self, item):
        print(item)

obj = Foo()
obj["xxx"] = 123
#xxx 123

obj["000"] #自动触发类中的__getitem__
#000

此时,当我们直接调用del obj[“000”]时,又会报错。

class Foo():

    def __setitem__(self, key, value):
        print(key, value)


    def __getitem__(self, item):
        print(item)

obj = Foo()
obj["xxx"] = 123
#xxx 123

obj["000"] #自动触发类中的__getitem__
#000

del obj["000"]
'''
Traceback (most recent call last):
  File "D:\test_supplier\develop_learning\123.py", line 236, in <module>
    del obj["000"]
AttributeError: __delitem__
'''

我们只需要增加一个__delitem__方法就可以解决这个问题。

class Foo():

    def __setitem__(self, key, value):
        print(key, value)


    def __getitem__(self, item):
        print(item)

    def __delitem__(self, key):
        print(key)

obj = Foo()
obj["xxx"] = 123
#xxx 123

obj["000"] #自动触发类中的__getitem__
#000

del obj["000"]
#000

(七) enterexit

打开文件、阅读文件后一定要关闭文件,否则会占用内容。为了防止忘记关闭文件的情况发生,可以使用with open 的语法。

f = open('xxx.csv')
f.read()
f.close()

with open('xxx.csv') as f:
    f.read()

我们想在类中也实现这样的操作,于是:

class Foo(object):

    def __init__(self):
        pass

obj = Foo()
with obj as f:
    pass

'''
Traceback (most recent call last):
  File "D:\test_supplier\develop_learning\123.py", line 249, in <module>
    with obj as f:
AttributeError: __enter__
'''

报错了,原因是没有__enter__函数

class Foo(object):

    def __init__(self):
        pass

    def __enter__(self):
        pass


obj = Foo()
with obj as f:
    pass

'''
Traceback (most recent call last):
  File "D:\test_supplier\develop_learning\123.py", line 253, in <module>
    with obj as f:
AttributeError: __exit__
'''

于是我们增加了__enter__函数,但是又在报错,这次说是没有__exit__

class Foo(object):

    def __init__(self):
        pass

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass


obj = Foo()
with obj as f:
    pass

当我们加上__exit__时,文件不再报错了。
总结:当使用“with 对象”语法时,内部就会执行__enter__函数。
当我们在__enter__函数中增加一个返回值时,f就自动等于返回值了。

class Foo(object):

    def __init__(self):
        pass

    def __enter__(self):
        return 666

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass


obj = Foo()
with obj as f: #在这里f就等于666
    print(123)
    print(777)

当执行为with里面的程序时,会自动触发__exit__函数,关闭当前程序。
超前知识:数据连接,每次对远程的数据进行操作时都必须经历。
1、连接=连接数据库
2、操作数据库
3、关闭数据

class SqlHelper(object):

    def __enter__(self):
        self.连接 = 连接数据库
        return 连接

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.连接.关闭

with SqlHelper() as :
    连接.操作

总结:with 对象可以让人们重点关注操作代码的编写。
面试题目:补充完善代码。

class Content:
    
    def do_something(self):
        print('内部执行')
        

with Content() as ctx:
    print('内部执行')
    ctx.do_something()
    

从上面的代码中可以知道,主要考察的是with+对象的语法。我们可以知道,代码中缺少__enter__和__exit__函数

class Content:

    def do_something(self):
        print('内部执行')
        
    def __enter__(self):
        return 666
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        pass


with Content() as ctx:
    print('内部执行')
    ctx.do_something()

当我们把代码完善到这个程度时,就会发现,ctx可以调用do_something,那么ctx必须是实例对象,如果要求ctx为实例对象,就必须在__enter__函数中返回实例对象自己。

class Content:

    def do_something(self):
        print('内部执行')

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass


with Content() as ctx:
    print('内部执行')
    ctx.do_something()
'''
内部执行
内部执行
'''

(八) __add__类方法

如果我们相同在构建的类中实现add功能,就必须添加__add__函数。加减乘除计算都是一样的道理。

class Foo(object):

    def __init__(self, name):
        self.name = name

    def __add__(self, other):
        return '{}-{}'.format(self.name, other.name)

v1 = Foo("alex")
v2 = Foo("nnn")

print(v1 + v2)
#alex-nnn

(九) __iter__类方法

1、迭代器的定义

(1)当类中定义了__iter__和__next__两种方法,这两种方法要同时存在;
(2)__iter__方法需要由返回对象本身,即:self;
(3)__next__方法,返回下一个数据,如果没有数据了,则需要抛出一个StopIteration的异常。

#创建迭代器
class IT(object):
    def __init__(self):
        self.counter = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == 3:
            raise StopIteration()
        return self.counter

#根据实例化创建一个迭代器对象
obj1 = IT()
#v2 = obj1.__next__()
v2_ = next(obj1)
print(v2) #1
print(v2_)#1

v3 = next(obj1) #2
#v4 = next(obj1)  #由于当数值等于3的时候就会停止迭代,因此v4会报错哦
print(v3)
#print(v4)

obj2 = IT()
for item in obj2:
    print(item)
    
'''
1
2
'''

迭代器对象支持通过next()来取值,其功能等同于__next__(),如果取值结束则会自动抛出StopIteration()函数。for循环内部在循环时,先执行 iter__方法,获取一个迭代器对象,然后不断执行__next()取值,有异常则StopIteration()终止循环。

2、生成器

含有yield关键字的函数,调用该函数时会返回一个生成器。

#创建生成器函数

def generator_function():
    print('hello1')
    yield 1
    print('hello2')
    yield 2
    print('hello3')

g = generator_function() #函数没有马上执行,而是返回了一个生成器,当然也是一种迭代器
print(g) #<generator object generator_function at 0x000001E21A97BF90>
print(next(g)) #当使用next()方法的时候则开始执行,遇到yield暂停
'''
hello1
1
'''
print(next(g)) #继续使用next()函数时,继续从上次停止的地方开始执行,然后遇到yeild再次停止
'''
hello2
2
'''
print(next(g)) #从原来暂停的地方再次执行,没有yield函数,但是由于没有要继续执行的内容,所以还是停止了
#hello3

3、可迭代对象

#创建可迭代对象
class IT(object):
    def __init__(self):
        self.counter = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == 3:
            raise StopIteration()
        return self.counter

    
class Foo():
    def __iter__(self):
        return IT()

obj = Foo()
for item in obj:
    print(item)
'''
1
2
'''

range()函数本身就是一个可迭代对象,因为有__iter__方法,但是没有__next__方法。

v1 = range(10001)
print(dir(v1))
#['__bool__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index', 'start', 'step', 'stop']

4、练习

(1)利用可迭代对象和迭代器定义range函数
class IterRange(object):
    def __init__(self, num):
        self.num = num
        self.counter = -1


    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == self.num:
            raise StopIteration
        return self.counter



class Xrang(object):
    def __init__(self, max_num):
        self.max_num = max_num

    def __iter__(self):
        return IterRange(self.max_num)

obj = Xrang(10001)
for item in obj:
    print(item)
(2)利用可迭代对象和生成器实现range函数
class Xrange(object):

    def __init__(self, max_num):
        self.max_num = max_num

    def __iter__(self):
        counter = 0
        while counter < self.max_num:
            yield counter
            counter += 1

obj = Xrange(100)
for item in obj:
    print(item)

5、判断可迭代对象&迭代器

from collections.abc import Iterator, Iterable

v1 = [11, 22, 33]
print(isinstance(v1, Iterable)) #True
print(isinstance(v2, Iterator)) #False

v2 = v1.__iter__()
print(isinstance(v2, Iterator)) #True
print(isinstance(v2, Iterable)) #True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值