一、Python基础
01 注释
注释是为了提高程序可读性,它不参与代码的运行,仅起到辅助代码阅读的作用;开发过程中,核心代码一般要给上注释,便于代码的阅读
- 单行注释:#
单行注释只能注释掉一行的内容,因此一般的简单说明用单行注释
# 注释内容
- 多行注释:
''' '''
Python中 ’ 和 " 并不影响代码的运行,但是要成对出现,即不可出现' "
或者 " '
的组合
'''
多行注释
'''
多行注释一般单独占一块区域,用来解释一个区域的代码或者一个函数块的功能
补充:选中多行后,在pycharm中使用快捷键Crtl + / 可以快捷将选中行改为注释
02 变量
变量即存储临时数据的空间(数据的容器);
变量定义的语法:
变量名 = 变量值
注意:=
不代表任何相等的意思,仅代表赋值
变量命名的规则:
-
必须以字母或下划线开头;
-
变量名由字母、数字、下划线组成;
-
变量名不能由数字开头;
-
变量名严格区分大小写;
-
不能包含空格、连字符、标点符号或其他特殊字符。
变量命名的规范:
-
变量取名应做到见名知意;
-
变量名采用下划线命名法且单词首字母全都小写,下划线命名法即两个单词之间用_连接,python中一般不使用小驼峰命名法;
-
不能使用Python的内置关键字。
补充:在Python中,变量、函数、文件名、包名、模块名等都用下划线命名法
Python中的数据类型
-
数值型:int(整型),float(浮点型);
-
布尔型:True,False;
-
str(字符串);
-
list(列表);
-
set(集合);
-
tuple(元组);
-
dict(字典)
type() 函数可以直接查看变量的数据类型
#整型
int1 = 12
print(type(int1)) # <class 'int'>
#浮点型
float1 = 12.12
print(type(float1)) # <class 'float'>
#布尔型
boole1 = True
print(type(boole1)) # <class 'bool'>
#字符串
name = "name"
print(type(name)) # <class 'str'>
#列表
list1 = [1,2,3,4]
print(type(list1)) # <class 'list'>
#元组
tuple1 = (1,2,3,4)
print(type(tuple1)) # <class 'tuple'>
#集合
set1 = {1,2,3,4}
print(type(set1)) # <class 'set'>
#字典
dict1 = {'name' : "xiaoming",'age' : 12}
print(type(dict1)) # <class 'dict'>
数据类型转换
(1)float型转化为int型
注意
- float型转化为int型时,会直接去掉小数点及其后面的小数部分,仅仅保留整数部分,不是四舍五入
num = 12.945
print(int(num)) #12
(2)int型转化为float型
注意
- int型转化为float型时,会直接在整数部分后面添上
.0
,仅添上一个0
num1 = 12
print(float(num1)) # 12.0
(3)int类型、float型转化为str
num1 = 100
num2 = 12.945
print(type(str(num1)))
print(type(str(num2)))
#<class 'str'>
#<class 'str'>
int类型和float型转化为str后,可以使用有关字符串的函数,但是无法进行数学运算
03 格式化输出
字符串格式化:格式化是字符串所具有的功能,字符串的格式化跟输出函数没有任何关系
方式一:占位符实现格式化输出
格式:" 字符串 占位符 " % 变量
重点掌握:
-
字符串占位符为:
%s
- 浮点型占位符为:
%f
,其中%.nf
表示保留到小数点后n位,如%.2f
表示保留到小数点后两位(也可以使用round(数字,保留的位数))
- 浮点型占位符为:
-
整型占位符为:
%d
,其中%0nd
表示,该数据一共输出n位,不足的位数在前方补0 -
字符占位符为:
%c
name = "小明"
age = 19
score = 90.5
print("学生姓名为:%s,年龄为:%03d,成绩为:%.2f" % (name,age,score))
# 学生姓名为:小明,年龄为:019,成绩为:90.50
方式二:f-string字符串格式化
格式:f"字符串 {需要填充的内容}"
注意
-
f{整型变量名:0nd}
表示占据n位,不足的用0补齐(和整型占位符为: %d,其中 %0nd 语法一致) -
f{浮点型变量名:.nf}
表示保留到小数点后n位,如%.2f表示保留到小数点后两位
name = "小明"
age = 19
score = 90.5
print(f"学生姓名为:{name},年龄为:{age:03d},成绩为:{score:.2f}") #学生姓名为:小明,年龄为:019,成绩为:90.50
方式三:format函数
格式:"字符串 {索引}".format(索引位置的值)
注意
-
如果没有写索引值,则默认从索引0的值开始填充;
-
一个索引值所代表的数据,可以多次被引用
name = "小明"
age = 19
score = 90.5
print("学生姓名为:{0},年龄为:{1:03d},成绩为:{2:.2f};\n {1:03d},{2:.2f},{2:.2f},{1:03d}".format(name,age,score))
# 学生姓名为:小明,年龄为:19,成绩为:90.5;
# 19,90.5,90.5,19
补充
- {整型变量名:0nd}
,表示占据n位,不足的用0补齐
{浮点型变量名:.nf}
,表示保留到小数点后n位,如%.2f
表示保留到小数点后两位
04 输入
Python中使用的输入函数一般是input()函数,它是一个阻塞函数,必须等用户输入信息且按Enter键结束输入后,后续代码才能运行
格式:input(提示字符)
num = input("请输入一个数字:")
print(type(num))
# 请输入一个数字:3
# <class 'str'>
在Python中,input() 函数返回的是一个字符串
05 运算符
(1)算术运算符
+、-、* 、 / 、% 、// 、 **
分别代表加、减、乘、除、取余、整除、幂
运算的优先级和数学中的运算优先级相同,%、//的优先级和 * / 优先级相同
总的运算优先级:+ - < * / // % < **
(2)赋值运算符
Python中的赋值运算符即:=
赋值格式:变量名 = 变量值
如果同时赋值多个变量,变量之间用 , 间隔,且 =左边的变量名和 =右边的变量值一一对应,变量名的个数和变量值的个数必须相同
补充:复合算术运算符
+=、-=、*=、/=、%=
解释:
X += Y —>X + Y,X -= Y —>X - Y, X * = Y —>X * Y, X /= Y —>X / Y
X %= Y —>X % Y
(3)比较运算符
<,>,!=,<=,>=
比较运算符的运算返回值为bool值,成立为Ture,不成立为Flase
补充
在Python中,比较运算符可以直接连用,不必使用||进行或,且的连接
例如:想判断某个变量是否在某个区间,Java代码如下:
public class select {
public static void main(String[] args) {
int num = 10;
if(num > 0 || num < 20){
System.out.println(true);
}else{
System.out.println(false);
}
}
}
而Python代码如下:
num = 10
print(0 < num < 20) #Ture
(4)逻辑运算符
and,or,not (与MySQL中的相同),其返回结果都是bool类型
运算结果:
-
and:同真即真;
-
or:同假即假;
-
not:真变假,假变真
(5)短路运算符
在Python中,0、空字符串""和None都被看为False,其他数值型和非空字符串都被看为Ture
num = 0
str = ''
cha = None
if (num or str or cha ): # 同假即假
print("真值输出")
else:
print("假值输出")
# 假值输出
又有如下规则
-
在计算 a and b 时,如果a是False,根据运算法则,无论b为何结果,整体的值为False;如果a是True,根据运算法则,结果仅被b影响,因此整体的值为b;
-
在计算 a or b 时,如果a是True,根据运算法则,无论b为何结果,整体的值为True;如果a是False,根据运算法则,结果仅被b影响,因此整体的值为b;
因此,当Python执行判断语句时,只要一个条件就能判断出整个判断语句的最终值,那么Python不会继续执行后续的判断语句
(6)三目运算符
运算符的返回值是 if --else 条件的返回值
num1 = 5
num2 = 6
num_max = num1 if num1 > num2 else num2 # 如果num1 > num2 ,则返回为num1,否则返回num2
print(num_max) #num2 = 6
06 选择结构
if语句格式:
if 条件:
条件成立执行的代码1
条件成立执行的代码2
后续代码 # 没有缩进,无论条件是否成立,都会实现
注意
- Python中对于缩进有着极其严苛的标准,默认将同一缩进的代码视为包含在统一代码块中,因此非if选择结构的代码不会进行缩进
if…else…语句格式
if 条件:
条件成立执行的代码1
else:
条件成立执行的代码2
后续代码 # 没有缩进,无论条件是否成立,都会实现
if…elif…else 语句格式
if 条件:
条件成立执行的代码1
elif 条件:
条件成立执行的代码2
else:
条件成立执行的代码3
后续代码 # 没有缩进,无论条件是否成立,都会实现
-
不管是哪种if结构,只有一个条件内的代码能被执行
-
if语句可以进行嵌套使用,以达到多条件判断的目的
07 循环结构
while循环
基本语法
while 条件:
条件成立时重复执行的代码1
条件成立时重复执行的代码2
循环的大体框架
-
初始条件
-
循环条件(判断跳出和执行循环的条件)
-
循环体(重复要做的)
-
下次循环的准备(i++)
如何写循环
-
初始状态如何?
-
重复的条件是什么?
-
重复做什么事?
-
如何才能到下次循环?
while循环的两个关键字:break和continue
break
break即终止当前循环;例如一共五个枣,吃到第三课发现了半条虫子,后续的枣子就都不吃了
num = 1
while(num <= 5):
if (num == 3):
print("有半条虫子,不吃了!")
break #关闭循环 循环内后续所有代码不执行
print("吃了%d颗枣" % num)
num += 1
continue
continue即终止本次循环,不影响后续循环
num1 = 0
while(num1 < 5):
num1 += 1
if (num1 == 3):
print("有一条虫子,换一颗枣吃")
continue #此时不会执行后续的代码 但是会继续执行循环
print(f"吃了{num1}颗枣")
while循环嵌套
嵌套while循环,顾名思义,就是一个while循环内嵌套着另一个while循环。外层循环控制主要流程,内层循环处理细节逻辑。通过合理设置循环条件,我们可以实现各种复杂的逻辑控制。
注意事项
-
1、避免死循环:在设置while循环条件时,务必小心避免死循环。死循环会导致程序无法正常退出,消耗大量系统资源。
-
2、合理设置循环变量:在使用嵌套while循环时,需要合理设置循环变量,确保程序按照预期运行。
-
3、优化性能:在某些情况下,过度使用嵌套while循环可能导致程序性能下降。因此,在编写代码时,应尽量优化算法和逻辑结构。
while循环的else结构
基本结构
while 条件:
条件成立时执行的代码
else :
条件不成立执行的代码,随后循环终止
for循环
基本语法
for 临时变量 in 数据容器:
重复执行的代码
-
for循环的次数由数据容器中数据量的个数决定
-
for循环是不需要循环条件的,因此不会出现循环不成立的情况
-
for循环必须配合数据容器使用
range函数
range函数返回的是一个整数序列,基本语法如下:
range(start,stop,step)
其含义是:从start开始,以step为步长,到stop结束,但是不包含stop
例如:range(1,11,2):从1开始,到10结束,以2为步长,即1-10内的奇数
注意
-
range默认从0开始,即start不写就默认为0
-
step默认为1
-
range内的迭代值无法被print输出
-
步长为正数时:start必须大于stop,否则没有数据
-
步长为负数时:start必须小于stop,否则没有数据
注意
- for循环中的
break
关键字,continue
关键字的功能和它们在while循环中的效果相同
for i in range(3):
user_name = input("请输入用户名:")
password = input("请输入密码:")
if user_name == "admin" and password == "admin8888":
print("登陆成功!")
break
else:
times = 2 - i # i从0开始
print(f"用户名或密码错误,你还剩{times}次机会")
if times == 0:
print("3次机会用尽,程序退出!")
08 字符串
定义:字符串是Python中的一种数据类型,通常由"“或者’'括起来,由于Python对”"和’'并不严格区分,因此在Python中不存在字符类型
char = 'a'
print(type(char)) # <class 'str'>
-
字符串的底层就是将字符串的每一个字符存连续地存储起来,并给每一个字符特定的索引;
-
索引值按照从左往右是从0开始的,从右往左是从-1开始的;
-
通过不同的索引值可以获取到字符串中的特定字符,格式为:字符串名称[索引值]
str = "人生苦短,我用pytohn"
print(str[0]) # 获取字符串的第一个字符:人(从左往右,以0为索引下标)
print(str[-8]) # 获取字符串的第一个字符:我(从右往左,以-1为索引下标)
字符串切片
所谓切片,即对数据容器中的部分数据进行操作;字符串、列表、元组都支持切片操作
语法:数据容器[开始位置索引:结束位置索引:步长]
str = "兰州牛肉面"
print(str[0:4]) # 兰州牛肉
注意
-
字符串、列表、元组的切片,都会生成一个新的数据列,不会对原来的数据进行更改
-
开始位置的索引值是包含的,但是结束位置的索引值是不包含的;
-
步长就是数据的间隔(相邻数据索引值的差值),当步长为1时,可以省略不写
-
开始位置索引值可以省略,此时步长若为正数,则起始位置为字符串的开始;若为负数,则起始位置为字符串结尾;
-
结束位置索引值可以省略,此时步长若为正数,则结束位置为字符串的开始;若为负数,则结束位置为字符串结尾
字符串操作方法
1、字符串查找
字符串查找即在字符串中查找子串出现的次数
index函数
index函数返回的是某个字符在字符串的索引值
语法格式:index(子字符串,开始位置索引值,结束为止索引值)
- 开始位置索引值和结束位置索引值不写时,默认以整个字符串进行查找
str = "好好学习天天向上啊"
print(str.index("习")) # 3
print(str.index("向上")) # 6 查找的是‘向’这个字的索引值
print(str.index("向下")) # ValueError: substring not found
注意
-
当index函数中的字符个数超过1个时,默认按照最开始的字符进行查找
-
当index函数无法找到对应的子字符串时,会报错
find函数
find函数返回的是某个字符在字符串的索引值
语法格式:find(子字符串,开始位置索引值,结束为止索引值)
- 开始位置索引值和结束位置索引值不写时,默认以整个字符串进行查找
str = "好好学习天天向上啊"
print(str.index("习")) # 3
print(str.index("向上")) # 6 查找的是‘向’这个字的索引值
print(str.index("向下")) # ValueError: substring not found
注意
-
当find函数中的字符个数超过1个时,默认按照最开始的字符进行查找
-
当find函数无法找到对应的子字符串时,会返回-1,有时候可以按照find的返回值进行数据的查找
rindex函数和rfind函数
rindex函数、rfind函数的用法和index函数、find函数一样,但是rindex函数和rfind函数是从右往左
进行查询,返回的是子字符串的索引
count函数
count函数用于计算指定子字符串在字符串中出现的个数
语法结构:字符串.count(子字符串,开始位置索引值,结束位置索引值)
str = "好好学习天天向上啊"
print(str.count("好")) # 2
2、替换字符串
语法结构:replace(旧子串,新子串,替换次数)
注意
-
替换次数不写时,默认全部替换;
-
替换次数不差过子串出现的次数,如果超过了也只会替换出现的所有子串
str = "好好学习天天向下"
print(str.replace("向下", "向上")) # 好好学习天天向上
# 旧字符串出现的次数仅1次 哪怕替换次数给再多也无法替换
3、分割字符串
语法结构:split(分隔符,最大分割次数)
split函数会按照指定分隔符,将字符串拆成一个个小字符串,最后返回的是以字符串形式组成的列表
str = "好好,学习,天天,向上"
print(str.split(",")) # ['好好', '学习', '天天', '向上']
4、字符串合并
语法结构:合并的分隔符.join(可迭代类型)
注意
- 在使用join时,必须保证可迭代类型中的所有数据都是字符串类型
str = "好好 学习 天天 向上"
new_str = str.split(" ")
print(new_str) #['好好', '学习', '天天', '向上']
print("".join(new_str)) #好好学习天天向上
5、字符串转换
(1)capitalize
capitalize() 将字符串的第一个字母大写,同时将其余字母小写,但是对汉字、数字、符号等不做处理
str = "hello world HELLO"
print(str.capitalize()) # Hello world hello
(2)title
title()将所有单词首字母大写 其余字母变小写,但是对汉字、数字、符号等不做处理
str = "hello world HELLO"
print(str.title()) #Hello World Hello
(3)upper和lower
upper()将所有字母全部变为大写,lower()将所有字母变为小写
str = "hello world HELLO"
print(str.lower()) # hello world hello
print(str.upper()) # HELLO WORLD HELLO
6、字符串的删除
(1)字符串两边内容的删除
strip()去除字符串左右两边指定的字符
语法格式:字符串.strip(需要消除的字符)
str = '$$$---hello python$$$'
print(str.strip("$")) # ---hello python
-
strip()中如果不传入参数,则默认去除字符串左右两端的空白(包括制表符\t、换行符\n、空格等)
-
如果strip()中有多个字符,如果字符串中首尾出现了包含在内的字符,则会删除否则不删除,跟如何书写的没有关系
str = '12334hello python41323123'
#字符串首尾出现了123,包含了1、2、3的就删
print(str.strip("123")) # 4hello python4
#字符串首尾出现了1、2、3、4,包含了1、2、、3、4的就删
print(str.strip("1234")) # hello python
print(str.strip("4123")) # hello python
(2)字符串某一边内容的删除
-
rstrip()表示删除字符串右边的指定内容;
-
lstrip()表示删除字符串左边的指定内容
str = '12334hello python41323123'
print(str.rstrip("1234")) # 12334hello python
print(str.lstrip("1234")) # hello python41323123
7、字符串的判断
判断即判断字符串是否满足某种规则,返回值是布尔型True或False
(1)startwith和endwith
-
startwith即判断字符串是否以某个字符开头
-
endwith即判断字符串是否以某个字符结尾
(2)is判断
方法名 | 解释 |
---|---|
isalnum() | 判断是否全部为数字或字母 |
isspace() | 判断是否全部为空格 |
isnumeric() | 判断是否全部为数字(可以辨别中文的数字四、肆,阿拉伯数字4) |
isdigit() | 判断是否全部为数字 |
isdecimal() | 判断是否全部为数字 |
isidentified() | 判断是否为标识符(命名规则) |
isalpha | 判断是否全部为字母(默认中文当做字母) |
- 如果不希望中文也被认作字母,可以使用encode(‘utf-8’).isalpha()
09 列表
定义:列表名 = [数据1,数据2,数据3,…]
- 列表中可以存储不同的数据类型,如int型、布尔型、浮点型、列表等,但是一般情况下列表中的数据类型是一致的
列表的操作
1、查询
同字符串一样,列表中的值也可以使用索引值进行获取,不过多赘述;
列表的特有方法 in/not in
-
数据 in 列表名:表示查询列表中是否包含这个数据,返回值为布尔型;
-
数据 not in 列表名:表示查询列表中是否不包含这个数据,返回值为布尔型;
2、增加
方法名 | 解释 |
---|---|
append() | 增加指定数据到列表中 |
insert() | 在指定位置增加数据 |
extend() | 在列表的末尾增加数据或增加一个序列 |
append()
append()方法不会产生新的列表,而是在原列表的基础上直接进行修改,默认是在列表的末尾增加数据
extend()
语法结构:列表1.extend(列表2)
注意
-
调用完extend()方法后,列表1的数据会被改写,而列表2的数据不会变
-
如果列表2是一个字符串类型的列表,那么调用完extend()方法后,字符串会被拆分为一个个字符添加到列表1中
insert()
语法格式:列表.insert(插入的位置索引,要插入的对象)
注意:
-
使用insert()插入数据后,原来的索引位上的数据会变成新插入的数据,而后续所有数据的索引位全部加1(即向后移动一位)
-
由于insert()会改变其他数据的索引值,因此使用append()插入数据要更加安全
补充:
- 列表可以进行拼接
list1 = [1,2,3,4,2,4,3]
list1 += [6,7,8,9]
print(list1) # [1, 2, 3, 4, 2, 4, 3, 6, 7, 8, 9]
默认在原有列表的末尾增加指定的列表数据
3、删除
del()
del()函数将数据引用切断,不仅能删除元素更可以删除整个变量
list1 = [1,2,3,4,5]
list2 = [1,2,3,4,5]
del list2[1]
print(list2) # [1, 3, 4, 5]
del list1
print(list1) # name 'list1' is not defined.
- 被删除元素的索引下标必须存在
pop()
pop()函数删除指定索引对应的元素,并返回该被删除的元素
list3 = [1,2,3,4]
print(list3.pop(2)) # 3
print(list3) # [1, 2, 4]
-
pop函数会造成索引值的变化
-
如果不给pop函数传参,默认删除最后的一个元素
-
被删除元素的索引下标必须存在
remove()
remove()删除指定的元素
list4 = [1,2,3,4,2,4,3]
list4.remove(2)
print(list4) # [1, 3, 4, 2, 4, 3]
print(list4.remove(2)) # None
-
remove()函数无法返回被删除的元素;
-
如果列表中有多个与被删除元素相同的元素,remove()函数只会删除从左往右的第一个相同元素
-
被删除元素必须存在
clear()
clear()函数会清空列表
list = [1,2,3,4,2,4,3]
list.clear()
print(list) # []
4、列表遍历
(1)while遍历列表
list = [1,2,3,4,2,4,3]
i = 0
while i < len(list):
print(list[i])
i += 1
(2)for循环遍历列表
list = [1,2,3,4,2,4,3]
for i in list:
print(
推荐使用for循环进行数据容器(字符串、列表、字典等等)的遍历
10 元组
元组使用小括号 ( ),列表使用方括号 [ ]
元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可
- 元组中只包含一个元素时,需要在元素后面添加逗号 ”,“ ,否则括号会被当作运算符使用
tuple1 = (1)
print(type(tuple1)) # <class 'int'>
tuple2 = (1,)
print(type(tuple2)) # <class 'tuple'>
访问元组
元组可以使用下标索引来访问元组中的值
tup1 = ('Google', 'Runoob', 1997, 2000)
tup2 = (1, 2, 3, 4, 5, 6, 7 )
print ("tup1[0]: ", tup1[0]) # tup1[0]: Google
print ("tup2[1:5]: ", tup2[1:5]) # tup2[1:5]: (2, 3, 4, 5)
注意
-
元组是不可增删改的,元组内的数据不可更改
-
count、index、len三个函数依然适用于元组,其含义跟列表中的含义一样
-
for循环遍历元组和for循环遍历列表的语法相同
11 字典
字典是另一种可变数据容器,且可存储任意类型对象;
定义:dic = {key1 : value1, key2 : value2, key3 : value3 }
-
字典的每个键值对用冒号 : 分割,每个对之间用逗号’,'分割,整个字典包括在花括号 {} 中;
-
键必须是唯一的,但值则不必;值可以取任何数据类型,但键必须是不可变的,如字符串,数字。
-
创建字典可以用内置函数dict(),其语法是:dict(键 = 值)
dic = dict(name = 'Alice', age = 20, gende = 'female')
print(dic) # {'name': 'Alice', 'age': 20, 'gende': 'female'}
访问字典中的键或者值
语法结构:
-
字典名[键](获取值)
-
字典名[值](获取键)
tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
print ("tinydict['Name']: ", tinydict['Name']) # tinydict['Name']: Runoob
print ("tinydict['Age']: ", tinydict['Age']) # tinydict['Age']: 7
修改字典
1、增加键值对
语法结构:字典名[键] = 值
dic = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
dic['School'] = "菜鸟教程" # 添加信息
print(dic) #{'Name': 'Runoob', 'Age': 7, 'Class': 'First', 'School': '菜鸟教程'}
2、更改键的值
语法结构:字典名[键] = 新的值
dic = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
dic['Age'] = 8
print(dic) # {'Name': 'Runoob', 'Age': 8, 'Class': 'First'}
3、删除字典中的元素
语法结构:del 字典名[键]
tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
del tinydict['Name'] # 删除键 'Name' 连同值一起删除
print(tinydict) # {'Age': 7, 'Class': 'First'}
12 集合
集合(set)是一个无序的不重复元素序列;集合中的元素不会重复,并且可以进行交集、并集、差集等常见的集合操作。
可以使用大括号 { } 创建集合,元素之间用逗号 , 分隔, 或者也可以使用 set() 函数创建集合
set1 = {1, 2, 3, 4} # 直接使用大括号创建集合
set2 = set([4, 5, 6, 7]) # 使用 set() 函数从列表创建集合
注意
- 创建空集合必须使用set()函数,不能直接定义{ },因为这样是定义空字典
由于集合是无序不重复的特性,因此可以做为去重的方法
list1 = [1,2,3,4,5,3,2,1,3,5,7]
set1 = set(list1)
list2 = list(set1)
print(list2) # [1, 2, 3, 4, 5, 7]
集合的基本操作
1、添加元素
add()
语法格式:集合名.add(单个数据)
add()函数将单个元素添加到集合中,如果元素已存在,则不进行任何操作
set1= set(("Google", "Runoob", "Taobao"))
set1.add("Jingdong")
print(set1) # {'Taobao', 'Jingdong', 'Runoob', 'Google'}
update()
语法格式:集合名.update(参数)
update()函数中的参数可以是列表,元组,字典等,可以添加多个元素进集合
set1= set(("Google", "Runoob", "Taobao"))
set1.update(["Jingdong","Viphome","LOL"])
print(set1) # {'Runoob', 'Jingdong', 'Taobao', 'Google', 'Viphome', 'LOL'}
2、删除元素
(1)remove()
remove()函数将元素从集合中移除,如果元素不存在,则会发生错误
(2)discard()
discard()函数将元素从集合中移除,如果元素不存在,不会发生错误
(3)pop()
pop()函数会随机移除集合中的一个元素,此方法执行结果并不相同,pop()方法会对集合进行无序的排列,然后将这个无序排列集合的左面第一个元素进行删除
方法名 | 解释 |
---|---|
isdisjoint() | 判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False。 |
issubset() | 判断指定集合是否为该方法参数集合的子集。 |
union() | 返回两个集合的并集 |
13 推导式
Python 推导式是一种强大且简洁的语法,可以将一种数据类型转化为另一种数据类型
Python 支持各种数据结构的推导式:
- 列表(list)推导式
- 字典(dict)推导式
- 集合(set)推导式
- 元组(tuple)推导式
列表推导式
列表推导式格式:[表达式 for 变量 in 列表] 或者 [表达式 for 变量 in 列表 if 条件]
names = ['Bob','Tom','alice','Jerry','Wendy','Smith']
new_names = [name.upper()for name in names if len(name) > 3]
print(new_names) # ['ALICE', 'JERRY', 'WENDY', 'SMITH']
字典推导式
字典推导式基本格式:
- { key: value for value in 集合 }
或者 - { key: value for value in 集合 if 条件}
dic = {x: x**2 for x in (2, 4, 6)} #以集合中的数据为键,一定规则为值存放入字典
print(dic) # {2: 4, 4: 16, 6: 36}
集合推导式
集合推导式基本格式:
- { 规则 for 变量 in 集合 }
或 - { 规则 for 变量 in 集合 if conditional }
a = {x for x in 'abracadabra' if x not in 'abc'} #字符串内除去abc的其他字母被写入集合
print(a) # {'d', 'r'}
元组推导式
元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的元组;元组推导式基本格式:
- (expression for item in Sequence )
或 - (expression for item in Sequence if conditional )
a = (x for x in range(1,10))
print(a) # <generator object <genexpr> at 0x000001AF7ECD4040> 这里返回的是生成器对象
print(tuple(a)) # (1, 2, 3, 4, 5, 6, 7, 8, 9) 使用tuple()函数将生成器转化为元组
14 函数
1、函数的定义与调用
函数的定义
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段
我们可以定义一个有自己想要功能的函数,以下是简单的规则:
-
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ();
-
任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数;
-
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明;
-
函数内容以冒号 : 起始,并且缩进;
-
return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None
语法格式:
def 函数名(参数列表):
函数体
return 返回值
函数的调用
函数的调用可以直接使用定义好的函数名(参数) 直接调用
def square_area(lenth,width):
if lenth != 0 and width != 0:
return lenth * width
else:
print("存在0值,数据有误!")
lenth = float(input("请输入长:"))
width = float(input("请输入宽:"))
print("面积为:{}".format(square_area(lenth,width)))
- 函数必须先定义再调用,即调用语句必须在函数定义语句下面,否则会报错
2、参数传递
在Python中,参数是没有数据类型的(不同于java);类型属于对象,对象有不同类型的区分,变量是没有类型的
a=[1,2,3]
a="Runoob"
-
以上代码中,[1,2,3] 是 List 类型,“Runoob” 是 String 类型,而变量 a 是没有类型的,它仅仅是一个对象的引用(一个指针),可以是指向 List 类型对象,也可以是指向 String 类型对象
-
在函数定义时传入的参数叫做形参,只能在函数体内部使用;在调用时传入的参数叫做实参,传入进函数体内部被形参接收
可更改参数与不可更改参数
在 python 中,strings(字符串), tuples(元组), int(整型),float(浮点型) 是不可更改的对象,而 list(列表),dict(字典),set(集合) 则是可以修改的对象。
-
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a;
-
可变类型:变量赋值 la=[1,2,3,4]** 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了
python 函数的参数传递:
- 不可变类型:如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身;如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象;
# 传入可变参数
def change(a):
print(id(a)) # 对象1 id:140710767215400
a = 10
print(id(a)) # 新对象 id:140710767215688
a = 1 # 对象1
print(id(a)) #140710767215400
change(a)
- 可变类型:如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响
def changeme(mylist):
mylist.append([1, 2, 3, 4])
print("函数内取值: ", mylist) # 函数内取值: [10, 20, 30, [1, 2, 3, 4]]
return
mylist = [10, 20, 30]
changeme(mylist)
print("函数外取值: ", mylist) # 函数外取值: [10, 20, 30, [1, 2, 3, 4]]
# 这个mylist实际上是已经被调用changme函数后的列表
位置参数
位置参数即按照位置顺序进行赋值的参数(形参)
def function1(num1,num2,num3):
print(num1,num2,num3)
function1(1,2,3) #1 2 3
- 位置参数的数量必须与函数体定义的参数数量相同,否则会报错
关键字参数
关键字参数就是通过“关键字 = 值”的形式赋值
def function1(num1,num3,num2):
print(num1,num3,num2)
function1(num1 = 1 ,num2 = 2,num3 = 3) # 1 3 2
- 位置参数和关键字参数可以一起使用,但是要注意避免重复赋值
def function1(num1,num3,num2):
print(num1,num3,num2)
function1(1 ,num2 = 2,num1 = 3) #TypeError: function1() got multiple values for argument 'num1'
缺省参数
缺省参数即在定义函数时,给参数一个默认值,如果没有给参数赋值,则参数使用默认值
def func(a,b,c,d = 10):
print(a,b,c,d)
func(a = 1, b = 2, c = 3) # 没有传入d的值因此输出默认d的值 1 2 3 10
func(a = 1, b = 2, c = 3, d = 4) # 传入d的值 会输出传入的值 1 2 3 4
位置不定长参数
语法格式
def 参数名(*args):
函数体
def func(*args):
return args
print(func(1, 2, 3)) # (1, 2, 3)
print(type(func(1, 2, 3))) # <class 'tuple'>
- 使用位置不定长参数时,数据传入函数内部后会被打包成一个元组,并被args接收,且在函数体内以元组的身份参与运算
关键字不定长参数
语法结构
def 参数名(**kwargs):
函数体
def func(**kwargs):
return print(kwargs)
func(a = 1, b =2, c = 3) # {'a': 1, 'b': 2, 'c': 3}
- kargs在传参后会将实参位置未定义参数的关键字转化为字典的形式储存,并保存在kargs中
def func(**kwargs):
print(f"学生信息:{kwargs}")
func(name = "张三", age = 18, gender = '男') # 学生信息{'name': '张三', 'age': 18, 'gender': '男'}
补充
-
形参排布顺序为:位置参数 >> 位置不定长参数 >> 缺省参数 >> 关键字不定长参数
-
调用时,先使用顺序赋值,后使用关键字赋值
3、拆包与组包
(1)组包
组包即将多个数据整合为一个数据容器,赋值给一个变量的过程
a = 1,2,3,4
print(a) # (1,2,3,4) 是一个元组
(2)拆包
拆包即将一个数据容器拆分成多个数据,赋值给多个变量的过程,例如通过循环,取用列表和字典中元素
4、函数的返回值
返回值:将函数内部运算的结果传入函数体外部;使用return关键字搭配使用
语法结构:
-
函数的返回值如果不写或者只写return,默认会返回None
-
在一个函数体中,return后会直接跳出函数体,后面的代码不会被执行
-
return只能返回一个元素,如果想返回多个元素,只能使用数据容器(列表、元组等)
5、变量的作用域
(1)局部变量
在函数体内部定义的变量即局部变量,函数体外即被释放
def sum():
a = 1
b = 2
print(a + b)
sum()
print(a + b) # NameError a和b是局部变量 在函数体外不可使用
(2)全局变量
全局变量一般顶格书写,在函数体内部和外部都可以使用
def sum():
print(a + b)
a = 11
b = 10
sum() # 21
print(a + b) # 21
注意
- 在python中,for循环、if分支中的变量全部都是全局变量
list1 = [9,10,11,12,13,14,15,16]
for i in range(0,8):
print(list1[i])
print(i) # 7 最后一次循环的临时变量值
if True:
a = 1
print(a) # 1
(3)global关键字
global关键字即声明某个变量为全局变量
a = 100
b = 1
def whatisa():
a = 1 # 局部变量 外部无法使用
global b # 改为全局变量
b = 10
whatisa()
print(a) # 100
print(b) # 10
拓展:在python中,所有的变量都遵循legb原则,即调用变量时的顺序
legb原则
-
l:local
首先在函数体内部查询 -
e:edge
在外部函数中查询 -
g:globa
在全局变量中查询 -
b:buil-in
在系统内部变量中查询
6、引用类型
在Python中,数据分为三个维度:值(判断== )、数据结构(int,float,…)、唯一标识(id),唯一标识可以看做是内存地址
- 值相等,数据结构和唯一标识不一定相等
# 值相等,数据结构和唯一标识不一定相等
# 值相同
num = 0
boole1 = False
print(num == boole1) # True
# 数据结构不同
print(type(num)) # <class 'int'>
print(type(boole1)) # <class 'bool'>
#唯一标识不同
print(id(num)) # 140712513487624
print(id(boole1)) # 140712512019040
- 值和数据结构都相等的,唯一标识不一定相等
# 值和数据结构都相等的,唯一标识不一定相等
# 值相同
list1 = [1,2,3,4,5]
list2 = [1,2,3,4,5]
print(list1 == list2) # True
# 数据结构相同
print(type(list1)) # <<class 'list'>
print(type(list2)) # <class 'list'>
#唯一标识不同
print(id(list1)) # 2439105380224
print(id(list2)) # 2439162217664
- 唯一标识相同,值和数据结构必定相同
# 唯一标识相同,值和数据结构必定相同
# ID相同
str1 = "1234"
str2 = "1234"
print(id(str1)) # 2851893434864
print(id(str2)) # 2851893434864
print(type(str1)) # <class 'str'>
print(type(str2)) # <class 'str'>
print(str1 == str2) # True
补充: 使用is关键字可以判断变量id是否相同
str1 = "1234"
str2 = "1234"
list1 = [1,2,3]
list2 = [1,2,3]
print(str1 is str2) # True
print(list1 is list2) # False
15 文件处理
1、文件的基本操作
(1)打开文件
open()函数可以打开一个已经存在的文件或者创建一个指定文件
语法格式:file = open(name,model)
-
name:目标文件的地址字符串,可以是绝对路径也可以是相对路径
-
model:设置文件的打开方式
model | 解释 |
---|---|
x | 写模式,新建一个文件,如果该文件已存在则会报错 |
r | 以只读方式打开文件,这是默认模式 |
w | 打开一个文件只用于写入;如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除;如果该文件不存在,创建新文件 |
a | 打开一个文件用于追加;如果该文件已存在, 新的内容将会被写入到已有内容之后;如果该文件不存在,创建新文件进行写入 |
# 创建新文件
file1 = open("text.txt", 'w', encoding='utf-8')
# file1.write("1234")
file = open("text.txt", 'r', encoding='utf-8')
print(file.read())
file.close()
(2)文件写入
在读取模式是’w’的前提下,使用file.write(写入内容)可以将需要写入的内容写入进文件;
注意
-
重新执行write()会清空文件中已有的内容
-
写入文件时,必须要保证文件打开的编码格式和文件写入的编码格式一致
-
当要写入多行数据时,可以使用 “”“写入内容”“” 进行写入,此时会将内容和格式一同写入文件
(3)文件读取
在读取模式是’r’的前提下
-
使用file.read(n) 可以将需要写入的文件内容读取出来;其中n代表读取出来的最大字符数,为空默认读取全部数据
-
也可以使用readline() 函数进行读取,它的作用是:读取一整行的数据
file = open("test.txt", 'r', encoding = 'utf-8')
while True:
lines = file.readline() # 一行行读 知道读到空字符串即停止
if lines == "":
break
print(lines) # 空山新雨后,天气晚来秋。
# 床前明月光,疑是地上霜。
- readlines() 的作用是:读取所有的文件以 【\n】为分隔符 , 将所有的行以字符串元素的方式保存到列表当中进行返回
file = open("test.txt", 'r', encoding = 'utf-8')
lines = file.readlines()
print(lines) # ['空山新雨后,天气晚来秋。\n', '床前明月光,疑是地上霜。']
补充:可以使用os模块中的相关功能对文件进行重命名和删除功能
-
重命名:os.rename(旧文件名称,新文件名称)
-
删除:os.remove(文件名);删除文件时不会返回任何提示信息,而且不出出现在系统回收站中,此操作需谨慎(一般建议对需要删除的文件进行备份)
2、文件夹处理
Python中的文件夹处理需要使用os模块中的相关功能,在操作文件夹前要导入os模块
import os
(1)创建文件夹
os.mkdir(文件夹名称) ,创建文件夹必须保证此文件夹不存在,否则报错
- 可以创建多级文件夹,但如果上级文件夹不存在则会报错
(2)删除文件夹
os.rmdir(文件夹名称),删除文件夹必须保证文件夹存在,否则报错
-
可以删除多级文件夹,但如果上级文件夹不存在则会报错
-
删除文件夹时必须保证文件夹为空,文件夹不是空文件夹会报错
二、面向对象
1 面向对象技术简介
-
类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
-
方法: 类中定义的函数。
-
类变量: 类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
-
数据成员: 类变量或者实例变量用于处理类及其实例对象的相关的数据。
-
方法重写: 如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
-
局部变量: 定义在方法中的变量,只作用于当前实例的类。
-
实例变量: 在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
-
继承: 即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
-
实例化: 创建一个类的实例,类的具体对象。
-
对象: 通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
类的定义
类(Class): 用来描述具有相同的属性和方法的对象的集合
类名的定义要使用大驼峰命名法(每个单词的首字母大写)
语法格式:
class (类名):
类的实例化
语法格式:对象名 = 类名()
class MyClass:
i = 12345
def study(self):
return 'hello world'
# 实例化类
x = MyClass()
# 访问类的属性和方法
print(x.i) # 12345
print( x.study()) # hello world
(1) self关键字
在类中有一个特殊的关键字——self,指向的是实例化对象本身
在类的内部定义方法时会自动传入参数self,调用实例方法时,无需对self进行传值
self的作用
首先看一个例子
class Student(object):
def study(self):
print(self)
s1 = Student()
print(s1) # #<__main__.Student object at 0x000001C70854E7D0>
s1.study() # #<__main__.Student object at 0x000001C70854E7D0>
这里s1和self的地址值相同,意味着调用方法时会将对象本身传入方法内进行使用
self可以在方法内部调用实例所拥有的属性或方法
class Student(object):
def study(self):
print("我在学习")
self.eat()
def eat(self):
print("我在吃饭")
s1 = Student()
s1.study() # 我在学习
# 我在吃饭
s1仅执行了study()方法,但是输出了eat()方法里的内容
(2) 添加和获取对象属性
属性即特征,对象属性既可以在类的外面获取也可以在类里面添加和获取
类外部添加和获取属性
语法结构:
-
添加属性:对象名.属性名 = 值
-
获取属性:对象.属性名
class Student(object):
def eat(self):
print("今天吃了面包!")
s1 = Student()
s1.name = "zhangsan"
print(s1.name) # zhangsan
s2 = Student()
s2.age = 18
print(s1.age,s2.name) #AttributeError: 'Student' object has no attribute 'age'
s1.name = "liis"
print(s1.name) # liis
print(s1.__dict__) # {'name': 'liis'}
-
对象被创建后,添加实例属性不会对其他对象造成影响
-
使用 对象名.属性名 = 值 ,如果当前对象属性存在,则会重新赋值;如果不存在,则会创建一个对象属性
-
使用
对象名.__dict__
可以查看对象中的属性和对应的值,结果存储在一个字典中
类内部添加属性
语法结构
-
添加属性:self.属性名 = 值
-
获取属性:self.属性名
class Student(object):
def add_attr(self):
self.name = "xiaoming"
self.age = 19
self.gender = "女"
s1 = Student()
s1.add_attr()
print(s1.name,s1.age,s1.gender) # xiaoming 19 女
s1.name = "gaiguo"
print(s1.name) # gaiguo
-
在内部添加实例属性后,要在外部调用才能被传入
-
在类的外部可以更改内部添加的实例属性
-
在内部添加实例属性也不会影响对象之间的关系
(3) 魔术方法
魔术方法一般是系统特定时机自动调用的函数或者方法,绝大多数情况下不需要手动调用
一般格式:
__func__()
1 __init__()方法
在对象创建完成后,初始化对象自动调用的方法
class Student(object):
def __init__(self):
print("直接调用")
s1 = Student() # 直接调用
只需实例化对象,不需要手动调用,init方法自动调用
2 带参的__init__方法
class Student(object):
def __init__(self,name,age):
print(name,age)
# s1 = Student("jack") # TypeError: Student.__init__() missing 1 required positional argument: 'age'
# s1 = Student("jack",16,18) # TypeError: Student.__init__() missing 1 required positional argument: 'age'
s1 = Student("jack",16) # jack 16
- 如果
__init__
方法内提供了参数,那么在实例化对象时必须传入相同数量的参数(不包括self的其他参数数量),否则会报错
class Student(object):
def __init__(self,name,age):
self.name = name
self.age = age
s1 = Student("jack",16)
print(s1.name,s1.age) # jack 16
s2 = Student("jack",18)
print(s2.name,s2.age) # jack 18
使用 self.参数名 = 参数名 可以实现动态传递,此时必须给每个变量单独赋值或者给默认值,否则会报错
3 __str__
方法
__str__
方法是数据被转换为str类型时自动调用的方法,且只能返回字符串类型
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"姓名:{self.name},年龄:{self.age}"
s1 = Student("jack", 16)
# 直接输出s1 输出的是内存地址
# print(s1) # <__main__.Student object at 0x000001B72F941350>
# 重写__str__方法后 再输出
print(s1) # 姓名:jack,年龄:16
自动调用__str__
方法的场景
-
强制类型转换:str(对象)
-
隐式类型转换:%s占位符,接收对象
2 面向对象三大特征
面向对象的三大特征即封装、继承和多态
-
封装:将属性和方法写到类中的操作即为封装,封装可以为属性和方法添加私有权限;
-
继承:子类默认继承父类所有的属性和方法,子类也可以重写父类的属性和方法;
-
多态:多态必须在继承的条件下才能实现,不同对象调用同一方法或接口,表现不同的状态
1、封装
将属性和方法写入类的内部可以使实例获得较为全面的功能,并可以为属性和方法添加私有权限,保证接口的安全性
封装的优点
-
可以让一个对象完成所有的功能或业务,同时代码维护和迭代也较为方便;
-
可以设置私有属性和私有方法,提高代码安全性;
-
降低模块或者类的使用难度,暴露少量接口即可完成全部功能
私有属性和私有类
属性或者方法只能在类内部调用而无法在类外部调用时,该类或方法成为私有类或私有方法
语法格式:__属性
或者 __方法
class Student(object):
def drive(self):
print("开着敞篷车")
def shopping(self):
self.drive()
print("购物去")
s1 = Student()
s1.drive() # 开着敞篷车
此时 dirve()只是一个中间方法,不会单独使用,因此将其私有化
class Student(object):
def __drive(self):
print("开着敞篷车")
def shopping(self):
self.__drive()
print("购物去")
s1 = Student()
# s1.drive() # AttributeError: 'Student' object has no attribute 'drive'
# 此时已无法再类外部使用drive()方法
s1.shopping()
# 开着敞篷车
# 购物去
使用__dict__
查看私有属性,私有属性一定带有类名
class Student(object):
def __init__(self,name,age):
self.name = name
self.__age = age # 私有属性
s1 = Student("张三",18)
print(s1.__dict__) # {'name': '张三', '_Student__age': 18}
私有属性的获取与修改
如果一个数据只能存储数据而无法被获取到,那么这个数据存储方案将毫无意义;在Python中,使用get()和set()方法进行私有属性的获取与设置
class Student(object):
def __init__(self,name,age):
self.name = name
self.__age = age
def get_age(self):
return self.__age
def set_age(self,age):
self.__age = age
s1 = Student("张三",18)
print(s1.get_age()) # 18
s1.set_age(81)
print(s1.get_age()) # 81
使用set()方法时,不需要直接调用私有属性
因此,使用get()和set()方法可以对私有属性进行赋值,并在类的外部进行使用
使用get()和set()方法的意义
-
某些数据在存入或者提取时,不能直接全部显示,也不能无法被调用,此时需要按照一定的规则进行加工,这时get()和set()方法就显得极为方便:例如:身份证号中间数字脱敏,电话号脱敏
-
存入数据逻辑可以变化:例如存入性别时,可以有如下四个值:0、1、男、女,使用get()和set()方法后可以进行完全统一,不管如何输入都可以统一存放
2、继承
为了体现类的共性与个性,需要使用继承
语法结构
# 父类
calss B(object):
pass
# 子类
class A(B)
pass
在python中支持多继承,即一个类可以继承多个其他类
(1)单继承
单继承:一个子类继承一个父类,并且可以多级继承
所谓多级继承,即被继承的父类可以是其他类的子类 (孙子类–>父类–>爷爷类)
class Perrson(object):
def __init__(self,name,age):
self.name = name
self.age = age
class Father(Perrson):
def shout(self):
print("Man!")
def dance(self):
print("What can I say?")
class Son(Father):
pass
s1 = Son("张三",23) # 因为 Son 继承了Father Person 类,且Person类传入了参数 因此实例化对对象时要传参
s1.shout()
s1.dance()
-
在类Son中,并没有写入其他方法,但是对象s1可以使用父类Father和Person中的公有方法;如果父类中的是私有方法,子类无法调用
-
如果父类或者更高级的继承类中实现了
__init__
方法,并书写了参数,则实例化对象时必须传入参数,且数量不得有误 -
使用
类名.__mro__
可以输出类的继承链条,同时这个顺序也是方法或者属性查找的顺序
(2)多继承
多继承:一个类定义时继承了多个父类,可以同时使用多个父类中的方法或者属性
语法结构 : class 子类名(父类名1,父类名2…)
class Person(object):
def sing(self):
print("我要唱歌")
class Father(object):
def shout(self):
print("Man!")
def dance(self):
print("What can I say?")
class Son(Person,Father):
pass
s1 = Son()
s1.sing() # Person类中的方法
s1.shout() # Father类中的方法
s1.dance() # Father类中的方法
当多个父类中,拥有相同的方法时,会优先调用继承位置更靠前的父类中的方法
class Person(object):
def shout(self):
print("我要唱歌")
class Father(object):
def shout(self):
print("Man!")
def dance(self):
print("What can I say?")
class Son(Person,Father): # Person类的继承位置更靠前
pass
s1 = Son()
s1.shout() # 我要唱歌
s1.dance() # What can I say?
3、多态
多态即子类重写父类中的方法,调用不同子类的相同父类方法,产生不同的执行结果
要求
- 多态必须依赖继承
- 子类必须重写父类的方法
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
class Father(Person):
def shout(self):
print("Man!")
class Son(Father):
def shout(self):
print("What can I say!")
def __init__(self): # 重写__init__方法后,哪怕父类中有参数子类也不需要再传入参数
pass
s1 = Son()
s1.shout() # 重写了父类的方法
3 异常、模块和包
1、异常
(1)异常捕获
语法结构
# 如果try中的代码出现异常则执行except中的代码,否则执行try中的代码
# 想要捕获多个异常:如果异常类型超过两个则添加括号,否则不添加
# 使用 as 变量 可以将异常信息传递到变量中,打印这个变量可以获取异常的详细信息
try:
可能发生异常的代码
except (可能出现的异常类型) as 变量:
出现异常后执行的代码
# 或者在try后面添加多个except
try:
可能发生异常的代码
except 可能出现的异常类型1 as 变量:
出现异常后执行的代码
except 可能出现的异常类型2 as 变量:
出现异常后执行的代码
except 可能出现的异常类型3 as 变量:
出现异常后执行的代码
...
try:
print(a)
print(1/0)
except(ZeroDivisionError,NameError) as error:
print(error) # name 'a' is not defined
如果不知道具体的异常信息,可以直接使用 except Exception 捕获所有异常的父类,它包括了所有的异常
try:
print("a" + 3) # TypeError
print(a)
print(1/0)
except(ZeroDivisionError,NameError) as error:
print(error)
except Exception:
print("不知道具体的异常,但是能捕获") # 不知道具体的异常,但是能捕获
(2)else…finally
语法格式
try:
可能发生异常的代码
except:
出现异常后执行的代码
else:
try中没出现异常则执行的代码
finally:
无论是否出现异常都会执行的代码
try:
print("a" + 3)
print(a)
print(1/0)
except(ZeroDivisionError,NameError) as error:
print("出现异常")
else:
print("没出现异常")
finally:
print("无论出不出现异常都会执行")
print("能执行吗?") # TypeError: can only concatenate str (not "int") to str
# 无论出不出现异常都会执行
上述例子中
-
出现了TypeError,但是并未捕获到,所以else的语句无法执行;
-
由于未捕获异常,因此程序崩溃,未缩进的print()语句无法执行;
-
但是哪怕是程序崩溃,finally中的语句都会被执行
2、模块
模块(Module)就是一个.py文件,包含了Python对象定义和Python语句;模块能定义函数、类和变量,也包含了可执行的代码
(1)模块的导入方式
- import 模块名 as 别名
- from 模块名 import 功能名 as 别名
- from 模块名 import * (导入这个模块中的全部功能)
(2)自定义模块
自定义模块中可以书写很多内容,但是导入时会将所有内容执行一遍;
自定义模块导入其他文件中、全局变量、函数和类;
自定义模块的注意事项:
- 自定义模块的命名必须符合标识符命名规则;
- 自定义模块的命名不能与系统模块重名
- 自定义模块要见名知意
__name__
__name__
的作用是:说明当前文件执行的模块名
如果__name__
的结果是__main__
,这说明是在当前文件中打开;如果__name__
的结果是__main__
结果是其他文件名,则说明是在导入模块中打开
# model.py
a = 10
print(a) # 10
print(__name__) # __main__
# model_new.py
import model
# 10
# model
__all__
__all__
表示控制import的功能列表
语法结构:__all__
= [功能名1,功能名2…],不包含在[]内的功能列表无法被导入使用
3、包
包就是一个文件夹,该文件夹下包含很多有联系的模块还有一个名为__init__.py
的文件,包的本质依然是模块,
导包的方法:
- import 包名.模块名
- from 包名 import 模块名
- from 包名.模块名 import 功能名
在__init__
.py文件中通过__all__
= [] 控制import * 导入的内此时不会完全导入* 而是导入[]内的内容