Python学习全内容

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.函数的递归调用

简单的说:就是函数自己调用自己,每次调用时传入不同的值

新调用的函数输出完后,会返回上一个调用的函数并执行剩下的语句

递归的重要规则

  1. 执行一个函数时,就创建一个新的空间(栈空间)

  2. 函数的变量是独立的,比如n变量

  3. 递归必须向退出递归的条件逼近,否则就是无限递归,出现RecursionError:maximum recursion depth exceeded

  4. 当一个函数执行完毕,或遇到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}")
  1. 函数作为参数传递,传递的不是数据,而是业务处理逻辑

  2. 一个函数,可以接收多个函数作为参数传入

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.字符串常用方法

image-20240321210746512

注:返回字符串的副本,表示原来的字符串不变,而是返回一个新的字符串

字符串的比较

比较规则:首先比较两个字符串中的第一个字符,如果相等则继续比较下面的字符,直到字符不相等时,其比较结果也就是两个字符串的比较结果,两个字符串中的所有后续字符将不再比较

比较原理:两个字符串进行比较的时候,是比较其的码值,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]

注意事项和细节

  1. 字典的Key通常是字符串或数字,Value可以是任意数据类型

  2. 字典不支持索引,会报错KeyError

  3. 既然字典不支持索引,所以对字典进行遍历不支持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}")
  4. 空字典通过{}或者dict()创建

  5. 字典的key必须是唯一的,如果指定了多个相同的key,后面的键值会覆盖前面的

43.字典的常用操作

  1. len(d):返回字典d中的项数

  2. d[key]:返回d中以key为键的项,如果映射中不存在key,则会引发KeyError

  3. d[key] = value:将d[key]设为value,如果key已经存在,则会修改value,如果key没有存在则是增加key-value

  4. del d[key]:将d[key]从d中移除,如果映射不存在key则会引发KeyError

  5. pop(key[default]):如果key存在于字典中,则将其移除并返回其值,否则返回default,如果default未给出且key不存在字典中,则会引发KeyError

  6. keys():返回字典的所有的key

  7. key in d:如果d中存在键key则返回Ture,否则False

  8. 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支持对象动态的增加方法

  1. 动态的给p对象添加方法m1,注意只是针对p对象添加方法

  2. m1是你新增加的方法的名称,有程序员指定

  3. 即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:将方法转为静态方法(不会接受隐式的第一个参数)

静态方法:

  1. 通过@staticmethod 可以将方法转为静态方法

  2. 如果是一个静态方法可以不带self

  3. 静态的方法的调用形式有变化,可用类名调用,也可用属性

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)}")

注意事项:

  1. 一个类中只有一个_ init _方法,即使你写了多个,也只有最后一个生效

  2. Python可以动态的生成对象属性

  3. 构造方法不能有返回值,比如,你返回字符串,会报”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.封装入门

  1. 封装就是把抽象出的数据[属性]和对数据的操作[方法],封装在一起,数据被保护在内部

  2. 程序只有通过被授权的操作,才能对数据进行访问

封装的好处

  1. 隐藏实现细节

  2. 封装可以对数据进行验证

  3. 可以保护数据隐私,要求授权才可以访问

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.继承入门

继承的基本介绍

  1. 继承可以解决代码复用,让我们的编程更加靠近人类思维

  2. 当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法

# 继承的基本语法
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.继承注意事项和细节

  1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问

    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()
  2. Python语言中,“Object”是所有其他类的基类(Ctrl+H)

  3. 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()
  4. 在多重继承中,如果有同名的成员,遵守从左到右的继承优先级(即左边的父类优先级高)

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()

调用父类对象的注意事项和使用细节

  1. 子类不能直接访问父类的私有成员

  2. 访问不限于直接父类,而是建立从子类向上级父类的查找关系A->B->C

  3. 建议使用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类型

  1. Union类型可以定义联合类型注解

  2. 在变量、函数(方法)都可以使用Union联合类型注解

  3. 使用的时候,需要先导入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.多态

  1. 不同的对象调用相同的方法,表现出不同的状态,称为多态

  2. 多态通常作用在继承关系上

Python的多态特点

  1. Python中函数/方法的参数是没有类型限制的,所以多态在python中的体验并不是很严谨

  2. 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函数

  1. 用于判断对象是否为某个类或其子类的对象

  2. 基本语法: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.抽象类入门

  1. 在默认情况下,Python不提供抽象类,Python附带一个模块,该模块为定义抽象类提供了基础

  2. 当我们需要抽象基类时,让类继承ABC,使用@abstractmethod声明抽象类方法,这个类就是抽象类

  3. 抽象类的价值更多作用是在于设计,设计好后让子类继承

    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.抽象类细节和练习

  1. 抽象类不能被实例化

  2. 抽象类需要继承ABC,并且至少需要一个抽象方法

    from abc import ABC, abstractmethod
    ​
    class AAA(ABC)
        name = "tim"
        
        # @abstractmethod
        # def f1(self):
        #     pass
    ​
    # 如果没有一个抽象方法,能实例化
    obj1 = AAA()
    print("ok")
  3. 抽象类中可以有普通方法

    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("~~~")
  4. 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,否则它仍然是一个抽象类

练习

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.异常处理细节与练习

  1. 如果异常发生了,则异常发生后面的代码不会执行,会直接进入到except

    num1 = 10
    num2 = 0
    try: 
        res = num1 + num2
        print("hi...")
    except Exception as e:
        print(f"出现了异常,异常信息->{e}")
  2. 如果异常没有发生,则顺序执行try的代码块,不会进入到except的子句

num1 = 10
num2 = 2
try:
    res = num1/num2
    print("hi...")
except Exception as e:
    print(f"出现了异常 异常信息->{e}")
print("继续执行")
  1. 如果希望没有发生异常时,要执行某代码块,则使用else子句

    try:
        可能出现异常的代码
    except[异常 as 别名]:
        发生异常时,对异常处理的代码
    else:
        没有发生异常,执行的代码
  2. 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用finally子句

    try:
        可能出现异常的代码
    except[异常 as 别名]:
        发生异常时,对异常处理的代码
    [else:]
        没有发生异常时,执行的代码
    finally:
        不管有没有异常,都要执行的代码
  3. 可以有多个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("继续执行...")
  4. 一个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

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值