【python基础教程——一文教你入门python,够详细够实用】

文章目录

  • 前言
  • 1 Python程序基本结构
    • 1.1 代码缩进
    • 1. 2 代码注释
      • 1.2.1 单行注释
      • 1.2.2 多行注释
    • 1.3 语句分隔
    • 1.4 语句续行
    • 1.5 关键字与大小写
  • 2 输入和输出
    • 2.1 基本输入
    • 2.2 基本输出
      • 2.2.1 省略所有参数(输出空白行)
      • 2.2.2 输出一个或多个对象
      • 2.2.3 指定输出分隔符
      • 2.2.4 指定输出结尾符号
      • 2.2.5 指定输出到文件
    • 2.3 高级输出
      • 2.3.1 使用%格式化输出
      • 2.3.2 使用format格式化输出
      • 2.3.3 使用f格式化输出
      • 2.3.4 最小字段宽度和精度
  • 3 python变量
    • 3.1 变量与对象
    • 3.2 变量理解
    • 3.3 变量命名
      • 3.3.1 命名规则
      • 3.3.2 命名法则
    • 3.4 变量赋值
  • 4 数据类型
    • 4.1 Number 数字类型
      • 4.1.1 int 整型
      • 4.1.2 float 浮点数类型
      • 4.1.3 complex 复数类型
      • 4.1.4 boole 布尔类型
        • 4.1.4.1 计算表达式
        • 4.1.4.2 True 布尔真值
        • 4.1.4.3 False 布尔假值
      • 4.1.5 运算符
        • 4.1.5.1 运算符
        • 4.1.5.2 比较运算符
        • 4.1.5.3 赋值运算符
        • 4.1.5.4 位运算符
        • 4.1.5.5 逻辑运算符
        • 4.1.5.6 成员运算符
        • 4.1.5.7 身份运算符
        • 4.1.5.8 运算符优先级
    • 4.2 String 字符串类型
      • 4.2.1 初识字符串
        • 4.2.1.1 定义字符串
        • 4.2.1.2 创建字符串
        • 4.2.1.3 引号嵌套
      • 4.2.2 访问字符串中的值
        • 4.2.2.1 字符串是序列
        • 4.2.2.2 获取特定位置单个字符
        • 4.2.2.3 切片
      • 4.2.3 字符串基本操作
        • 4.2.3.1 字符串拼接
        • 4.2.3.2 字符串遍历
        • 4.2.3.3 成员运算符
        • 4.2.3.3 字符串格式化
      • 4.2.4 常用内置函数和方法
    • 4.3 List 列表类型
      • 4.3.1 初识列表
        • 4.3.1.1 列表定义
        • 4.3.1.2 创建列表
        • 4.3.1.3 列表嵌套
      • 4.3.2 访问列表中的值
        • 4.2.2.1 列表是序列
        • 4.2.2.2 获取特定位置列表元素
        • 4.2.2.3 切片
      • 4.3.3 列表基本操作
        • 4.3.3.1 列表拼接
        • 4.3.3.2 添加列表元素
        • 4.3.3.3 更新列表元素
        • 4.3.3.4 查找列表元素
        • 4.3.3.5 删除列表元素
      • 4.3.4 列表常用函数和方法
    • 4.4 Tuple 元组类型
      • 4.4.1 初始元祖
        • 4.4.1.1 元祖定义
        • 4.4.1.2 创建元祖
      • 4.4.2 元组跟列表区别
    • 4.5 Set 集合类型
      • 4.5.1 初识集合
        • 4.5.1.1 集合定义
        • 4.5.1.2 创建集合
      • 4.5.2 基本操作
        • 4.5.2.1 访问集合值
        • 4.5.2.2 添加元素
        • 4.5.2.2 移除元素
        • 4.5.2.3 计算集合元素个数
        • 4.5.2.4 清空集合
        • 4.5.2.5 成员运算符
      • 4.5.3 集合常用函数
    • 4.6 DICtionary 字典类型
      • 4.6.1 初识字典
        • 4.6.1.1 字典定义
        • 4.6.1.2 创建字典
        • 4.6.1.3 嵌套字典
      • 4.6.2 基本操作
        • 4.6.2.1 访问字典值
        • 4.6.2.2 添加字典元素
        • 4.6.2.3 更新字典元素
        • 4.6.2.4 删除字典元素
        • 4.6.2.5 清空字典
        • 4.6.2.6 获取字典全部的key
        • 4.6.2.7 成员运算符
      • 4.6.3 字典常用方法和内置函数
    • 4.7 数据类型通用特性
      • 4.7.1 for循环遍历
      • 4.7.2 len() 统计元素个数
      • 4.7.3 max() 统计最大元素
      • 4.7.4 min() 统计最小元素
      • 4.7.5 sorted() 排序
      • 4.7.6 数据类型转换
      • 4.7.6.1 隐式类型转换
      • 4.7.6.2 显式类型转换
    • 4.8 推导式
      • 4.8.1 列表推导式
      • 4.8.2 字典推导式
      • 4.8.3 集合推导式
      • 4.8.4 元祖推导式
  • 5. 各种控制语句
    • 5.1 条件控制语句if-else
      • 5.1.1 if语句的基本格式
      • 5.1.2 if-else语句的基本格式
      • 5.1.3 if-elif-else语句的基本格式
      • 5.1.4 if嵌套
    • 5.2 循环控制语句
      • 5.2.1 while控制语句
      • 5.2.2 while 循环使用 else 语句
      • 5.2.3 for循环控制语句
      • 5.2.4 for循环使用 else 语句
      • 5.2.5 for语句中的range语句
      • 5.2.6 for循环的变量作用域
      • 5.2.7 循环的嵌套
      • 5.2.8 循环中断break及continue
  • 6. 函数
    • 6.1 函数的定义
    • 6.2 函数参数
      • 6.2.1位置参数
      • 6.2.2 关键字参数
      • 6.2.3 默认参数
      • 6.2.4 不定长位置参数 \*args
      • 6.2.5 不定长关键字参数 \*\*kwargs
    • 6.3 匿名函数
    • 6.4 函数作为参数传递
    • 6.5 函数的返回值
    • 6.6 函数的说明文档
    • 6.6 函数的嵌套
    • 6.7 变量的作用域
  • 7.文件
    • 7.1 文件的编码
      • 7.1.1 什么是文件
      • 7.1.2 编码规则
    • 7.2 文件的常用操作
      • 7.2.1 文件的打开操作
      • 7.2.2 文件的关闭操作
      • 7.2.3 文件的读取操作
      • 7.2.4 文件的写入操作
    • 7.3 os模块的使用
  • 8. 异常
    • 8.1 异常的定义
    • 8.2 异常的捕获
      • 8.2.1 捕获常规异常
      • 8.2.2 捕获特定异常
      • 8.2.3 捕获多个异常
      • 8.2.4 捕获全部异常
    • 8.2.4 异常的else语句
    • 8.2.5 异常的finally语句
    • 8.3 异常的传递
    • 8.4 抛出异常
    • 8.5 Python 模块
      • 8.5.1 模块的导入
        • 8.5.1.1 import 语句
        • 8.5.1.2 from ... import 语句
        • 8.5.1.3 as 别名
      • 8.5.2 自定义模块
        • 8.5.2.1 定义模块
        • 8.5.2.2 调试模块
      • 8.5.3模块的查找路径
    • 8.6 包
      • 8.6.1 包的概念
      • 8.6.2 创建包
      • 8.6.3 导入包
      • 8.6.4 导入第三方包
      • 8.6.5 包的访问路径
  • 9. 面向对象
    • 9.1 类和对象
      • 9.1.1 类的定义
      • 9.1.2 对象的定义
    • 9.2 实例化对象
    • 9.3 类属性
      • 9.3.1 定义类属性
      • 9.3.2 访问类属性
        • 9.3.2.1 类外部访问
        • 9.3.2.1 类内部访问
      • 9.3.3 修改类属性
    • 9.4 类方法
      • 9.4.1 定义类方法
      • 9.4.2 访问类方法
    • 9.5 实例属性
      • 9.5.1 定义实例属性
        • 9.5.1.1 不传参数方式定义
        • 9.5.1.2 传参方式定义
      • 9.5.2 访问实例属性
      • 9.5.3 添加实例属性
    • 9.6 实例方法
      • 9.6.1 实例方法定义
      • 9.6.2 调用实例方法
    • 9.7 私有属性
      • 9.7.1 定义私有属性
      • 9.7.2 访问私有属性
        • 9.7.2.1 类内部访问
        • 9.7.2.2 类外部访问
    • 9.8 私有方法
      • 9.8.1 定义私有方法
      • 9.8.2 访问私有方法
        • 9.8.2.1 类内部访问
        • 9.8.2.2 类外部访问
        • 9.8.3 属性和方法总结
    • 9.9 内置魔法方法
      • 9.9.1 _ _new_ _ 生成对象方法
      • 9.9.2 _ _str_ _ 字符串方法
      • 9.9.3 _ _del_ _ 析构方法
      • 9.9.4 _ _call_ _ 方法
      • 9.9.5 _ _eq_ _ == 符号比较方法
    • 9.10 继承
      • 9.10.1 继承的基础语法
      • 9.10.2 单继承
      • 9.10.2 多继承
      • 9.10.3 方法重写
      • 9.10.4 调用父类同名成员
    • 9.11 类型注解
      • 9.11.1 变量类型注解
      • 9.11.2 容器类型注解
      • 9.11.3 函数类型注解
      • 9.11.4 Union类型注解
    • 9.12 多态

前言

本文讲述python的基础知识,内容过多,建议收藏阅读。
如果你能把本文看完,并且把每个代码运行都自己敲打执行一遍,必能入门python!!!

【python基础教程——一文教你入门python,够详细够实用】_第1张图片

1 Python程序基本结构

Python 程序结构涉及代码块、注释、语句分隔、语句续行、关键字与大小写等内容

1.1 代码缩进

在Java 、C/C++等语言中,用花括号表示代码块,例如:

if(x > 100){
    y = x *5 -1;
}else{
    y = 0; 
}

Python使用缩进(空格)来表示代码块。通常,语句末尾的冒号表示代码块的开始。在if、for、while、函数、类等定义中都会使用到代码块。例如:

if x > 100:
    y = x *5 -1
else:
    y = 0

在包含代码嵌套是,冒号代表语句块的开始,应注意同级代码块的缩进量应保持相同:

x = 5
if x < 0:
    print("参数X的值不合法")
    print('X < 0')
else:
    for i in [1,2,3,4,5]:
        print(i)
    print('X > 0')
print(x)

编码规范:使用空格来缩进,tab在不同环境下对应空格长度可能发生变化,在某些ide上tab键可能是8个空格长度

1. 2 代码注释

注释用于为程序添加说明文字,当Python运行程序时,会忽略掉被注释的内容。

1.2.1 单行注释

单行注释用“#”表示注释开始,“#”之后的语句不会被编译器执行。单行注释可以单独占一行,也可以放在语句末尾。

# 注释单独占一行,定义一个变量n
n = 0
---------------------------------------
b = 100  # 注释放在语句末尾,定义的变量b

1.2.2 多行注释

多行注释使用三个英文的单引号“ ‘’’ ”或者双引号“ “”" ”作为注释的开始和结束符号。

'''多行注释,这个是开头的三个单引号,
         这是一段内容
   这是结束的三个单引号'''
----------------------------------
"""多行注释,这个是开头的三个双引号,
         这是一段内容
   这是结束的三个双引号"""

1.3 语句分隔

使用分号分隔语句,从而将多条语句写在一行。

print(100);print(2+3)  

如果冒号之后的语句块只有一条语句,Python允许将语句写在冒号之后,冒号之后可以是分号分隔的多条语句。

if x > 1:y = x **2 
else:y=1;print('x <= 1')   #冒号(:)后的每一个语句缩进量相同

1.4 语句续行

通常,Python中的一条语句占一行,没有类似于Java中的分号等语句结束符号。在遇到较长的语句时,可使用语句续行符号,将长语句写在多行中。
使用“\”符号续行

if x < 100\
    and z > 10:
    y = x*5-1
else:
    y = 0

使用括号续行(包括使用圆括号()、方括号[]和大括号{}等),在使用括号时,括号内的内容可分多行书写,括号中的空白和换行符都会被忽略。

if x < 100\
    and z > 1:
    y = x*5-1
else:
    y = 100

1.5 关键字与大小写

Python中也有各种标识符,如if、for、while等,可称为关键字。
Python对大小写敏感,关键字和各种自定义的标识符(如变量名、函数名等)在使用时区分大小写。

# if 不能写成If或IF,否则在编译时python提示语法出错
>>>If 2<9:
  File "",line I
    If 2<9:
       ^
SyntaxError: invalid syntax

ab与Ab是两个不同的变量

>>>ab = 10
>>>Ab = 20
>>>print(ab,Ab)

10 20 # 结果输出为10 20 则证明ab与Ab是两个不同的变量

【python基础教程——一文教你入门python,够详细够实用】_第2张图片


好了,我们已经完成了第一章的学习,下面我们进入第二章。

2 输入和输出

2.1 基本输入

如果我们想要获取用户输入的信息,我们可以使用input语句。input函数用于获得用户输入数据,基本格式如下:

变量 = input (提示字符串)

其中,变量和字符串是可以省略的。用户按【Enter】键完成输入,【Enter】键之前的全部字符均作为输入内容。

>>>a = input('请输入数据:')
请输入数据:'shiting
>>>a
'shiting

其中input函数是将用户输入以字符串返回,这个特点需要我们特别注意,例如:我们在python中打出”“a = input(请输入一个整数)”,此时变量a的类型仍然是为字符串。
如果需要输入整数或小数,则需要使用int或float函数进行相应的数据类型转换

>>>a = input('请输入一个整数:')   # 实际a的类型为字符串
请输入一个整数:2
>>>a + 1        # 运行会报错,因为a是一个字符串,试图执行加法运算


# 可以改为:
a = input('请输入一个整数:')
int(a)+1    #将字符串转为整数再执行相关加法运算,ok
# 或者改为:
a = int(input('请输入一个整数:'))

另外,在使用input输入数据时,我们可以使用【Ctrl+Z】组合键中断输入;但是假如没有输入任何数据,按下【Ctrl+Z】组合键,则会产生EOFError异常

2.2 基本输出

Python3.x中使用print函数完成基本输出操作,print函数基本格式:

print(value, ..., sep=' ', end='\n', file=sys.stdout , flush=False)

参数的具体含义如下:

value–表示输出的对象。输出多个对象时,需要用 , (逗号)分隔。

sep – 用来间隔多个对象。

end – 用来设定以什么结尾。默认值是换行符 \n,我们可以换成其他字符。

file – 要写入的文件对象。

flush – 是否刷新缓冲区

2.2.1 省略所有参数(输出空白行)

print函数所有参数均可以省略。当无参数时,print函数输出一个空白行

>>>print()  # 无参数时,输出空白行

>>>

2.2.2 输出一个或多个对象

print函数可同时输出一个或多个对象,无论什么类型的数据都可以直接输出。

#输出一个对象
>>>print(123456)    # 123456 

>>>num = 19
>>>print(num)    #19  输出数值型变量
 
>>>str = 'Duan Yixuan'
>>>print(str)  #Duan Yixuan  输出字符串变量
 
>>>list = [1,2,'a']
>>>print(list)   #[1, 2, 'a']  输出列表变量
 
>>>tuple = (1,2,'a')
>>>print(tuple)    #(1, 2, 'a') 输出元组变量
 
>>>dict = {'a':1, 'b':2}
>>>print(dict)   # {'a': 1, 'b': 2} 输出字典变量
----------------------------------------------------------------
 
 # 同时输出多个对象
>>>print(123,'abc','com')  #123 abc com  对象之间默认用空格分隔

2.2.3 指定输出分隔符

print函数默认分隔符为空格,可用sep参数指定输出对象的分隔符号

>>>print(123,'abc','com',sep='#')   # 指定使用'#'作为输出分隔符
123#abc#com

>>>print("www", "4399", "com", sep=".")  # 指定使用'.'作为输出分隔符
www.4399.com

2.2.4 指定输出结尾符号

print函数默认以回车换行符号( \n)作为输出结尾符号,即在输出后会换行,后面的print函数的输出会在新的一行开始。可用end参数指定输出结尾符号

>>>print("abc");print(000)   # 一行写完多条输出print语句,仍会每一条都换行
abc
000

>>>print('abc',end='+');print(000)  #指定使用”+“作为结尾符号,输出在一行
abc+000 

2.2.5 指定输出到文件

print 函数默认输出到标准流(即sys.stdout)。可用 file参数 指定输出到特定文件。

>>>file1 = open('data.txt','w')  # 打开文件
>>>print(123,'abc',45,'book',file = file1)  # 用file参数指定输出到文件
>>>file1.close()  # 关闭文件
>>>print(open('data.txt').read())  # 输出从该文件中读出的内容
123 abc 45 book

2.3 高级输出

2.3.1 使用%格式化输出

在C语言中,我们可以使用printf(“%-0.3d”,num)之类的形式,实现数据的的格式化输出
在python中,我们也可以实现类似的操作: %是一个占位符

%格式符 相应作用
c 字符及其ASCII码
s 字符串
d 有符号整数(十进制)
f 浮点数字(用小数点符号)
u 无符号整数(十进制)
o 无符号整数(八进制)
x 无符号整数(十六进制)
X 无符号整数(十六进制大写字符)
e 浮点数字(科学计数法)
E 浮点数字(科学计数法,用E代替e)
g 浮点数字(根据值的大小采用%e或%f)
G 浮点数字(类似于%g)
p 指针(用十六进制打印值的内存地址)
n 存储输出字符的数量放进参数列表的下一个变量中

常用格式化输出:%d %f %s ,

num = 156         # 整数
print('%d' %num)  # 156
print('%f' %num)  # 156.000000  默认精度为6
print('%s' %num)  # 156

num = 156.1415    # 浮点数
print('%d' %num)  # 156
print('%f' %num)  # 156.141500 默认精度为6
print('%s' %num)  # 156.1415

num = '156'       # 字符串
print('%d' %num)  # TypeError: %d format: a number is required, not str
print('%f' %num)  # TypeError: must be real number, not str
print('%s' %num)  # 156

nun = [1,4]       # 列表
print('%s' %num)  # [1,4]


#同时输出多个变量用()
num = 156.1415  
n = 456
print('%d,%f' %(n,num))  # 456,156.141500

2.3.2 使用format格式化输出

format()–该函数把字符串当成一个模板,通过传入的参数进行格式化,并且使用大括号‘{}’作为特殊字符代替‘%’,且不用相应的格式字符

num = 156                # 整数
print('{}'.format(num))  # 156

num = 156.1415           # 浮点数
print('{}'.format(num))  # 156.1415

num = '156'              # 字符串
print('{}'.format(num))  # 156


#同时输出多个变量
n = 456
num = 156.1415  
print('{},{}'.format(n,num))  # 456,156.1415

相对基本格式化输出采用‘%’的方法,format()功能更强大,
优点:
1.带数字编号,可调换顺序,即“{1}”、“{2}”
2.带关键字,即“{a}”、“{tom}”

num = 156.1415  
n = 456
print('{1},{0}'.format(n,num))  # 通过索引控制
156.1415456     # 即format(n,num)中{0}=n,{1}=num

print('{a},{b}'.format(a=n,b=num))  # 通过关键字控制
156.1415,456      # 即format(n,num)中{0}=n,{1}=num
456,156.1415      # 即format{a=n,b=num}中指定{a}=n,{b}=num

2.3.3 使用f格式化输出

f-string用大括{ }表示被替换字段,其中直接填入替换内容即可。

num = 156              # 整数
print(f'{num}')        # 156

num = 156.1415         # 浮点数
print(f'{num}')        # 156.1415

num = '156'            # 字符串
print(f'{num}')        # 156

#同时输出多个变量
n = 456
num = 156.1415  
print(f'{n}{num}')  # 456,156.1415

2.3.4 最小字段宽度和精度

最小字段宽度:转换后的字符串至少应该具有该值指定的宽度。
如果是*(星号),则宽度会从值元组中读出。

精度:点(.)后跟精度,表示输出值的精度大小
如果需要输出实数,精度值表示出现在小数点后的位数。
如果需要输出字符串,那么该数字就表示最大字段宽度。
如果是*,那么精度将从元组中读出。
用%格式化输出

num = 156.1415     #最小字段宽度和精度支持各种格式化输出
print('**********')  # 用来判断宽度
print('%10f' %num)  # 字段宽10
print('%.3f' %num)  # 精度3,四舍五入
print('%10.3f' %num)  # 字段宽10,精度3
print('%010.3f'%num)  #010表示字宽10,不够用0填充
print('%+010.3f'%num)  # 添加+ 表示显示正负号
print('%-10.3f'%num)  # 添加负号表示左对齐

#执行结果为:
**********
156.141500
156.142
   156.142
000156.142
+00156.142
156.142 

用format()格式化输出,同样需要跟%输出一样,只是多了{:}

num = 156.1415     #最小字段宽度和精度支持各种格式化输出
print('**********')  # 用来判断宽度
print('{:10f}'.format(num));   # 字段宽度10
print('{:.3f}'.format(num))    # 精度3
print('{:10.3f}'.format(num))  # 字段宽10,精度3
print('{:010.3f}'.format(num))  #010表示字宽10,不够用0填充
print('{:+010.3f}'.format(num))  # 添加+ 表示显示正负号
print('{:<10.3f}'.format(num))  # 添加<表示左对齐

#执行结果为:
**********
156.141500
156.142
   156.142
000156.142
+00156.142
156.142

制表符\t,可以占用四个字节。 第二章节内容完结啦。

【python基础教程——一文教你入门python,够详细够实用】_第3张图片


3 python变量

C、C++和Java等都是属于静态数据类型语言,即要求变量在使用前必须声明其数据类型。例如,我们需要定义一个变量为x,其数据类型为int

int x;

但对于python属于动态数据类型语言,他不需要对变量进行声明即可使用。

3.1 变量与对象

x = 5

对于上面的赋值语句,python在执行时总共执行了如下几个步骤:
第一步:创建表示整数5的对象。(注意:在python中所有的数据都是以对象的方式存在,学会了python,你就学会了创建对象)
第二步:检查变量x是否存在,若不存在则创建它。
第三步:建立变量x到对象5之间的引用

上面说的可能有些复杂,可以看完全文的内容后,再回来了解。

3.2 变量理解

在python中使用变量,需要理解下面几点:
1、变量在第一次赋值时被创建,再次出现时可以直接使用
2、严格来说变量没有数据类型的概念。数据类型属于对象,类型决定了对象在内存中的存储方式
3、变量引用了对象。当在表达式中使用变量时,变量立即被其引用的对象替代。
4、所以变量在使用前必须对其进行赋值

x = 5      # 创建对象5,第一次使用,创建变量x, 引用对象5
print(x + 3) 
#执行结果为:
8

对同一个变量赋值不同的数据类型,则会改变变量的类型

x = 5
x = 'yyds'
print(x)
#执行结果为:
yyds

3.3 变量命名

3.3.1 命名规则

变量的命名规则应包含如下:

  • 必须以下划线或字母开头,不能以数字开头
  • 变量名称只能包含下划线、字母或者数字
  • 变量名区分大小写
  • 禁止使用python保留字
myname1 = "须佐"
my_name_2 = "须佐"
_myname3 = "须佐"

避免使用如下样式:

  • 前后有下划线的变量名通常为系统变量,例如:namedoc
  • 以一个下划线开头的变量(如_name)不能被from…import*语句从模块导入
  • 以两个下划线开头、末尾无下划线的变量(如__abc)是类的私有变量

3.3.2 命名法则

驼峰式命名法,混合使用大小写字母来构成变量和函数的名字。包含:骆驼法则和帕斯卡法则
骆驼法则(Camel):又名小驼峰命名(lowerCamelCase),除第一个单词之外,其他单词首字母大写。

TaskRepository taskRepository			 #成员变量			 
androidStudio = "安卓开发工具"      		 #局部变量

帕斯卡法则(Pascal):又名大驼峰命名(CamelCase),每个单词的首字母都大写。

class TaskDate()     #类名
Login				 #命名空间

蛇形法则:每个单词都以下划线字符分隔。

get_uername()
test_login01 = 'z'   #测试方法名
PI = 3.1415926   	 #常量
LAST_DATA            #枚举名称

命名规范
1、模块名和包名尽量短小,并且全部使用小写字母,可以使用下划线,如:mymodule.py,module_name.py,common包名
2、类采用单词首字母大写形式(即Pascal)。
3、函数、类的属性和方法的命名规则同模块的类似,也是全部小写字母,多个字母间用下划线“”分隔。
4、常量命名时采用全部大写字母,可以使用下划线。
5、使用单下划线“
”开头的模块变量或者函数是受保护的,在使用from xxx import * 语句从模块中导入时这些变量或函数不能被导入。

3.4 变量赋值

赋值语句用于创建变量、建立变量到对象的引用。python中有多种赋值语句:简单赋值、序列赋值、多目标赋值、增强赋值等。
(1)简单赋值

x =100    #为一个变量建立对象引用

(2)序列赋值
序列赋值可以一次性为多个变量赋值。python会顺序匹配变量名和值。

n, m = 1, 2        # 使用省略圆括号的元组赋值
print(n, m)        # 输出:1,2

(a, b) = (3, 4)	   # 使用元组赋值
print(a, b)   	   # 输出:3,4  

x, y, z="kpo"	   # 用字符串赋值
print(x, y, z)     # 输出:'k','p','o'

注意可以在变量名之前使用“*”,为变量创建列表对象引用。此时,不带星号的变量匹配一个值,剩余的值会作为带星号变量的列表对象

x, *y = 'cctest'   # x匹配第一个字符,剩余字符作为列表匹配y
print(x, y)        # 输出:'c','ctest'

(3)多目标赋值
可以使用“=”,为连续多个变量赋同一个值

n=m=p= 520        # 将520赋值给变量n、m、p
print(n, m, p)    # 输出:520,520,520

前面几章节的内容都比较简单,接下来开始进入重点

【python基础教程——一文教你入门python,够详细够实用】_第4张图片

4 数据类型

数据类型决定了程序如何存储和处理数据。Python中完善的数据类型系统,使得在Python程序中可以轻松完成各种数据处理,python中的内置数据类型如下

数字类型: int, float, complex
序列类型: str, list, tuple, range
映射类型: dict
套装类型: set, frozenset
布尔类型: bool
二进制类型: bytes, bytearray, memoryview

标准数据类型如下:
不可变类型(3 个):Number(数字)、String(字符串)、Tuple(元组);
可变类型(3 个):List(列表)、Dictionary(字典)、Set(集合)。

可变、不可变区分依据是保存数据的源内存空间是否允许修改
1、不可变类型:数字、字符串、元组
源内存空间中数据不允许修改, 如果想要修改, 只能开辟新内存空间,让变量引用指向新内存空间数据的地址
2、可变类型:字典、列表、集合
源内存空间中的数据可以修改,不需要开辟新内存空间,只要在源内存基础上修改数据

4.1 Number 数字类型

数字 是程序处理的一种基本数据,Python 数字数据类型用于存储数值。
数据类型是不允许改变的,这就意味着如果改变数字数据类型的值,将重新分配内存空间。
在变量赋值时 Number 对象将被创建:

var1 = 1
print(id(var1))   # 2621878588880
var1 = 10
print(id(var1))   # 2621878592144

id()函数可以查询变量的内存地址,我们可以看到在对var1变量进行再次赋值后,其内存地址改变了,说明数字类型是一个不可变类型

可以通过使用del语句删除单个或多个对象的引用

del var1,var2

Python中核心对象包含的数字类型包括: 整型(int) 、浮点型(float)、复数(complex)、布尔类型(boole)

4.1.1 int 整型

整型就是不带小数点的数,一般的整型都是十进制。在Python 3里,只有一种整数类型 int,表示为长整型,没有 python2 中的 Long。理论上来说,只要计算机的内存空间足够,整数可以无穷大。

>>>2**100 # 输出2的100次方
1267650600228229401496703205376
>>>3**100 # 输出3的100次方
515377520732011331036461129765621272702107522001

Python还允许将整型表示为二进制、八进制、十六进制。

  • 二进制:以0b或0B开头,后面跟二进制数字(0、1)如:0b1001、0B1003
  • 八进制:以0o或0O开头,后面跟八进制数字(0~7)如:0o1002、0O1003
  • 十六进制:以0x或0X开头,后面跟十六进制数字(0~9、A ~ F)字母大写或者小写都可以。如:0x12AB、0X231BD

不同进制只是整数的不同书写形式,程序运行时都会处理为十进制数。这个念书变量在程序中使用时,都会生成一个整数对象

可以使用int函数将一个字符串按指定进制转换为整数。int函数基本格式如下:

int(x,基数= 10# 如果X不是数字或如果基数给出,则X必须是一个字符串
>>>int('110')     # 111       # 默认按十进制转换
>>>int('110',2)     # 6       # 按二进制转换
>>>int('110',8)    # 72       # 按八进制转换
>>>int('110',10)   # 110      # 按十进制转换
>>>int('110',16)   # 272      # 按十六进制转换

>>>int(110,2)   # 基数给出,X必须为字符串  错误

int函数中第一个字符可以是正负号,其他字符不能包含小数及其他符号。

>>>int(+12)    
>>>int('+12')  # +12
>>>int('-12')  # -12

>>>int('+-123')  # 字符串中同时包含了正负号 错误
>>>int('12.3')   # 字符串中包含了小数       错误
>>>int('123asd')  # 字符串中包含了字母      错误

python中提供了内置函数bin(x)、oct(x)和bex(x)用于将整数转换为对应进制的字符串。

>>>bin(21)   # '0b10101'  #转换为二进制字符串
>>>oct(21)   # '0o25'     #转换为八进制字符串
>>>hex(21)   # '0x15'     #转换为十六进制字符串

4.1.2 float 浮点数类型

12.5、2.、3.0、12.3e+10等都是合法的浮点数常量。float()函数来创建浮点数
float()函数基本格式如下:

float(X)  # X为数字或者字符串构成的浮点数
>>>float(12.0)  # 12.0
>>>float(+12.0)  # +12.0
>>>float(-12.0)  #-12.0
>>>float('12.2333')  #12.2333

>>>float('wqhfaf')  #字符串包含字母, 错误

4.1.3 complex 复数类型

复数常量表示为“实部+虚部”形式,虚部以j或J结尾。如2+3j、2+3J。可用complex()函数来创建复数

complex (实部,虚部)
>>>complex(2,3)  # 2+3j 
>>>complex(2)  # 2+0j

4.1.4 boole 布尔类型

bool类型标识 True 和 False,常用语表达式是否为True or False

4.1.4.1 计算表达式

比较两个值,将计算表达式结果并返回布尔值答案:

print(1 > 2)        # False

if 1 == 2:          # True
    print("aaaa")   
else:
    print('bbbb')
4.1.4.2 True 布尔真值

True表示真值,几乎任何值都会被评估,任何非空的字符串、列表、元组、集合、字典都是True

bool("abc")            # True
bool(123)              # True
bool(["yys", "age"])   # True
4.1.4.3 False 布尔假值

False表示空值(例如()、[]、{}、‘’、数字0)及计算为None的值

bool(0)     # False
bool("")    # False
bool(())    # False
bool([])    # False
bool({})    # False
bool(None)  # False

一般我们使用内置的 type() 函数可以用来查询变量所指的对象类型。

a = True
print(type(a)) #输出 

此外还可以用 isinstance 来判断:

a = 111
isinstance(a, int)  # 使用isinstance函数判断变量 a 是否是整型
# 输出结果为布尔值,True or False

注意:
Python3 中,boole 是 int 的子类,True 和 False 可以和数字相加, True==1、False==0 会返回 True.
在 Python2 中是没有布尔型的,它用数字 0 表示 False,用 1 表示 True

4.1.5 运算符

Python 语言支持以下类型的运算符:

  • 算术运算符
  • 比较运算符
  • 赋值运算符
  • 位运算符
  • 成员运算符
  • 身份运算符
4.1.5.1 运算符

python支持基本的算术运算:加法(+)、减法(-)、乘法(*)、除法(/)、取整除(//)、取余(%)、幂(**)

a, b=8, 5

c = a + b   # 13     两个数相加
d = a - b   # 3      两个数相减
e = a * b   # 40     两个数相乘
f = a / b   # 1.6    a除以b  
g = a // b  # 1      取整除   往小的方向取整数,返回向下取整后的结果
h = a % b   # 6      返回除法的余数
j = a ** b  # 32768  返回a的b次方

注意:在整数除法中,除法 / 总是返回一个浮点数

4.1.5.2 比较运算符

python中的比较运算符有:大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)、不等于(!=)

a,b=1020

print(a > b)    # False   
print(a < b)    # True     
print(a == b)   # False
print(a >= b)   # False
print(a <= b)   # True
print(a != b)   # True
4.1.5.3 赋值运算符

python中的赋值运算符有:简单赋值(=)、加法赋值(+=)、减法赋值(-=)、乘法赋值(*=)、除法赋值(/=)、取整除赋值(//=)、取模赋值(%=)、幂赋值(**=)

a,b=21,10
c = a + b    # 31

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
4.1.5.4 位运算符

按位运算符是把数字看作二进制来进行计算的,python中的位运算符有:按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、左移动(<<)、右移(>>)

a = 60            # 60 = 0011 1100 
b = 13            # 13 = 0000 1101

c = a & b      # 如果两个相应位都为1, 则该位的结果为1, 否则为0  # 12 = 0000 1100 
c = a | b      # 如果两个相应位都为0, 则该位的结果为0, 否则为1  # 61 = 0011 1101
c = a ^ b      # 如果两个相应位相异, 则该位的结果为1, 否则为0   # 49 = 0011 0001 
c = a ~ b      # 把每个二进制位取反, 即把1变为0, 把0变为1       # -61 = 1100 0011
c = a << 2     # 把每个二进制位左移若干位,高位丢弃,低位补0    # 240 = 1111 0000
c = a >> 2     # 把每个二进制位右移若干位,高位补0,低位丢弃    # 15 = 0000 1111 
4.1.5.5 逻辑运算符

python支持的逻辑运算符有:与(and)、或(or)、非(not)

a , b= 10 , 20

print(a and b)  # 如果 a 为 False,返回 a 的值,否则返回 b 的计算         # True 
print(a or b)   # 如果 a 是 True,返回 a 的值,否则返回 b 的计算值        # True
print(not a)    # 如果 a 为 True,返回 False 。如果 a 为 False,它返回 True。  # False 
4.1.5.6 成员运算符

除了以上的一些运算符之外,Python还支持成员运算符:在(in) 和 不在(not in )

a , b= 10 , 20
list = [1, 2, 3, 4, 5 ]

print(a in list)      # 如果在序列中找到值返回 True,否则返回 False     # False  
print(b not in list)  # 如果在序列中没有找到值返回 True,否则返回 False  # True 
4.1.5.7 身份运算符

身份运算符用于比较两个对象的存储单元,python有身份运算符:是(is) 和 不是(not is)

a , b= 10 , 20

print(a is b)    # 判断是不是引用自一个对象,相同返回 True,否则返回 False
print(a not is b) # 判断是不是引用自不同对象, 不同返回 True,否则返回 False

注意:is 和 == 两者不一致
is的作用是用来检查对象的标识符是否一致,即比较两个对象在内存中是否拥有同一块内存空间。即 a is b 是 id(a) == id(b)

4.1.5.8 运算符优先级

运算符优先级一览表,列出了从最高到最低优先级的所有运算符,同一行表示优先级相同。在同一个表达式中,按照优先级从高到低依次计算。优先级相同则按照从左到右的顺序计算

运算符 描述
** 乘方(指数)
+x, -x, ~x 正,负,按位非 NOT
+*, @, /, //, % 乘,矩阵乘,除,整除,取余
+, - 加,减
<<, >> 左移,右移
& 按位与
^ 按位异或
按位或
in,not in, is,is not, <, <=, >, >=, !=, == 身份、成员、比较运算符
not
and
or
=,-=,+=,*=,/=,//=,**= 赋值系列

简单来说,运算符优先级按类别排序:算术 > 位 > 身份 >成员 > 比较 > 逻辑 > 赋值

4.2 String 字符串类型

字符串是字符的容器,一个字符串可以存储任意数量的字符。除了数字,字符串是 Python 中最常用的数据类型,

4.2.1 初识字符串

4.2.1.1 定义字符串

字符串在python中有多种定义形式:

  • 单引号定义:name = '阴阳师'
  • 双引号定义:name = "阴阳师"
  • 三引号定义:name = '''阴阳师'''

三引号定义方式与多行注释写法一样,同样支持换行操作

4.2.1.2 创建字符串

我们可以使用单引号(‘’)或双引号(“”),也可用str()函数来创建字符串
创建字符串很简单,只要为变量分配一个值即可。例如:

x1 = '阴阳师'
x2 = "yys"
x = '''阴阳师'''
x = str('阴阳师')

创建空字符串可以使用:x=''或者x=str('')

4.2.1.3 引号嵌套

当需要定义的字符串本身是包含:单引号、双引号自身时?该怎么写

  • 单引号定义方式,可以内含双引号
  • 双引号定义方式,可以内含单引号
  • 可以使用转义字符(\)将引号解除效用,转变成普通字符串
x1 = '我的阴阳师名称"名字"'    
x2 = "I'm yys"
x3 = '阴阳师中我的名字:\'yys\''

4.2.2 访问字符串中的值

4.2.2.1 字符串是序列

字符串str是文本序列类型,可以支持序列类型的各种操作。
字符串的截取格式:变量[头下标:尾下标:步长]

 
# 如一个字符串: 'z  i  u  v  c'
# 从前面索引:    0  1  2  3  4
# 从后面索引:   -5 -4 -3 -2 -1

注意:计算机中索引值以 0 为开始值,-1 为从末尾的开始位置。

4.2.2.2 获取特定位置单个字符

可以根据索引,来获取特定位置的的字符,如下:

s = 'yys'

print(s[0])     # 获取头位置字符,即:y
print(s[-1])    # 获取末尾位置字符,即:s
print(s[1])     # 获取索引为1处的字符, 即:y

python中没有字符数据类型,单个字符就是长度为1的字符串

4.2.2.3 切片

可以使用切片语法返回一系列字符串,格式s[start:end:length],
start指定开始索引,end指定结束索引,length指定步长,返回s[start]至s[end]之间的所有字符,不包括s[end]

正步长
当步长为正时,end必须在start的右侧,且不能等于start。步长默认为1

正索引切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从前面索引:      0  1  2  3  4

print(s[3:1])     # 正步长,end在start右侧,切片为空
print(s[1:1])     # end等于start,则切片为空
print(s[1:3])     # 输出索引 1 到 4 位置之间的字符,不包含索引4,即:iuv

负索引切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从后面索引:     -5 -4 -3 -2 -1

print(s[-2:-4])   # 正步长,end在start右侧,切片为空
print(s[-3:-3])     # end等于start,切片为空
print(s[-4:-1])  # 输出索引 -4 到 -1 位置之间的字符,不包含索引-1,即:iuv

负步长
当步长为负时,end必须在start的左侧,且不能等于start

正索引切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从前面索引:      0  1  2  3  4

print(s[1:3:-1])     # 负步长,end不在start的左侧,切片为空
print(s[1:1:-1])     # end等于start,切片为空
print(s[3:1:-1])     # 输出索引 3 到 1 位置之间的字符,不包含索引1,即:vu

负索引切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从后面索引:     -5 -4 -3 -2 -1


print(s[-4:-2:-1])   # 负步长,end不在start的左侧,切片为空
print(s[-4:-4:-1])  # end等于start,切片为空
print(s[-2:-4:-1])   # 输出索引 -2 到 -4 位置之间的字符,不包含索引1,即:vu

省略开始或结束索引,切片

# 如一个字符串:s= 'z  i  u  v  c'
# 从前面索引:      0  1  2  3  4
# 从后面索引:     -5 -4 -3 -2 -1

print(s[:3:1])  # 省略开始索引,输出 开始 到 3 位置的字符,不包含索引3,即:ziu
print(s[2::1])  # 省略结束索引,输出 2 到 结束 位置的字符,不包含索引3,即:ziu
print(s[::-1]) # 表示字符串逆序输出:cvuiz

4.2.3 字符串基本操作

4.2.3.1 字符串拼接

可以使用 ‘+’ 运算符,来连接或组合多个字符串:

a = "Hello"
b = "World"

c = a + b
print(c)    # 返回 "Hello" 和 "World" 字符串拼接结果,即:HelloWorld

d = a + ' ' + b
print(d)    # 在"Hello" 和 "World" 字符串之间拼接个空格,即:Hello World
4.2.3.2 字符串遍历

range()函数遍历

4.2.3.3 成员运算符

in:判断字符串中是否包含指定字符

txt = "yys tins is shijian zui 好玩"
print("yys" in txt)      # 如果字符串中包含给定的字符,返回True
print("lol" in txt)      # 如果字符串中不包含给定的字符,返回False

not in:判断字符串中是否不包含指定字符

txt = "yys tins is shijian zui 好玩"
print("lol" not in txt)  # 如果字符串中不包含给定的字符,返回True
print("yys" in txt)      # 如果字符串中包含给定的字符,返回False
4.2.3.3 字符串格式化

字符串格式化常用三种操作:%s、format()、f-string
最基本的用法是将一个值插入到一个有字符串格式符 %s 的字符串中,如下:

print("我叫 %s 今年 %d 岁!" % ('小羽', 1))%s 

字符串格式化操作符辅助指令:

符号 功能
* 定义宽度或者小数点精度
- 用做左对齐
+ 在正数前面显示加号( + )
在正数前面显示空格
% ‘%%‘输出一个单一的’%’
* 定义宽度或者小数点精度

详细可查看第2章的高级输出

4.2.4 常用内置函数和方法

len() – 统计字符串长度
语法格式:len(str)
参数:str–字符串

s = "this is CCTV!"

print(len(s))     # 返回字符串长度,包含空格,即:13

count() – 统计字符串里某个字符出现的次数
语法格式:str.count(sub, start=0,end=len(string))
sub – 搜索的子字符串
start – 开始索引,默认为0
end – 结束索引,默认为字符串的长度

s = "this is CCTV!"

print(s.count('i'))     # 返回整个字符串中,字符 'i' 出现次数 ,即 2
print(s.count('i',0,5)) # 返回索引 0 到 5 字符串中,字符 'i' 出现次数,即 1

find() – 检测字符串中是否包含指定字符串
语法格式:str.find(str, beg=0, end=len(string))
str – 指定检索的字符串
beg – 开始索引,默认为0。
end – 结束索引,默认为字符串的长度

s = "this is CCTV!"
 
print(s.find('s'))         # 找到了,返回开始的索引值,即:3
print(s.find('is', 1))    #  找到了,返回开始的索引值,即:2
print(s.find('sss', 0 , 5))  # -1 ,没找到返回-1

类似的有:rfind() --从右开始匹配,检测字符串中是否包含指定字符串

index() – 检测字符串中是否包含指定字符串
语法格式:str.index(sub, beg=0, end=len(string))
sub – 检测的字符串
beg – 开始索引,默认为0。
end – 结束索引,默认为字符串的长度

s = "this is CCTV!"
 
print(s.index('s'))         # 找到了,返回开始的索引值,即:3
print(s.index('is', 1))    #  找到了,返回开始的索引值,即:2
print(s.index('sss', 0 , 5))  # -1 ,没找到否则抛出异常,即报错

注意:index() 方法与 find() 方法一样,只不过如果 sub 不在 string中会报一个异常。
类似的有:rindex() --从右开始匹配,检测字符串中是否包含指定字符串

join() – 将序列中的元素以指定的字符连接生成一个新的字符串
语法格式:sub.join(seq)
参数:
seq – 要连接的元素序列,元组或者列表
sub – 为指定字符

seq = ("y", "y", "s") # 字符串序列

print('.'.join(seq))   # 将序列 seq 中的字符一个个以'.'相连得到字符串,即:'y.y.s'

replace() – 替换字符串
语法格式:str.replace(old, new, max)
old – 原字符串
new – 新字符串
max – 可选参数,最大替换次数

s = "this is CCTV!"

print(s.replace('is','ws'))   # 用'ws'字符串替换原字符中的'is'字符串,即:'thws ws CCTV!' 

split() – 通过指定分隔符对字符串进行切片,
语法格式:str.split(sub="", num=string.count(str))
sub – 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等
num – 分割次数。默认为 -1, 即分隔所有

s = "this is CCTV!"

print(s.split())   # 返回分割后的字符串列表,即:['this','is','CCTV!']

endswith() – 检测字符串是否以指定后缀结尾
语法格式:str.endswith(suffix, start=0 end=len(string))
suffix – 该参数可以是一个字符串或者是一个元素。
start – 开始索引,默认为0
end – 结束索引,默认为字符串的长度

s = "this is CCTV!"

print(s.endswith('i'))         # False
print(s.endswith('CCTV!'))     # True

类似的有:startwith()–检测字符串是否以指定前缀开始

isdigit():检测字符串是否只由数字组成,只对正整数有效,负数及小数均返回不正确。
max():返回字符串中最大的字母
min():返回字符串中最小的字母
capitalize():将字符串的首字母变成大写,其他字母变小写
swapcase():将字符串的大小写字母进行相互转换,将大写变为小写,小写变为大写
lower():转换 string 中所有大写字符为小写

Python 使用反斜杠 \ 来转义特殊字符或在字符串前面添加一个 r,表示原始字符串:

print(r'this is CCTV!')

与 C 语言字符串不同的是,Python 中字符串不能被改变。所以向一个索引位置赋值,比如 word[0] = ‘m’ 会导致错误。
注意:字符串不能被改变

4.3 List 列表类型

4.3.1 初识列表

4.3.1.1 列表定义

List(列表) 是写在方括号 [] 之间、用逗号分隔开的元素列表,是 Python 中使用最频繁的数据类型。
列表可以完成大多数集合类的数据结构实现。它支持数字,字符串甚至别的数据类型组合

list1 = list(['yys', '游戏' , 18])
lsit2 = ['yys', '游戏' , 18]
4.3.1.2 创建列表

创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可。或者使用 list 函数

list1 = ['yys', '游戏' , 18, Ture]
lsit2 = [1, 2, 3, 4]
list1 = list(('yys', '游戏' , 18))

创建空列表可以使用:x=[] 或者 x = list()

4.3.1.3 列表嵌套

列表可以包含各种数据类型,包括列表,如下

list1 = [['yys', '游戏' , 18], [1, 2, 3], []]

4.3.2 访问列表中的值

4.2.2.1 列表是序列

和字符串一样,列表同样可以被索引和截取,列表被截取后返回一个包含所需元素的新列表
列表的截取格式:mylist[start:end]

# 如一个列表   : ['yys', 'zz', '1', '3', 'x']
# 从前面索引:     0      1    2    3    4
# 从后面索引:    -5     -4   -3   -2   -1
4.2.2.2 获取特定位置列表元素

可以根据索引,来获取特定位置的的列表元素,如下:

list1 = list(['yys', '游戏' , 18])
print(list[0])       # 获取头位置列表元素,即:'yys'
print(list[-1])        # 获取尾位置列表元素,即:'18'
print(list[1])        # 获取索引为 1 处列表元素,即:'游戏'
4.2.2.3 切片

同样,可以使用切片语法返回一系列列表,格式mylist[start:end:length],
start指定开始索引,end指定结束索引,返回s[start]至s[end]之间的所有元素,不包括s[end],length指定步长
正步长
当步长为正时,end必须在start的右侧,且不能等于start。步长默认为1

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从前面索引:      0      1    2    3    4

print(mylist[3:1])      # 正步长,end在start右侧,切片为空
print(mylist[1:1])      # end等于start,切片为空
print(mylist[1:3])     # 输出索引 1 到 4 位置之间的元素,不包含索引4,即:['zz', '1', '3']

负索引切片

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从后面索引:     -5     -4   -3   -2   -1


print(mylist[-1:-4])      # 正步长,end在start右侧,切片为空
print(mylist[-1:-1])      # end等于start,切片为空
print(mylist[-4:-1])     # 输出索引 -4 到 -1 位置之间的列表元素,不包含索引-1,即:['zz', '1', '3']

负步长
当步长为负时,end必须在start的左侧,且不能等于start

正索引切片

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从前面索引:      0      1    2    3    4

print(mylist[1:3:-1])     # end不在start的左侧
print(mylist[1:1:-1])     # end等于start,切片为空
print(mylist[3:1:-1])     # 输出索引 3 到 1 位置之间的字符,不包含索引1,需要逆序:['3','1']

负索引切片

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从后面索引:     -5     -4   -3   -2   -1


print(s[-4:-2:-1])   # end不在start的左侧
print(s[-4:-4:-1])  # end等于start,切片为空
print(s[-2:-4:-1])   # 输出索引 -2 到 -4 位置之间的列表元素,不包含索引1,需要逆序即:['3','1','zz']

省略开始或结束索引,切片

# 如: mylist = ['yys', 'zz', '1', '3', 'x']
# 从前面索引:      0      1    2    3    4
# 从后面索引:     -5     -4   -3   -2   -1

print(mylist[:3])  # 省略开始索引,输出 开始 到 3 位置的字符,不包含索引3,即:['yys', 'zz', '1']
print(mylist[2:])  # 省略结束索引,输出 2 到 结束 位置的字符,不包含索引3,即:['1', '3', 'x']
print(mylist[::-1])  # 逆序输出列表,即['x','3','1','zz','yys']

4.3.3 列表基本操作

4.3.3.1 列表拼接

可以使用 ‘+’ 运算符,来连接或组合多个列表:

list1 = [1997, 2000, 2]
list2 = [4, 5, 6]

print(list1 + list2)    # 返回列表拼接的结果,即:[1997, 2000, 2, 4, 5, 6]
4.3.3.2 添加列表元素

1.末尾添加
将元素添加到列表的末尾,可以使用 append()

list1 = [1,2,3,4,5]

list1.append(88)   # 在末尾添加元素
print(list1)       # 即:[1,2,3,4,5,88]

2.指定位置添加
将元素添加到列表中的指定位置前面,可以使用 insert()

list1 = [1,2,3,4,5]

list1.insert(1, 88)     # 在索引1位置前面添加元素
print(list1)            # 即:[1,88,2,3,4,5]

3.合并两个列表
将一个列表中的元素附加到当前列表,可以使用 extend()

list1 = [1,2,3,4,5]
list2 = [88,77,66]

list1.extend(list2)   # 在list1末尾附加列表2元素
print(list1)          # 即:[1,2,3,4,5,88,77,66]
4.3.3.3 更新列表元素

1.更改单个元素值
更改特定位置元素值,需要使用索引

list1 = [1,2,3,4,5]

list1[1] = 88       # 将索引1位置元素值更改为88
print(list1)      ,即:[1,88,3,4,5]

2.更改多个元素值
更改特定位置元素值,需要使用索引范围

list1 = [1,2,3,4,5]

list1[1:3] = [88,77]    # 将索引1到索引3位置,不包括索引3,元素值更改
print(list1)            # 即:[1,88,77,4,5]
4.3.3.4 查找列表元素

1.成员运算符
可以判断某个元素是否属于这个列表,可以用 in 或 not in

list1 = [1,2,3,4,5]

print(1 in list1)            # 1属于这个列表,即:True
print(3 not in list1)        # 3属于这个列表,即:False

2.查找列表元素索引
查找列表中某个值得索引位置,可以使用index()

list1 = [1,2,3,4,5]

print(list.index(3))            # 查找元素值3的索引,即:2
4.3.3.5 删除列表元素

1.删除指定值
将列表中特定值删除,可以使用remove()

list1 = [1,2,3,4,5]
list1.remove(5)     # 将列表中删除值为5的元素
print(list1)        # 即:[1,88,3,4]

2.删除指定索引
将列表中指定索引值删除,可以使用pop()

list1 = [1,2,3,4,5]
list1.pop(2)        # 将列表中删除索引为2的元素
print(list1)        # 即:[1,2,4,5]

3.删除列表
删除列表可以使用del关键字

list1 = [1,2,3,4,5]
del list1[0]      # 将列表中删除索引为0的元素
print(list1)      # 即:[1,2,4,5]

del list    # 将列表删除

4.清空列表
清空列表可以使用 clear()

list1 = [1,2,3,4,5]
list1.clear()      # 将列表中的元素清空
print(list1)      # 即:[]

4.3.4 列表常用函数和方法

函数/方法 描述 返回值
len(list) 统计列表元素个数 返回个数
max(list) 统计列表元素最大值 返回最大值
min(list) 统计列表元素最小值 返回最小值
list.count(obj) 统计某个元素在列表中出现的次数 返回次数
list.index(obj) 从列表中找出某个值第一个匹配项的索引位置 返回索引位置
list.pop([index=-1]) 移除列表中的一个元素(默认最后一个元素) 返回该元素的值
list.append(obj) 在列表末尾添加新的对象 无返回值,会修改原列表
list.extend(seq) 在列表末尾追加另一个序列中的多个值 无返回值,会修改原列表
list.insert(index, obj) 将对象按指定索引插入列表 无返回值,会修改原列表
list.remove(obj) 移除列表中某个值的第一个匹配项 无返回值,会修改原列表
list.sort( key=None, reverse=False) 对原列表进行排序 无返回值,会修改原列表排序
list.reverse() 反向排序列表中元素 无返回值,会修改原列表排序
list.clear() 清空列表 无返回值,会修改原列表
list.copy() 复制列表 返回一个列表的浅复制

列表是一个有序且可变的集合,允许成员重复
注意:List中的元素是可以改变的

4.4 Tuple 元组类型

4.4.1 初始元祖

4.4.1.1 元祖定义

Python 的元组与列表类似,不同之处在于元组的元素不能修改,元祖用小括号(),列表使用方括号[]

tup1 = ('yys', '游戏', 18, True)
tup2 = (1, 2, 3, 4, 5 )
4.4.1.2 创建元祖

元组创建很简单,只需要在小括号()中添加元素,并使用逗号隔开即可,也可以使用tuple函数

tup1 = ('yys', '游戏', 18, True)
tup2 = tuple((1, 2, 3, 4, 5))

创建空元祖可以使用:tup = () 或者 tup = tuple()

元组中只包含一个元素时,需要在元素后面添加逗号 , ,否则括号会被当作运算符使用:

tup1 = (50)
type(tup1)     # 不加逗号,类型为整型   

tup1 = (50,)
type(tup1)     # 加上逗号,类型为元组   

注意:元祖元素的数据类型可以是任何数据类型:字符串、整型、布尔数据类型或者嵌套元祖

4.4.2 元组跟列表区别

元组的各种操作及函数跟列表基本一致
关键区别在于:元组中的元素不可被修改,即元组是不可变的

所谓元组的不可变指的是元组所指向的内存中的内容不可变,但是其内容中的内容是可变的

tup = ('r', 'u', 'n', 'o', 'o', 'b')
tup[0] = 'g'    # 对元组元素修改会报错

tup = (1,2,[122,[2]],5,8)
tup[2] = 'g'  # 当对元组中的元素对象操作时,一样会报错
tup[2][1] = 'g'  # 当对元组中的元素对象里面的元素对象操作时,则不会报错
tuple1 = tuple(('yys', '游戏' , 18))
print(tuple)             # 输出完整元组
print(tuple[0])          # 输出元组的第一个元素

注意:元组的元素不能修改

4.5 Set 集合类型

4.5.1 初识集合

4.5.1.1 集合定义

集合(set)是由一个或数个形态各异的大小整体组成的,构成集合的事物或对象称作元素或是成员,集合写在大括号 { } 里面,元素之间用逗号隔开。

myset = {'yys','玉藻前','10086'}
myset = {'yys'}
4.5.1.2 创建集合

可以使用大括号 { } 或者 set() 函数创建集合

myset = {'yys','玉藻前','10086'}
thisset = set(('yys','玉藻前','10086'))

创建空集合可以使用:myset = set(),不可以使用myset={} 是用来创建空集合,因为这是创建空字典的方法

4.5.2 基本操作

4.5.2.1 访问集合值

集合是一个无序的不重复的元素序列,不能通过索引访问

4.5.2.2 添加元素

s.add()
将元素 x 添加到集合中,如果元素已存在,则不进行任何操作

myset = {'yys','玉藻前','10086'}

myset.add(110)  # 将元素 110  添加到集合中 
myset.add('yys')  # 如果元素已存在,不进行任何操作

s.update()
将元素 x 添加到集合中,如果元素已存在,则不进行任何操作,x可以是列表,元组,字典

myset = {'yys','玉藻前','10086'}

myset.update([1,4])   # 将元素 1,4 一个个添加到集合中 
print(myset)   # {1, 4 'yys','玉藻前','10086'} 
4.5.2.2 移除元素

s.remove()

元素 x 从集合 s 中移除,如果元素不存在,则会发生错误

myset = {'yys','玉藻前','10086'}

myset.remove('yys')   # 移除'yys'
print(myset)   # {'玉藻前','10086'}
myset.remove('yys')   # 元素不存在,报错

s.discard()

元素 x 从集合 s 中移除,如果元素不存在,不会发生错误

myset = {'yys','玉藻前','10086'}

myset.remove('1111')   # 移除'111',元素不存在,不报错
print(myset)   # {'yys','玉藻前','10086'}

**s.pop() **

随机删除集合中的一个元素

myset = {'yys','玉藻前','10086'}
myset.pop()  # set 集合的 pop 方法会对集合进行无序的排列,然后删除这个无序排列集合的第一个元素
4.5.2.3 计算集合元素个数

len(s)
计算集合中元素个数。

myset = {'yys','玉藻前','10086'}
len(myset)   # 3
4.5.2.4 清空集合

s.clear()

myset = {'yys','玉藻前','10086'}
myset.clear()  # 清空集合
4.5.2.5 成员运算符

in:判断元素是否在集合中

myset = {'yys','玉藻前','10086'}

print("yys" in myset)      # 元素在集合中,返回True
print("lol" in myset)      # 元素不在集合中,返回False

not in:判断元素是否不在集合中

myset = {'yys','玉藻前','10086'}

print("lol" not in myset)   # 元素不在集合中,返回True
print("yys" in myset)       # 元素在集合中,返回False

4.5.3 集合常用函数

方法 描述 返回值
add() 添加元素 无返回值,直接修改原集合
update() 给集合添加元素 无返回值,直接修改原集合
pop() 随机移除元素 无返回值,直接修改原集合
remove() 移除指定元素 返回移除的元素,且修改原集合
discard() 移除指定元素 无返回值,直接修改原集合
copy() 拷贝一个集合 返回原集合
clear() 移除集合中的所有元素 无返回值,直接修改原集合
union() 返回两个集合的并集,重复的元素只会出现一次 返回两个集合的并集

注意:集合中的元素是可以改变的

4.6 DICtionary 字典类型

4.6.1 初识字典

4.6.1.1 字典定义

字典(dictionary)是Python中另一个非常有用的内置数据类型。

字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合,可以提供基于 key 检索 value 的场景

生活中的字典是:      python中的字典是:
[][含义]          [key][value]

字典的每个键值对 key=>value 用冒号 : 分割,每个对之间用逗号(,)分割,整个字典包括在花括号 {} 中 ,如下:

d = {key1 : value1, key2 : value2, key3 : value3 }
tinydict = {'name': 'yys', 'age': 18, 'cop': 'wy'}

字典中,键(key)必须使用不可变类型,值可以取任何数据类型。key 必须唯一,否则会遗漏部分键值对,如下:

tinydict = {'name': 'yys', 'age': 18, 'age':19 } 

print(tinydict)   # 输出tinydict = {'name': 'yys','age':19 } ,重复的key只会保留最后一个的键值对

注意:字典中的 key 不允许重复,重复添加等同于覆盖原有的数据

4.6.1.2 创建字典

可以使用花括号 {} 函数创建字典

hashmap = {'name': 'yys', 'age': 18, 'cop': 'wy'}

创建空字典可以使用:hashmap = {} 或者 hashmap = dict()
注意:dict 作为 Python 的关键字和内置函数,变量名不建议命名为 dict。

4.6.1.3 嵌套字典

字典的 value 可以是任意数据类型,所以 value 也可以是一个字典

stu_score_dict = {'周杰伦': {'语文': 100, '数学': 90}, '林俊杰': {'语文': 90, '数学': 88}}

# 写成另一种通俗易懂的排列
stu_score_dict = {
                '周杰伦': {'语文': 100, '数学': 90}, 
                '林俊杰': {'语文': 90, '数学': 88}
}

4.6.2 基本操作

4.6.2.1 访问字典值

字典是无序的对象集合,字典同集合一样,不可以使用下标索引(偏移存取),字典当中的元素是通过键来存取的。
访问字典中的值,只需要把相应的键放入到方括号中:

my_dict = {'name': 'zzz','code':1, 'age': 18}

print (my_dict['one'])       # 输出键为 'one' 的值
print (my_dict)          # 输出完整的字典

如果用字典里没有的键访问数据,会输出错误:

my_dict = {'name': 'zzz','code':1, 'age': 18}

print (my_dict['yys'])       # 程序报错,KeyError: 'yys'
4.6.2.2 添加字典元素

语法:dict[key]=value , 结果:字典被修改,新增一个键值对

my_dict = {'name': 'zzz', 'age': 18}

my_dict['sex']= 'boy'  # 新增一个键值对
print(my_dict)     # 输出添加后的结果,{'name': 'zzz', 'age': 18, 'sex':'boy'}
4.6.2.3 更新字典元素

语法:dict[key]=value , 结果:字典被修改,键值对被更新
原因:因为字典中 key 不可以重复,所以对已存在的key 进行上述操作,就是更新 value 值

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

my_dict['sex']= 'girl'  # 修改键sex 的值 
print(my_dict)     # 输出修改后的结果,{'name': 'zzz', 'age': '18', 'sex':'girl'}
4.6.2.4 删除字典元素

语法1:dict.pop(key) , 结果:获取指定key 的值,同时字典被修改,字典中指定key 的数据被删除

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

print(my_dict.pop('sex'))   # 删除键 sex ,并返回结果: 'boy'
print(my_dict)     # 输出删除后的结果,{'name': 'zzz', 'age': 18}

语法2:del dict[key] , 结果:删除 字典中指定key 的数据

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

del my_dict[sex]   # 删除键 sex 
print(my_dict)     # 输出删除后的结果,{'name': 'zzz', 'age': 18}

同时,del 还可以删除整个字典,语法:del dict

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

del my_dict         # 删除字典
print(my_dict)      # 程序报错,NameError: name 'my_dict' is not defined
4.6.2.5 清空字典

语法:dict.clear() ,结果:清空元素

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

my_dict.clear()        # 删除字典
print(my_dict)      # 输出清空后的结果,{}
4.6.2.6 获取字典全部的key

语法:dict.keys()

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

print(my_dict.keys())      # 输出结果,dict_keys(['name', 'age', 'sex'])
4.6.2.7 成员运算符

in:判断键是否在字典中

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

print("name" in my_dict)      # 元素在集合中,返回True
print("lol" in my_dict)      # 元素不在集合中,返回False

not in:判断键是否不在字典中

my_dict = {'name': 'zzz', 'age': 18, 'sex':'boy'}

print("lol" not in my_dict)   # 元素不在集合中,返回True
print("name" in my_dict)       # 元素在集合中,返回False

4.6.3 字典常用方法和内置函数

函数/方法 描述 返回值
len(dict) 计算字典元素个数 返回键的总数
max(dict) 求的是 key 的最大值 返回键的最大值
min(dict) 求的是 key 的最小值 返回键的最小值
dict.fromkeys() 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值 返回新字典
dict.get(key, default=None) 返回指定键的值,如果键不在字典中返回 default 设置的默认值 返回指定键的值
dict.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default 返回键的值
dict.update(dict2) 把字典参数 dict2 的 key/value(键/值) 对更新到字典 dict 里 无返回值,会修改原字典
dict.items() 以列表返回视图对象,是一个可遍历的key/value 对 返回key/value 对的列表
dict.keys() 以列表返回视图对象,是一个可遍历的key 集 返回 key 视图对象
dict.values() 以列表返回视图对象,是一个可遍历的value 集 返回 value 视图对象
pop(key[,default]) 删除字典 key(键)所对应的值,返回被删除的值。 返回被删除的值
popitem() 反向排序列表中元素 返回并删除字典中的最后一对键和值
dict.clear() 删除字典内所有元素 无返回值,会修改原列表
dict.copy() 复制字典 返回一个字典的浅复制

注意:视图对象不是列表,不支持索引,可以使用 list() 来转换为列表。

4.7 数据类型通用特性

不同的数据类型尽管各自有各自特点,但是他们也有一些相通的操作

4.7.1 for循环遍历

在遍历上,5类数据类型都支持for循环遍历

注意:列表、元组、字符串支持while循环,字典、集合不支持(无法下标索引)

4.7.2 len() 统计元素个数

语法:len(容器)

my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
my_str = 'abcde'
my_set = {1, 2, 3, 4, 5}
my_dict = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}

print((len(my_list)))    # 输出:5
print((len(my_tuple)))   # 输出:5
print((len(my_str)))     # 输出:5
print((len(my_set)))     # 输出:5
print((len(my_dict)))    # 输出:5

4.7.3 max() 统计最大元素

语法:max(容器)

my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
my_str = 'abcde'
my_set = {1, 2, 3, 4, 5,}
my_dict = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}

print((max(my_list)))    # 输出:5
print((max(my_tuple)))   # 输出:5
print((max(my_str)))     # 输出:'e'
print((max(my_set)))     # 输出:5
print((max(my_dict)))    # 输出:'key5'  得到的是最大的键

字符串使用ascii 码比较大小,字典返回最大的键

4.7.4 min() 统计最小元素

my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
my_str = 'abcde'
my_set = {1, 2, 3, 4, 5,}
my_dict = {'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5}

print((min(my_list)))    # 输出:1
print((min(my_tuple)))   # 输出:1
print((min(my_str)))     # 输出:'a'
print((min(my_set)))     # 输出:1
print((min(my_dict)))    # 输出:'key1'  得到的是最小的键

4.7.5 sorted() 排序

sorted() 函数会返回一个排序列表,不改变原有序列
sorted(容器,reverse=False),reverse = False表示升序排列

my_list = [2, 3, 4, 1, 5]
my_tuple = (2, 3, 1, 4, 5)
my_str = 'deabc'
my_set = {2, 1, 3, 4, 5,}
my_dict = {'key2': 2, 'key3': 3, 'key1': 1, 'key4': 4, 'key5': 5}

print((sorted(my_list)))    # 输出:[1, 2, 3, 4, 5]
print((sorted(my_tuple)))   # 输出:[1, 2, 3, 4, 5]
print((sorted(my_str)))     # 输出:['a', 'b', 'c', 'd', 'e']
print((sorted(my_set)))     # 输出:[1, 2, 3, 4, 5]
print((sorted(my_dict)))    # 输出:['key1', 'key2', 'key3', 'key4', 'key5']

注意:排序后,全部的数据类型都会变为列表

4.7.6 数据类型转换

python 是弱类型语言,跟 C语言强类型语言不一样,它并不需要声明变量的数据类型
Python 数据类型转换可以分为两种:隐式类型转换 和 显式类型转换

4.7.6.1 隐式类型转换

在隐式类型转换中,Python会自动将一种数据类型转换为另一种数据类型,不需要我们去干预。例如:

num_int = 123
num_flo = 1.23
num_new = num_int + num_flo

在运算时,python会自动将较低数据类型(整数)就会转换为较高数据类型(浮点数)以避免数据丢失

4.7.6.2 显式类型转换

转列表:list(容器)

print((list(my_tuple)))   # 输出:[1,2,3,4,5]
print((list(my_str)))     # 输出:['a','b','c','d','e']
print((list(my_set)))     # 输出:[1,2,3,4,5]
print((list(my_dict)))    # 输出:['key1', 'key2', 'key3', 'key4', 'key5']

转元组:tuple(容器)

print((list(my_list)))   # 输出:(1,2,3,4,5)
print((list(my_str)))     # 输出:('a','b','c','d','e')
print((list(my_set)))     # 输出:(1,2,3,4,5)
print((list(my_dict)))    # 输出:('key1', 'key2', 'key3', 'key4', 'key5')

转字符串:str(容器)

print((str(my_list)))   # 输出:[1,2,3,4,5]
print((str(my_tuple)))     # 输出:(1,2,3,4,5)
print((str(my_set)))     # 输出:{1,2,3,4,5}
print((str(my_dict)))    # 输出:{'key1': 1, 'key2': 2, 'key3': 3, 'key4': 4, 'key5': 5},字典转为字符串才会保留value

只有字典转为字符串才会保留value

转集合:set(容器)

print((set(my_list)))   # 输出:{1, 2, 3, 4, 5}
print((set(my_tuple)))     # 输出:{1, 2, 3, 4, 5}
print((set(my_str)))     # 输出:{'d', 'a', 'e', 'c', 'b'}
print((set(my_dict)))    # 输出:{'key2', 'key5', 'key4', 'key1', 'key3'}, 仅保留键,保持无序

数据类型转为集合,重复元素的会被去重
转字典:dict(容器)
转字典需要满足一定的条件,因为一定要满足键值对这个概念,所以一般的列表、元组、字符串、集合都无法转为字典

在显式类型转换中,使用预定义函数将用户对象的数据类型转换为所需的数据类型。
常用的预定义函数如下:

函数 描述
int(x [,base]) 将x转换为一个整数
float(x) 将x转换到一个浮点数
complex(real [,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
tuple(s) 将序列 s 转换为一个元组
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个 (key, value)元组序列。
frozenset(s) 转换为不可变集合
chr(x) 将一个AScii码转换为字符
ord(x) 将一个字符转换为对应AScii码
oct(x) 将一个整数转换为一个2进制字符串
oct(x) 将一个整数转换为一个八进制字符串
hex(x) 将一个整数转换为一个十六进制字符串

这些函数返回一个新的对象,表示转换的值,用法举例:

var = int(200) # 强调var为整型
var = dict(name="yys", age=188)    # 强调var为字典

# 进制转换
i = 23
bin(i) # 转换成二进制0b10111

4.8 推导式

Python 推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个新的数据序列的结构体。
Python 支持各种数据结构的推导式:

  • 列表(list)推导式
  • 字典(dict)推导式
  • 集合(set)推导式
  • 元组(tuple)推导式

4.8.1 列表推导式

列表推导式格式为:

[表达式 for 变量 in 列表] 
[out_exp_res for out_exp in input_list]

或者 

[表达式 for 变量 in 列表 if 条件]
[out_exp_res for out_exp in input_list if condition]
  • out_exp_res:列表生成元素表达式,可以是有返回值的函数
  • for out_exp in input_list:迭代 input_list 将 out_exp 传入到 out_exp_res 表达式中
  • if condition:条件语句,可以过滤列表中不符合条件的值

例子:过滤掉长度小于或等于3的字符串列表
在没有学习列表推导式前,我们的正常写法是这样的:

names = ['yys','timlin','bobo','wen','wendi']
new_names = []
for name in names:
    if len(name)>3:
        new_names.append(name)
print(new_names) 

使用列表推导式,仅仅只需一句话就可以将for循环的内容写完

names = ['yys','timlin','bobo','wen','wendi']
new_names = [name for name in names if len(name)>3]
print(new_names)     # ['timlin','bobo','wendi']

列表推导式写法是将for语句简化,但其提升的效率极高

又如例子:计算 30 以内可以被 3 整除的整数:

 multiples = [i for i in range(30) if i % 3 == 0]

扩展
语句格式也可以为:结果值1 if 判断条件 else 结果2 for 变量名 in 原列表
如:[i if i % 3 else [] for i in range(30)]
但是 else不可以省略,原理的话应该是使用了三目运算符
i if i % 3 else [] 可以看做是一个表达式

python 的列表推导比 for 循环、while 循环要快很多。分析了下原因:列表推导内的迭代在解释器内是以 C 语言的速度运行的 (一般是 for 循环的两倍,对大型文件操作而言,用列表推导效果尤其明显), while 语句是纯粹用 Python 代码写成,所以速度最慢。

4.8.2 字典推导式

字典推导基本格式:

{key_expr: value_expr for value in collection}{key_expr: value_expr for value in collection if condition}

例子:
使用字符串及其长度创建字典:

listdemo = ['Google','Runoob', 'Taobao']
# 将列表中各字符串值为键,各字符串的长度为值,组成键值对
newdict = {key:len(key) for key in listdemo}
print(newdict)      # {'Google': 6, 'Runoob': 6, 'Taobao': 6}

字典推导式基本结构与列表推导式一致,区别是

  • 字典推导式中的表达式一定要键值对
  • 外层要使用{}

4.8.3 集合推导式

集合推导式基本格式:

{expression for item in Sequence}{expression for item in Sequence if conditional}

例子:
判断不是 abc 的字母并输出:

a = {x for x in 'abracadabra' if x not in 'abc'}
print(a)    # {'d', 'r'}

字典推导式基本结构与列表推导式一致,区别是:

  • 外层要使用{}

4.8.4 元祖推导式

元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的元组。
元组推导式基本格式:

(expression for item in Sequence)(expression for item in Sequence if conditional)

例子:
生成一个包含数字 1~9 的元组:

tpl = (x for x in range(1,10))
print(tuple(tpl))       # (1, 2, 3, 4, 5, 6, 7, 8, 9)

元组推导式和列表推导式的用法区别:

  • 元组推导式是用()圆括号
  • 另外元组推导式返回的结果是一个生成器对象,需要使用tuple()转换成元祖

【python基础教程——一文教你入门python,够详细够实用】_第5张图片

这就开始学晕了吗?加油后面继续!

5. 各种控制语句

5.1 条件控制语句if-else

5.1.1 if语句的基本格式

程序中的判断语句:

if 判断的条件:
    条件成立时,要做的事

如下:

age = 18 

if age >= 18:      当条件为真时,执行if里面代码块的内容
    print('我已经成年了')    # 输出:我已经成年了

注意

  1. 判断语句的结果,必须是布尔类型:True或False
  2. 归属if判断的代码语句块,需要填充4个空格缩进

5.1.2 if-else语句的基本格式

if 判断的条件:
    条件成立时,要做的事
else:
    不满足条件时,要做的事

如下:

age = int(input"请输入你的年龄:")

if age >= 18:  # 当条件为真时,执行if里面代码块的内容
    print('你已经成年了')    # 输出:我已经成年了
    
else:   # 当条件为假时,执行else里面代码块的内容
    print('你未成年了')    # 输出:我未成年了

注意:else和if同级,else里面的内容也要使用缩进

5.1.3 if-elif-else语句的基本格式

if 条件1:
    条件1成立时,要做的事
elif 条件2:
    条件2成立时,要做的事
else:
    以上条件都不满足时,要做的事

如下案例:

age = int(input"请输入你的年龄:")

if age >= 18:  # 当条件为真时,执行if里面代码块的内容
    print('你已经成年了')    # 输出:你已经成年了
elif age <4:  # 当条件为真时,执行if里面代码块的内容
    print('你不可以游玩')    # 输出:你不可以游玩


else:   # 当条件为假时,执行else里面代码块的内容
    print('虽然未成年,但是也可也玩')    # 输出:虽然未成年,但是也可也了

5.1.4 if嵌套

可以通过多个if来控制不同的条件判断

if 条件1:
    条件1成立时,要做的事
    if 条件2:
        条件2成立时,要做的事
    else:
    条件2不满足时,要做的事
else:
    条件1不满足时,要做的事
  • 嵌套语句可以用于多条件和多层次的逻辑判断中
  • 嵌套语句可以根据需求,自由组合if -elif-else
  • 嵌套语句一定要注意空格缩进,py中通过空格缩进来决定层次关系

5.2 循环控制语句

5.2.1 while控制语句

while循环语法格式:

while 条件:
    条件满足时,要做的事

1、while的条件需要布尔类型
2、需要规划循环终止条件,否则将无限循环
3、while需要跟if一样,需要空格缩进

5.2.2 while 循环使用 else 语句

while…else…
如果 while 后面的条件语句为 false 时,则执行 else 的语句块。
语法格式如下:

while <expr>:
    <statement(s)>
else:
    <additional_statement(s)>

# expr 条件语句为 true 则执行 statement(s) 语句块,如果为 false,则执行 additional_statement(s)。

如下:

count = 0
while count < 5:
   print (count, " 小于 5")
   count = count + 1
else:
   print (count, " 大于或等于 5")

注意:while循环的循环条件时自定义的,自行控制循环条件

5.2.3 for循环控制语句

for基础语法格式:

for 临时变量 in 待处理数据集:
    循环满足条件时执行的代码

例如遍历一个字符串:

# 定义一个字符串str_t
str_t = 'name'

# 使用for循环处理字符串
for x in str_t:
    print(x)

for循环只能从被处理的数据集中,依次取出内容进行处理。
理论上来说,for循环是无法构建无限循环的(被处理数据集无法无限大)
for循环是一种轮询机制,对一批内容进行逐个处理

5.2.4 for循环使用 else 语句

for…else
在 Python 中,for…else 语句用于在循环结束后执行一段代
语法格式如下:

for item in iterable:
    # 循环主体
else:
    # 循环结束后执行的代码

当循环执行完毕(即遍历完 iterable 中的所有元素)后,会执行 else 子句中的代码,如果在循环过程中遇到了 break语句,则会中断循环,此时不会执行 else 子句。

sites = ["age", "yys","time-s","lol"]
for site in sites:
    if site == "yys":
        print("找到阴阳师!")
        break
    print("循环数据 " + site)
else:
    print("没有循环数据!")
print("完成循环!")

在执行上面的脚本时,在循环到 "yys"时会跳出循环体。所以else语句不会被执行

5.2.5 for语句中的range语句

range格式有三种

range(num)range(num1,num2)range(num1,num2,step)
语法1
range(num)
获得一个从0开始,到num结束的数字序列(不含num本身)
如:range(5)得到的数据是:0,1,2,3,4

语法2
range(num1,num2)
获得一个从num1开始,到num2结束的数字序列(不含num2本身)
如:range(5,10)得到的数据是:5,6,7,8,9

语法3
range(num1,num2,step)
获得一个从num1开始,到num2结束的数字序列(不含num2本身),数字之间的步长为step(默认为1)
如:range(5,10,2)得到的数据是:5,7,9

5.2.6 for循环的变量作用域

for基础语法格式:

for 临时变量 in 待处理数据集:
    循环满足条件时执行的代码

临时变量,在编程规范上,作用范围仅限定在for循环的内部

如果在for循环外部去访问这个临时变量:

  • 实际上是可以访问到的
  • 但是编程规范上不允许、不建议这么做
  • 如需访问临时变量,可以预先在循环外定义它

5.2.7 循环的嵌套

循环的嵌套跟if的嵌套类似

for循环 或 while循环:
    循环满足时要做的事情
    ...
    for循环 或 while循环:
        循环满足时要做的事情
        ...

注意缩进,嵌套for和while都是通过缩进来确定层次关系(即自己控制的内容)
for循环和while循环可以相互嵌套使用

5.2.8 循环中断break及continue

break:
直接结束所在循环

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

注意:

  • break及continue 都能在for和while循环中使用
  • 在嵌套的循环中,break及continue 都只能作用在所在循环中,无法控制上层循环

至此第五章内容结束!
【python基础教程——一文教你入门python,够详细够实用】_第6张图片

6. 函数

6.1 函数的定义

函数:是组织好的,可以重复使用的,用来实现特定功能的代码段,能提高应用的模块性,和代码的重复利用率
Python 中使用 def 关键字来定义函数。
函数的定义:

def 函数名(参数列表):
    函数体
    return 返回值

函数的调用:

函数名(参数)

例如:

def say_hi():      
    print("hi 我是yys")
    return False

say_hi()

注意:

  • 参数可以省略,但仍需要在函数名后加入()
  • 返回值可以省略
  • 函数必须先定义在使用

6.2 函数参数

函数传入参数的作用使得在函数运行的时候,可以接受外部传入的数据,传入多个参数时,需要逗号隔开
使用方式有:

def add(x,y):
    result = x + y
    return result

c = a(2,3)

形式参数:函数定义中的参数 ,如上 (x,y) 称之为形式参数
实际参数:函数调用中的参数,如上 (2,3) 称之为实际参数

函数的传入参数可以有以下几类:

  • 位置参数
  • 关键字参数
  • 默认参数
  • 不定长参数

6.2.1位置参数

位置参数:调用函数时根据函数定义的参数位置来传递参数,须以正确的顺序传入函数。

def printme(name,age):
   "打印任何传入的字符串"
   print (f'你的名字是{name},年龄{age})
   return
 
printme()   # TypeError: printme() missing 1 required positional argument: 'str'

printme('bob',18) 

注意
传递的参数与定义的参数的顺序及个数必须一致

6.2.2 关键字参数

关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名自动匹配传入的参数值

def printinfo( name, age ):
   "打印任何传入的字符串"
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
printinfo( age=50, name="runoob" )

此例子可以得出,在函数调用时只需要带上关键字参数(形参带上),就可以让形参自动对应实际参数对应值
注意
函数调用时,如果有位置参数,那么位置参数必须在关键字参数的前面,但是关键字参数之间不存在先后顺序

6.2.3 默认参数

调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传入 age 参数,则使用默认值:

def printinfo( name, age = 35 ):
   "打印任何传入的字符串"
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
printinfo( name="runoob" )

此例子可以看出,如果一开始在定义函数时就给形参设置了默认值,那么在实际调用时不传入该形参,就会使用默认值
注意
默认参数一定要在关键字或者位置参数后面

6.2.4 不定长位置参数 *args

即不清楚实际会传入的参数有多少,需要能处理比当初声明时更多的参数,使用不定长参数.
在定义的形式参数前面加了星号 * 的,则此参数会以元组(tuple)的形式存在,接收不定长数量的参数传入

def printinfo( arg1, *vartuple ):
   "打印任何传入的参数"
   print (arg1)
   print (vartuple)
 
printinfo( 70, 60, 50 )

一般来顺分配原则是必需参数会对应相应位置的实际参数值,剩余的全归类为不定长位置参数

6.2.5 不定长关键字参数 **kwargs

如果在参数前面加了两个星号 ** ,则参数会以字典的形式导入

def printinfo( arg1, **vartuple ):
   "打印任何传入的参数"
   print (arg1)
   print (vartuple)
 
printinfo(1, a=2,b=3)

顺序一般是:先必须参数、再关键字参数(包含默认参数)、然后是不定长位置参数、不定长关键字参数

6.3 匿名函数

Python 使用 lambda 来创建匿名函数。
函数的定义中:

  • def 关键字,可以定义带有名称的函数
  • Lambda关键字,可以定义匿名函数(无名称)

有名称的函数,可以无限重复使用
匿名函数,只可临时使用一次

匿名函数的语法:

lambda 参数列表:表达式
lambda [arg1 [,arg2,.....argn]]:expression
  • lambda 是关键字,表示定义匿名函数
  • 表达式就是函数的执行逻辑,只能写一行,而不是一个代码块。
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

lambda 的参数形式:
无参数 lambda : 表达式
一个参数 lambda 参数 : 表达式
默认参数 lambda key=value : 表达式
不定长位置参数 lambda *args : 表达式
不定长关键字参数 lambda **kwargs : 表达式

例子:

sum = lambda a,b:a+b
    sum(a,b)

6.4 函数作为参数传递

将一个函数名A作为参数 ,传入到另一个函数B中。如:

def test_func(func):
    result = add(1,2)
    print(result)

def add(x,y):
    return x+ y
    
test_func(add)
  • test_func需要一个函数作为参数传入,这个函数需要接收2个数字进行计算,计算逻辑由被传入函数来决定
  • add函数接收2个函数进行计算
  • test_func(add)将函数add 作为参数,传入到了test_func函数中使用,最终在test_func函数内部,由传入的add函数,完成计算操作

在上面这个例子中,计算逻辑的传递,而非数据的传递
任何逻辑都可以行定义一个函数作为函数参数传递

6.5 函数的返回值

函数的返回值:在函数执行完成后,返回给函数调用者的结果
语法:

return [表达式]

return 语句用于退出函数,选择性地将一个表达式返回给调用方。
注意

  • 不带参数值的 return 语句返回 None
  • 函数体在遇到 return 语句时就会返回,所以 return 后的代码不会执行

扩展:
None表示:空的、无意义的
其类型是:

应用场景:

  1. 用在函数返回值上
    函数返回的 None,表示函数返回了空的意思,等效于 return None
  2. 用在if判断上
    在if判断中,None 等同于 False
  3. 用在声明无意义的变量上
    定义变量,但暂时不需要变量有具体的值。如:name = None

6.6 函数的说明文档

就是通过多行注释,在函数定义和函数体之前给函数添加注释,用于辅助理解函数的作用

def func(x):
    """
    函数说明
    :param x:
    :return:
    """
    return 
  • 函数说明 – 用于简洁描述此函数功能
  • :param: – 用于解释参数
  • :return: – 用于解释返回值

6.6 函数的嵌套

函数跟循环控制语句一样,可以嵌套,即:

def func1():
    return true

def func2():
    c = func1()
    return c

c2 = func2()

即将一个定义的函数在另一个函数里面调用,那么在调用func2时,就会先执行func1

6.7 变量的作用域

变量的作用域是指变量的作用范围(变量可以在哪用,不可以在哪用)
py中有四种作用域:

  • L(Local):最内层,包含局部变量,比如一个函数/方法内部。
  • E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,A(B()) ,那么对于 B 中的变量来说,A 中的作用域就为 nonlocal。
  • G(Global):当前脚本的最外层,比如当前模块的全局变量。
  • B(Built-in): 包含了内建的变量/关键字等

扩展:python中变量查找是遵循LGB原则,即优先在局部作用域(local scope)中对变量进行查找,失败则在闭包或者外层嵌套函数的外部作用域(enclosing scope)中查找,没有找到则在全局作用域(global scope)中进行查找,最后尝试再内建作用域(build-in scope)内查找

规则顺序: L –> E –> G –> B
总结:在局部找不到,便会去局部外的局部找(例如闭包/嵌套),再找不到就会去全局找,最后去内置中找。

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

def A():
    num =100
    print(num)
    
A()
print(num)   # 报错,num未定义

在函数外部调用函数内部定义的变量是非法的,因为局部变量在函数体外无法使用

非全局变量/非局部变量 Enclosing

def outer():
    num = 2  # 闭包函数外的函数中,定义一个局部变量
    def inner():
        print(num)  # 输出外部局部变量的值2 
        num = 3 重新定义一个局部变量
        print(num)
    inner()
    print(num)
    
outer()  # 2, 3, 2
  • 在此例函数outer,知道我们可以在嵌套函数内部使用外部函数定义的局部变量
  • 在函数里面,对变量进行修改,其实是重新定义了一个局部变量,并对其赋值,其不影响外部函数的非全局变量num
  • 所以在最后print(num)是输出仍然是2

如果需要在函数内部实现对全局变量的修改,需要使用关键字 nonlocal

def outer():
    num = 10
    def inner():
        nonlocal num   # 用nonlocal声明内部函数的局部变量num 为非全局变量
        num = 100
        print(num)
    inner()
    print(num)
    
outer()  # 10,100,100   最后输出的print(num)时,此时的num已被inner()成功修改

全局变量 Global
指变量在函数体内、外都能生效

num = 100

def A():
    print(num)

def B():
    print(num)  # 输出全局变量的值
    num = 50    # 重新定义一个局部变量num
    print(num)  # 输出局部变量的值

A()     # 100
B()     # 100 ,50
print(num)  # 100 
  • 在此例函数A,知道我们可以在函数内部使用外部定义的全局变量
  • 函数B,可以让我们了解,当在函数里面,对变量进行修改,其实是重新定义了一个局部变量,并对其赋值,其不影响外部的全局变量
  • 所以在最后print(num)是输出仍然是100

如果需要在函数内部实现对全局变量的修改,需要使用关键字 global

num = 100

def C():
    global num  # 将内部的局部变量num定义全局变量
    num =20     
    print(num)

C()     # 20
print(num)  # 20  最后输出的print(num)时,此时的num已被C()成功修改

【python基础教程——一文教你入门python,够详细够实用】_第7张图片

7.文件

7.1 文件的编码

7.1.1 什么是文件

一般来说,我们在计算机中编写的数据会存储在内存中,但是内存中存放的数据在计算机关机后即会消失。如果要长久保存数据,就要使用硬盘、光盘、U盘等设备。为了便于数据的管理和检索,引入了“文件”的概念

一篇文章、一段视频、一个可执行的文件都可以被保存为一个文件,并且赋予一个文件名。操作系统以文件为单位管理磁盘中的数据。文件可分多种类别:

  • 文本文件:TXT等
  • 视频文件:WMV、AVI、MPEG、DV、MOV、MOD等
  • 音频文件:MP3、WAV、FLAC、WMA、MIDI、CDA等
  • 图像文件:jpg、png、gif等
  • 可执行文件:.exe、.sys等

7.1.2 编码规则

为什么需要使用编码?
我们知道,计算机底层的机器语言只识别0和1,对于丰富的文本内容计算机又该如何识别呢?我们是怎么转化的呢?
可以使用编码技术(密码本)将内容翻译成0和1存储在计算机中
编码技术:使用特定的翻译规则,将内容翻译成二进制0和1,不同的编码技术,翻译的结果不一样,所以写入和打开文件的编码技术要一致
文件的编码技术有:UTF-8、GBK、Big5
UTF-8是目前全球通用的编码格式,除非特别要求,一般默认使用此编码格式

7.2 文件的常用操作

文件操作的步骤:

  • 打开
  • 读写
  • 关闭

7.2.1 文件的打开操作

Python 对文件进行操作,需要使用open() 方法用于打开文件,并返回文件对象
完整的语法格式为:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
参数说明:

  • file:文件路径(相对或者绝对路径),必需参数
  • mode:文件打开模式,可选,默认只读
  • buffering:设置缓冲,可选,默认-1
  • encoding:编码格式,可选,一般为UTF-8
  • errors: 报错级别,可选
  • newline: 区分换行符,可选
  • closefd: 传入的file参数类型,可选
  • opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。可选

常用的格式为:open(file,mode,encoding='UTF-8')

mode参数:

参数 描述 文件指针位置
r 以只读方式打开文件,默认模式 位于文件的开头
rb 以二进制格式打开一个文件用于只读,一般用于非文本文件如图片等 位于文件的开头
r+ 打开一个文件用于读写 位于文件的开头
rb+ 以二进制格式打开一个文件用于读写,一般用于非文本文件如图片等 位于文件的开头
w 打开一个文件只用于写入。如果文件不存在,则创建新文件 位于文件的开头(原内容会被清空)
wb 以二进制格式打开一个文件只用于写入。如果文件不存在,则创建新文件 位于文件的开头(原内容会被清空)
w+ 打开一个文件用于读写。如果文件不存在,则创建新文件 位于文件的开头(原内容会被清空)
wb+ 以二进制格式打开一个文件用于读写。如果文件不存在,则创建新文件 位于文件的开头(原内容会被清空)
a 打开一个文件用于写入。如果文件不存在,则创建新文件 位于文件的结尾
ab 以二进制格式打开一个文件用于写入。如果文件不存在,则创建新文件 位于文件的结尾
a+ 打开一个文件用于读写。如果文件不存在,则创建新文件 位于文件的结尾
ab+ 以二进制格式打开一个文件用于读写。如果文件不存在,则创建新文件 位于文件的结尾

注意:

  • 默认为文本模式,如果要以二进制模式打开,加上 b
  • 默认是以只读方式打开文件
  • w 和 a都是写入,但是两者文件指针的位置不一样,w 文件指针位于开头,会覆盖原本内容;a文件指针位于结尾,不会覆盖原本内容

举例:

f = open('cc.txt','r',encording="UTF-8")

7.2.2 文件的关闭操作

文件的关闭一般都是用close()方法,文件打开操作完毕后,必须进行关闭操作
close() 方法用于关闭一个已打开的文件。关闭后的文件不能再进行读写操作, 否则会触发 ValueError 错误

语法格式:file.close()

7.2.3 文件的读取操作

文件的读取有四种方法:

  • read() 从文件读取指定的字符数
  • readline() 从文件读取整行
  • readlines() 用于读取所有行(一次性读取,直到结束符 EOF)并返回列表
  • for line in 文件对象

read()
用于从文件读取指定的字符数(文本模式 t)或字节数(二进制模式 b)
语法格式:file.read([size])
参数: size: 从文件中读取的字符数(文本模式)或字节数(二进制模式),默认为 -1,如果未给定参数 size 或 size 为负数则表示读取整个文件
返回值:返回读取到的内容

举例,读取文件的内容:
cc.txt文件内容如下:

这是第一行
这是第二行
这是第三行
这是第四行
这是第五行
# 打开文件
fd = open("cc.txt", "r+",encording="UTF-8")
print ("文件名为:{}".format(fd.name)

line = fo.read(10)          # 读取10个字符
print ("读取的字符串: {}".format(line)

fd.close()  # 关闭文件

总结:read()方法,可以指定需要读取的字符数量

readline()
用于从文件读取整行,包括 “\n” 字符。行的切分是" \n "字符
语法格式:file.readline([size])
参数: size: 从文件中读取的字符数(文本模式)或字节数(二进制模式),默认为 -1,如果未给定参数 size 或 size 为负数则返回指定大小的字节数,包括 “\n” 字符

当执行readline() 时,code会扫描文件中的每一个字节,直到找到一个 \n 位置,然后停止并读取此前的文件内容。并且fileobject 会记录每次调用readline()后的对于读取位置,这样readline()下次被调用的时候就会读取下一行。

举例,读取文件内容:
cc.txt文件内容:

1:www.runoob.com
2:www.runoob.com
3:www.runoob.com
4:www.runoob.com
5:www.runoob.com
fd = open("cc.txt", "r+",encording="UTF-8")  打开文件,获得一个文件对象
print ("文件名为:{}".format(fd.name)

line = fd.readline()   # 读取第一行,并将读取位置指针置于第一行末尾
print ("读取第一行:{}".format(line)

line = fd.readline(5)   # 读取第二行的前5个字符,并将读取位置指针置于第二行末尾
print ("读取到的字符串:{}".format(line)

fd.close()  # 关闭文件

注意:

  • 每次调用readline()的fileobject会记录此次读取位置,这样readline()下次被调用的时候就会读取下一行
  • '\n’也会包含在读取的字符串中,常用 strip() 对头尾的空白字符处理

readlines()
用于读取所有行(按照行的方式一次性读取,直到结束符 EOF)并返回列表,每一行的数据为一个元素
语法格式:file.readlines()
返回值:返回列表,包含所有的行

举例,读取文件内容:
cc.txt文件内容:

1:www.runoob.com
2:www.runoob.com
3:www.runoob.com
4:www.runoob.com
5:www.runoob.com
fd = open("cc.txt", "r+",encording="UTF-8")  打开文件,获得一个文件对象
print ("文件名为:{}".format(fd.name)

for line in fd.readlines():                          #依次读取每行  
    line = line.strip()                             #去掉每行头尾空白  
    print ("读取到的数据:{}".format(line)

fd.close()  # 关闭文件

for line in 文件对象
for 循环读取文件行
格式:for line in 文件对象
每一个临时变量 line 都记录了文件的一行数据

fd = open("cc.txt", "r+",encording="UTF-8")  打开文件,获得一个文件对象
print ("文件名为:{}".format(fd.name)

for line in fd:
    print ("读取到的数据:{}".format(line) 

fd .close() # 关闭文件

7.2.4 文件的写入操作

写入操作常用方法有:

  • write() 向文件中写入指定字符串
  • writelines() 向文件中写入一序列的字符串, 换行需要加入’\n’

write()
用于向文件中写入指定字符串。
如果文件打开模式带 b,那写入文件内容时,str (参数)要用 encode 方法转为 bytes 形式
语法格式:file.write([str])
参数:str – 要写入文件的字符串
返回值:返回写入的字符长度。

在文件关闭前或缓冲区刷新前,字符串内容存储在缓冲区中,这时你在文件中是看不到写入的内容的

seek() 方法用于移动文件读取指针到指定位置。
语法格式:file.seek(offset,whence=0)
参数:

  • offset – 开始的偏移量,也就是代表需要移动偏移的字节数,如果是负数表示从倒数第几位开始。
  • whence:表示要从哪个位置开始偏移:
  • 0 代表从文件开头开始算起,
  • 1 代表从当前位置开始算起,
  • 2 代表从文件末尾算起

举例,
cc.txt文件内容如下:

1:www.runoob.com
2:www.runoob.com
3:www.runoob.com
4:www.runoob.com
5:www.runoob.com
fd = open("runoob.txt", "r+",encording="UTF-8")
print("文件名为: {}".format(fd.name))
 
str = "6:www.runoob.com"
fd.seek(0, 2)  # 重新设置文件指针移动到末尾
line = fd.write( str )

fd.seek(0,0)   # 重新设置文件指针移动到开头
for index in range(6):
    line = next(fd)
    print("文件行号{}{}".format(index, line))

fd.flush()  # 刷新 将内存中的文件写入硬盘,可以让文件在未关闭下仍然可以更新内容
fd.close()  # 内置了flush方法,关闭文件

注意:

  • 操作文件时,需要注意文件指针的位置,如 mode=‘w’ 和 mode=‘a’
  • 直接调用write(),内容并未真正写入文件,而是积攒在程序的内存中,称之为缓冲区
  • 当调用flush的时候,内容会真正的写入文件,避免频繁的操作硬盘,导致效率下降

writelines()
用于向文件中写入一序列的字符串。
这一序列字符串可以是由迭代对象产生的,如一个字符串列表。换行需要制定换行符 \n。
语法格式:file.writelines([str])
参数:str – 要写入文件的字符串序列
返回值:该方法没有返回值。

fd = open("cc.txt", "w+")
print ("文件名为: ", fd.name)
seq = ["菜鸟教程 1\n", "菜鸟教程 2"]  # 字符串序列,换行需要加入'\n'
fd.writelines(seq)      # 写入字符串序列

fd.close()    # 关闭文件

注意:

  • 无返回值
  • 换行需要加入’\n’

7.3 os模块的使用

待补充

【python基础教程——一文教你入门python,够详细够实用】_第8张图片

8. 异常

8.1 异常的定义

异常是指程序在运行过程中发生了错误

bug就是指异常的意思,因为历史上有因虫子导致计算机故障的案例,所以,bug就代表软件出现错误

8.2 异常的捕获

为什么要捕获bug?
因为当程序遇到bug时,会有两种情况:

  1. 整个程序因为一个bug停止运行
  2. 对bug进行提醒,整个程序继续运行

当没有对bug进行处理时,我们的程序就只会走第一种情况,但是实际上,我们更希望程序走第二种情况
所以捕获异常作用:提前假设某处会发生异常,当真的发生异常时,可以按照我们预先准备的情况发生

8.2.1 捕获常规异常

基本语法:

try:
    可能发生异常的代码
except:
    出现异常时执行的代码

举例:尝试以’r’模式打开文件,如果文件不存在,则以’w’模式打开
try:
f = open(‘cc.txt’,‘r’)
except:
f =open(‘cc.txt’.‘w’)

8.2.2 捕获特定异常

基本语法:

try:
    可能发生异常的代码
except 异常类型:
    出现异常时执行的代码

当需要捕获特定异常时,把该异常类型放在except后面

举例:尝试打印name变量,如果name变量未定义,则提示错误信息

try:
    print(name)
except NameError as e:  # 捕捉特定的 NameError 异常
    print('name变量定义错误')

注意:

  1. 如果尝试执行的代码异常类型与要捕获的不一致,则无法捕获异常
  2. 一般try下方只放一行尝试执行的代码

8.2.3 捕获多个异常

基本语法:

try:
    可能发生异常的代码
except 异常类型组:
    出现异常时执行的代码

当需要捕获多个异常时,可以把要捕获的异常类型用元组形式书写在except后面

举例:
待补充。。。

注意:

  • 未正确设置捕获异常类型,则无法捕获异常

8.2.4 捕获全部异常

基本语法格式:

try:
    可能发生异常的代码
except exception:
    出现异常时执行的代码

通常捕获全部异常使用捕获exception类型对象
另一种写法就是捕获常规异常的写法

8.2.4 异常的else语句

try…except…else
try/except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后。

基本语法格式:

try:
    可能发生异常的代码
except exception:
    出现异常时执行的代码
else:
    没有异常时要执行的代码  

else 子句将在 try 子句没有发生任何异常的时候执行。

8.2.5 异常的finally语句

try…except…else…finally
表示有没有异常都要执行的语句
基本语法格式:

try:
    可能发生异常的代码
except Exception:
    出现异常时执行的代码
else:
    没有异常时要执行的代码 
finally:
    有没有异常都要执行的代码

总结:

  • 在异常中,else和finally都是可选的,可写可不写
  • 捕获全部的异常可以用:except 或 except Exception
  • 可以对异常改用别名,except [异常 as 别名]:

8.3 异常的传递

异常是具有传递性的
简单来说就是当你调用一个函数时,可以其嵌套调用的函数会发生异常,如果其没有对异常进行捕获,那么该异常就会传递到当前调用的函数上。
举例:

def func01():
    print('这是func01开始')
    num = 1 / 0    # 除数为0,引发异常
    print('这是func01结束')
    
def func02():
    print('这是func02开始')
    func01()    # 调用func01 函数
    print('这是func02结束')

def main():
    try:
        func02()    # 调用func02
    except Exception:
        print(Exception)

main() 

在上述的例子中,当主函数中的func02调用到func01函数时,发生异常,func01函数没有对其进行捕获,异常就会传递到func02函数,func02函数也没有对这个异常进行捕获,该异常就会传递到main函数中,被main函数捕获。

注意:

  • 当所有函数都没有捕获异常时,程序会报错

8.4 抛出异常

为什么还要手动设置异常呢?首先要分清楚程序发生异常和程序执行错误,它们完全是两码事,程序由于错误导致的运行异常,是需要程序员想办法解决的;但还有一些异常,是程序正常运行的结果,比如用 raise 手动引发的异常。
Python 使用 raise 语句抛出一个指定的异常
基本语法格式:raise [exceptionName [(reason)]]
[] 里的参数为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。

三种用法:

  • raise:该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。
  • raise 异常类名称:表示引发执行类型的异常。
  • raise 异常类名称(描述信息):表示在引发指定类型的异常的同时,附带异常的描述信息。

举例:
raise默认引发 RuntimeError异常

try:
    a = input("输入一个数:")
    if(not a.isdigit()):
        raise
except Exception as e:
    print("引发异常:", repr(e)) 
输入一个数:a
引发异常: RuntimeError('No active exception to reraise')

注意:

  • 需要使用repr()函数,才能看到异常名称类型,
  • 如果使用format()函数则只能看到异常说明信息

raise引发当前上下文中捕获的异常,即except 块中的异常

try:
    a = input("输入一个数:")
    if(not a.isdigit()):
        raise ValueError("a 必须是数字")
except ValueError as e:
    print("引发异常:", repr(e))
    raise
输入一个数:a
引发异常: ValueError('a 必须是数字')
Traceback (most recent call last):
  File "E:\project.py\Leetcode\August\sads.py", line 8, in 
    raise ValueError("a 必须是数字")
ValueError: a 必须是数字

raise 异常类名称raise 异常类名称(描述信息):引发指定异常。

try:
    a = int(input("输入一个数:"))
    if a == 0:
        raise ZeroDivisionError("除数不能为零")
except ZeroDivisionError as e:
    print("引发异常:", repr(e))
输入一个数:0
引发异常: ZeroDivisionError('除数不能为零')

8.5 Python 模块

模块是 Python 程序架构的一个核心概念

  • 每一个以扩展名 py 结尾的 Python 源代码文件都是一个 模块
  • 模块名 同样也是一个 标识符,需要符合标识符的命名规则
  • 在模块中定义的 全局变量 、函数、类 都是提供给外界直接使用的 工具
  • 模块 就好比是 工具包,要想使用这个工具包中的工具,就需要先 导入 这个模块

8.5.1 模块的导入

模块在使用前需要先导入,模块的导入语法如下:
[from 模块名] import [模块 | 类 | 变量 | 方法 | *] [as 别名]
[]是可选的意思,表示里面的参数可以省略
常用的导入方式有:

  • import 模块名
  • import 模块名 as 别名
  • from 模块名 import *
  • from 模块名 import 类、变量、方法等
  • from 模块名 import 类、变量、方法等 as 别名

注意

一个模块只会被导入一次,不管你执行了多少次 import。这样可以防止导入模块被一遍又一遍地执行。

使用 import 语句的时候,Python 解释器是怎样找到对应的文件的呢?

Python 的搜索路径,搜索路径是由一系列目录名组成的,Python 解释器就依次从这些目录中去寻找所引入的模块。

8.5.1.1 import 语句

基本语法:

import 模块名
import 模块名、模块名

模块名.功能名()

通过 import 导入模块后,就可以通过 模块名.功能名 来使用模块中任意内容

举例:导入time模块:

import time  # 首先导入内置的time模块

print('开始')
time.sleep(3) # 必须以“模块名.对象名//模块名.方法名”的形式进行访问
print('结束')

注意:

  • 当引用一个解释器未安装/定义的模块时,会引发ModuleError的错误
  • 按住 Control键 + 鼠标左键点击,可进入该模块的文件
  • 引入模块后,可以通过 模块名. 使用任意功能
  • 模块的导入一般写在开头位置
  • 模块的功能被使用后,导入语句会高亮,否则会置灰
8.5.1.2 from … import 语句

基本语法:

from 模块名 import 功能名
from 模块名 import 功能名, 功能名

功能名()

相比于直接import 直接导入整个模块
通过 from 导入模块,可以确切导入模块中的具体某个或者某几个功能。

举例:导入time模块中的sleep()方法:

from time import sleep() # 导入time模块中的sleep() 方法

print('开始')
sleep(1)  # 直接使用对象“对象名//方法名”访问
print('结束')

相比于import导入,使用 from 这种方式仅导入明确指定的对象(函数),在使用该功能时,不需要在前面加入模块名
注意:

  • 使用from导入模块,在使用导入的功能时,可以直接用功能名()
  • 仅可以使用导入的功能,不可以使用模块中未导入的其他功能
from math import sin,cos,tan  # 可以一次从一个文件中导入多个函数

当然from 也可也把全部的功能导入进来,只需使用如下声明:from modname import *
这种导入与improt导入类似,只是在使用功能时,写法不一样使用

8.5.1.3 as 别名

基本语法:

# 给模块定义别名
import 模块名 as 别名

# 给功能定义别名
from 模块名 import 功能名 as 别名

作用:给部分过长的模块名/功能名 更改为简短的名称
举例:

import time as t # 将time模块更改名为 t

print('开始')
t.sleep(3)    # 必须以“别名.对象名//别名.方法名”的形式进行访问
print('结束')
from time import sleep as sl   # 将time模块中的sleep 方法更改为sl别名

print('开始')
sl(1)
print('结束')

注意:

  • 使用as将模块名或者方法名更改别名后,无法再使用原模块名或方法名,其属于未定义内容
  • 模块的导入一般写在开头位置

8.5.2 自定义模块

  • 每个py文件都可以当作一个模块,模块的名字即是文件的名字
  • 自定义模块名必须符合标识符的命名规则
8.5.2.1 定义模块

有些时候需要自定义一些模块。
新建模块的方法:
举例:新建一个Python文件,命名为my_module.py,并定义test函数:
my_module.py

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

使用 import 导入my_module 模块,调用 my_module.py 中的 test 方法

import my_module

my_module.test(10,20)
8.5.2.2 调试模块

__name__属性
每个模块都有一个__name__属性,当其值是’main’时,表明该模块自身在运行,否则是被引入
这一属性很重点,方便调试,一般我们在单个文件中调试函数是如下:

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

但是上面这样的写法,当文件被导入其他文件时,就会调用test()

def test(a,b):
    print(a+b)
    
if __name__ == '__main__':
    print('程序自身在运行')
    test() 
else:
    print('我来自另一模块')

使用__name__属性,这样可以让文件程序自身运行时执行相应的调试功能test() ,非自身运行时,不执行调用test()

# 模块1代码
def my_test(a, b):
    print(a + b)

# 模块2代码
def my_test(a, b):
    print(a - b)
   
# 导入模块和调用功能代码
from my_module1 import my_test
from my_module2 import my_test

# my_test函数是模块2中的函数
my_test(1, 1)

注意:

  • 一个模块如果是在该模块自身运行: _ name _ == ‘_ main _’
  • 一个模块被另一个程序引入时:_ name _ != ‘_ main _’
  • 如果使用from … import …或from … import *导入多个模块的时候,且模块内有同名功能。当调用这个同名功能的时候,调用到的是后面导入的模块的功能。

__all__属性
==可以控制import * 能够导入的内容==

如果存在一个叫做 all 的列表变量,那么在使用 from ,module import * 的时候就把这个列表中的所有名字作为模块方法导入。

举例:有个模块my_module.py的文件内容如下:

__all__ = ["testA"]

def testA():
    print('testA')
    
def testB():
    print('testB')

在另一个文件中,使用import * 导入

from my_module import *

testA()       #只能导入testA函数
testB()    # testB函数报红,说明没有这个函数

因为在_ all _ 的列表中,没有 testB 这个函数,所以上面引用 testB 函数失败

8.5.3模块的查找路径

当导入一个模块,Python解析器对模块位置的搜索顺序是:

  • 当前目录
  • 如果不在当前目录,Python则搜索在shell变量PYTHONPATH下的每个目录。
  • 如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/

模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

注意:

  • 自己的文件名不要和已有模块名重复,否则导致模块功能无法使用
  • 使用from 模块名 import 功能的时候,如果功能名字重复,调用到的是最后定义或导入的功能。

8.6 包

8.6.1 包的概念

将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py 文件,那么这个文件夹就称之为包。

  • 包 是一个 包含多个有联系的模块组织在一起 的 特殊目录(文件夹)
  • 目录下有一个 特殊的文件__init__.py
  • 包名的 命名方式 和变量名一致,小写字母 + _

作用:使用 import 包名 可以一次性导入 包 中 所有的模块

init.py 文件的作用是将文件夹变为一个Python模块,我们在导入一个包时,
实际上是导入了它的__init__.py文件,这样我们可以在__init__.py文件中批量导入我们所需要的模块,
而不再需要一个一个的导入。

8.6.2 创建包

一般操作[New] — [Python Package] — 输入包名 — [OK] — 新建功能模块(有联系的模块)。

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

示例
新建包mypackage
新建包内模块:my_module1.pymy_module2.py
my_module1.py

print(1)


def info_print1():
    print('my_module1')

my_module2.py

print(2)


def info_print2():
    print('my_module2')

8.6.3 导入包

模块和包的导入方法基本一致,只是需要写清楚这个模块来源哪个包
import 包名.模块名
基本语法:

# 导入
import 包名.模块名

# 调用功能
包名.模块名.功能名()

举例:

# 导入my_package.my_module1 
import my_package.my_module1

# 调用
my_package.my_module1.info_print1()

from 包名.模块名 import 功能名
基本语法:

# 导入
from 包名.模块名 import 功能名

# 调用功能
功能名()

举例:

# 从 my_package.my_module1 里导入 info_print1 函数
from my_package.my_module1 import info_print1

# 调用
info_print1()

import 语法中的item总结:

import item.subitem.subsubitem 这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者是包,但是不可以是类,函数或者变量的名字。

import 语法会首先把 item 当作一个包定义的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,抛出一个 :exc:ImportError 异常。

from package import item 这种形式,对应的 item 既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。

as 别名
跟前面module的用法一致

_ all _属性
导入语句遵循如下规则:如果包定义文件 _ init .py 存在一个叫做 _ all _ 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。
注意all _属性仅能控制from package import * 导入的

8.6.4 导入第三方包

对于一个第三方的包,如果我们想使用其中的功能的话,那么我门首先需要导入这个包
例如:导入requests包:

如果使用pycharm,可以在设置-解释器环境里面安装包。
在命令提示符中,可以使用 pip 工具来安装

pip安装包
基本用法:pip install packagename

pip的网络优化
由于pip时连接的国外的网站进行包的下载,所以有时候会下载失败或者速度很慢
优化做法,让其连接国内的网站进行包的安装:
基本语法:pip install packagename -i 网址 --trusted-host 网址的顶级域名
参数:

  • packagename:需要安装的包名
  • -i :表示切换,后接需要更改的连接网址
  • –trusted-host :表示信任,后接前面连接网址的顶级域名

举例:
安装:pip install packagename -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
卸载:pip uninstall packagename -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

常用的国内镜像源
中国科学技术大学 : https://pypi.mirrors.ustc.edu.cn/simple
豆瓣:http://pypi.douban.com/simple/
阿里云:http://mirrors.aliyun.com/pypi/simple/
清华大学:https://pypi.tuna.tsinghua.edu.cn/simple

8.6.5 包的访问路径

相对路径访问
package/
– – init.py
– – subpackage1/
– – – – init.py
– – – – moduleX.py
– – – – moduleY.py
– – – – – – def spam()
– – subpackage2/
– – – – init.py
– – – – moduleZ.py
– – ---- – – def eggs()
– – moduleA.py
– – – – def foo()
假设当前文件是moduleX.pysubpackage1 / __ init__.py,则以下是新语法的正确用法:(.py文件不是模块)

同级文件目录下引用
引用moduleY.py文件中的方法: import moduleY

不同级文件目录下引用
引用 import subpackage2// from subpackage2 import py文件中的方法

#  .表示当前目录,对于`moduleX.py`文件,当前目录路径为:package/subpackage1/
from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY

# ..表示上一级目录,对于`moduleX.py`文件,当前目录路径为:package/
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo

# ...表示上上一级目录
from ...package import bar
from ...sys import path

父目录调用子目录
例如 moduleA.py 调用subpackage2中的 moduleZ.py 文件
父目录调用子目录,可以使用以下两种方式

# 方式一
from subpackage2 import moduleZ  

# 方式二
from subpackage2.moduleZ import eggs 
from subpackage2.moduleZ import *  

推荐常用方式二

同级目录下文件的调用
例如moduleX.py件调用subpackage2中的moduleZ.py文件

import sys
sys.path.append('../B')    sys.path.append(os.path.split(os.getcwd())[0])
from B.B1 import *

【python基础教程——一文教你入门python,够详细够实用】_第9张图片

9. 面向对象

面向对象编程(Object-oriented Programming,简称OOP)是一种编程范例,它提供了一种结构化程序的方法,以便将属性和行为捆绑到单个对象中。面向对象编程OOP将现实世界的实体建模为软件对象,以及与之相关的数据,并可以执行某些功能。
对象是面向对象编程范例的核心,不仅在函数编程中表示数据,而且在程序的整体结构中也是如此

三大特性
封装、继承、多态

封装 :根据 职责 将 属性方法 封装 到一个抽象的 类 中

封装的意义
将属性和方法放到一起做为一个整体,然后通过实例化对象来处理;
隐藏内部实现细节,只需要和对象及其属性和方法交互就可以了;
对类的属性和方法增加 访问权限控制。

9.1 类和对象

9.1.1 类的定义

:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法
类就是封装

类大体结构为:

  • 类:
    • 类属性
    • 实例属性
    • 类方法
    • 实例方法

在Python中,定义类是通过class关键字来实现的

class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>

在Python中定义类很简单,使用关键字class既可,后面接上类的名称(需要使用大驼峰命名)

在Python 3中,定义新类时,Python 3隐式使用object作为父类;在python2.X中,需要主动指定使用

# Python 2.x类定义:
class ClassNameobject):
    <statement-1>
    .
    .
    .
    <statement-N>

(object)表示该类对象继承自Python内置的类对象object,Python中所有的类对象都继承自一个统一的基类:object

9.1.2 对象的定义

对象:python中一切皆对象。 上述的类其实也是一个对象object.
语法解析,当解释器执行class语句时,就会创建一个类对象,类的数据类型是type类型

# 定义一个类对象
class Dog:
    pass

注意
对象包括两个数据成员(类变量和实例变量)和 类方法

9.2 实例化对象

将抽象对象转变为实体化对象,就是实例化对象
实例化一个类是通过在类名后面加小括号“()”来实现
类的实例化就是创建一个类的实例,类的具体对象
根据类对象创建实例对象基本语法: 变量名 = 类名([实参])

# 定义类对象
class Dog:
    
    name = '大黄'
    
# 类对象
dog1 = Dog

# 实例对象
dog2 = dog1() 

注意:python的类,带括号是实例化,不带括号是赋值
具体需要了解一个_ new _ 方法

9.3 类属性

类属性通常用于保存与类相关的常量或配置信息,类属性是属于类的。
类属性:定义在类里面,类方法外面的变量就是类属性
类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用

9.3.1 定义类属性

属性的定义方法跟变量的定义方法类似,保持一致的命名规则
如下是定义一个空属性name :

class Dog:
    
    name = None  # 名字

9.3.2 访问类属性

访问公有类属性可以分为:类外部访问类内部访问

9.3.2.1 类外部访问

类外部访问可以通过两种方式访问类属性:

  1. 创建一个类之后,可以通过类名访问其属性
  2. 类实例化后,可以通过实例名访问其属性

属性引用使用和 Python 中所有的属性引用一样的标准语法:obj.name。

注意:推荐类属性使用 类名.name 方式操作访问

当某个实例调用类属性时,它们访问的是类属性的副本,这意味着当类属性的值发生改变时,所有实例都会受到影响

通过类名访问其属性
调用方法:类名.name
如下:

#类定义
class People:
    # 定义基本属性
    name = '小美'
    age = 18

# 直接通过类名访问其属性
print("我叫:%s,今年:%s岁" % (People.name, People.age))

输出结果:

我叫:小美,今年:18岁

通过实例名访问其属性
调用方法:实例名.name

class People:
    # 定义基本属性
    name = '小美'
    age = 18

a = People()
print("我叫:%s,今年:%s岁" % (a.name, a.age))

输出结果:

我叫:小美,今年:18岁
9.3.2.1 类内部访问

类内部访问也分为类方法访问和实例方法访问

类方法访问类属性
类方法访问类属性需要使用cls关键字
cls 关键字
cls 关键字是类方法定义的时候,必须要填写的参数

  • 它用来表示类自身的意思
  • 当我们使用类对象调用方法的时候,cls 会被python自动传入
  • 在类方法的内部,想要访问类的类变量,必须使用cls
  • cls 在传参的过程时候可以忽略
class People:
    # 定义基本属性
    name = '小美'
    age = 18
    
    @classmethod
    def adc(cls):
        print("我叫:%s,今年:%s岁" % (name, age)) # 报错,类内部使用应该用self来绑定如:cls.name, cls.age

实例方法访问类属性
实例方法访问类属性需要使用self关键字

self 关键字
self关键字是实例方法定义的时候,必须要填写的参数

  • 它用来表示实例自身的意思
  • 当我们使用类对象调用方法的时候,self会被python自动传入
  • 在实例方法的内部,想要访问类的类变量,必须使用self
  • self在传参的过程时候可以忽略

举例:

class People:
    # 定义基本属性
    name = '小美'
    age = 18
    
    def adc(self):
        print("我叫:%s,今年:%s岁" % (name, age)) # 报错,类内部使用应该用self来绑定如:self.name, self.age

9.3.3 修改类属性

修改一个类属性的值有两种方法

  • 对象名.属性名 = 数据 ----> 直接修改
  • 对象名.方法名() ----> 间接修改

对象名.属性名 = 数据 ----> 直接修改

class People:
    # 定义基本类属性
    name = '小美'
    age = 18

#定义两个实例化对象
a=People()
b = People()

# 通过类名.变量名来修改基本属性
People.name = '小帅'
People.age = 24
print("我叫:%s,今年:%s岁" % (People.name, People.age))

# 通过实例名.变量名来修改基本属性
a.name = "小梅"
a.age = 25
print("我叫:%s,今年:%s岁" % (a.name, a.age))

# 检查没有主动修改的b实例对象中类属性值有无改变
print("我叫:%s,今年:%s岁" % (b.name, b.age))

输出结果:

我叫:小帅,今年:24岁
我叫:小梅,今年:25岁
我叫:小帅,今年:24岁

详解:

  1. 类对象名.变量名访问的方式可以更改了类属性,从上述中实例b的输出可知
  2. 实例对象名.变量 = 数据 默认是给实例对象添加实例属性,并不能操作类属性

注意

  1. 类属性只能通过类对象修改,不能通过实例对象修改
  2. 如果类属性和实例属性同名,实例对象名只能操作实例属性

对象名.方法名() ----> 间接修改
需要先了解方法的知识才比较好懂这个内容

class Boy:
    name = 'silver'  # 私有变量
    
    def chName(self,name): # 定义一个方法,使得在外部可以调用
        self.name = name
        
b = Boy()
b.chName('逍遥')
print(b.name)  输出结果:'逍遥'

通过调用方法,来修改属性

9.4 类方法

在类中可以定义函数用来记录行为
类中定义的行为(函数)叫做类方法,也叫做成员方法

9.4.1 定义类方法

类方法需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数

class A(object):
    name = 'I am Class A'
 
    @classmethod
    def class_method(cls, s):
        print("调用类方法")

a = A()
A.class_method()
a.class_method()

9.4.2 访问类方法

有两种访问方式:

  • 使用类直接调用
  • 使用实例调用
class A(object):
    name = 'I am Class A'
 
    @classmethod
    def class_method(cls, s):
        print("调用类方法")

a = A()
A.class_method()
a.class_method()

能够通过实例对象和类对象去访问。类方法通常使用类直接调用,也可以用实例调用(不推荐)。当实例调用的时候,Python会将实例的最底层类(即实例直接所属类)型传入cls参数中

注意:类方法是无法调用实例属性的
举例子:

class A(object):
    def __init__(self):
        self.age = 18
        
    @classmethod
    def class_method(cls):
        print("调用实例属性%s "%(cls.age))  # 出错,类无age属性

a = A()
A.class_method()
a.class_method()

运行结果:

    print("调用实例属性%s " % (cls.age))  # 出错,类无age属性
AttributeError: type object 'A' has no attribute 'age'

类方法没有实例属性,无法调用该属性

9.5 实例属性

实例属性是从属于实例对象的属性,也称为“实例变量”,其跟类变量不一样
类体中,所有函数内部:以self.变量名的方式定义的变量,称为实例属性或实例变量
实例变量就是一个用 self 修饰的变量

9.5.1 定义实例属性

定义实例属性需要使用我们的魔法构造方法:_ init _
_ init _() 方法也称之为构造方法:

  1. 在创建类对象的时候,会自动执行_ init _() 方法
  2. 在创建类对象的时候,将传入参数传递给 _ init _ 方法使用

_ init _() 方法无需主动调用,在创建新的类对象时会自动调用,其可以传入参数也可也不传入参数

9.5.1.1 不传参数方式定义

举例:

class Lange:
    
    # 魔法构造方法
    def __init__(self):   
        self.name = "中文"
        self.address = "http://"
        
    # 下面定义了一个say实例方法
    def say(self):
        self.age = 13
        
clang = Lange()
print(clang.name)
print(clang.address)
print(clang.age)

输出结果:

"中文"
"http://"
报错:AttributeError: 'Lange' object has no attribute 'age'

Lange 类中,nameaddress 以及 age 都是实例变量。但是Lange类的实例对象都会包含 nameadd 实例变量,而只有调用了 say() 方法的实例对象,才包含 age 实例变量

9.5.1.2 传参方式定义
class Student:

    # 魔法构造方法
    def __init__(self, name):
        self.name = name  # 此时实例变量name等于外部传入的参数name

s = Student('小红')
print(s.name)

输出结果:

小红

此例中,此时实例变量name等于外部传入的参数name。这使得类具有很好的扩展性

9.5.2 访问实例属性

在类内部访问
使用:self.name
例如:

class Student:

    # 魔法构造方法
    def __init__(self):
        self.name = "中文"


    # 下面定义了一个say1实例方法
    def say1(self):
        print("我的名字是:%s" %self.name) 


    # 下面定义了一个say2实例方法
    def say2(self):
        print("我的名字是:%s" %name)


s = Student()
print(s.say1())
print(s.say2())

输出结果:

我的名字是:中文
NameError: name 'name' is not define

在上面的例子中,在类方法中,调用实例变量需要使用self关键字
结合之前的学习,在类方法中,调用类变量也需要使用self关键字

在类外部调用
使用:实例对象名.name

class Student:

    # 魔法构造方法
    def __init__(self):
        self.name = '小红'  

s = Student()
print(s.name)  #使用实例对象名.name调用
print(Student.name) #使用类对象名.name调用

输出结果:

小红
AttributeError: type object 'Student' has no attribute 'name'

在上述例子中,调用实例变量只能使用 实例对象名.name 调用

总结
在类方法中,不管调用实例变量还是类变量,都需要使用self关键字
在类外部,调用实例变量只能使用 实例对象名.name 调用

9.5.3 添加实例属性

可以在对象实例化后,再给对象添加实例属性
举例:

class Student:

   # 魔法构造方法
   def __init__(self):
       self.name = '小红'  

s = Student()
s.age = 18  # 新增一个实例属性,age

在前面类变量中提到通过实例对象可以访问类变量,但无法修改类变量的值。这是因为,通过实例对象修改类变量的值,不是在给“类变量赋值”,而是定义新的实例变量
实例变量只能通过对象名访问,无法通过类名访问。

9.6 实例方法

9.6.1 实例方法定义

在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例
定义语法

def 方法名(self, 形参1, ....., 形参n):
    方法体

9.6.2 调用实例方法

在类内部调用实例方法时,需要使用self关键字
但是在类外部调用实例方法时,无需传入self参数
如:

class Student:
    name = '小蓝'
    
    # 定义实例方法,并且使用self关键字
    def say_1(self):
        # 在方法的内部,想要访问类的类变量,必须使用self
        print("hello 大家好,我叫做%s"%(self.name)) 
    
    # 定义实例方法,并且使用self关键字,外部传入参数
    def say_2(self,msg):
        print("时间过得真快,%s"%(msg))
    
    # 内部调用实例方法
    def say_3(self):
        print("我是方法3") 
        self.say_1()     

stu = Student()
stu.say_1()                 # 类外部调用实例方法
stu.say_2("我已经15岁了")   # 类外部调用实例方法
stu.say_3() 

输出结果:

hello 大家好,我叫做小蓝
时间过得真快,我已经15岁了
hello 大家好,我叫做小蓝

总结

  • self 表示类对象本身的意思
  • 在方法的内部,想要访问类的类变量,必须使用self
  • self 虽然出现在形参列表中,但是无需理会

9.7 私有属性

对于部分属性和行为不希望对外公开或者开放使用。所以有了私有属性这个概念

9.7.1 定义私有属性

__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问,在类内部的方法中使用时 self.__private_attrs

私有属性也可也分为私有类属性和私有实例属性
举例:

class Boy:
    __name = 'silver'  # 私有类属性
    
    def __init__(self):
        __age = 18    # 私有实例属性

9.7.2 访问私有属性

9.7.2.1 类内部访问

私有属性,可以在类内部通过self或者cls调用

class Boy:
    __name = 'silver'  # 私有变量
    
    def __init__(self):
        self.__age = 18     # 私有实例属性
    
    def get1(self):      # 类内部,实例方法调用
        print("实例方法调用:%s %s"%(self.__name, self.age))
    
    @classmethod
    def get2(cls):      # 类内部,类方法调用
        print("类方法调用:%s %s"%(cls.__name))  

总结:
无论是公有还是私有属性
在类内部,实例方法调用需要 self 调用类或者实例属性
在类内部,类方法调用需要 cls 调用类属性, 但是无法调用实例属性

9.7.2.2 类外部访问

私有属性不能在类的外部被使用或直接访问,通用方法:定义一个可以调用的公有方法

class Boy:
    __name = 'silver'  # 私有变量
    
    def getName(self):
        print(self.__name)
    
a = Boy()
a.getName()

通过定义公有方法,使得私有属性可以在外部调用

9.8 私有方法

__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods。

9.8.1 定义私有方法

私有方法也可也分为私有类方法和私有实例方法
举例:

class A(object):
    
    __name = '小明'
    
    def __init__(self):
        self.__age = 18

    @classmethod        
    def __class_method(cls):  # 定义私有类方法
        print("调用私有类属性%s " % (cls.__name)) 
    
    def __self_method(self):  # 定义私有实例方法
        print("调用私有实例属性%s " % (self.__age)) 

9.8.2 访问私有方法

9.8.2.1 类内部访问

私有方法,可以在类内部通过self或者cls调用

class A(object):
    
    __name = '小明'
    
    def __init__(self):
        self.__age = 18

    @classmethod        
    def __class_method(cls):  # 定义私有类方法
        print("调用私有类属性%s " % (cls.__name)) 
    
    def __self_method(self):  # 定义私有实例方法
        print("调用私有实例属性%s " % (self.__age)) 
    
     @classmethod      
    def get1(cls):  # 
        print("调用私有类方法 ") 
        cls.__class_method()
    
    def get2(self):  # 
        print("调用私有实例方法 ") 
        self.__self_method()  
        
9.8.2.2 类外部访问

私有属性不能在类的外部被使用或直接访问,通用方法:定义一个可以调用的公有方法

class A(object):
    __name = '小明'

    def __init__(self):
        self.__age = 18

    @classmethod
    def __class_method(cls):  # 定义私有类方法
        print("调用私有类属性%s " % (cls.__name))

    def __self_method(self):  # 定义私有实例方法
        print("调用私有实例属性%s " % (self.__age))

    @classmethod
    def get1(cls):  #
        print("调用私有类方法 ")
        cls.__class_method()

    def get2(self):  #
        print("调用私有实例方法 ")
        self.__self_method()


a = A()
a.get1()
a.get2()

运行结果:

调用私有类方法 
调用私有类属性小明 
调用私有实例方法 
调用私有实例属性18

注意:

  • 类的属性和方法,在对象实例化时,会被实例化为实例方法,所以cls类属性和类方法,可以用 self 来访问,但是实例属性和实例方法,不能被 cls访问
9.8.3 属性和方法总结

调用属性总结

  • 类内部
    • 实例方法中需要self.name调用类属性或者实例属性
    • 类方法中需要cls.name调用类属性
  • 类外部
    • 推荐用类名.属性名调用类属性
    • 推荐用对象名.属性名调用实例属性,虽然也可调用类属性,但不推荐
    • 只能通过调用公有方法来间接调用私有属性

调用方法总结

  • 类内部
    • 实例方法中需要self.method()调用类方法或者实例方法
    • 类方法中需要cls.method()调用类方法
  • 类外部
    • 推荐用类名.方法名()调用类方法
    • 推荐用对象名.方法名()调用实例方法,虽然也可调用类方法,但不推荐
    • 只能通过调用公有方法来间接调用私有方法

私有属性和方法总结

  • 命名:都是以双下划线__作为开头
  • 访问限制:无法通过类对象直接访问 ,本类中内部可以访问;
  • 继承:都不会被子类继承,子类也无法访问
  • 作用:通常用来处理类的内部事情,不通过对象处理,起到安全作用。

9.9 内置魔法方法

除了前面使用到的_ init _ 构造方法,python中还存在一些内置的类方法,各自有各自的功能,统称为魔法方法。
魔法方法:

  • _ init _ 构造方法,在生成对象时自动调用
  • _ new _ 生成方法,在生成对象时调用
  • _ str _ 字符串方法
  • _ del _ 析构方法
  • _ call _ 当对象被当作函数调用时,自动调用
  • _ eq _ == 符号比较方法

9.9.1 _ new _ 生成对象方法

__new__魔术方法返回的就是self的内存地址

  1. 如果不在__new__方法里面调object的__new__方法就不会创建对象,__init__不会被执行;
  2. 如果不在__new__方法里面return创建好的对象,__init__不会被执行
class Test:
    def __new__(cls, *args, **kwargs):
        print("我是__new__方法")
        obj = object.__new__(cls)
        print(obj)
        return obj

    def __init__(self):
        print(self)
        print("我是__init__方法")

a = Test()

运行结果:

我是__new__方法
<__main__.Test object at 0x123902f70>
<__main__.Test object at 0x123902f70>
我是__init__方法

对象初始化时执行__new__,目的是为该对象分配内存空间。
对象初始化时一般先执行__new__,再执行__init__,如果缺少__new__返回的对象,那么将不会执行__init__

9.9.2 _ str _ 字符串方法

__str__方法用于返回对象的描述信息:

  • 如果不使用__str__方法,直接print,或者return,返回的是对象的内存地址。
  • 如果在__str__中定义了描述信息,print或者return时,返回的就不是内存地址,显示更友好,实现了类到字符串的转化。

举例:
不使用__str__方法

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

stu = Student('小花',20)
print(stu)    # 输出类对象地址
print(str(stu))  # 将类对象转化为字符串

运行结果:

<__main__.Student object at 0x000001CD8B6ED340>
<__main__.Student object at 0x000001CD8B6ED340>

当类对象需要被转换为字符串时,会输出内存地址。

使用__str__方法
可以自定义方法内容,通过__str__方法来控制类转化为字符串的行为

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"name={self.name},age={self.age}"

stu = Student('小花',20)
print(stu)
print(str(stu))

运行结果:

name=小花,age=20
name=小花,age=20

_ str _ 字符串方法 相当于是对 str 运算符重载
还有一个魔术方法__repr__,与__str__类似,当同时出现时,str__优先级高于__repr

9.9.3 _ del _ 析构方法

对象被删除的时候调用此方法:

  1. 对象在内存中被释放时,自动触发执行;
  2. 此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以__del__()的调用是由解释器在进行垃圾回收时自动触发执行的
class Test:

    def __init__(self):
        print("初始化对象")

    def __del__(self):
        print("对象被删除了")

a = Test()
print("end")

运行结果:

初始化对象
对象被删除了

9.9.4 _ call _ 方法

默认自动调用,把类实例当成函数执行的时候会触发__call__方法,对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
举例:

class Test:

    def __call__(self, *args, **kwargs):
        print("调用了__call__")
   
        
a = Test()        
a()

运行结果:

调用了__call__

9.9.5 _ eq _ == 符号比较方法

调用相等判断的时候自动调用

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

    def __eq__(self, other):
        print(self.age)
        print(other.age)
        return self.age == other.age  #判断当前的跟其他的



t1 = Test("狗子", 22)
t2 = Test("小李", 23)
print(t1 == t2) 

运行结果:

22
23
False

当调用了 == 符号时,就会去自动调用__eq__ 方法

9.10 继承

继承: 实现代码的重用,相同的代码不需要重复的编写

作用:继承就是可以获取另外一个类的静态属性或者普通方法,(并非所有成员)。让类和类之间产生父子关系,子类可以拥有父类的静态属性和方法。

9.10.1 继承的基础语法

在Python中,新建的类可以继承一个或者多个父类,其中:

  • 父类又可以称为基类或者超类,新建的类称为派生类或子类
  • 子类 继承自 父类,可以直接 使用 父类中已经封装好的公有方法,不需要再次开发
  • 子类 封装 子类特有的 属性和方法

继承又可以分为:单继承多继承
继承的基本语法:
单继承

class 类名(父类名):

    pass

多继承

class 类名(父类名1, 父类名2):

    pass

9.10.2 单继承

子类继承一个父类,不仅可以调用子类定义方法,也调用父类中的方法
单继承举例:

# 定义一个类使用4g通话,再定义一个类使用5g通话
class iphone: # 定义一个父类iphone
    name = '苹果手机'
    
    def call_by_4g(self):
        print("4g通话")

# 定义一个子类iPhone8 继承至父类
class iphone8(iphone): 
    face_id = '100001'
    
    def call_by_5g(self):
        print("新功能,5g通话")
        
        
phone = iphone8()
print(phone.name)    # 打印父类的name属性
phone.call_by_4g()   # 调用父类的方法
phone.call_by_5g()   # 调用子类方法

继承具有传递性:
如果C 类从 B 类继承,B 类又从 A 类继承,那么 C 类就具有 B 类和 A 类的所有属性和方法

9.10.2 多继承

子类继承多个父类,不仅可以调用子类定义方法,也调用父类中的方法
举例:

class NFCReader:
     nfc_type = '第三代'
     producer = "MM"
     
    def read_card(self):
        print("nfc读卡")
    
    def write_card(self):
        print("nfc写卡")

class RemoteControl(self):
    rc_type = "第二代"
    
    def control(self):
        print("红外遥控")
    
class MYphone(NFCReader, RemoteControl):
    pass

phone = MYphone()
phone.read_card()  # 调用父类的读卡功能
phone.control()  # 调用父类的红外遥控功能

MYphone 这个类继承了 NFCReader 和 RemoteControl 两个父类,所以它具有两个类所拥有的全部功能

父类之间 存在 同名的属性或者方法
继承多个父类,如果有同名的成员(属性和方法),那么默认以(从左到右的)继承顺序为优先级

class NFCReader:
     nfc_type = '第三代'
     producer = "MM"
     
    def read_card(self):
        print("nfc读卡")
    
    def write_card(self):
        print("nfc写卡")

class RemoteControl(self):
    producer = "NN"
    rc_type = "第二代"
    
    def control(self):
        print("红外遥控")
    
class MYphone(NFCReader, RemoteControl):
    pass

phone = MYphone()
phone.producer()  # 输出结果为:"MM"

注意:开发时,应该尽量避免这种容易产生混淆的情况!
—— 如果 父类之间 存在 同名的属性或者方法,应该 尽量避免 使用多继承

Python 中的 MRO —— 方法搜索顺序
Python 中针对 类 提供了一个 内置属性 mro 可以查看 方法 搜索顺序
MRO 是 method resolution order,主要用于 在多继承时判断 方法、属性 的调用 路径
在搜索方法时,是按照 mro 的输出结果 从左至右 的顺序查找的:

  1. 如果在当前类中 找到方法,就直接执行,不再搜索
  2. 如果没有找到,就继续查找下一个类中是否有对应的方法,如果找到,就直接执行,不再搜索
  3. 如果找到最后一个类,还没有找到方法,程序报错

9.10.3 方法重写

子类继承父类的方法和属性后,可以进行复写。
即:再子类中重写定义同名的属性或方法

class iphone: # 定义一个父类iphone
    name = '苹果手机'
    
    def call_by(self):
        print("使用4g通话")


class Myphone(iphone): 
    name = '这是我的苹果手机'   # 复写父类属性
    
    def call_by(self):
        print("新功能,可以使用5g通话")  # 复写父类方法
        
myphone = Myphone()
print(myphone.name)   # 输出, '这是我的苹果手机'
myphone.call_by()   # 输出, '新功能,可以使用5g通话'

9.10.4 调用父类同名成员

一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果在类内部需要使用被复写的父类成员,需要使用以下两种调用方式:

  1. 使用类名调用父类成员, 具体为: 父类名.name \ 父类名.method
  2. 使用super()调用父类成员,具体为:super().name \ super().method

使用类名调用父类成员
举例:

class iphone:  # 定义一个父类iphone
    name = '苹果手机'

    def call_by(self):
        print("使用4g通话")


class Myphone(iphone):
    name = '这是我的苹果手机'  # 复写父类属性

    def call_by(self):
        print("新功能,可以使用5g通话")  # 复写父类方法

    def call_by_parent(self):
        print("调用父类的属性和方法,")
        print(iphone.name)
        iphone.call_by(self)


myphone = Myphone()
myphone.call_by_parent() 

运行结果:

调用父类的属性和方法,
苹果手机
使用4g通话

注意:

  1. 需要注意再使用类名.method() 调用父类方法时,需要传入参 数self
  2. 不推荐使用这种方法调用,因为一旦 父类发生变化,方法调用位置的 类名 同样需要修改

使用super()调用父类成员
举例:

class iphone:  # 定义一个父类iphone
    name = '苹果手机'

    def call_by(self):
        print("使用4g通话")


class Myphone(iphone):
    name = '这是我的苹果手机'  # 复写父类属性

    def call_by(self):
        print("新功能,可以使用5g通话")  # 复写父类方法

    def call_by_parent(self):
        print("调用父类的属性和方法,")
        print(super().name)
        super().call_by()


myphone = Myphone()
myphone.call_by_parent() 

运行结果同上,

super类
在 Python 中 super 是一个 特殊的类,super() 就是使用 super 类创建出来的对象
使用的场景:就是在 重写父类方法时,调用 在父类中封装的方法实现

注意:

  1. 使用super.method() 调用父类方法时,不需要传入参 数self
  2. 只可以在子类内部调用给你父类的同名成员,子类的实例对象默认都是调用子类复写后的
  3. 子类对象不能在自己的方法内部,直接访问父类的 私有属性 或 私有方法,可以通过父类的公有方法间接访问

9.11 类型注解

python在3.5版本之后引入了类型注解,以方便静态类型检查工具、IDE等第三方工具进行类型检查,起提示的作用,对 Python 程序的运行不会产生任何影响
类型注解:在代码中涉及数据交互的地方,提供数据类型的注解

主要功能:

  1. 帮助第三方IDE工具(如Pycharm)对代码进行类型检查,做代码提示
  2. 帮助开发者对变量进行类型注解

主要分为:变量类型注解、函数类型注解、容器类型注解

提示:按快捷键 ctrl + p 可以查看提示

9.11.1 变量类型注解

Python 是动态语言,其显著特点是在声明变量时,你不需要显式声明它的类型,不用纠结类型声明、类型转化等麻烦事
举例:

age = 20
print(age+1)

上面例子中虽然代码里没有明确指定 age 的类型,但是程序运行时隐式推断出它是 int 类型,因此可以顺利执行 age + 1 的动作。但是:如果变量的类型有错,编辑器、IDE等工具无法在早期替你纠错,只能在程序运行阶段才能够暴露问题。
所以,引入了类型注解方法,来明确的声明变量的类型。
基础语法:变量名: 数据类型 = 值
如:

var_1: int = 18
var_2: float = 3.5
var_3: str = 'abc'
var_4: bool = False
var_5: list = []

扩展-- 类对象类型注解

class Student:
    pass

stu: Student = Student()

语法是:对象名: 抽象类名 = 抽象类名()

9.11.2 容器类型注解

列表、字典、元组等包含元素的复合类型,用简单的 list,dict,tuple 不能够明确说明内部元素的具体类型。
因此要用到 typing 模块提供的复合注解功能

from typing import List, Dict, Tuple

my_list: List[int] = [1,2,3]
my_tuple: Tuple(str,int,bool) = ("yys", 889, True)
my_set: Set[int] = {1,2,3}
my_dict: Dict[str, int] = {"yys": 889}

在Python 3.9+ 版本后,内置的容器类型就支持了复合注解

my_list: list[int] = [1,2,3]
my_tuple: tuple(str,int,bool) = ("yys", 889, True)
my_set: set[int] = {1,2,3}
my_dict: dict[str, int] = {"yys": 889}

注意:

  1. 元组类型设置类型注解时,需要将每个元素都标记出来
  2. 字典类型设置类型注解时,需要2个类型,第一个是key,第二个是value

9.11.3 函数类型注解

函数和方法的形参及返回值都可以进行类型注解
函数和方法的形参类型注解
基本语法:

def 函数方法名(形参名: 类型, 形参名: 类型,......):
    pass

举例:

def add(x: int, y: int):
    return x + y

当调用add函数时,按下ctrl+p可以查看提示x和y的变量类型

函数和方法的返回值类型注解
基本语法:

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

举例:

def add(x: int, y: int) -> int:
    return x + y
    
print(add(1,2))    

注意:返回值类型注解需要使用符号:->

9.11.4 Union类型注解

当列表或者字典等数据类型中存储的数据类型为混合类型时,就需要使用Union进行联合类型注解
语法:Union[类型1, 类型2......]

from typing import Union

# 使用Union对列表内的数据类型,进行联合类型注解
my_list: list[Union[str, int]] = [1,2,'yys']
# 使用Union对字典内的数据类型,进行联合类型注解
my_tuple: dict[str, Union[str, int]] = {'yys': '招财', 'age': 18}

Union类型注解也可也运用在函数(方法)形参及返回值中

Union的使用总结:

  • 导包:from typing import Union
  • 使用:Union[类型1, 类型2…]

虽然python是一门动态语言,但是对于在项目中使用来说,希望大家写好类型注解,编译器能在我们调用时提前进行检查,能减少我们程序出错的概率

9.12 多态

多态定义:不同的 子类对象 调用相同的 父类方法,产生不同的执行结果
总结:

  1. 多态 可以 增加代码的灵活度
  2. 以 继承 和 重写父类方法 为前提
  3. 是调用方法的技巧,不会影响到类的内部设计

步骤:

  1. 定义父类,并提供公共方法
  2. 定义子类(继承父类),并重写父类方法
  3. 传递子类对象给调用者,可以看到不同子类执行效果不同

举例子,“需求:警务人员和警犬一起工作,警犬分2种:追击敌人和追查毒品,携带不同的警犬,执行不同的工作”:



# 1. 定义父类,提供公共方法: 警犬 和 人
class Dog(object):
 def work(self):  # 父类提供统一的方法,哪怕是空方法
     pass


# 2. 定义子类,子类重写父类方法:定义2个类表示不同的警犬
class ArmyDog(Dog):   # 继承Dog类
 def work(self):   # 子类重写父类同名方法
     print('追击敌人...')


class DrugDog(Dog):
 def work(self):
     print('追查毒品...')


# 定义人类
class Person(object):
 def work_with_dog(self, dog):  # 传入不同的对象,执行不同的代码,即不同的work函数
     dog.work()    # 在方法内部,直接让 狗对象 调用 work 方法


# 3. 创建对象,调用不同的功能,传入不同的对象,观察执行的结果
ad = ArmyDog()
dd = DrugDog()


jingyuan = Person()
jingyuan.work_with_dog(ad)
jingyuan.work_with_dog(dd)

恭喜你,你已经学完了python基础的全部内容。完结撒花!
【python基础教程——一文教你入门python,够详细够实用】_第10张图片

以上是笔者学习过程中的笔记,如有错误,欢迎大家指正
参考资料:
官方文档:https://docs.python.org/zh-cn/3/index.html
菜鸟编程:https://www.runoob.com/python3/python3-tutorial.html
视频资料:https://www.bilibili.com/video/BV1qW4y1a7fU

你可能感兴趣的:(Python,python,学习)