8天Python从入门到精通-全部总结

1、python基础语法

1.1 字面量

1.掌握字面量的含义
2.了解常见的字面量类型
3.基于print语句完成各类字面量的输出

字面量: 在代码中,被写下来的固定的值,称之为字面量

常用的值类型

Python中常用的有6种值(数据)的类型

类型描述说明
数字(Number)支持 •整数(int) •浮点数(float) •复数(complex) •布尔(bool)整数(int),如:10、-10
浮点数(float),如:13.14、-13.14
复数(complex),如:4+3j,以j结尾表示复数
布尔(bool)表达现实生活中的逻辑,即真和假,True表示真,False表示假。 True本质上是一个数字记作1,False记作0
字符串(String)描述文本的一种数据类型字符串(string)由任意数量的字符组成
列表(List)有序的可变序列Python中使用最频繁的数据类型,可有序记录一堆数据
元组(Tuple)有序的不可变序列可有序记录一堆不可变的Python数据集合
集合(Set)无序不重复集合可无序记录一堆不重复的Python数据集合
字典(Dictionary)无序Key-Value集合可无序记录一堆Key-Value型的Python数据集合

字符串

1.2 注释

注释:在程序代码中对程序代码进行解释说明的文字。

作用:注释不是程序,不能被执行,只是对程序代码进行解释说明,让别人可以看懂程序代码的作用,能够大大增强程序的可读性。

  • 单行注释:以 #开头,#右边 的所有文字当作说明,而不是真正要执行的程序,起辅助说明作用

    # 当行注释
    
  • 多行注释: 以 一对三个双引号 引起来,来解释说明一段代码的作用使用方法

    """
    	多行注释
    """
    
  • 注释的作用是

    注释是代码中的解释型语句,用来对代码内容进行注解

    注释不是代码,不会被程序执行

  • 单行注释如何定义

    通过 # 号定义,在#号右侧的所有内容均作为注释

    建议在#号和注释内容之间,间隔一个空格

    单行注释一般用于对一行或一小部分代码进行解释

  • 多行注释如何定义

    通过一对三个引号来定义(“”“注释内容”“”),引号内部均是注释,可以换行

    多行注释一般对:Python文件、类或方法进行解释

1.3 数据类型

# 我们可以通过type(被查看类型的数据)
type(111) # <class 'int'>
type(11.11) # <class 'float'>
type("字符串") #<class 'str'>
name ="str"
type(name)

1.4 数据类型转换

语句(函数)说明
int(x)将x转换为一个整数
float(x)将x转换为一个浮点数
str(x)将对象 x 转换为字符串
  • 任何类型,都可以通过str(),转换成字符串

  • 字符串内必须真的是数字,才可以将字符串转换为数字

1.5 标识符

标识符是用户在编程的时候所使用的一系列名字,用于给变量、类、方法等命名

标识符命名中,只允许出现

  • 英文
  • 中文
  • 数字
  • 下划线(_)

其余任何内容都不被允许

不推荐使用中文,数字不可以开头 \textcolor{red}{不推荐使用中文,数字不可以开头} 不推荐使用中文,数字不可以开头

标识符大小写敏感,不可以使用关键字

命名规范:

  • 见明知意
  • 下划线命名法
  • 英文字母全小写

1.6 运算符

运算符描述实例
+两个对象相加 a + b 输出结果 30
-得到负数或是一个数减去另一个数 a - b 输出结果 -10
*两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200
/b / a 输出结果 2
//取整除返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0
%取余返回除法的余数 b % a 输出结果 0
**指数a**b 为10的20次方, 输出结果 100000000000000000000
赋值运算符描述实例
=赋值运算符把 = 号右边的结果 赋给 左边的变量,如 num = 1 + 2 * 3,结果num的值为7
复合赋值运算符描述实例
+=加法赋值运算符c += a 等效于 c = c + a
-=减法赋值运算符c -= a 等效于 c = c - a
*=乘法赋值运算符c *= a 等效于 c = c * a
/=除法赋值运算符c /= a 等效于 c = c / a
%=取模赋值运算符c %= a 等效于 c = c % a
**=幂赋值运算符c ** = a 等效于 c = c ** a
//=取整除赋值运算符c //= a 等效于 c = c // a
"""
演示Python中的各类运算符
"""
# 算术(数学)运算符
print("1 + 1 = ", 1 + 1) # 1 + 1 =  2
print("2 - 1 = ", 2 - 1) # 2 - 1 =  1
print("3 * 3 = ", 3 * 3) # 3 * 3 =  9
print("5 / 2 = ", 5 / 2) # 5 / 2 =  2.5
print("11 // 2 = ", 11 // 2) # 11 // 2 =  5
print("9 % 2 = ", 9 % 2) # 9 % 2 =  1
print("2 ** 2 = ", 2 ** 2) # 2 ** 2 =  4
# 赋值运算符
num = 1 + 2 * 3
# 复合赋值运算符
# +=
num = 1
num += 1 # num = num + 1
print("num += 1: ", num) # num += 1:  2
num -= 1
print("num -= 1: ", num) # num -= 1:  1
num *= 4
print("num *= 4: ", num) # num *= 4:  4
num /= 2
print("num /= 2: ", num) # num /= 2:  2.0
num = 3
num %= 2
print("num %= 2: ", num) # num %= 2:  1

num **= 2
print("num **=2: ", num) # num **=2:  1

num = 9
num //= 2
print("num //= 2:", num) # num //= 2: 4

1.7 字符串扩展

字符串类型的不同定义方式

字符串有3种不同的定义方式:

​ 双引号定义法 “字符串”

​ 双引号定义法 ‘字符串’

​ 双引号定义法 “”“字符串”“”

字符串引号嵌套

  • 单引号定义法,可以内含双引号

  • 双引号定义法,可以内含单引号

  • 可以使用转移字符(\)来将引号解除效用,变成普通字符串

字符串拼接

print("字符串" + "拼接")

name = "zhangsan"
print("hello " + name)
# 不可以直接拼接数字类型的
"""
	字符串无法和非字符串变量进行拼接
	因为类型不一致,无法接上
	就像接力赛一样,不是队友,不能接力的哦
"""
"""
其中的,%s 
%  表示:我要占位
s   表示:将变量变成字符串放入占位的地方

"""
name = "zhangsan"
my_name ="lisi"
my_age = 17.9
message ="hello %s my name is %s" % (name,my_name)
print(message)
# hello zhangsan my name is lisi
message2 =f"hello {name} my name is {my_name} my age is {my_age}"
age ="  %f " % my_age
print(message2)# hello zhangsan my name is lisi my age is 17.9
print(age) # 17.900000

print("%.2f" % my_age)# 17.90
print("%6.2f" % my_age)# 这里会有空格17.90

print("2 * 2 的结果是:%d" % (2 * 2) ) # 2 * 2 的结果是:4
print(f"2 * 2 的结果是:{2 * 2}"  ) # 2 * 2 的结果是:4
print("字符串 占位符 %s " % type("占位符") ) # 字符串 占位符 <class 'str'>

格式符号转化
%s将内容转换成字符串,放入占位位置
%d将内容转换成整数,放入占位位置
%f将内容转换成浮点型,放入占位位置 (需要控制精度)

数字精度控制

我们可以使用辅助符号"m.n"来控制数据的宽度和精度

  • m,控制宽度,要求是数字(很少使用),设置的宽度小于数字自身,不生效

  • .n,控制小数点精度,要求是数字,会进行小数的四舍五入

示例:

  • %5d:表示将整数的宽度控制在5位,如数字11,被设置为5d,就会变成:[空格][空格][空格]11,用三个空格补足宽度。

  • %5.2f:表示将宽度控制为5,将小数点精度设置为2

    小数点和小数部分也算入宽度计算。如,对11.345设置了%7.2f 后,结果是:[空格][空格]11.35。2个空格补足宽度,小数部分限制2位精度后,四舍五入为 .35

  • %.2f:表示不限制宽度,只设置小数点精度为2,如11.345设置%.2f后,结果是11.35

字符串快速格式化

这种写法不做精度控制

也不理会类型

适用于快速格式化字符串

通过语法:f"内容{变量}"的格式来快速格式化

1.8 数据输入

在Python中,与之对应的还有一个input语句,用来获取键盘输入。

  • 数据输出:print

  • 数据输入:input

使用上也非常简单:

  • 使用input()语句可以从键盘获取输入(都是字符串类型)

  • 使用一个变量接收(存储)input语句获取的键盘输入数据即可

print("请输入指令:")
cmd = input()
print(cmd)

2、判断语句

2.1 布尔类型和比较运算符

比较运算符

运算符描述示例
==判断内容是否相等,满足为True,不满足为False如a=3,b=3,则(a == b) 为 True
!=判断内容是否不相等,满足为True,不满足为False如a=1,b=3,则(a != b) 为 True
>判断运算符左侧内容是否大于右侧 满足为True,不满足为False如a=7,b=3,则(a > b) 为 True
<判断运算符左侧内容是否小于右侧 满足为True,不满足为False如a=3,b=7,则(a < b) 为 True
>=判断运算符左侧内容是否大于等于右侧 满足为True,不满足为False如a=3,b=3,则(a >= b) 为 True
<=判断运算符左侧内容是否小于等于右侧 满足为True,不满足为False如a=3,b=3,则(a <= b) 为 True

2.2 if语句的基本格式

# 定义变量
age = 30
# 进行判断
if age >= 18:   # 最后已:结尾
    print("我已经成年了")  # 前面缩进四个空格,编辑器在:后直接回车即可

if语句的注意事项

  • 判断条件的结果一定要是布尔类型

  • 不要忘记判断条件后的: 引号

  • 归属于if语句的代码块,需在前方填充4个空格缩进

if else

if elif else

判断语句的嵌套

3、循环语句

"""
演示while循环基础练习题:求1-100的和
"""
sum = 0
i = 1
while i<=100:
    sum += i
    i += 1

print(f"1-100累加的和是:{sum}")

  • while的条件需得到布尔类型,True表示继续循环,False表示结束循环

  • 需要设置循环终止的条件,如i += 1配合 i < 100,就能确保100次后停止,否则将无限循环

  • 空格缩进和if判断一样,都需要设置

"""
演示使用while的嵌套循环
打印输出九九乘法表
"""

# 定义外层循环的控制变量
i = 1
while i <= 9:

    # 定义内层循环的控制变量
    j = 1
    while j <= i:
        # 内层循环的print语句,不要换行,通过\t制表符进行对齐
        print(f"{j} * {i} = {j * i}\t", end='')
        j += 1

    i += 1
    print()     # print空内容,就是输出一个换行
# print语句中,加上 end=’’ 即可输出不换行了
print("hello", end = '')
print("world", end = '')
  1. continue的作用是:

中断所在循环的当次执行,直接进入下一次

  1. break的作用是:

直接结束所在的循环

  1. 注意事项:
  • continue和break,在for和while循环中作用一致

  • 在嵌套循环中,只能作用在所在的循环上,无法对上层循环起作用

4、python函数

函数:是 组织好的,可重复使用的 \textcolor{Green}{组织好的,可重复使用的} 组织好的,可重复使用的,用来实现特定功能的代码段。

def 函数(参数...):
    """
    函数说明 注释
    """
	函数体
	return 返回值

None类型

Python中有一个特殊的字面量:None,其类型是:<class ‘NoneType’>

无返回值的函数,实际上就是返回了:None这个字面量

None表示:空的、无实际意义的意思

函数返回的None,就表示,这个函数没有返回什么有意义的内容。

也就是返回了空的意思

应用场景

None作为一个特殊的字面量,用于表示:空、无意义,其有非常多的应用场景。

  • 用在函数无返回值上

  • 用在if判断上

    • 在if判断中,None等同于False

    • 一般用于在函数中主动返回None,配合if判断做相关处理

      def check_age(age):
          if age> 18:
              return "SUCCESS"
          return None
      
      
      if not check_age(5):
          print("少儿不宜")
      
  • 用于声明无内容的变量上

    • 定义变量,但暂时不需要变量有具体值,可以用None来代替 name=None

局部变量

所谓局部变量是定义在函数体内部的变量,即只在函数体内部生效

局部变量的作用:在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量

def test():
	n = 10 #就是局部变量
	print(n)

全局变量

所谓全局变量,指的是在函数体内、外都能生效的变量

n = 100 # 全局变量

global关键字

使用 g l o b a l 关键字可以在函数内部声明变量为全局变量 \textcolor{red}{使用 global关键字 可以在函数内部声明变量为全局变量} 使用global关键字可以在函数内部声明变量为全局变量

num = 100
def testA():
    print(num)

def testB():
    global num
    num = 200
    print(num)

testA() #100
testB() #200
testA() #200 如果没有global 则为100

5、python数据容器

5.1 数据容器入门

数据容器,就是为了批量存储或批量使用多份数据

Python中的数据容器:

一种可以容纳多份数据的数据类型,容纳的每一份数据称之为1个元素

每一个元素,可以是任意类型的数据,如字符串、数字、布尔等。

数据容器根据特点的不同,如:

  • 是否支持重复元素

  • 是否可以修改

  • 是否有序,等

分为5类,分别是:

列表(list)、元组(tuple)、字符串(str)、集合(set)、字典(dict)

5.2 数据容器:list列表

列表的定义

# 字面量
[元素1,元素2,元素3,....]
# 定义变量
变量名称 =  [元素1,元素2,元素3,....]
# 定义空列表
变量名称 = []
变量名称 = list()

列表内的每一个数据,称之为元素

  • 以 [] 作为标识

  • 列表内每一个元素之间用, 逗号隔开

列表的下标

list = [1,2,3,4]
print(list[0])
print(list[1])
print(list[2])
print(list[3])
# 反向获取
"""
或者,可以反向索引,也就是从后向前:从-1开始,依次递减(-1、-2、-3......)
"""
list = [1,2,3]
print(list[-1]) # 3
print(list[-2]) # 2
print(list[-3]) # 1
# 嵌套
list = [[1,2,3],[4,5,6]]
print(list[0][1]) # 2

注意: \textcolor{red}{注意:} 注意:

  1. 列表的下标索引是什么?

    列表的每一个元素,都有编号称之为下标索引

    从前向后的方向,编号从0开始递增

    从后向前的方向,编号从-1开始递减

  2. 如何通过下标索引取出对应位置的元素呢?

    列表[下标],即可取出

  3. 下标索引的注意事项:

    要注意下标索引的取值范围,超出范围无法取出元素,并且会报错

列表的常用操作(方法)

  • 查找某元素的下标

    功能:查找指定元素在列表的下标,如果找不到,报错ValueError

    语法:列表.index(元素)

    index就是列表对象(变量)内置的方法(函数)

    list = ['a','b','c']
    print(list.index('b')) # 1
    print(list.index(4))   # ValueError: 4 is not in list
    

列表的修改功能(方法)

  • 修改特定位置(索引)的元素值:

    语法:列表[下标] = 值

    可以使用如上语法,直接对指定下标(正向、反向下标均可)的值进行:重新赋值(修改)

my_list = ['a', 'b', 'c']
my_list[1] = 'vvv'
my_list[-1] = 'aaa'
print(my_list)  # ['a', 'vvv', 'aaa']
  • 插入元素

    语法:列表.insert(下标, 元素),在指定的下标位置,插入指定的元素

    my_list = ['a', 'b', 'c']
    my_list.insert(1, 'bbb')
    print(my_list) # ['a', 'bbb', 'b', 'c']
    
  • 追加元素:

    • 语法:列表.append(元素),将指定元素,追加到列表的尾部
    • 语法:列表.extend(其它数据容器),将其它数据容器的内容取出,依次追加到列表尾部
    my_list = ['a', 'b', 'c']
    my_list.append("d")
    my_list.append(["aa", 2])
    print(my_list) # ['a', 'b', 'c', 'd', ['aa', 2]]
    
    my_list = ['a', 'b', 'c']
    my_list.extend("vvv")
    my_list.extend(["aaa", 222])
    print(my_list) # ['a', 'b', 'c', 'v', 'v', 'v', 'aaa', 222]
    
  • 刪除元素

    • 语法1: del 列表[下标]

    • 语法2:列表.pop(下标)

    • 删除某元素在列表中的第一个匹配项 —> 列表.remove(元素)

    • 清空列表内容,—> 语法:列表.clear()

    • 统计某元素在列表内的数量 —> 语法:列表.count(元素)

    • 统计列表内,有多少元素 语法:len(列表) 可以得到一个int数字,表示列表内的元素数量

    • my_list = ['a', 'b', 'c']
      my_list.pop(2)
      del my_list[0]
      print(my_list)  # ['b']
      # 删除某元素在列表中的第一个匹配项
      my_list = ['a', 'b', 'c']
      my_list.remove('b')
      print(my_list) # ['a', 'c']
      # 清空列表内容,语法:列表.clear()
      my_list = ['a', 'b', 'c']
      my_list.clear()
      print(my_list) # []
      # 统计某元素在列表内的数量
      my_list = ['a','a','a', 'b', 'c']
      print(my_list.count('a')) # 3
      # 统计列表内,有多少元素 
      my_list = ['a','a','a', 'b', 'c']
      print(len(my_list)) # 5
      
编号使用方式作用
1列表.append(元素)向列表中追加一个元素
2列表.extend(容器)将数据容器的内容依次取出,追加到列表尾部
3列表.insert(下标, 元素)在指定下标处,插入指定的元素
4del 列表[下标]删除列表指定下标元素
5列表.pop(下标)删除列表指定下标元素
6列表.remove(元素)从前向后,删除此元素第一个匹配项
7列表.clear()清空列表
8列表.count(元素)统计此元素在列表中出现的次数
9列表.index(元素)查找指定元素在列表的下标 找不到报错ValueError
10len(列表)统计容器内有多少元素

5.3 list遍历

my_list = ['a','a','a', 'b', 'c']
# while
i = 0
while i < len(my_list):
    print(my_list[i])
    i += 1
# for
for i in my_list:
    print(i)

while循环和for循环,都是循环语句,但细节不同:

  • 在循环控制上:

    while循环可以自定循环条件,并自行控制

    for循环不可以自定循环条件,只可以一个个从容器内取出数据

  • 在无限循环上:

    while循环*可以通过条件控制做到无限循环

    for循环理论上不可以,因为被遍历的容器容量不是无限的

  • 在使用场景上:

    while循环适用于任何想要循环的场景

    for循环适用于,遍历数据容器的场景或简单的固定次数循环场景

5.4 tuple(元组)

元组同列表一样,都是可以封装多个、不同类型的元素在内。

但最大的不同点在于: 元组一旦定义完成,就不可修改 \textcolor{red}{元组一旦定义完成,就不可修改} 元组一旦定义完成,就不可修改

定义元组

元组定义:定义元组使用小括号,且使用逗号隔开各个数据,数据可以是不同的数据类型。

# 定义元组字面量
(元素,元素,....)
# 定义元组变量
变量名称 = (元素,元素,....)
t1 = (1 , 'hello', True)
t2 = ('Hello',) # 后面的逗号一定要有,否则不是元组类型
# 定义空元组
变量名称 = ()
变量名称 = tuple() 
#嵌套
t1 = ((1,2,3),(4,5,6))
print(t1[0][0]) # 1

元组的相关操作

编号方法作用
1index()查找某个数据,如果数据存在返回对应的下标,否则报错
2count()统计某个数据在当前元组出现的次数
3len(元组)统计元组内的元素个数

元组由于不可修改的特性,所以其操作方法非常少。

t1 = (1, 2, 3)
# 尝试元组的修改
# t1[0] = 5  # 'tuple' object does not support item assignment

# 可以修改元组内的list的内容(修改元素、增加、删除、反转等)
t2 = (1, 2, 3, [4, 5, 6])
t2[3][1] = 44
print(t2)
# 不可以替换list为其它list或其它类型
# t2[3] = [3]  # tuple' object does not support item assignment
print(t2)

元组的遍历

t1 = (1, 2, 3)
i = 0
while i < len(t1):
    print(t1[i])
    i += 1
    
for i in t1:
    print(i)

元组的特点

经过上述对元组的学习,可以总结出列表有如下特点:

  • 可以容纳多个数据

  • 可以容纳不同类型的数据(混装)

  • 数据是有序存储的(下标索引)

  • 允许重复数据存在

  • 不可以修改(增加或删除元素等)

  • 支持for循环

多数特性和list一致,不同点在于不可修改的特性。

5.5 str(字符串)

和其它容器如:列表、元组一样,字符串也可以通过下标进行访问

  • 从前向后,下标从0开始

  • 从后向前,下标从-1开始

同元组一样,字符串是一个:无法修改的数据容器。

所以:

  • 修改指定下标的字符 (如:字符串[0] = “a”)

  • 移除特定下标的字符 (如:del 字符串[0]、字符串.remove()、字符串.pop()等)

  • 追加字符等 (如:字符串.append())

均无法完成。如果必须要做,只能得到一个新的字符串,旧的字符串是无法修改

字符串的常用操作

  • 查找特定字符串的下标索引值

  • 字符串的替换

    ​ 语法:字符串.replace(字符串1,字符串2)

    功能:将字符串内的全部:字符串1,替换为字符串2

    注意:不是修改字符串本身,而是得到了一个新字符串哦

  • 字符串的分割

    语法:字符串.split(分隔符字符串)

    功能:按照指定的分隔符字符串,将字符串划分为多个字符串,并存入列表对象中

    注意:字符串本身不变,而是得到了一个列表对象

  • 字符串的规整操作(去前后空格)

    语法:字符串.strip()

  • 字符串的规整操作(去前后指定字符串)

    ​ 语法:字符串.strip(字符串)

  • 统计字符串中某字符串的出现次数

    语法:字符串.count(字符串)

  • 统计字符串的长度

    语法:len(字符串)

    数字(1、2、3…)

    字母(abcd、ABCD等)

    ​ 符号(空格、!、@、#、$等)

    ​ 中文

    ​ 均算作1个字符

编号操作说明
1字符串[下标]根据下标索引取出特定位置字符
2字符串.index(字符串)查找给定字符的第一个匹配项的下标
3字符串.replace(字符串1, 字符串2)将字符串内的全部字符串1,替换为字符串2 不会修改原字符串,而是得到一个新的
4字符串.split(字符串)按照给定字符串,对字符串进行分隔 不会修改原字符串,而是得到一个新的列表
5字符串.strip() 字符串.strip(字符串)移除首尾的空格和换行符或指定字符串
6字符串.count(字符串)统计字符串内某字符串的出现次数
7len(字符串)统计字符串的字符个数

字符串的遍历 同列表 元组一样

字符串的特点

作为数据容器,字符串有如下特点:

  • 只可以存储字符串

  • 长度任意(取决于内存大小)

  • 支持下标索引

  • 允许重复字符串存在

  • 不可以修改(增加或删除元素等)

  • 支持for循环

基本和列表、元组相同

不同与列表和元组的在于:字符串容器可以容纳的类型是单一的,只能是字符串类型。

不同于列表,相同于元组的在于:字符串不可修改

name = "hello  world"
print(name.index("d"))
print(name.index("world"))
# 不是修改字符串本身,而是得到了一个新字符串哦
name = "斗破苍穹 消炎"
new_name = name.replace("消炎", "肖炎")
print(name) # 斗破苍穹 消炎
print(new_name) # 斗破苍穹 肖炎
hobby = "足球 篮球 羽毛球"
new_hobby = hobby.split(" ")
print(hobby) # 足球 篮球 羽毛球
print(new_hobby) # ['足球', '篮球', '羽毛球']

# 字符串的规整操作(去前后空格)
name = "  我喜欢跳绳 "
new_name = name.strip()
print(name) #   我喜欢跳绳
print(new_name) # 我喜欢跳绳
# 去掉指定字符串
name = "1test"
print(name) # 1test
print(name.strip("1")) # test
print(name.strip("test")) # 1
# 统计字符串中某字符串的出现次数
name = "aaabbb"
print(name.count("a")) # 3
# 统计字符串长度
print(len(name)) # 6
# 遍历
i = 0
while i < len(name):
    print(name[i])
    i += 1
for i in name:
    print(i)

5.6 数据容器的切片

序列是指:内容连续、有序,可使用下标索引的一类数据容器

列表、元组、字符串,均可以可以视为序列。

元素1元素2元素3元素…元素n
下标012n-1
元素1元素2元素3元素…元素n
下标-n-(n-1)-(n-2)-1

序列的典型特征就是:有序并可用下标索引,字符串、元组、列表均满足这个要求

序列的常用操作 - 切片

序列支持切片,即:列表、元组、字符串,均支持进行切片操作

切片:从一个序列中,取出一个子序列

语法:序列[起始下标:结束下标:步长]

表示从序列中,从指定位置开始,依次取出元素,到指定位置结束,得到一个新序列

  • 起始下标表示从何处开始,可以留空,留空视作从头开始

  • 结束下标(不含)表示何处结束,可以留空,留空视作截取到结尾

  • 步长表示,依次取元素的间隔

  • 步长1表示,一个个取元素

  • 步长2表示,每次跳过1个元素取

  • 步长N表示,每次跳过N-1个元素取

  • 步长为负数表示,反向取(注意,起始下标和结束下标也要反向标记)

注意,此操作不会影响序列本身,而是会得到一个新的序列(列表、元组、字符串)

my_list = [1, 2, 3, 4,5]
new_list = my_list[1:4]
print(new_list) # [2, 3, 4]
print(my_list[:]) # [1, 2, 3, 4, 5]
print(my_list[::2]) #[1, 3, 5]
print(my_list[:4:2]) #[1, 3]

my_tuple = (1,2,3,4,5)
print(my_tuple[:]) # (1, 2, 3, 4, 5)
print(my_tuple[::2]) # (1, 3, 5)
my_str = "12345"
print(my_str[::3]) # 14
print(my_str[::-1]) # 54321

5.7 数据容器 - 集合set

集合的定义

# 定义集合的字面量
{元素,元素,....元素}
# 定义集合的变量
变量名称 = {元素,元素,....元素}
# 空集合
变量名称 = set()
  • 列表使用:[]

  • 元组使用:()

  • 字符串使用:“”

  • 集合使用:{}

首先,因为集合是无序的,所以 集合不支持:下标索引访问 \textcolor{red}{集合不支持:下标索引访问} 集合不支持:下标索引访问

但是集合和列表一样,是允许修改的,所以我们来看看集合的修改方法。

  • 添加新元素

    语法:集合.add(元素)。将指定元素,添加到集合内

    结果:集合本身被修改,添加了新元素

  • 移除元素

    语法:集合.remove(元素),将指定元素,从集合内移除

    结果:集合本身被修改,移除了元素

  • 从集合中随机取出元素

    语法:集合.pop(),功能,从集合中 随机 \textcolor{red}{随机} 随机取出一个元素

    结果:会得到一个元素的结果。同时集合本身被修改,元素被移除

  • 清空集合

    语法:集合.clear(),功能,清空集合

    结果:集合本身被清空

  • 取出2个集合的差集

    语法:集合1.difference(集合2),功能:取出集合1和集合2的差集(集合1有而集合2没有的)

    结果:得到一个新集合,集合1和集合2不变

  • 消除2个集合的差集

    语法:集合1.difference_update(集合2)

    功能:对比集合1和集合2,在集合1内,删除和集合2相同的元素。

    结果:集合1被修改,集合2不变

  • 2个集合合并

    语法:集合1.union(集合2)

    功能:将集合1和集合2组合成新集合

    结果:得到新集合,集合1和集合2不变

  • 查看集合的元素数量

    语法:len(集合)

    功能:统计集合内有多少元素

    结果:得到一个整数结果

编号操作说明
1集合.add(元素)集合内添加一个元素
2集合.remove(元素)移除集合内指定的元素
3集合.pop()从集合中随机取出一个元素
4集合.clear()将集合清空
5集合1.difference(集合2)得到一个新集合,内含2个集合的差集 原有的2个集合内容不变
6集合1.difference_update(集合2)在集合1中,删除集合2中存在的元素 集合1被修改,集合2不变
7集合1.union(集合2)得到1个新集合,内含2个集合的全部元素 原有的2个集合内容不变
8len(集合)得到一个整数,记录了集合的元素数量
my_set = {"hello", "world"}
# 添加元素
my_set.add("python")
print(my_set)  # {'python', 'hello', 'world'}
# 移除元素
my_set.remove("hello")
print(my_set)  # {'python', 'world'}
print("-------pop_set pop 随机 每次结果有可能不一致--------")
pop_set = {"hello", "world", "python"}
ele = pop_set.pop()
print(pop_set)  # {'world', 'python'}
print(ele)  # {'world', 'python'}

print("---------清空集合---------")
pop_set.clear()
print(pop_set)  # set()
"""
集合 差集
得到一个新的集合,原来的集合不变
"""
set1 = {1, 2, 3}
set2 = {3, 4, 5}
diff_set = set1.difference(set2)
print(set1) # {1, 2, 3}
print(set2) # {3, 4, 5}
print(diff_set) # {1, 2}

print("------消除两个集合的差集--------")
set1 = {1, 2, 3}
set2 = {3, 4, 5}
diff_set = set1.difference_update(set2)
print(set1) #{1, 2}
print(set2) # {3, 4, 5}
print(diff_set) # None  无返回
print("------消除两个集合的合并--------")
set1 = {1, 2, 3}
set2 = {3, 4, 5}
union_set = set1.union(set2)
print(set1) #{1, 2, 3}
print(set2) # {3, 4, 5}
print(union_set) # {1, 2, 3, 4, 5}

print("集合元素的数量" + str(len(set1)))
print("------遍历-------")
for i in set1:
    print(i)

集合特点

  • 可以容纳多个数据

  • 可以容纳不同类型的数据(混装)

  • 数据是无序存储的(不支持下标索引)

  • 不允许重复数据存在

  • 可以修改(增加或删除元素等)

  • 支持for循环

  • 不可以使用while循环,因为不支持下标索引

5.8 数据容器-dict(字典、映射)

就是map

字典的嵌套

字典的Key和Value可以是任意数据类型(Key不可为字典)

那么,就表明,字典是可以嵌套的

字典的常用操作

  • 新增元素

    语法:字典[Key] = Value,结果:字典被修改,新增了元素

  • 更新元素

    语法:字典[Key] = Value,结果:字典被修改,元素被更新

    注意:字典Key不可以重复,所以对已存在的Key执行上述操作,就是更新Value值

  • 删除元素

    语法:字典.pop(Key),结果:获得指定Key的Value,同时字典被修改,指定Key的数据被删除

  • 删除元素

    语法:字典.pop(Key),结果:获得指定Key的Value,同时字典被修改,指定Key的数据被删除

  • 获取全部的key

    语法:字典.keys(),结果:得到字典中的全部Key

  • 遍历字典

    语法:for key in 字典.keys()

  • 计算字典内的全部元素(键值对)数量

    语法:len(字典)

    结果:得到一个整数,表示字典内元素(键值对)的数量

编号操作说明
1字典[Key]获取指定Key对应的Value值
2字典[Key] = Value添加或更新键值对
3字典.pop(Key)取出Key对应的Value并在字典内删除此Key的键值对
4字典.clear()清空字典
5字典.keys()获取字典的全部Key,可用于for循环遍历字典
6len(字典)计算字典内的元素数量

总结字典有如下特点:

  • 可以容纳多个数据

  • 可以容纳不同类型的数据

  • 每一份数据是KeyValue键值对

  • 可以通过Key获取到Value,Key不可重复(重复会覆盖)

  • 不支持下标索引

  • 可以修改(增加或删除更新元素等)

  • 支持for循环,不支持while循环

# dict   map
my_dict = {'key1': 'value1', 'key2': 'v2'}
print(my_dict.get("key1"))  # value1
print(my_dict["key1"])  # value1
stu_score = {
    "zhangsan": {"Chinese": 100, "Maths": 10, "English": 1},
    "lisi": {"Chinese": 2, "Maths": 3, "English": 4}
}
print(stu_score['zhangsan']['Maths'])  # 10

print(stu_score['lisi'])  # {'Chinese': 2, 'Maths': 3, 'English': 4}
# 获取一个不存在的 key
print(stu_score.get('lssi'))  # None
# print(stu_score['lssi'])  # KeyError: 'lssi'

# 新增元素
stars = {
    "周杰伦": 88,
    "张杰":99
}
stars['张国荣'] = 100
print(stars) # {'周杰伦': 88, '张杰': 99, '张国荣': 100}
stars['张杰'] = 1
print(stars) # {'周杰伦': 88, '张杰': 1, '张国荣': 100}

# 获取全部的key
keys = stars.keys()
print(keys) # dict_keys(['周杰伦', '张杰', '张国荣'])
"""
明星:周杰伦,粉丝数:88
明星:张杰,粉丝数:1
明星:张国荣,粉丝数:100
"""
for key in stars.keys():
    print(f"明星:{key},粉丝数:{stars[key]}")

# 计算字典内的全部元素(键值对)数量
print(len(stars)) # 3
# 删除元素
stars.pop('张国荣')
print(stars) # {'周杰伦': 88, '张杰': 1}
# 清空
stars.clear()
print(stars) # {}

数据容器的对比

数据容器可以从以下视角进行简单的分类:

  • 是否支持下标索引

    • 支持:列表、元组、字符串 - 序列类型
    • 不支持:集合、字典 - 非序列类型
  • 是否支持重复元素:

    • 支持:列表、元组、字符串 - 序列类型
    • 不支持:集合、字典 - 非序列类型
  • 是否可以修改

    • 支持:列表、集合、字典
    • 不支持:元组、字符串
各种维度对比列表元组字符串集合字典
元素数量支持多个支持多个支持多个支持多个支持多个
元素类型任意任意仅字符任意Key:Value Key:除字典外任意类型 Value:任意类型
下标索引支持支持支持不支持不支持
重复元素支持支持支持不支持不支持
可修改性支持不支持不支持支持支持
数据有序
使用场景可修改、可重复的一批数据记录场景不可修改、可重复的一批数据记录场景一串字符的记录场景不可重复的数据记录场景以Key检索Value的数据记录场景

5.9 数据容器的通用作用

功能描述
通用for循环遍历容器(字典是遍历key)
max容器内最大元素
min()容器内最小元素
len()容器元素个数
list()转换为列表
tuple()转换为元组
str()转换为字符串
set()转换为集合
sorted(序列, [reverse=True])排序,reverse=True表示降序 得到一个排好序的列表

6、函数进阶

6.1 函数多返回值

# 函数多返回值
def test():
    return 1,2
x,y = test()
print(x) # 1
print(y) # 2

按照返回值的顺序,写对应顺序的多个变量接收即可

变量之间用逗号隔开

支持不同类型的数据return

6.2 函数的多种传参

  • 位置参数
    • 调用函数时根据函数定义的参数位置来传递参数
    • 传递的参数和定义的参数的顺序及个数必须一致
  • 关键字参数
    • 函数调用时通过“键=值”形式传递参数
    • 可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求
    • 可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求
  • 缺省参数
    • 缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前,包括函数定义和调用).
    • 当调用函数时没有传递参数, 就会使用默认是用缺省参数对应的值
    • 函数调用时,如果为缺省参数传值则修改默认参数值, 否则使用这个默认值
  • 不定长参数
    • 不定长参数也叫可变参数. 用于不确定调用的时候会传递多少个参数(不传参也可以)的场景
    • 当调用函数时不确定参数个数时, 可以使用不定长参数
    • 位置传递
    • 关键字传递
# 位置参数
# 传递的参数和定义的参数的顺序及个数必须一致
def h(name, age, gender):
    print(f'名字:{name},年龄:{age},性别:{gender}')
h("lisi",1,'女')
# 关键字参数
h(name="老六",age=18,gender='男')
# 可以不固定顺讯
h(age=60,name="老六",gender="男")
# 可以和位置参数混合使用,位置参数必须在前,且匹配参数顺序
h('小明',age=60,gender="男")

def h(name, age, gender="男"):
    print(f'名字:{name},年龄:{age},性别:{gender}')
h('小明',age=11)
h('小明',age=11,gender="女")
"""
传进的所有参数都会被args变量收集,
它会根据传进参数的位置合并为一个元组(tuple),args是元组类型,这就是位置传递
"""
def user_info(*agrs):
    print(agrs)
user_info("TOM") # ('TOM',)
user_info("TOM",2) # ('TOM', 2)
# 参数是“键=值”形式的形式的情况下, 所有的“键=值”都会被 kwargs 接受, 同时会根据“键=值”组成字典
# 注意是两个**
def user_info2(**kwargs):
    print(kwargs)
user_info2(name='TOM',age=10,gender="女")

6.3 函数作为参数

def test_fun(compute):
    result = compute(1,2)
    return result
def compute(x,y):
    return x + y
print(test_fun(compute)) # 3

def test_fun(compute):
    result = compute(1,2)
    return result
def compute(x,y):
    return x * y
print(test_fun(compute)) # 2

def test_fun(compute):
    result = compute(1,2)
    return result
def compute(x,y):
    return x - y
print(test_fun(compute)) # -1

函数compute,作为参数,传入了test_func函数中使用。

  • test_func需要一个函数作为参数传入,这个函数需要接收2个数字进行计算,计算逻辑由这个被传入函数决定

  • compute函数接收2个数字对其进行计算,compute函数作为参数,传递给了test_func函数使用

  • 最终,在test_func函数内部,由传入的compute函数,完成了对数字的计算操作

所以,这是一种,计算逻辑的传递,而非数据的传递。

就像上述代码那样,不仅仅是相加,相见、相除、等任何逻辑都可以自行定义并作为函数传入

6.3.1 lambda匿名函数

函数的定义中

  • def关键字,可以定义带有名称的函数

  • lambda关键字,可以定义匿名函数(无名称)

有名称的函数,可以基于名称重复使用。

无名称的匿名函数,只可临时使用一次。

匿名函数定义语法:

lambda 传入参数: 函数体(一行代码)
  • lambda 是关键字,表示定义匿名函数

  • 传入参数表示匿名函数的形式参数,如:x, y 表示接收2个形式参数

  • 函数体,就是函数的执行逻辑,要注意:只能写一行,无法写多行代码

def test_fun(conpute):
    return conpute(1,2)
print(test_fun(lambda x, y: x + y)) # 3
print(test_fun(lambda x,y: x * y))  #2

7、文件操作

文件操作包括 打开、关闭、读、写等操作

文件操作的步骤

  1. 打开文件
  2. 读写文件(这个也可以没有)
  3. 关闭文件
  • Mode常用的三种访问模式

    模式描述
    r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
    w打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,原有内容会被删除。 如果该文件不存在,创建新文件。
    a打开一个文件用于追加。如果该文件已存在,新的内容将会被写入到已有内容之后。 如果该文件不存在,创建新文件进行写入。
  • open()函数

    • """
      name:是要打开的目标文件名的字符串(可以包含文件所在的具体路径)。
      mode:设置打开文件的模式(访问模式):只读、写入、追加等。
      encoding:编码格式(推荐使用UTF-8) 
      """
      open(name,mode,encoding)
      f = open('python.txt', 'r', encoding=”UTF-8)
      # encoding的顺序不是第三位,所以不能用位置参数,用关键字参数直接指定
      #注意:此时的`f`是`open`函数的文件对象,对象是Python中一种特殊的数据类型,拥有属性和方法,可以使用对象.属性或对象.方法对其进行访问,后续面向对象课程会给大家进行详细的介绍
      
  • read()方法

    • # num表示要从文件中读取的数据的长度(单位是字节),如果没有传入num,那么就表示读取文件中所有的数据
      文件对象.read(num)
      
    • readlines()方法
      # readlines可以按照行的方式把整个文件中的内容进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素
      f = open('python.txt')
      content = f.readlines()
      
      # ['hello world\n', 'abcdefg\n', 'aaa\n', 'bbb\n', 'ccc']
      print(content)
      
      # 关闭文件
      f.close()
      
      
    • readline()方法:一次读取一行内容

      f = open('python.txt')
      
      content = f.readline()
      print(f'第一行:{content}')
      
      content = f.readline()
      print(f'第二行:{content}')
      
      # 关闭文件
      f.close()
      
      
    • for循环读取文件行

      for line in open("python.txt", "r"):
          print(line)
      
      # 每一个line临时变量,就记录了文件的一行数据
      
      
    • close() 关闭文件对象

      f = open("python.txt", "r")
      
      f.close()
      
      # 最后通过close,关闭文件对象,也就是关闭对文件的占用
      # 如果不调用close,同时程序没有停止运行,那么这个文件将一直被Python程序占用。
      
      
    • with open 语法

      with open("python.txt", "r") as f:
          f.readlines()
      
      # 通过在with open的语句块中对文件进行操作
      # 可以在操作完成后自动关闭close文件,避免遗忘掉close方法
      
      
操作功能
文件对象 = open(file, mode, encoding)打开文件获得文件对象
文件对象.read(num)读取指定长度字节 不指定num读取文件全部
文件对象.readline()读取一行
文件对象.readlines()读取全部行,得到列表
for line in 文件对象for循环文件行,一次循环得到一行数据
文件对象.close()关闭文件对象
with open() as f通过with open语法打开文件,可以自动关闭

文件的写入、文件的追加

f= open("python.txt",'w')
# 文件写入
"""
文件如果不存在,使用”w”模式,会创建新文件
文件如果存在,使用”w”模式,会将原有内容清空

"""
f.write("hello1 python")
# 调用flush 内容会真正的写入文件
f.flush()

# 文件追加
# 文件存在追加
f = open("python.txt",'a')
f.write("\nhello apend pyhon")
f.flush()
# 文件不存在 创建文件
f = open("python1.txt",'a')
f.write("hello apend pyhon")
f.flush()

8、异常模块与包

8.1 异常的捕获

try:
    可能发生错误的代码
except:
    如果出现异常执行的代码
try:
    f = open("p.txt",'r')
except:
    f = open("p.txt",'w')

try:
    print(name)
except NameError as e:
    print("变量名称尚未定义")
    print(e) # name 'name' is not defined
# 捕获多个异常
try:
    print(1/0)
except (NameError,ZeroDivisionError) as e:
    print('ZeroDivisionError错误...')
    print(e)
# 捕获所有异常
try:
    print(name)
except Exception as e:
    print(e)


# else 没有异常执行
try:
    print(1)
except Exception as e:
    print(e)
else:
    print("我是 else ,没有异常 执行此处")

try:
    f = open('test.txt', 'r')
except Exception as e:
    print("异常执行")
    f = open('test.txt', 'w')
else:
    print('没有异常,真开心')
finally:
    print('有没有异常,都执行')
    f.close()

异常的传递性

当函数func01中发生异常, 并且没有捕获处理这个异常的时候, 异常会传递到函数func02, 当func02也没有捕获处理这个异常的时候main函数会捕获这个异常, 这就是异常的传递性.

def fun01():
    print("fun01开始")
    num = 1 / 0
    print("fun01结束")
def fun02():
    print("fun02开始")
    fun01()
    print("fun02结束")

def main():
    try:
        fun02()
    except Exception as e :
        print(e)

main()
#当所有函数都没有捕获异常的时候, 程序就会报错

8.2 模块:

Python 模块(Module),是一个 Python 文件,以 .py 结尾. 模块能定义函数,类和变量,模块里也能包含可执行的代码.

模块的作用: python中有很多各种不同的模块, 每一个模块都可以帮助我们快速的实现一些功能, 比如实现和时间相关的功能就可以使用time模块,我们可以认为一个模块就是一个工具包, 每一个工具包中都有各种不同的工具供我们使用进而实现各种不同的功能.

大白话:模块就是一个Python文件,里面有类、函数、变量等,我们可以

拿过来用(导入模块去使用)

模块导入方式

[form 模块名] import [模块 ||变量 |函数 | * ] [as 别名]

常用的组合形式:

  • import 模块名

    import 模块名
    import 模块名1,模块名2
    
    模块名.功能名()
    
    # 导入时间模块
    import time
    print("开始" + str(time.time()))
    # 休眠1s
    time.sleep(1)
    print("结束" + str(time.time()))
    
  • from 模块名 import 类、变量、方法等

    # 导入时间模块的 sleep 方法
    from time import sleep
    print("start")
    sleep(1)
    print("end")
    
  • from 模块名 import *

    # 导入时间模块中所有的方法
    from time import *
    print("开始")
    # 让程序睡眠1秒(阻塞)
    sleep(1)
    print("结束")
    
    
  • import 模块名 as 别名

    # 别名
    import time as tt
    tt.sleep(1)
    print("end")
    from time import sleep as s
    s(1)
    print("e")
    
  • from 模块名 import 功能名 as 别名

自定义模块

每个Python文件都可以作为一个模块,模块的名字就是文件的名字. 也就是说自定义模块名必须要符合标识符命名规则

新建test_module.py

def test(a,b):
    return a+ b

新建test_module2.py

def test(a,b):
    return a+ b
def test3(a,b):
    return a- b


if __name__ == '__main__':
    print(test(1, 4))

在test.py中引用test_module.py

import test_module
print(test_module.test(1, 2))

当导入多个模块的时候,且模块内有同名功能. 当调用这个同名功能的时候,调用到的是后面导入的模块的功能

 # -1from test_module import test3
from test_module2 import test3

print(test3(2, 3)) # -1

如果一个模块文件中有**__all__**变量,当使用from xxx import *导入时,只能导入这个列表中的元素

test_module.py

def test(a,b):
    return a+ b
def test3(a,b):
    return a* b

__all__ = ["test"]

测试模块

每个Python文件都可以作为一个模块,模块的名字就是文件的名字. 也就是说自定义模块名必须要符合标识符命名规则

def test(a, b):
    print(a + b)


test(1, 1)
from test_module import *

print(test(2, 3))# 执行使用test方法

问题:

此时,无论是当前文件,还是其他已经导入了该模块的文件,在运行的时候都会自动执行test函数的调用

解决方案:

def test(a, b):
    print(a + b)

# 只在当前文件中调用该函数,其他导入的文件内不符合该条件,则不执行test函数调用
if __name__ == '__main__':
    test (1, 1)

8.3 包

从物理上看,包就是一个文件夹,在该文件夹下包含了一个 __init__.py文件,该文件夹可用于包含多个模块文件

从逻辑上看,包的本质依然是模块

包的作用

当我们的模块文件越来越多时,包可以帮助我们管理这些模块, 包的作用就是包含多个模块,但包的本质依然是模块

基本步骤

[New] -> [Python Package]-> 输入包名 -> [OK] -> 新建功能模块(有联系的模块)

注意:新建包后,包内部会自动创建__init__.py文件,这个文件控制着包的导入行为

在先新建test1.py

print(1)
def info_print1():
    print("test1")

在先新建test2.py

print(2)
def test_print2():
    print("test2")

__init__.py 暂时为空

import my_package.test1
import my_package.test2

my_package.test1.info_print1()
my_package.test2.test_print2()

__init__.py 文件中利用__all__=[]控制允许导入模块的列表

#     __all__针对的是 ’ from ... import * ‘ 这种方式
# 对 ‘ import xxx ’ 这种方式无效 上面的可以继续使用

__all__ = ['test1'] # test1为模块名
from my_package import *
from my_package import test2

test1.info_print1()
# AttributeError: module 'my_package.test2' has no attribute 'info_print1'
# 即使制定了导入 也会异常
test2.info_print1() 

8.4 第三方包

Python程序的生态中,有许多非常多的第三方包(非Python官方),可以极大的帮助我们提高开发效率,如:

  • 科学计算中常用的:numpy包

  • 数据分析中常用的:pandas包

  • 大数据计算中常用的:pyspark、apache-flink包

  • 图形可视化常用的:matplotlib、pyecharts

  • 人工智能常用的:tensorflow

这些第三方的包,极大的丰富了Python的生态,提高了开发效率。

但是由于是第三方,所以Python没有内置,以我们需要安装它们才可以导入使用哦。

安装第三方包 - pip

第三方包的安装非常简单,我们只需要使用Python内置的pip程序即可。

打开我们许久未见的:命令提示符程序,在里面输入:

pip install 包名称

即可通过网络快速安装第三方包

PIP网络优化

由于pip是连接的国外的网站进行包的下载,所以有的时候会速度很慢。

我们可以通过如下命令,让其连接国内的网站进行包的安装:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名称
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy

https://pypi.tuna.tsinghua.edu.cn/simple 是清华大学提供的一个网站,可供pip程序下载第三方包

9、面向对象

类的定义和使用

类的使用语法:

"""
class是关键字,表示要定义类了
类的属性,即定义在类中的变量(成员变量)
类的行为,即定义在类中的函数(成员方法)

"""
class 类名称:
	类的属性
	类的行为
    
# 创建类对象的语法:
队形 = 类名称()

成员变量、成员方法

class Student:
    name = None
    age = None

    def say_hello(self):
        print(f"hello,{self.name}")
    """
    可以忽略self. :忽略self
    """
    def ignore(self,msg):
        print(f"可以忽略self. :{msg}")

student = Student()
student.name = 'test'
student.say_hello()
student.ignore("忽略self") # 可以忽略self. :忽略self

在类中定义成员方法和定义函数基本一致,但仍有细微区别:

可以看到,在方法定义的参数列表中,有一个:self关键字

self关键字是成员方法定义的时候,必须填写的。

  • 它用来表示类对象自身的意思

  • 当我们使用类对象调用方法的是,self会自动被python传入

  • 在方法内部,想要访问类的成员变量,必须使用self

类只是一种程序内的**“设计图纸**”,需要基于图纸生产实体(对象),才能正常工作

这种套路,称之为:面向对象编程

构造方法

Python类可以使用:__init__()方法,称之为构造方法。

可以实现:

  • 在创建类对象(构造类)的时候,会自动执行。

  • 在创建类对象(构造类)的时候,将传入参数自动传递给__init__方法使用。

class Student:
    """
    属性可以省略
    """
    name= None
    age = None
    gender = None
    """
    构建类时传入的参数会自动提供给__init__方法
    构建类的时候__init__方法会自动执行

    """
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
        print("create object")

if __name__ == '__main__':
    student = Student("lisi",17,'女')
    print(f"名字:{student.name} 年龄:{student.age},性別:{student.gender}")

构造方法注意事项

  • 重要的事情说三遍,构造方法名称:__init__ __init__`` __init__ , 千万不要忘记init前后都有2个下划线

  • 构造方法也是成员方法,不要忘记在参数列表中提供:self

  • 在构造方法内定义成员变量,需要使用self关键字

    • 变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示
       def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
            print("create object")
    

魔术方法

变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示

方法功能
__init__构造方法,可用于创建类对象的时候设置初始化行为
__str__用于实现类对象转字符串的行为
__lt__用于2个类对象进行小于或大于比较 `
__le__用于2个类对象进行小于等于或大于等于比较
__eq__用于2个类对象进行相等比较

__str__

class Student:
    """
    属性可以省略
    """
    name= None
    age = None
    gender = None
    """
    构建类时传入的参数会自动提供给__init__方法
    构建类的时候__init__方法会自动执行

    """
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
        print("create object")


if __name__ == '__main__':
    student = Student("lisi",17,'女')
   # 当类对象需要被转换为字符串之时,会输出如下结果(内存地址)
    print(student) # <__main__.Student object at 0x0000017DF74976D0>
    print(str(student)) # <__main__.Student object at 0x0000017DF74976D0>
    # 内存地址没有多大作用,我们可以通过__str__方法,控制类转换为字符串的行为

在对象实现了str方法之后

class Student:
    """
    属性可以省略
    """
    name= None
    age = None
    gender = None
    """
    构建类时传入的参数会自动提供给__init__方法
    构建类的时候__init__方法会自动执行

    """
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
        print("create object")
    def __str__(self) -> str:
        return f"学生姓名:{self.name} ,学生年龄:{self.age},学生性别:{self.gender}"


if __name__ == '__main__':
    student = Student("lisi",17,'女')
    print(student) # 学生姓名:lisi ,学生年龄:17,学生性别:女
    print(str(student)) # 学生姓名:lisi ,学生年龄:17,学生性别:女

__lt__ 小于符号比较方法

直接对2个对象进行比较是不可以的,但是在类中实现__lt__方法,即可同时完成:小于符号 和 大于符号 2种比较

class Student:
    """
    属性可以省略
    """
    name= None
    age = None
    gender = None
    """
    构建类时传入的参数会自动提供给__init__方法
    构建类的时候__init__方法会自动执行

    """
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
        print("create object")

    def __lt__(self, other):
        return self.age < other.age

if __name__ == '__main__':
    student1 = Student("lisi",17,'女')
    student2 = Student("zhangsan",28,'男')
    print(student1 > student2) # False
    print(student1 < student2) # True

__eq__比较运算符实现方法

  • 不实现__eq__方法,对象之间可以比较,但是是比较内存地址,也即是:不同对象==比较一定是False结果

    class Student:
    
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
    
    if __name__ == '__main__':
        student1 = Student("lisi",17,'女')
        student2 = Student("zhangsan",17,'男')
        print(student1 == student2) # False
    
  • 实现了__eq__方法,就可以按照自己的想法来决定2个对象是否相等了

    class Student:
    
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
    
        def __eq__(self, o: object) -> bool:
            return self.age == o.age
    
    
    if __name__ == '__main__':
        student1 = Student("lisi",17,'女')
        student2 = Student("zhangsan",17,'男')
        print(student1 == student2) # True
    

面向对象的三大特性

面向对象编程,是许多编程语言都支持的一种编程思想。

简单理解是:基于模板(类)去创建实体(对象),使用对象完成功能开发。

面向对象包含3大主要特性:

  • 封装

  • 将现实世界中的事物的属性、行为封装到类中,描述为成员变量、成员方法从而完成程序对现实世界事物的描述

  • 继承

    • 单继承

    • 多继承

      • 多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。

        即:先继承的保留,后继承的被覆盖

  • 多态

私有成员

既然现实事物有不公开的属性和行为,那么作为现实事物在程序中映射的类,也应该支持。

类中提供了私有成员的形式来支持。

  • 私有成员变量

  • 私有成员方法

定义私有成员的方式非常简单,只需要:

  • 私有成员变量:变量名以__开头(2个下划线)

  • 私有成员方法:方法名以__开头(2个下划线)

即可完成私有成员的设置

"""
私有成员无法被类对象使用,但是可以被其它的成员使用
在类中提供仅供内部使用的属性和方法,而不对外开放(类对象无法使用)

"""
class Student:
    __private_param = None
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
        self.__private_param = "私有"

    def __prvate_method(self):
        print("私有方法:" + self.__private_param)

    def __str__(self) -> str:
        self.__prvate_method()
        return f"私有变量:{self.__private_param}"


if __name__ == '__main__':
    student1 = Student("lisi",17,'女')
    print(student1)
    # student1.__private_param # 'Student' object has no attribute '__private_param

多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。

即:先继承的保留,后继承的被覆盖

class Phone:
    IMEI = None
    producer = "vvv"

    def call_by_5g(self):
        print("5g通话")


class NFCReader:
    nfc_type = None
    producer = "HM"

    def read_card(self):
        print("读取NFC卡")

    def write_card(self):
        print("写入NFC卡")


class RemoteControl:
    rc_type = "红外遥控"

    def controll(self):
        print("红外线遥控开启")


# 单继承
class MySimplePhnoe(Phone):
    simple = "单继承"

# 多继承
class MyPhnoe(Phone, NFCReader, RemoteControl):
    pass


if __name__ == '__main__':
    my_phnoe = MyPhnoe()
    print(my_phnoe.producer) # None 而非后面继承的  后面继承的类属性不会覆盖前面的类

复写

类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。

即:在子类中重新定义同名的属性或方法即可。

class Phone:
    IMEI = None
    producer = "vvv"

    def call_by_5g(self):
        print("5g通话")



class MySimplePhnoe(Phone):
    IMEI = "复写一个"
    def test(self):
        # 方式一 调用父类成员变量
        print(f"父类的IMEI是:{Phone.IMEI}")
        Phone.call_by_5g(self)
        # 方式二 调用父类成员变量
        print(f"父类的IMEI是:{super().IMEI}")
        super().call_by_5g()


""" 输出结果
复写一个
父类的IMEI是:None
5g通话
父类的IMEI是:None
5g通话
"""
if __name__ == '__main__':
    simple = MySimplePhnoe()
    print(simple.IMEI) # 复写一个
    simple.test()

类型注解

通过工具提示快速知道使用的方法需要的是什么类型的参数

Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具。

类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。

主要功能:

  • 帮助第三方IDE工具(如PyCharm ctrl +p)对代码进行类型推断,协助做代码提示

  • 帮助开发者自身对变量进行类型注释

支持:

  • 变量的类型注解

函数(方法)形参列表和返回值的类型注解

变量:类型 = 值
var_1:int = 10
  • 元组类型设置类型详细注解,需要将每一个元素都标记出来

  • 字典类型设置类型详细注解,需要 2个类型,第一个是key 第二个是value

my_list: list[int] = [1, 2, 3]
# 元组类型设置类型详细注解,需要将每一个元素都标记出来
my_tuple: tuple[int, str, bool] = (1, "sdd", True)
my_set: set[int] = {1, 2, 3}
# 元组类型设置类型详细注解,需要将每一个元素都标记出来
my_dict: dict[str, int] = {"key", 111}

除了使用 变量: 类型, 这种语法做注解外,也可以在注释中进行类型注解。

语法

# type: 类型
在注释中进行类型注释

函数(方法)类型注解

def 函数方法名(形参名:类型,形参名:类型,形参名:类型,....) -> 返回值类型:
	pass

Union类型

使用Union[类型, …, 类型]

可以定义联合类型注解

Union联合类型注解,在变量注解、函数(方法)形参和返回值注解中,均可使用

from typing import Union
my_list: list[Union[int,str]] = [1, 2, 3,"ddd"]
my_dict: dict[str, Union[str,int]] = {"key", 111,"key2","value"}


def func(data:Union[int,str]) -> Union[str,int] :
    pass

多态

多态,指的是:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。


"""
Animal
抽象类(也可以称之为接口)
抽象类:含有抽象方法的类称之为抽象类
抽象方法:方法体是空实现的(pass)称之为抽象方法

"""
class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        print("汪汪汪")
class Cat(Animal):
    def speak(self):
        print("喵喵喵")

def make_noise(animal:Animal):
    animal.speak()
# 同样的行为(函数),传入不同的对象,得到不同的状态
make_noise(Dog())
make_noise(Cat())

10、数据库

pymysql

pip install pymysql
import pymysql
from pymysql import Connection

conn = Connection(
    host="localhost",
    port=3306,
    user="root",
    password="root",
    # 默认不为true 不自动提交
    autocommit=True
)
print(conn.get_server_info())


cursor = conn.cursor()
conn.select_db("db2019")
# cursor.execute("select * from payment")
"""
游标对象使用fetchall()方法,得到的是全部的查询结果,是一个元组
这个元组内部嵌套了元组,嵌套的元组就是一行查询结果
"""
# results:tuple = cursor.fetchall()
# for row in results:
#     print(row)


cursor.execute("insert into payment values (21,'python21')")
conn.close()

11、高阶

11.1 闭包

在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包

"""
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包
"""
def account_create(initial_amount = 0):
    def atm(num,deposit=True):
        nonlocal initial_amount
        if deposit:
            initial_amount += num
            print(f"存款金额:{num},账户余额:{initial_amount}")
        else:
            initial_amount -= num
            print(f"取款金额:{num},账户余额:{initial_amount}")

    return atm
"""
存款金额:300,账户余额:300
存款金额:400,账户余额:700
取款金额:300,账户余额:400
"""
fn = account_create()
fn(300)
fn(400)
fn(300,False)

优点,使用闭包可以让我们得到:

  • 无需定义全局变量即可实现通过函数,持续的访问、修改某个值

  • 闭包使用的变量的所用于在函数内,难以被错误的调用修改

缺点:

  • 由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存

11.2 装饰器

装饰器其实也是一种闭包, 其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能。

定义一个闭包函数, 在闭包函数内部:

  • 执行目标函数

  • 并完成功能的添加

装饰器的一般写法

def outer(func):
    def inner():
        print("业务前处理")
        func()
        print("业务后处理")
    return inner

def sleep():
    import random
    import time
    print("休眠中")
    time.sleep(random.randint(1,5))

fn = outer(sleep)
fn()

装饰器语法糖写法

def outer(func):
    def inner():
        print("业务前处理")
        func()
        print("业务后处理")
    return inner

@outer
def sleep():
    import random
    import time
    print("休眠中")
    time.sleep(random.randint(1,5))

sleep()

11.3 单列模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。

在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

  • 定义: 保证一个类只有一个实例,并提供一个访问它的全局访问点

  • 适用场景:当一个类只能有一个实例,而客户可以从一个众所周知的访问点访问它时。

在一个文件中定义

class Tool:
    pass

str_tool = Tool()

在另一个文件中定义

import my_package.test1
t1 = my_package.test1.str_tool
t2 = my_package.test1.str_tool
# t1 和 t2 是同一个对象
print(t1) # <my_package.test1.Tool object at 0x00000184D806BD10>
print(t2) # <my_package.test1.Tool object at 0x00000184D806BD10>

  • 节省内存

  • 节省创建对象的开销

11.4 多线程

进程 与线程

现代操作系统比如Mac OS X,UNIX,Linux,Windows等,都是支持“多任务”的操作系统。

进程: 就是一个程序,运行在系统之上,那么便称之这个程序为一个运行进程,并分配进程ID方便系统管理。

线程:线程是归属于进程的,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位。

进程就好比一家公司,是操作系统对程序进行运行管理的单位

线程就好比公司的员工,进程可以有多个线程(员工),是进程实际的工作者

操作系统中可以运行多个进程,即多任务运行

一个进程内可以运行多个线程,即多线程运行

进程之间是内存隔离的, 即不同的进程拥有各自的内存空间。 这就类似于不同的公司拥有不同的办公场所。

线程之间是内存共享的,线程是属于进程的,一个进程内的多个线程之间是共享这个进程所拥有的内存空间的。

这就好比,公司员工之间是共享公司的办公场所

并行执行

进程之间是内存隔离的, 即不同的进程拥有各自的内存空间。 这就类似于不同的公司拥有不同的办公场所。

线程之间是内存共享的,线程是属于进程的,一个进程内的多个线程之间是共享这个进程所拥有的内存空间的。

这就好比,公司员工之间是共享公司的办公场所

threading模块

import threading
thread= threading.Thread([group[target[,name[,agrs[,kwagrs]]]]])
# group 暂时无用,未来预留参数
# target 执行的目标任务名
# args 以元组的方式给执行任务传参
# kwagrs 以字典的方式给任务传参
# name 线程名一般不用设置
thread.start()
import threading
import time
def sing():
    while True:
        print("我在唱歌,到睿米发骚拉西道")
        time.sleep(1)
def dance():
    while True:
        print("我在跳舞。。。。")
        time.sleep(2)
# target 后面不要加括号
threading.Thread(target=sing).start()
threading.Thread(target=dance).start()

需要传参的话可以通过:

  • args参数通过元组(按参数顺序)的方式传参

  • 或使用kwargs参数用字典的形式传参

import threading
import time


def sing():
    while True:
        print("我在唱歌,到睿米发骚拉西道")
        time.sleep(1)


def dance(msg,msg1):
    while True:
        print(msg + ":"+ msg1)
        time.sleep(2)
def dance2(msg):
    while True:
        print(msg)
        time.sleep(2)

# target 后面不要加括号
threading.Thread(target=sing).start()
# agrs 根据位置顺序
threading.Thread(target=dance, args=("args1","args2",)).start()
# kwargs 使用字典, key 为参数名
threading.Thread(target=dance2, kwargs={"msg":"dd"}).start()

11.5 Socket

客户端和服务端

2个进程之间通过Socket进行相互通讯,就必须有服务端和客户端

Socket服务端:等待其它进程的连接、可接受发来的消息、可以回复消息

Socket客户端:主动连接服务端、可以发送消息、可以接收回复

Socket服务端编程

import socket
host= "127.0.0.1"
port = 9999
# 创建socket对象
socket_server = socket.socket()
# 绑定IP与端口
socket_server.bind((host,port))
# 开启监听
# backlog 为 int 值,表示允许的连接数量,超出的会等待,可以不填,不填会自动设置一个合理值
socket_server.listen()
# 接受客户端连接,获得连接对象
# accept 是阻塞方法
# 返回的是二元组
conn,address = socket_server.accept()
print(f"接收到连接 来自{address}")

# 通过recv接口客户端发送的消息
while True:
    data = conn.recv(1024).decode("UTF-8")
    # recv 方法返回的是字节数组(Bytes),可以通过decode解码为字符串
    # recv 参数 是缓冲区大小一般设置为1024
    if data == 'exit':
        break
    print(f"接收到的数据是:{data}")
    send_data = input("请输入回复的消息:")
    conn.send(send_data.encode("UTF-8"))
conn.close()
socket_server.close()

客户端

import socket
host= "127.0.0.1"
port = 9999
socket_client = socket.socket()
socket_client.connect((host,port))

while True:
    senf_msg = input("请输入要发送的信息")
    if senf_msg == 'exit' :
        break
    socket_client.send(senf_msg.encode("UTF-8"))
    recv_data = socket_client.recv(1024).decode("UTF-8")
    print(f"服务端回复的消息:{recv_data}")
socket_client.close()

正则表达式

正则表达式,又称规则表达式(Regular Expression),是使用单个字符串来描述、匹配某个句法规则的字符串,常被用来检索、替换那些符合某个模式(规则)的文本。

简单来说,正则表达式就是使用:字符串定义规则,并通过规则去验证字符串是否匹配。

比如,验证一个字符串是否是符合条件的电子邮箱地址,只需要配置好正则规则,即可匹配任意邮箱。

比如通过正则规则: (^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$) 即可匹配一个字符串是否是标准邮箱格式

但如果不使用正则,使用if else来对字符串做判断就非常困难了。

正则的三个基础方法

Python正则表达式,使用re模块,并基于re模块中三个基础方法来做正则匹配。

分别是:match、search、findall 三个基础方法

  • re.match(匹配规则, 被匹配字符串)

    从被匹配字符串开头进行匹配, 匹配成功返回匹配对象(包含匹配的信息),匹配不成功返回空

  • search(匹配规则, 被匹配字符串)

    搜索整个字符串,找出匹配的。从前向后,找到第一个后,就停止,不会继续向后

  • findall(匹配规则, 被匹配字符串)

    匹配整个字符串,找出全部匹配项
    元字符匹配

在刚刚我们只是进行了基础的字符串匹配,正则最强大的功能在于元字符匹配规则。

单字符匹配:

字符功能
.匹配任意一个字符(除了\n),.匹配点本身
[]匹配[]列举的字符
\d匹配数字0-9
\D匹配非数字
\s匹配空白、空格、Tab键
\S匹配非空白
\w匹配单词字符,即a-z,A-Z,0-9、_
\W匹配非单词字符

数量匹配

字符功能
*匹配前一个规则的字符出现0至无数次
+匹配前一个规则的字符出现1至无数次
?匹配前一个规则的字符出现0或者1次
{m}匹配前一个规则的字符出现m次
{m,}匹配前一个规则的字符出现最少m次
{m,n}匹配前一个规则的字符出m到n次
边界匹配
字符功能
^匹配字符串开头
$匹配字符串结尾
\b匹配一个单词的边界
\B匹配非单词的边界
分组匹配
字符功能
|匹配左右任意一个表达式
()将括号中字符作为一个分组
  • 匹配账号,只能由字母和数字组成,长度限制6到10位规则为: ^[0-9a-zA-Z]{6, 10}$

  • 匹配QQ号,要求纯数字,长度5-11,第一位不为0规则为:^[1-9][0-9]{4, 10}&

    [1-9]匹配第一位,[0-9]匹配后面4到10位

  • 匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址

    规则为:^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+&

  • [\w-]+ 表示出现a-z A-Z 0-9 _ 和 - 字符最少一个,最多不限

  • (\.[\w-]+)*,表示出现组合 . 和a-z A-Z 0-9 _-的组合最少0次,最多不限

    用于匹配:abc.ced.efg@123.com中的ced.efg这部分

  • @表示匹配@符号

  • (qq|163|gmail)表示只匹配这3个邮箱提供商

  • (\.[\w-]+)+表示a-z A-Z 0-9 _ -的组合最少1次,最多不限

    用于匹配abc.ced.efg@123.com.cn中的.com.cn这种

    最后使用+表示最少一次,即比如:.com

    多了可以是:.com.cn.eu这样

    11.6 递归

递归在编程中是一种非常重要的算法

递归: 即方法(函数)自己调用自己的一种特殊编程写法

# 函数调用自己,即称之为递归调用
def fun():
	if ...:
		fun()
return ....

1、什么是递归

在满足条件的情况下,函数自己调用自己的一种特殊编程技巧

2、 递归需要注意什么?

  • 注意退出的条件,否则容易变成无限递归

  • 注意返回值的传递,确保从最内层,层层传递到最外层

3、 os模块的3个方法

  • os.listdir,列出指定目录下的内容

  • os.path.isdir,判断给定路径是否是文件夹,是返回True,否返回False

  • os.path.exists,判断给定路径是否存在,存在返回True,否则返回False

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python从入门到精通是一套针对Python编程语言的学习教程,旨在帮助初学者快速掌握Python的基础知识并逐步深入学习高级主题。以下是该教程的大致内容: 第一Python基础 - Python的历史和特点 - 安装Python环境 - 变量和数据类型 - 运算符和表达式 - 条件语句和循环语句 第二:函数和模块 - 函数的定义和调用 - 函数参数和返回值 - 模块的导入和使用 - 常用内置函数的介绍 第三:数据结构 - 列表、元组、字典和集合的使用 - 列表和字典的常用操作方法 - 列表推导式和字典推导式 第四:文件操作和异常处理 - 文件的读写操作 - 异常的处理和捕获 - 上下文管理器的使用 第五:面向对象编程 - 类和对象的概念 - 类的定义和实例化 - 继承、多态和封装的概念 - 魔术方法和属性装饰器 第六:模块和包管理 - 模块的创建和使用 - 包的创建和使用 - 导入模块和包的方法 - 第三方库的安装和使用 第七:网络编程和数据库操作 - 网络编程的基本概念 - 使用socket进行网络通信 - 数据库的连接和操作 - SQL语句的执行和结果处理 第八:高级主题 - 多线程和多进程编程 - 正则表达式的使用 - 异步编程和协程 - Python的Web开发框架介绍 以上是八Python从入门到精通教程的大致内容,通过学习这些内容,你将能够掌握Python的基础知识并具备一定的编程能力。如果你有任何关于Python的问题,欢迎继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值