Python
1.快速入门
在命令行界面输出hello wold
2.PyCharm使用技巧
删除当前行:Delet + Shift
快速格式化代码:Ctrl + alt + L
查看类的层级关系: Ctrl + H
撤回:Ctrl + Z
\“ : 代表一个双引号
\t : table
多行注释:''' ''' 或者 ”“” “”“
如何查看Python文档:3.11.8 Documentation
3.变量
type(a) 输出a的类型
4.格式化输出
%操作符
name = "Zhang Kewei" age = 20 gender = 'Man' score = 88.88 print("Personal Information : %s %d %s %.2f" %(name,age,gender,score))
format()函数
print("Personal Information : {} {} {}{}".format(name,age,gender,score))
f-strings
print(f"Personal Information : {name} {age} {gender} {score}")
5.加号的使用
在两边都是数值型的时候,会做加法运算
score = 50 print(score + 20)
在两边都是字符串的时候,会做拼接运算
name = 'Zhang' print(name + 'Kewei')
通过type函数查看数据类型
6.整数类型
9 ** 2 代表的是9的2次方
python的整数有十进制八进制二进制
十六进制:前缀加0x
八进制:前置加0o
二进制:前缀加0b
Python的整形是变长的,每次增加4个字节
可以通过sys.getsizeof 查看对象的大小
7.浮点数
5.12e2 代表5.12✖10的二次方
如何避免浮点数的精度问题?
可以使用Decimal类,要先导入
from decimal import Decimal
8.字符串类型
若字符串内存在双引号,可以用单引号引起来输出
str1 = 'tom said:"Hello Python"'
输出比较复杂的格式的时候,可以用三个单引号''''''或者三个双引号""""""来输出,例如输出一些代码的时候,会保持字符串原样输出
在整个字符串前面加上'r',可以使整个字符串不被转义
9.字符串驻留机制
说明:
Python仅保存一份相同且不可变字符串,不同的值被存放在字符串的驻留池中,Python的驻留池机制对相同的字符串只保留一份拷贝,后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新的创建变量.
好处:当需要的值相同的字符串时,可以直接从字符串池中拿出来使用,避免频繁的创建和销毁,提升效率和节约内存
原因:因为内容一样,计算机会认为浪费效率,所有会不生产地址,直接指向相同的数据,这就是驻留机制
id()函数,可以返回对象/数据的内存地址
驻留机制的几种情况
-
字符串是由26个英文字母大小写,0~9,_组成
-
字符串长度为0或者1时
-
字符串在编译时进行驻留,而非运行时
-
[-5,256]的整数数字
PyCharm对字符串进行了优化处理
但是在Win+R中也可以通过sys中的intern方法,强制2个字符串指向一个对象
s2 = sys.intern(s1)
10.数据类型转换
隐式类型转换:Python变量的类型不是固定,会根据变量值在运行时决定的
在运算时,数据类型回向刚精度自动转换
显式类型转换:int(x) 将x强制转换成int类型
注意:对一个变量进行强制转换,会返回一个数据/值,但并不会影响到原变量指向的数据/值的数据类型
11.算数运算符
%:取余 运算公式:a%b = a - a //b * b
//:取整数部分
**:返回x的y次幂
12.逻辑运算符
a = 10 b = 20
and:如果x为true,则返回y的值,若为false,则返回x的值
x and y = 20
or:如果x为true,则返回x的值,若为false,则返回y的值
x or y = 10
not:如果x为true,则返回false,为false则返回true
13.赋值运算符
复合运算符:+= ---> c+=a == c = c + a
平常交换两个值的量: a = 1 b = 2 temp
temp = a a = b b = temp
Python中有个简单的方法支持变量交换
x , y = y , x
特殊方法
a = 1 b = 2
a = a + b
b = a - b
a = a - b
14.三元运算符
a = 100 b = 200 max = a if a>b else b print(max)
求三个值中的最大
a = 400 b = 500 c = 300 MAX1 = a if a>b else b MAX2 = MAX1 if MAX1>c else c print(MAX2)
15.运算符的优先级
算数运算>位运算>比较运算>逻辑运算>赋值运算
16.键盘输入
input
从控制台接受到的数据类型是String类型
直接转成需要的类型:
age = int(input("请输入年龄"))
17.进制
十进制如何转换二进制:将该数不断除以2,然后将每步的余数倒过来,就得到了二进制结果
其余的,跟次操作步骤类似
print(bin(32)) #二进制 print(oct(131)) #八进制 print(hex(237)) #十六进制
二进制如何转八进制:将二进制每三位一组,转成对应的八进制数即可
十六进制则是每四位一组
八进制如何转换二进制:将八进制每一位数,转换成3位的二进制即可
18.原码补码反码
1.二进制的最高位是符号位:0表示正数,1表示负数
例:3 => 0000 0011 -3 => 1000 0011
2.正数的原码,反码,补码都一样
3.负数的反码=它的原码符号位不变,其他位取反
例: -3 => 1111 1100(反码)
4.负数的补码=它的反码+1,负数的反码=负数的补码-1
例: -3 => 1111 1101(补码)
5. 0的反码,补码都是0
*6.在计算机运算的时候,都是以补码的方式来运算的
解读: 1 + 3 =? 1 =>补码:0000 0001 3 =>补码:0000 0011 1+3=> 0000 0100 (补码) 1 - 3 =? -3 =>原码:1000 0011 (通过原码算反码) 反码:1111 1100 (通过反码+1算补码) 补码:1111 1101 1+(-3)= 1111 1110(补码) 最后运算结果看他的原码 反码:1111 1101 算出原码:1000 0010 把加法和减法合二为一
7.当我们看运算结果的时候,要看他的原码
19.位运算
1.~按位取反
//规则:对数据的每个二进制位取反,即1变0,0变1(对补码取反,然后转换成原码输出)
2.&按位与
//规则:参与运算的两个值,如果两个相应位都为1,则该为位结果位1,否则位0
3.^按位异或
//规则:当两个对应的二级制位相异时,结果位1
4.|按位或
//规则:只要对应的二个二进制位有一个为1,结果就为1
5.<<左移
//规则:运算数的各二进制位全部左移若干位,由“<<”右边的数指定移动的位数,符号位不变,高位丢弃,低位补0 左移相当于X2
6.>>右移
//规则:运算数的各二进制位全部右移若干位,由“>>”右边的数指定移动的位数,符号位不变,低位溢出,用符号位补溢出的高位 右移相当于÷2
20.分支控制
1.单分支
*Python中首行缩进很重要,是用来界定代码块的
*最短的缩进对较长的缩进有包含关系
2.双分支
year = int(input("请输入年份")) if (year%4==0 and year%100 !=0)or year%400 ==0: print("该年是闰年") else:print("该年不是闰年")
3.多分支
score = int(input("小头儿子的期末成绩为:")) if score == 100: print("奖励一辆BMW") elif 80 < score <= 99: print("奖励一台IPhone15 Pro Max") elif 60 <= score <= 80: print("奖励一个ipad") else:print("你学了个P")
4.嵌套分支
season =str(input("现在是旺季吗")) age = int(input("你的年龄是多少")) if season == "Yes": if age <18: print("20") elif 18<= age <=60: print("60") elif age>60: print("30") else: if age>18: print(40) else:print(20)
21.循环控制
1.for循环
代码执行内存分析法:
在nums中存了10个地址,每个地址指向对应的数值
i不停的从nums中依次取值赋给i
range()函数:可以生成数列
range(start,stop,step=1) start默认为0,step默认为1
for i in range(1,11): print("Hello Python",i)
for和else结合使用:for完成正常遍历且不被打断,会进入else
for i in range(1,11): print("Hello Python",i) else: print("没有循环数据了")
2.while循环
#一直输入姓名,直到输入exit为止 name = str(input("输入你的姓名")) while name != "exit": name = str(input("输入你的姓名")) else: print("success")
i = 0 num = int(input("请输入一个整数")) while i <= num: print(f"{i}+{num - i} = {num}") i += 1
3.多重循环控制
一般使用两层,不建议超过三层,否则代码可读性不好
实质上,嵌套循环就是把内存循环当成外层循环的循环体
#接受一个整数,形成对应层数的空心金字塔 i = 0 j = 0 num = int(input("请输入一个数字")) # i控制层数 for i in range(num + 1): # 输出空格数 K for k in range(num - i): print(" ", end="") for j in range(2 * i - 1): # 这里的end=“”表示输出不换行 if j == 0 or j == 2 * (i - 1) or i == num: print("*", end="") else: print(" ", end="") # 每层输出后,换行 print("")
4.break语句
怎么随机生成整数:random.randint(x,y)
#注意,使用random需要提前导入random包 import random count =0 while True: n = random.randint(1,100) count += 1 if n == 97: break print(f"次数为:{count}")
break只会结束最近的外层循环,只要执行了break中断,就不会继续执行else
如果一个for循环被break终结,该循环的控制变量会保持其当前值
nums = [1,2,3,4,5,6] for i in nums: if i > 3: break print("i=",i)
登录状况:
count = 3 # 登录三次 for i in range(1, 4): name = input("请输入登入名") pwd = input("请输入密码") count -= 1 # 判断是否成功 if name == '张柯威' and pwd == '888': print("登录成功") break else: print(f'你还有{count}次登录机会')
5.continue语句
一旦执行到continue,就会停止本次循环,进行下一轮的循环
6.return语句
return使用在函数,表示跳出函数,整个函数剩下的代码,都不会执行
过路口代码
count = 0 while True: if money > 50000: money = money - money * 0.05 count += 1 elif money >= 1000: money = money - 1000 count += 1 else: break print(f"可以过{count}次数")
22.函数入门
-
函数代码块以def关键词开头,后接函数标识符名称和圆括号()
-
函数内容以冒号:起始,并且缩进
-
函数参数(a,b)可以有多个,也可以没有,其被称为形参列表
-
函数可以有返回值,也可以没有,如果没有return相当于与返回None
23.函数的调用机制
每调用一次函数都会生成一个新栈
可以按关键字传参
def book_info(name,price,author,amount): print(f"name->{name} price->{price} author->{author} amount->{amount}") book_info(name='红楼梦',price=60,amount=30000,author="曹雪芹") #理论上来说,在第三个参数位置应该是author,但是通过关键字传参,可以改变位置,如果位置对应,可以不用写关键字
函数支持默认参数/缺省参数
#即在设置参数时加上等号,若不传参则按默认值呈现 def book_info(name='红楼梦',price='100',author='CaoXueqing'): print(f"name->{name} price->{price} author->{author}") book_info() #默认参数要放在参数列表的最后,不然会报错
函数支持可变参数/不定长参数
#*号代表0到多 def sum(*args): print(f"agrs->{agrs} 类型是->{type(args)}") total = 0 #对args进行遍历,即对元组遍历 for ele in args: total += ele return total #调用测试 result = sum(1,2,3) print(f"result->{result}")
传入的多个关键字,会被组成一个字典(dict)
#写两个* def sum(**args): print(f"kwargs->{agrs} 类型是->{type(args)}") for arg_name in args: print(f"参数名->{arg_name} 参数值->{args[arg_name]}")
24.函数传参机制
字符串,数值类型的基本传参机制
#字符串和数值类型是不可变数据类型,当对应的变量的值发生了变化时,它对应的内存地址会改变 def f1(a): print(f"f1() a的值:{a} 地址是:{id(a)}") a += 1 print(f"f1() a的值:{a} 地址是:{id(a)}") # 定义变量a = 10 a = 10 print(f"f1() a的值:{a} 地址是:{id(a)}") # 调用f1(a) f1(a) print(f"f1() a的值:{a} 地址是:{id(a)}")
函数内的传参,不会影响到函数外的参数
什么是可变数据类型?什么是不可变?
若a=10,其地址为0x1122,将a改为a=11 其地址还是0x1122,为可变类型
容器传参机制,比如列表元组等
25.函数的递归调用
简单的说:就是函数自己调用自己,每次调用时传入不同的值
新调用的函数输出完后,会返回上一个调用的函数并执行剩下的语句
递归的重要规则
-
执行一个函数时,就创建一个新的空间(栈空间)
-
函数的变量是独立的,比如n变量
-
递归必须向退出递归的条件逼近,否则就是无限递归,出现RecursionError:maximum recursion depth exceeded
-
当一个函数执行完毕,或遇到return,就会返回,遵守谁调用,就将结果返还给谁
26.递归练习
猴子吃桃,每次吃一半并且多吃一个,第10天,还没吃就剩下一个了,求桃子数
def peach(day): if day == 10: return 1 else: return (peach(day + 1)+1)*2 print(peach(1))
汉诺塔
def hanoi_tower(num, a, b, c): if num == 1: print("第1个盘从:A->C") else: # 有多个盘,我们认为只有两个,上面所有的盘和最下面的盘 # 移动上面所有的盘到B柱子,这个过程会用到C柱子 hanoi_tower(num - 1, a, c, b) # 移动最下面的盘 print(f"第{num}个盘从:{a}->{c}") # 把上面所有的盘从B柱子移动到C柱子,过程中使用A柱子 hanoi_tower(num - 1, b, a, c) hanoi_tower(3, "A", "B", "C")
27.函数作为参数传递
def get_max_val(num1, num2): max_val = num1 if num1 > num2 else num2 return max_val def f1(fun, num1, num2): return fun(num1, num2) def f2(fun, num1, num2): return num1 + num2, fun(num1, num2) print(f1(get_max_val, 50, 20)) x, y = f2(get_max_val, 10, -20) print(f"x = {x} y = {y}")
-
函数作为参数传递,传递的不是数据,而是业务处理逻辑
-
一个函数,可以接收多个函数作为参数传入
28.lambda匿名函数
如果我们需要将函数进行传递,但是这个函数只使用一次,可以使用lambda匿名函数
1.lambda a,b:a if a>b else b就是匿名函数 2.不需要return,运算结果就是返回值
29.变量作用范围
# n1 就是全局变量 n1 = 100 def f1(): # n2就是局部变量 n2 = 200 print(n2) # 可以访问全局变量n1 print(n1) #调用 f1() print(n1) # 不能访问n2
在函数内未重新定义n1,那么默认使用全局变量n1;若在函数内部重新定义了n1,那么根据就近原则,使用的就是函数内部重新定义的n1
n1 = 100 def f1(): n1 = 200 print(n1) --->200 f1() print(n1) --->100
在函数内部使用global关键字,可以标明指定使用全局变量
n1 = 100 def f1(): global n1 n1 = 200 print(n1) --->200 f1() print(n1) --->200
30.数据容器概述
关于调节保留多少个小数
round(?,2) ? = 数值 2 = 保留的个数
分类:列表(list),元组(tuple),字符串(str),集合(set),字典(dict)
31.列表基本使用
用len()可以查看列表内的元素个数
list1 = ['red', 'green', 'blue', 'yellow', 'while', 'black'] index = 0 while index < len(list1): print(list1[index]) index += 1
list1 = ['red', 'green', 'blue', 'yellow', 'while', 'black'] for element in list1: print(element)
用列表解决养鸡场问题
hens = [3,5,1,3.4,2,50] total_weight = 0.0 for ele in hens: total_weight += ele print("总体重是",total_weight) avg_weight = total_weight/len(hens) print("平均体重是",avg_weight)
32.列表使用细节
-
如果我们需要一个空列表,可以通过[]或者list()来创建
-
列表元素可以有多个,而且数据类型没有限制,允许有重复的,并且是有序的
-
列表的索引和下标是从0开始的
-
列表索引必须在指定范围内使用,否则:IndexError:list index out of range(数组越界)
-
索引也可以从尾部开始取,尾部第一个索引为-1,以此类推
-
通过 列表[索引] = 新值 对数据进行更新,使用 列表.append(值) 方法来添加元素,使用del来删除元素
-
列表是可变序列
list1 = [1,2.1,'张柯威'] print(f"list:{list1} 地址:{id(list1)} {id(list1[2])} {list1[2]}") list1[2] = 'python' print(f"list:{list1} 地址:{id(list1)} {id(list1[2])} {list1[2]}") #注:修改的元素的地址发生了变化,所说的地址没有变化是指列表的地址没有变化
-
扩展:列表在赋值时候的特点
list1 = [1,2.1,'张柯威'] list2 = list1 print("list2=",list2) print("list1=",list1) #通过list2会影响到list1
-
扩展:列表在传参时候的特点
def f1(l): l[0] = 100 print("l的id:", id(l)) list10 = [1, 2.1, 200] print("list10的id:", id(list10)) f1(list10) print("list10:", list10) #新栈中的l也会指向list10的地址
33.列表的常用操作
len(list):列表元素个数
max(list):返回列表元素最大值
min(list):返回列表元素最小值
list(seq):将元组转换为列表
list.count(obj):统计某个元素出现的次数
list.extend(seq):在列表某位一次性追加另一个序列中的多个值
list.index(obj):从列表中找出某个值第一次出现在列表中的索引
list.reverse:反转列表
列表生成式
[列表元素的表达式 for 自定义变量 in 可迭代对象] [ele * 2 for ele in range(1,5)] #得到列表-->[2,4,6,8] [ele + ele for ele in "张柯威"] #得到列表-->["张张","柯柯","威威"]
输入五个成绩,然后输出
scores = [] for i in range(5): score = float(input("请输入成绩")) scores.append(score) print(scores)
33.元组的基本属性(tuple)
1.元组可以存放多个不同类型数据,元组是不可变序列
也就是说tuple不可变是指当你创建了tuple的时候,它就不能改变了,也就是说它也没有append(),insert()这样的方法,但它也有获取某个索引值的方法,但不能重新赋值
2.元组也是一种数据类型
#定义一个元组 tuple_a = (100,200,300,400,500) tuple_b = ('rea','green','blue','yellow')
34.元组使用注意细节
1.需要一个空元组,可以用(),或者tuple()来定义
2.元组的元素可以有多个,而且数据类型没有限制,允许有重复元素,并且是有序的
3.元组索引必须在指定范围内,否则:IndexError:tuple index out of range
4.元组是不可变序列
5.可以修改元组内list的内容
6.元组也可以最后一个元素的索引为-1,往前一位为-2
7.元组和列表的区别
1.在项目中,尤其是多线程环境中,有经验的程序员会考虑使用不变对象(一方面是因为对象状态不能修改,所以可以避免由此引起的不必要的程序错误;另一方面一个不变对象自动就是线程安全的,这样就可以省略掉处理同步化的开销,可以方便的被共享访问)。所以,如果不需要对元素进行添加,删除,修改的情况下,可以考虑使用元组
2.元组在创建时间和占用空间上面都优于列表
3.元组能够对不需要修改的数据写保护
35.元组的操作和练习
1.用 x in tuple_a 可以判断x是否在元组中
2.通过 del tuple_movie[3] [1] 来删除元素
3.通过tuple_movie[3].append来添加元素
36.字符串基本使用
1.说明:在Python中处理文本数据是使用str对象,也称为字符串,字符串是Unicode码构成的不可变序列
2.用ord(字符),可以查看对应的码值
3.字符串是不可变序列,不能修改
4.在Python中,字符串长度没有固定的限制,取决于计算机内存大小
37.字符串常用方法
注:返回字符串的副本,表示原来的字符串不变,而是返回一个新的字符串
字符串的比较
比较规则:首先比较两个字符串中的第一个字符,如果相等则继续比较下面的字符,直到字符不相等时,其比较结果也就是两个字符串的比较结果,两个字符串中的所有后续字符将不再比较
比较原理:两个字符串进行比较的时候,是比较其的码值,chr可以通过码值找到对应的字符
练习:
str_names = "tom jack mary nono smith zkw" str_names_list = str_names.split(" ") print(f"一共有{len(str_names_list)}个人名") str_names_re = str_names.replace("zkw","张柯威") print(str_names_re) str_names_upper = "" for ele in str_names_list: if ele.isalpha(): str_names_upper += ele.capitalize() print(f"如果人名是英文,则把首字母改成大写,处理结果是:{str_names_upper}")
38.切片的基本使用
什么是切片:从一个序列中,取出一个子序列,在实际开发中,程序员经常对序列进行切片操作
什么是序列:序列是指,内容连续,有序,可使用索引的一类数据容器
基本语法:
序列[ 起始索引:结束索引:步长]
注:切片操作是前闭后开,也就是截取的子序列,包含起始索引,但不包含结束索引
注:步长表示依次取出元素的间隔。
步长为1:一个一个的取出元素
步长为2:每次跳过一个元素取出
步长为N:每次跳过N-1个元素取出
# 对字符串进行切片 str = "hello,world" # 需求:截取"hello" str_slice = str[0:5:1] print("str_slice:", str_slice) # 对列表进行切片 list_a = ["jack", "tom", "yoyo", "nono", "zkw"] # 需求:截取["tom","nono"] list_slice = list_a[1:4:2] print("list_slice:",list_slice) # 对元组进行切片 tuple_a = (100,200,300,400,500,600) # 需求,截取(200,300,400,500) tuple_slice = tuple_a[1:5:1] print("tuple_slice",tuple_slice)
39.集合的基本使用
定义:集合是由不重复元素组成的无序容器,基本用法包括成员检测,消除重复元素,集合对象支持合集,交集,差集,对称差分等数学运算
1.不重复元素:简单地说,集合中不会有相同的元素
2.无序:集合中元素取出的顺序,和你定义时元素的顺序并不能保证一致
3.既然集合不支持索引,所以对集合进行遍历不支持while,只支持for
4.创建空集合只能用 set(),不能用{ },{ }创建的是空字典
40.集合的常用操作
1.x in s:检测x是否为s中的成员 2.add(elem):将元素elem添加到集合中 3.remove(elem):从集合中移除元素elem,如果elem不存在于集合中,会引发KeyError 4.pop():从集合中移除并返回任意一个元素,如果集合为空则会引发KeyError 5.clear():从集合中移除所有元素 6.union(*others) set|other|... :返回一个新集合,其中包含来自原始集合以及others指定的所有集合中的元素 ---------------------------------------------------------------------------- books = {'天龙八部','笑傲江湖'} books_2 = {'雪山飞狐','神雕侠侣','天龙八部'} books_3 = books.union(books_2) print(books_3) ---------------------------------------------------------------------------- 7.intersectior(*other) set&other&... :返回一个新集合,其中包含原集合以及others所指定的集合中的共有元素(求交集) ---------------------------------------------------------------------------- books = {'天龙八部','笑傲江湖'} books_2 = {'雪山飞狐','神雕侠侣','天龙八部'} books_3 = books.intersection(books_2) print(books_3) ---------------------------------------------------------------------------- 8.difference(*other) set-other-... :返回一个新集合,其中包含原集合以及others所指定的其他集合中的不存在的元素(求差集) ---------------------------------------------------------------------------- books = {'天龙八部','笑傲江湖'} books_2 = {'雪山飞狐','神雕侠侣','天龙八部'} books_3 = books - books_2 print(books_3) ----------------------------------------------------------------------------
41.集合生成式和练习
{ele * 2 for ele in range(1,5)} ==>得到的集合含有2,4,6,8这四个元素
42.字典的基本使用
通过x查询y的需求,是一种映射关系,可以用字典来解决
创建一个字典
dict_a = {key1:value1,key2:value2,key3:value3...} #如何查询? 字典名[key]
注意事项和细节
-
字典的Key通常是字符串或数字,Value可以是任意数据类型
-
字典不支持索引,会报错KeyError
-
既然字典不支持索引,所以对字典进行遍历不支持while,只支持for,对字典进行遍历,得到的是Key
#遍历方式1 - 依次取出key,再通过dict[key]取出对应的value for key in dict_b: print(f"key:{key} value:{dict_b[key]}") #遍历方式2 - 依次取出value for value in dict_b: print(f"value:{value}") #遍历方式3 - 依次取出key-value for key,value in dict_b.items(): print("key:{key} value:{value}")
-
空字典通过{}或者dict()创建
-
字典的key必须是唯一的,如果指定了多个相同的key,后面的键值会覆盖前面的
43.字典的常用操作
-
len(d):返回字典d中的项数
-
d[key]:返回d中以key为键的项,如果映射中不存在key,则会引发KeyError
-
d[key] = value:将d[key]设为value,如果key已经存在,则会修改value,如果key没有存在则是增加key-value
-
del d[key]:将d[key]从d中移除,如果映射不存在key则会引发KeyError
-
pop(key[default]):如果key存在于字典中,则将其移除并返回其值,否则返回default,如果default未给出且key不存在字典中,则会引发KeyError
-
keys():返回字典的所有的key
-
key in d:如果d中存在键key则返回Ture,否则False
-
clear():移除字典中的所有元素
字典生成式
#1.将两个列表合并 books = ["红楼梦","三国演义","西游记","水浒传"] anthors = ["曹雪芹","罗贯中","吴承恩","施耐庵"] 生成对应字典:{'红楼梦':'曹雪芹','三国演义':'罗贯中'...} #2.内置函数zip() {字典key的表达式:字典value的表达式 for 表示key的变量,表示value的变量 in zip(可迭代对象,可迭代对象)} {book:author for book,author in zip(books,authors)}
44.字典的相关练习
clerks = { "0010":{ "age":20, "name":"贾宝玉", "sal":12000 } }
1.查询员工号(0010),可以查询到的基本信息
print(f"员工号为0010的信息为: 名字{clerks['0010']['name']}")
2.动态的增加一个员工
clerks['0020'] = { "0010":{ "age"19, "name":"张柯威", "sal":12000 } }
3.删除0001员工
del clerks['0001']
4.根据需要修改员工的信息
clerks['0020']['name'] = '张柯威' clerks['0020']['entry_time'] = '2024-4-4' clerks['0020']['sal'] += clerks['0020']['sal']*0.1
5.遍历所有的员工,把所有员工的薪水在原工资上增20%
keys = clerks.keys() for key in keys: clerks[key]['sal'] = clerks[key]['sal']*0.2
45.传参机制
在函数内修改列表会影响到函数外的列表
不可变数据类型:数值类型,布尔,字符串,元组
可变数据类型:列表,集合,字典
46.冒泡排序
#使用冒泡排序排序[24,69,80,57,13]
list1 = [24, 69, 80, 57, 13] def bubble_sort(my_list): """ 功能:将列表内元素从小到大排序 :param my_list: :return: """ # j变量控制比较次数,同时可以作为比较元素的索引下标 for i in range(0, len(my_list) - 1): for j in range(0, len(my_list) - 1 - i): if my_list[j] > my_list[j + 1]: my_list[j], my_list[j + 1] = my_list[j + 1], my_list[j] print(my_list) bubble_sort(list1)
47.顺序查找
#输入名称,判断是否存在,如果存在,则返回下标,没有则提示没有 #names_list = ["白眉鹰王","金毛狮王","紫衫龙王","青翼蝠王"] def seq_search(my_list, find_val): find_index = -1 for i in range(len(my_list)): if my_list[i] == find_val: print("找到了该元素,下标为:", find_index) find_index = i break else: print("没有找到对应的元素") return find_index res_index = seq_search(names_list, find_name) print("res_index:", res_index)
如果有多个,怎么返回?
def seq_search(my_list, find_val): find_index = [] for i in range(len(my_list)): if my_list[i] == find_val: find_index.append(i) return find_index res_index = seq_search(names_list, find_name) print("res_index:", res_index)
48.二分查找
前期是排序好的列表
def binary_search(my_list,find_val): left_index = 0 right_index = len(my_list) - 1 find_index = -1 #初始默认没有找到 # 使用while循环不断折半 while left_index <= right_index: mid_index = (left_index + right_index)//2 if my_list[mid_index] > find_val: right_index = mid_index + 1 elif my_list[mid_index] < find_val: left_index = mid_index + 1 else: find_index = mid_index break return
49.断点调试
F7(跳入) F8(跳过) shift+F8(跳出) F9(resume,执行到下一个断点)
50.模块
模块(module)
#导入模块的指定功能 [from 模块名] import(函数|类|变量|*) #导入多个模块 import 模块1,模块2,... #给导入的模块或者功能取别名 import 模块 as 别名 from 模块 import 函数、类、变量 as 别名
注意事项和细节
1.使用__name__可以避免模块中测试代码的执行 2.使用__all__ = [函数]可以使其他文件通过from调用时,只能调用此函数(对import导入不起用)
51.包
导入:import 包名.模块
使用:包名.模块.功能
注:在使用Python Package创建包时,会生成_init__.py的文件
注意事项和使用细节
1.导入方式 from 包名 import 模块 这种方式导入,在使用模时,模块.功能 不需要带包名 2.导入包的模块的指定函、类、变量 from 包名.模块 import 函数、类、变量
52.第三方库
pip是Python的包管理器,是一个工具,允许你安装和管理第三方库
语法:pip install 库名/包名
如何用pycharm进行安装?
点击右下角的Python 3.11(pythonProject),然后点击interpreter Setting
数据源:-i Simple Index 阿里云
53.类与实例的关系
OOP方式解决小猫问题
# 定义cat类 class Cat: age = None name = None color = None # 通过Cat类,创建实例/对象 cat1 = Cat() # 通过对象名,属性名 可以给各个属性赋值 cat1.name = '小白' cat1.age = '2' cat1.color = '白色'
54.成员方法
# 成员方法的定义 def 方法名(self,形参列表): 方法体 #注:self是定义成员方法时需要写上的,表示当前对象本身,当我们通过对象调用方法的时候,self会隐式的传入。在方法内部,需要用到self,才能访问到成员变量
#成员方法的使用 class Person: name = None age = None def hi(self): print("hi,python") def cal01(self): result = 0 for i in range(1, 1001): result += i print(result) def cal02(self, n): result = 0 for i in range(1, n + 1): result += i print(result) def get_sum(self, x, y): return x + y p = Person() p.hi() p.cal01() p.cal02(10) print(p.get_sum(10,20))
注意事项:Python支持对象动态的增加方法
-
动态的给p对象添加方法m1,注意只是针对p对象添加方法
-
m1是你新增加的方法的名称,有程序员指定
-
即m1方法和函数hi关联起来,当调用m1方法时,会执行hi函数
55.self
如果我们在成员方法内,访问对象的属性/成员变量,该怎么办?-----self
class Cat: name = "波斯猫" age = 2 def info(self, name): print(f"name信息:{name}") # 加菲猫 # 通过self.属性名 可以访问到对象的属性/成员变量 print(f"属性name:{self.name}") cat = Cat() cat.info("加菲猫")
self是定义成员方法时需要写上的,如果不写则需要使用@staticmethod标注
@staticmethod:将方法转为静态方法(不会接受隐式的第一个参数)
静态方法:
-
通过@staticmethod 可以将方法转为静态方法
-
如果是一个静态方法可以不带self
-
静态的方法的调用形式有变化,可用类名调用,也可用属性
self代表当前对象本身,哪个对象调用就代表哪个对象
class Dog: name = "藏獒" age = 2 def hi(self): print(f"hi self:{id(self)}") dog2 = Dog() print(f"dog2:{id(dog2)}") dog2.hi() dog3 = Dog() print(f"dog3:{id(dog3)}") dog3.hi()
练习题
-
定义Person类
-
里面有name,age属性
-
并提供compare_to方法比较,判断是否是一个人
-
年龄和名字都一样,返回ture 否则 false
class Person: age = None name = None def compare_to(self, other): return self.name == other.name and self.age == other.age # 测试 p1 = Person() p1.name = "jack" p1.age = 18 p2 = Person() p2.name = "jack" p2.age = 19 print(p1.compare_to(p2))
56.作用域
我们所说的局部变量一般是指在成员方法中定义的变量,例如:
#n1,n2,result就是局部变量 def cal(self,n1,n2): result = n1 + n2 print(f"result={result}")
属性的作用域是在整个类中 / 局部变量的作用域是在它的方法中
属性和局部变量可以重名,访问时带上self,表示访问的属性,没有带self则是访问局部变量
57.构造方法
具体需求:
-
前面我们在创建Person类的对象时,是先把一个对象创建好后,再给他年龄,名字
-
如果现在我们要求,在创建Person类的对象时,就直接指定这个对象的年龄和姓名
def__init__(self,参数列表) 代码...
class Person: name = None age = None # 构造方法/构造器 # 构造方法是完成对象的初始化任务 def __init__(self, name, age): print(f"__init__执行了{name}{age}") # 1.把接收到的name和age赋给属性 # 2.self就是你当前的属性 print(f"self id:{id(self)}") self.name = name self.age = age p1 = Person("kobe",24) print(f"p1 id:{id(p1)}")
注意事项:
-
一个类中只有一个_ init _方法,即使你写了多个,也只有最后一个生效
-
Python可以动态的生成对象属性
-
构造方法不能有返回值,比如,你返回字符串,会报”TypeError"
58.练习题
# 编写类A01,定义方法max,实现求某个float列表list的最大值并返回 class A01: def max(self,lst): return max(lst) a = A01() print("最大值=",a.max([1.1,2.9,-1.9,67.9])) #编写Book类,定义方法update_price,实现更改某本书的价格,具体:如果价格>150,则改为150,如果>100则改为100,其他不变 class Book: def __init__(self,name,price): self.name = name self.price = price def update_price(self): if self.price > 150: self.price = 150 elif self.price > 100: self.price = 100 def info(self): print(f"书籍的信息是{self.name}{self.price}") book = Book("天龙八部",105) book.info() book.update_price() book.info() # 定义一个圆类Circle,定义属性:半径,提供显示圆周长功能的方法,提供显示圆面积的方法 class Circle: r = None def __init__(self,r): self.r = r def C(self): C = 2 * self.r * 3.14 print("周长:",round(C,2)) def S(self): S = 3.14 * self.r * self.r print("面积:", round(S,2)) cir = Circle(6) cir.C() cir.S() # 创建一个Cal计算类,在其中定义2个成员变量表示两个操作数,定义四个方法实现和,差,乘,除,商(要求除数为0的话,要提醒) class Cal: def __init__(self,num1,num2): self.num1 = num1 self.num2 = num2 def add(self): return self.num1 + self.num2 def dec(self): return self.num1 - self.num2 def mul(self): return self.num1 * self.num2 def div(self): if self.num2 == 0: print("请重新定义被除数") return None else: return self.num1 / self.num2 cal = Cal(2,0) print("和=",cal.add()) print("差=",cal.dec()) print("乘=",cal.mul()) print("除=",cal.div()) # 定义Music类,里面有音乐名name,音乐时长times属性,并有播放play功能,和返回本身属性信息的方法get info class Music: def __init__(self,name,times): self.name = name self.times = times def play(self): print(f"音乐名:{self.name},音乐时长:{self.times}") def get_info(self): return f"音乐信息为:名字:{self.name},时长:{self.times}" music1 = Music("逆战","3.14m") music1.play() print(music1.get_info())
59.封装入门
-
封装就是把抽象出的数据[属性]和对数据的操作[方法],封装在一起,数据被保护在内部
-
程序只有通过被授权的操作,才能对数据进行访问
封装的好处
-
隐藏实现细节
-
封装可以对数据进行验证
-
可以保护数据隐私,要求授权才可以访问
class Clerk: name = None __job = None __salary = None def __init__(self,name,job,salary): self.name = name self.__job = job self.__salary = salary # 提供公共的方法,对私有属性操作 def set_job(self,job): self.__job = job def get_job(self): return self.__job # 私有方法 def __hi(self): print("hi()") # 提供公共的方法,操作私有方法 def f1(self): self.__hi() clerk = Clerk("tiger","Python工程师",20000) print(clerk.name) clerk.set_job("Java工程师") print(clerk.get_job()) clerk.f1()
60.封装细节
class Clerk: name = None __job = None __salary = None def __init__(self,name,job,salary): self.name = name self.__job = job self.__salary = salary def get_job(self): return self.__job clerk = Clerk("apple","Python",20000) # 如果这样使用,因为python语言的动态特性,会动态的创建属性__job,但这 # 个属性和我们在类中定义的私有属性__job并不是同一个变量,我们在类中定义 # 的__job私有属性完整的名字_Clerk_job 用Debug观察 clerk.__job = "Go Enggnier" print(f"job={clerk.__job}") print("ok") print(f"job={clerk.get_job()}")
练习:
class Account: __name = None __balance = None __pwd = None def set_name(self,name): if len(name) <4 and len(name) >2: self.__name = name else: print("请重新输入") def set_balance(self,balance): if balance > 20: self.__balance = balance else: print("请重新输入") def set_pwd(self,pwd): if len(pwd) == 6: self.__pwd = pwd else: print("请重新输入") def query_info(self,name,pwd): if name == self.__name and pwd ==self.__pwd: return f"账号信息{self.__name},{self.__balance},{self.__pwd}" xiaoming = Account() xiaoming.set_name("xia") xiaoming.set_pwd("000000") xiaoming.set_balance(1000) print(xiaoming.query_info("xia","000000"))
61.继承入门
继承的基本介绍
-
继承可以解决代码复用,让我们的编程更加靠近人类思维
-
当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法
# 继承的基本语法 class DerivedClassName(BaseClassName): <statement-1> . . . <statement-N>
class Student: name = None age = None __score = None def __init__(self,name,age): self.age = age self.name = name def show_info(self): print(f"name={self.name} age={self.age}") def set_score(self,score): self.__score = score # 小学生类 - 继承Student class Pupil(Student): def testing(self): print("...小学生在考小学数学...") # 大学生类 - 继承Student class Graduate(Student): def testing(self): print("...大学生在考高等数学...") # 测试 student1 = Pupil("apple",10) student1.testing() student1.set_score(70) student1.show_info()
62.继承注意事项和细节
-
子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
class Base: # 共有属性 n1 = 100 # 私有属性 __n2 = 200 def __init__(self): print("Base 构造器") def hi(self): print("hi() 公共方法") def __hello(self): print("__hello()私有方法") # 提供公共方法,访问私有属性和方法 def test(self): print("属性:",self.n1,self.__n2) self.__hello() class Sub(Base): def __init__(self): print("Sub 构造器") def say_ok(self): # 我们发现父类的非私有方法属性可以访问 print("say_ok()",self.n1) self.hi() # 我们发现父类的私有属性和方法不可以访问 # print(self.__n2) # self.__hello() # 创建子类对象 sub = Sub() sub.say_ok() # 调用子类继承父类的公共方法,去实现访问父类的私有成员的效果 sub.test()
-
Python语言中,“Object”是所有其他类的基类(Ctrl+H)
-
Pyhton支持多重继承
# 基本语法 class DerivedClassName(Base1,Base2,Base3...) <statement-1> . . . <statement-N> class A: n1 = 100 def sing(self): print("A sing()...",self.n1) class B: n2 = 200 def dance(self): print("B dance()...",self.n2) class C(A,B): pass c = C() print("-------------") # 继承的属性信息 print(f"属性信息{c.n1} {c.n2}") # 调用继承的方法 c.dance() c.sing()
-
在多重继承中,如果有同名的成员,遵守从左到右的继承优先级(即左边的父类优先级高)
63.继承的练习
class Computer: CPU = None neicun = None yingpan = None def __init__(self,CPU,neicun,yingpan): self.CPU = CPU self.neicun = neicun self.yingpan = yingpan def get_details(self): return f"计算机信息:{self.CPU}\t内存:{self.neicun}\t硬盘:{self.yingpan}" class PC(Computer): brand = None def __init__(self,CPU,neicun,yingpan,brand): """ 1.通过super().xx的方式可以去调用父类的方法 2.这里,我们通过super().__init__(CPU,neicun,yingpan)去调用父类的构造器 3.self.brand = brand 表示子类特有的属性,由子类的构造器完成 """ super().__init__(CPU,neicun,yingpan) self.brand = brand def print_info(self): print(f"品牌:{self.brand}\t{self.get_details()}") class NotePad(Computer): color = None def __init__(self,CPU,neicun,yingpan,color): super().__init__(CPU, neicun, yingpan) self.brand = color def print_info(self): print(f"品牌:{self.brand}\t{self.get_details()}") macbook = PC("i7",32,1000,"THUNDEROBOT") macbook.print_info() dell = NotePad("intel",32,512,"balck") dell.print_info()
64.调用父类成员方法的细节
基本介绍:如果子类和父类出现同名的成员,可以通过父类名、super()访问父类成员
基本语法
# 访问父类成员方式1 -访问成员变量:父类名.成员变量 -访问成员方法:父类名.成员方法(self) 用类名调用要传入self # 访问父类成员方式2 -访问成员变量:super().成员变量 -访问成员方法:super().成员方法()
class A: n1 = 100 def run(self): print("A-run()...") class B(A): n1 = 200 def run(self): print("B-run()...") def say(self): print(f"父类的n1{A.n1} 本类的n1{self.n1}") # 调用父类的run A.run(self) # 调用本类的run self.run() def hi(self): print(f"父类的n1{super().n1}") # 调用父类的run super().run() b = B() b.say() print("---------") b.hi()
调用父类对象的注意事项和使用细节
-
子类不能直接访问父类的私有成员
-
访问不限于直接父类,而是建立从子类向上级父类的查找关系A->B->C
-
建议使用super()的方式,因为如果使用父类名方式,一旦父类发生变化,类名需要统一修改,比较麻烦
65.重写Override
class Person: name = None age = None def __init__(self,name,age): self.age = age self.name = name def say(self): return f"名字:{self.name},年龄:{self.age}" class Student(Person): id = None score = None def __init__(self,name,age,id,score): super().__init__(name,age) self.id = id self.score = score def say(self): return f"名字:{self.name},年龄:{self.age},学号:{self.id},成绩:{self.score}" jerry = Person("jeryy",18) print(jerry.say()) tom = Student("tom",20,1,100) print(tom.say())
66.类型注解
为什么要用类型注解
随着项目越来越大,代码也会越来越多,在这种情况下,如果没有类型注解,很容易某一个方法的参数类型是什么,一旦传入了错误类型的参数,Python是解释性语言,只有运行的时候才能发现问题,这对大型项目来说,是一个巨大的问题
# 基础数据注解-------------------------------------------- n1:int = 10 n2:float = 10.1 is_pass:bool = True name:str = "张柯威" # 实例对象类型注解---------------------------------- # 定义类Cat class Cat: pass # 实例对象类型注解 # cat:Cat:对cat进行类型注解,标注cat的类型是Cat类 cat: Cat = Cat() # 容器类型注解----------------------------------------- my_list:list = [100,200,300] my_tuple:tuple = ("run","sing","fly") my_set:set = {"jack","tim","zkw"} my_dict:dict = {"no1":"北京","no2":"上海"} my_dict:dict[str,int] = {"no1":100,"no2":200}# 主键为str,值的类型是int # 注释中使用注解---------------------------------------- # #type:float 用于标注 变量n3 的类型是 float n3 = 89.9 # type:float my_list3 = [100,200,300] #type:list[int] email = "zkw@qq.com" #type:str #函数(方法)的类型注解----------------------------------- def 函数/方法名(形参名,实参名)->返回值类型: 函数/方法体 //name:str 对形参name进行类型注解:标注name的类型是str def fun1(name:str) for ele in name: print(ele) fun1("张柯威") ''' 1.对形参a,b进行类型注解,标注其类型 2.->int 对返回值进行类型注解,标注返回值的类型为int ''' def fun2(a:int,b:int) -> int: return a + b print(f"结果是:{fun2(10,20)}") #最后的说明 类型注解是提醒型的,并不俗强制性的,pycharm会提示错误,但可以正常运行
Union类型
-
Union类型可以定义联合类型注解
-
在变量、函数(方法)都可以使用Union联合类型注解
-
使用的时候,需要先导入Union:from typing import Union
要使用Union,把光标放在红色波浪下,输入Alt+Enter #基本语法 Union[类型,类型...] 比如:联合类型:Union[X,Y,Z...]等价于X|Y,满足X或Y之一 # 实例 from typing import Union # 联合类型注解,a可以是int或者str a:Union[int,str]=100 #my_list是list类型,元素可以是int或者str my_list:list[Union[int,str]]=[100,200,300,"tim"]
67.多态
-
不同的对象调用相同的方法,表现出不同的状态,称为多态
-
多态通常作用在继承关系上
Python的多态特点
-
Python中函数/方法的参数是没有类型限制的,所以多态在python中的体验并不是很严谨
-
Python并不要求严格的继承关系,关注的不是对象的类型本身,而是他是否具有要调用的方法
class Animal: def cry(self): pass class Cat(Animal): def cry(self): print("喵喵喵") class Dog(Animal): def cry(self): print("汪汪汪") class Pig(Animal): def cry(self): print("噜噜噜") # 在Python OOP中,子类类型可以传递给父类类型 # 所以这里的Animal可以识别到子类,传进来的类型是Cat本身,并非Animal def func(animal:Animal): animal.cry() cat = Cat() dog = Dog() pig = Pig() func(cat) func(dog) func(pig)
isintance函数
-
用于判断对象是否为某个类或其子类的对象
-
基本语法:isinstance(object,classinfo) object:对象 classinfo:类名,基本类型等
练习题
class Employee: __name = None __MothSalary = None def __init__(self,name,salary): self.__name = name self.__MothSalary = salary def get_annual(self): return self.__MothSalary*12 def set_name(self,name): self.__name = name def get_name(self): return self.__name def set_salary(self,salary): self.__MothSalary = salary def get_salary(self): return self.__MothSalary class Worker(Employee): def work(self): print(f"普通工人:{self.get_name()}正在工作中") class Manager(Employee): __bonus = None def manage(self): print(f"经理:{self.get_name()}正在管理中") # 因为相比于worker类,manager多出来了一个奖金属性,所以需要重写一个构造器 def __init__(self,name,salary,bonus): super().__init__(name, salary) self.__bonus = bonus # 调用父类的get_anuual def get_annual(self): return super().get_annual() + self.__bonus def show_emp_annual(e:Employee): print(f"{e.get_name()}年工资是:{e.get_annual()}") #测试 worker = Worker("老王",10000) show_emp_annual(worker) manager = Manager("小李",15000,2500) show_emp_annual(manager) def working(e:Employee): # 如果是普通员工 if isinstance(e,Worker): e.work() # 如果是经理 elif isinstance(e,Manager): e.manage() else: print("您输入的职位不对") working(worker) working(manager)
68.魔术方法
什么是魔术方法
1.在Python中,所有以双下划线__包起来的方法,统称为Magic Method,它是一种特殊方法,普通方法需要调用,而魔术方法不需要调用就可以自动执行 2.魔术方法在类或对象的某些事情发生时,会自动执行。这些方法可进行重写 3.Python中常用的运算符,for循环等操作都是运行在魔术方法之上的
# 正常情况下,会输出它的类型,和地址 class Monster: name = None sex = None age = None def __init__(self,name,sex,age): self.name = name self.sex = sex self.age = age # 可以根据需求重写str ''' 1.在默认情况下调用的是父类object的__str__ 2.父类object的__str__返回的就是类型+地址 3.可以根据需求重写__str__ ''' def __str__(self): return f"{self.name} {self.sex} {self.age}" m = Monster("青牛怪","男",500) print(m) # 默认输出类型+地址
_ _ eq_ _ 方法
# 重写__eq__方法可以用于判断对象内容/属性是否相等 class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender # 没有重写__eq__前,==比较的是内存地址 def __eq__(self, other): # 判断other是不是person if isinstance(other,Person) return (self.name == other.name and self.age == other.age and self.gender == other.gender) return False p1 = Person("smith",20,"男") p2 = Person("smith",20,"男") dog = Dog("smith",20,"男") print(f"p1==p2:{p1 == p2}") # False 重写后变为Ture
其他的魔术方法
__it__(self,other):定义小于号的行为 __le__(self,other):定义小于等于号的行为 __ne__(self,other):定义不等号的行为 __gt__(self,other):定义大于号的行为 __ge__(self,other):定义大于等于号的行为
69.抽象类入门
-
在默认情况下,Python不提供抽象类,Python附带一个模块,该模块为定义抽象类提供了基础
-
当我们需要抽象基类时,让类继承ABC,使用@abstractmethod声明抽象类方法,这个类就是抽象类
-
抽象类的价值更多作用是在于设计,设计好后让子类继承
from abc import ABC, abstractmethod #Animal就是抽象类 class Animal(ABC): def __init__(self,name,age): self.name = name self.age = age # 这时:cry就是一个抽象方法 @abstractmethod def cry(self): pass # 注意抽象类(含有抽象方法),不能实例化 # TypeError: Can't instantiate abstract class Animal with abstract method cry # animal = Animal("动物",3) # 编写子类Cat,继承Animal并实现抽象方法 class Cat(Animal): def cry(self): print(f"{self.name}喵喵喵") cat = Cat("汤圆",2) cat.cry()
70.抽象类细节和练习
-
抽象类不能被实例化
-
抽象类需要继承ABC,并且至少需要一个抽象方法
from abc import ABC, abstractmethod class AAA(ABC) name = "tim" # @abstractmethod # def f1(self): # pass # 如果没有一个抽象方法,能实例化 obj1 = AAA() print("ok")
-
抽象类中可以有普通方法
from abc import ABC, abstractmethod class AAA(ABC): name = "tim" @abstractmethod def f1(self): pass def hi(self): print("hi()~~") def ok(self): pass class BBB(AAA): # 实现父类的f1抽象方法 def f1(self): print("BBB-f1()") obj2 = BBB() obj2.f1() obj2.hi() obj2.ok() print("~~~")
-
如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,否则它仍然是一个抽象类
练习
from abc import ABC,abstractmethod class Employee(ABC): def __init__(self,name,id,salary): self.name = name self.id = id self.salary = salary @abstractmethod def work(self): pass class Manager(Employee): def __init__(self,name,id,salary,bonus): super().__init__(name,id,salary) self.bonus = bonus def work(self): print(f"经理:{self.name},正在工作中") class CommonEmployee(Employee): def __init__(self, name, id, salary): super().__init__(name, id, salary) def work(self): print(f"普通员工:{self.name},正在工作中") manager = Manager("李总",1,15000,5000) commonemployee = CommonEmployee("小王",2,8000) manager.work() commonemployee.work()
71.本章练习
class Person: def __init__(self,name,age,job): self.name = name self.age = age self.job = job def __str__(self): return f"{self.name}-{self.age}-{self.job}" p1 = Person("smith",20,"java工程师") p2 = Person("king",18,"老师") p3 = Person("ZKW",26,"学生") my_list = [p1,p2,p3] for p in my_list: print(p) def bubble_sort(my_list:list[Person]): for i in range(0,len(my_list) - 1): for j in range(0,len(my_list) - 1 - i): if my_list[j].age < my_list[j+1].age: my_list[j],my_list[j + 1] = my_list[j + 1],my_list[j] bubble_sort(my_list) print("排序后".center(32,"-")) for p in my_list: print(p) # 简便代码 key=lambda ele:ele.age表示我指定按照列表元素的age进行排序 reverse=Ture:表示逆序 my_list.sort(key=lambda ele:ele.age,reverse=True) --------------------------------------------------- class Doctor: def __init__(self,name,age,job,gender,sal): self.name = name self.age = age self.job = job self.gender = gender self.sal = sal def __eq__(self, other): if isinstance(other,Doctor): return (self.name == other.name and self.age == other.age and self.job == other.job and self.gender == other.gender and self.sal == other.sal) return False p1 = Doctor("sam",18,"Doctor","男",15000) p2 = Doctor("sam",18,"Doctor","男",15000) print(f"p1==p2:{p1==p2}")
72.项目-房屋出租系统(基于模块开发)
# house_operation.py ''' @Project :Hello @Author :ZhangKewei @Date :2024/6/15 19:02 ''' """ 说明:提供对房屋的各种操作 """ from my_tools import * houses = [{"id": 1, "name": "tim", "phone": "113", "address": "上海", "rent": "800", "state": "已出租"}] def find_by_id(find_id): for house in houses: if house["id"] == find_id: return house return None def list_houses(): print("房屋列表".center(60, "=")) print("编号\t\t房主\t\t电话\t\t地址\t\t月租\t\t状态(已出租/未出租)") for house in houses: for value in house.values(): print(value, end="\t\t") print() print("房屋列表显示完毕".center(60, "=")) def main_menu(): print() print("房屋出租系统".center(32, "=")) print("\t\t\t1 新 增 房 源") print("\t\t\t2 查 找 房 屋") print("\t\t\t3 删 除 房 屋 信 息") print("\t\t\t4 修 改 房 屋 信 息") print("\t\t\t5 房 屋 列 表") print("\t\t\t6 退 出") id_counter = 1 def add_house(): print("添加房屋".center(60, "=")) name = input("姓名:") phone = input("电话:") address = input("地址:") rent = input("月租:") state = input("状态:") global id_counter id_counter += 1 # 构建房屋信息对应的字典 house = {"id": id_counter, "name": name, "phone": phone, "address": address, "rent": rent, "state": state} houses.append(house) print("添加房屋成功".center(60, "=")) def del_house(): print("删除房屋信息".center(32, "=")) del_id = int(input("请输入待删除的房屋(-1退出):")) if del_id == -1: print("放弃删除房屋信息".center(32,"=")) return choice = read_confirm_select() if choice == 'y': # 根据id去houses查找对应的房屋 house = find_by_id(del_id) if house: houses.remove(house) print("房屋信息已删除".center(32,"=")) else: print("房屋编号不存在,删除失败".center(32,"=")) else: print("取消删除房屋信息") def exit(): choice = read_confirm_select() if choice == "y": return True else: return False def find_house(): print("查找房屋信息".center(32,'=')) find_house_id = int(input("请输入你要查找的房屋id:")) house = find_by_id(find_house_id) if house: for value in house.values(): print(value, end="\t\t") print() else: print("你查找的房屋id不存在".center(32,"=")) def change_house(): print("查找房屋信息".center(32, '=')) change_id = int(input("请输入你要修改的房屋id(-1退出):")) if change_id == -1: print("放弃修改房屋信息".center(32,"=")) return house = find_by_id(change_id) if house: print("要修改的房屋信息".center(32,'=')) for value in house.values(): print(value, end="\t\t") name = input(f"姓名{house['name']}:") if len(name)>0: house['name'] = name phone = input(f"电话{house['phone']}:") if len(phone) > 0: house['phone'] = phone address = input(f"地址{house['address']}:") if len(address) > 0: house['address'] = address rent = input(f"租金{house['rent']}:") if len(rent) > 0: house['rent'] = rent state = input(f"状态(已出租/未出租){house['state']}:") if len(state) > 0: house['state'] = state else: print("你查找的房屋id不存在".center(32, "="))
# main.py ''' @Project :Hello @Author :ZhangKewei @Date :2024/6/15 19:00 ''' from house_operation import * """ 说明:出租系统的主程序 """ def main(): while True: main_menu() key = input("请输入您的选择(1~6):") if key in ["1","2","3","4","5","6"]: if key == "1": add_house() elif key == "2": find_house() elif key == "3": del_house() elif key == "4": change_house() elif key == "5": list_houses() elif key == "6": if exit(): break # 测试 if __name__ == "__main__": main() print("你退出了程序,欢迎下次使用")
# my_tools.py ''' @Project :Hello @Author :ZhangKewei @Date :2024/6/16 18:39 ''' def read_confirm_select(): print("请输入你的选择(Y/N):",end="") while True: key = input() if key.lower() == "y" or key.lower() == "n": break else: print("选择错误请从新输入:",end="") return key.lower()
73.错误与异常
捕获异常
try: num1 = 10 num2 = 0 res = num1/num2 except Exception as e: # 捕获后如何处理,由程序员自己决定 print(f"捕获到了异常,异常是{e}") print("程序执行完毕")
74.异常处理快速入门
# 捕获异常语法 try: 可能出现异常的代码 except[异常 as 别名] 发生异常时,对异常处理的代码 [else:] 没有发生异常,执行的代码 [finally:] 不管有没有异常,都要执行的代码
Ctrl+H可以查看其继承
75.异常处理细节与练习
-
如果异常发生了,则异常发生后面的代码不会执行,会直接进入到except
num1 = 10 num2 = 0 try: res = num1 + num2 print("hi...") except Exception as e: print(f"出现了异常,异常信息->{e}")
-
如果异常没有发生,则顺序执行try的代码块,不会进入到except的子句
num1 = 10 num2 = 2 try: res = num1/num2 print("hi...") except Exception as e: print(f"出现了异常 异常信息->{e}") print("继续执行")
-
如果希望没有发生异常时,要执行某代码块,则使用else子句
try: 可能出现异常的代码 except[异常 as 别名]: 发生异常时,对异常处理的代码 else: 没有发生异常,执行的代码
-
如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用finally子句
try: 可能出现异常的代码 except[异常 as 别名]: 发生异常时,对异常处理的代码 [else:] 没有发生异常时,执行的代码 finally: 不管有没有异常,都要执行的代码
-
可以有多个except子句,捕获不同的异常(进行不同的业务处理),如果发生异常,指挥匹配一个except,建议把具体的异常写在前面,基类异常在后比如(IndexError在前,Exception在后),这样当具体的异常匹配不到时,再由基类异常匹配
try: res = num1/num2 str_a = "hello" print(str_a[20]) open("d:/temp/temp/temp.txt"."r".encoding="utf-8") print("hi...") except IndexError as e: print(f"出现了异常IndexError 异常信息->{e}") except ZeroDivisionError as e: print(f"出现了异常ZeroDivisionError 异常信息->{e}") except Exception as e: print(f"出现了异常Exception 异常信息->{e}") finally: print("执行了finally~~~~") print("继续执行...")
-
一个except子句,也可以捕获不同的异常
num1 = 10 num2 = 0 try: res = num1/num2 str_a = "hello" print(str_a[20]) open("d:/temp/temp/temp.txt"."r".encoding="utf-8") print("hi...") except(IndexError,ZeroDivisionError,NameError) as e: print(f"捕获多种异常信息->{e}类型{type(e)}") finally: print("执行了finally~~~") print("继续执行...")
课后练习题
-
如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止
age = 0 while True: try: age = int(input("请输入年龄(要求是整数):")) break except Exception as e: print("你输入的年龄不是整数,please again") print(f"你输入的age={age}")
76.主动触发异常
try: # num1 = 10 # num2 = 0 # res = num1 + num2 ''' 1.raise:用于主动的触发异常 2.ZeroDivisionError:程序员指定的异常,可以根据需要指定 3.“主动触发ZeroDivisionError异常”是我们指定的异常信息 ''' raise ZeroDivisionError("主动触发ZeroDivisionError异常") except ZeroDivisionError as e: print(f"捕获到异常信息->{e} 类型->{type(e)}")
77.异常传递
如果一个异常发生了,但没有捕获异常的处理,那么这个异常就会传递给调用者处理,若所有的调用者都没有处理,最终会由系统处理
def f3(): print("---f3()start----") print(10 / 0) print("---f()end----") def f2(): print("---f2()start---") f3() print("---f2()end---") def f1(): try: f2() except Exception as e: print(f"f1()捕获异常->{e}") f1()
78.自定义异常
# 自定义异常 class AgeError(Exception): pass while True: try: age = int(input("请输入年龄(18~120):")) # 可以先写正确范围,然后取反 if not (18 <= age <= 120): raise AgeError("年龄需要再18~120之间") break except ValueError as e: print("你输入的不是整数") except AgeError as e: print(e) print(f"您输入的年龄是{age}")
79.文件
输入与输出
输入:数据从数据源(文件)到程序(内存)
输出:数据从程序(内存)到程序源(文件)
I/O类型
文本文件:通常是记事本可以打开的
二进制文件:比如图片,视频,音频等
创建文件
f1 = open("d://a//hi.txt","w",encoding="utf-8")
打开文件
f1 = open("d://a//hi.txt","r",encoding="utf-8")
读取文件
# 方式一 read() ,一次返回整个文件内容 content = f.read() f.close() // 关闭文件,释放文件占用的系统资源 # 方式二 f.readline() ,字符串末尾保留换行符 line1 = f.readline() # 方式三 f.readlines() ,列表形式读取文件中所有行 lines = f.readlines() # 方式四 for line in f形式读取文件
写入文件
# 在D盘的a目录下创建abc.txt文件,并写入10句“hello,world” f = open("d://a//abc.txt","w",encoding="utf-8") # 以w打开是覆盖内容 i = 1 while i <= 10: f.write(f"hello,world\n") i += 1 # 追加的方式写入,用a f = open("d://a//abc.txt","a",encoding="utf-8")
删除文件
# 删除文件 # 引入os文件,该模块提供更多的操作 import os if os.path.exists("d://a//abc.txt"): os.remove("d://a//abc.txt") else: print("不存在")
目录相关操作
# 创建一级目录 d://aaa import os if os.path.isdir("d://aaa"): print("d://aaa 目录已存在") else: os.dir("d://aaa") # 创建多级目录 d://bbb//ccc if not (os.path.isdir("d://bbb//ccc")): os.makedirs("d://bbb//ccc") else: print("d://bbb//ccc 目录已存在") # 删除目录 d://aaa # 删除目录使用rmdir,要求目录为空 删除多级目录用removedirs if os.path.isdir("d://aaa"): os.rimdir("d://aaa") else: print("d://aaa 目录不存在")
获取文件相关信息
# 获取文件相关信息(大小、创建时间、访问时间、修改时间等) import os import time f_stat = os.stat("d:/a/hello.txt") print("-----文件信息-----") print(f"文件大小->{f_stat.st_size} \n" f"最近的访问时间->{time.ctime(f_stat.st_atime)} \n" f"最近的修改时间->{time.ctime(f_stat.st_mtime)} \n" f"文件创建时间->{time.ctime(f_stat.st_ctime)}")
注意事项
# 1. f.flush():刷新流的写入缓冲区到文件 1.调用f.wirte(),内容并没有真正写入到文件,而是先积攒到缓冲区 2.当调用flush()时,内容辉真正写入到文件 3.这样是为了避免频繁的操作硬盘,导致效率低 # 2.f.close():刷新并关闭此流,也就是f.close()内置的flush功能 # 3.with open() as f:在处理文件对象时,子句体结束后,文件会自动关闭
80.文件操作实例
1.将一张图片拷贝到另一个文件,要求使用read()和write()
# 源文件 f_src_path = "D:/testy/th.jpg" # 目标文件 f_dst_path = "d:/a/th_new.jpg" # 打开源文件 f_src = open(f_src_path,"rb") # 读取源文件的数据 data = f_src.read() # 打开目标文件 f_dst = open(f_dst_path,"wb") # 写入文件 f_dst.write(data) # 关闭文件 f_dst.close() f_src.close() print("拷贝OK...")
2.遍历某个文件夹
# 遍历某个文件夹,判断它们分别是目录还是文件 import os # 指定要查看的目录 dir_path = "d:/a" # 获取文件夹(目录)的所有内容(元素) content_list = os.listdir(dir_path) # print("content_list:",content_list) # 遍历content_list,输出对应的信息 for ele in content_list: child_ele = dir_path + "/" + ele if os.path.isdir(dir_path + "/" + ele): print(f"目录:{child_ele}") else: print(f"文件:{child_ele}")
81.pycharts
pyecharts-gallery文档:Document