Python3.11.5的入门与实战

第一章 Python的环境搭建

  1. 首先我们应在python的官网下载python安装包
    点击这里>> 官网
    在这里插入图片描述
  2. 安装时注意勾选添加环境变量,不然就只能安装后手动添加了
    在这里插入图片描述
  3. 安装完成后进入cmd,输入python看到进入交互模式则表示安装完成
    在这里插入图片描述
  4. 在cmd里面编程是不方便的,我们还需要IDE,下载pycharm
    点击这里>>Pycharm
    向下滚动页面,找到社区版,除非你有高级的需求,否则不需要使用到专业版
    在这里插入图片描述
    Pycharm是很棒的pythonIDE,安装后选择自己的运行环境项目路径后,创建新的文件就可以开始愉快的写代码啦😊

第二章 基本数据类型

2.1 变量和标识符

什么是变量?

变量(variable):在程序运行时,可以发生变化的量,被称为变量
python如何定义变量?
python是弱数据类型语言,变量类型不固定,值是什么类型,变量就会自动变成什么类型。
而强数据类型的语言,例如Java,当定义数据类型后,不允许存储其他数据类型。

a = 10

如👆所示,这样就可以轻松的定义一个变量。
但在实际使用中最好是遵守如下的命名规范:
1> 变量名称只能由有效字符(大小写字母,数字,下划线)组成(name+ 报错语法错误)
2> 不能以数字开头
3> 不能是关键字或者是保留字
4> 变量命名尽量有意义(name age sex )
5> 小驼峰法 userAddress(除了第一个单词,其他单词首字母大写)
6> 下划线法(官方推荐)

标识符的命名规范

所谓的标识符就是对变量、常量、函数、类等对象起的名字。

首先必须说明的是,Python语言在任何场景都严格区分大小写!

Python对于标识符的命名有如下规定:

  • 第一个字符必须是字母表中的字母或下划线’_’

  • 标识符的其他的部分由字母、数字和下划线组成

  • 标识符对大小写敏感

python的常量

python并没有定义常量的方式,常量是通过变量来模拟的
常量的命名规范:所有字母大写的单词是常量,这是一种约定俗成的方式而非强制约束。

python的关键字

关键字:在编程语言中有特殊含义的单词
保留字:目前版本还没使用,但后面可能会用的单词
在这里插入图片描述

2.2 数据类型

基本数据类型

int		#整数
float	#浮点
bool	#布尔
	True False
str		#字符串
	ord()	#用来获取单个字符的编码(ASCII)
	chr()	#用来把编码转换成对应字符
转义字符 描述
(\在行尾时)续行符
(\\)反斜杠
(\')单引号
(\")双引号
\b退格(Backspace)
\000
\n换行
\r回车
\f换页
\yyy以\数字0开头后跟三位八进制数
\xyy以\字母x开头后跟至少2位十六进制数

数据类型转换

# 使用这种方式可以转换数据类型,
num = int(input())

2.3 常见的运算符

算术运算符

运算符含义备注
+加法运算
-减法运算
*乘法运算
/除法运算在c++ C Java等强数据类型语言是整除运算
%取余运算求模或者求余数
//整除运算整除(只要整数部分)
**幂次方运算

关系运算符

运算符含义
>大于
<小于
>=大于等于
<=小于等于
==等于
!=不等

注意: 一般情况下关系运算符的值是一个布尔值,只有True和False

逻辑运算符

运算符含义备注
and多个条件必须同时满足,则结果是true
or多个条件,至少一个为真,则为真
not取反 ,一般会和In关键字一起使用,表示意义相反

赋值运算符

运算符含义备注
=等于赋值
+=加等a += 值 等价于 a = a + 值
-=减等
*=乘等
/=除等
**=幂次方等
//=整除等

注意: python中没有自加自减运算

身份运算符

运算符含义备注
is判断两个标识符是不是引用自一个对象x is y,类似id(x)==id(y),如果引用的是同一个对象则返回True,否则返回False
is not判断两个标识符是不是引用自不同对象x is not y

注意: is与比较运算符“==” 的区别,两者有根本上的区别:

is用于判断两个变量的引用是否为同一个对象,而“==”用于判断变量引用的对象的值是否相等!
简单的说: ==是用来对变量的值进行判断的,而is判断的是内存地址。

成员运算符

in 与 not in是Python独有的运算符(全部都是小写字母),用于判断对象是否某个集合的元素之一
在这里插入图片描述

位运算符

a = 0011 1100
b = 0000 1101
­­­­­­­­­­­­­­­­­
a & b = 0000 1100
a | b = 0011 1101
a ^ b = 0011 0001
  ~ a = 1100 001

在这里插入图片描述

三目运算符

在python中的格式为:为真时的结果 if 判定条件 else 为假时的结果
例如:

a = input()
b = input()
max = a if a > b else b
print(max)
# 此代码,当满足a > b 时,输出if前面的值也就是a,不满足则输出else后面的值,也就是b

示例

1. 设计一个程序,判断输入的数字是不是质数

prime_num = int(input("请输入一个整数:"))			#获取用户输入内容
if prime_num <= 1:								#这个条件语句检查用户输入是否小于等于1;是:输出不是质数;否:执行后面的语句
    print(f"{prime_num}不是质数")
else:
    for i in range(2, int(prime_num**0.5)+1):	#如果输入大于1进入else。开始for循环,从2开始逐个遍历直到prime_num的平方根
        if prime_num % i == 0:					#检查prime_num是否能被i整除;
            print(f"{prime_num}不是质数")		#有能被整除的则打印不是质数
            break								#使用break跳出循环
    else:
        print(f"{prime_num}是一个质数")			#若循环正常结束则没有可以整除的,打印是一个质数

结果展示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 使用turtle画一个五环

import turtle as t		#导入turtle库取别名为t,方便书写
color = ["blue","black","red","yellow","green"]		#定义一个列表来存储五环的五种颜色
coordinate = [(-220, 50), (0, 50),(220, 50), (-110, -85), (110, -85)]		#定义列表来存储五环的圆心坐标

t.pensize(10)				#设置画笔的粗细

for i in range(5):			#for循环开始画圆画5个圆就循环5次
    t.color(color[i])		#根据i的值读取color列表的值获取颜色
    t.penup()				#把笔抬起来
    t.goto(coordinate[i])	#根据i的值读取coordinate列表的值获取坐标
    t.pendown()				#把笔放下
    t.circle(100)			#开始画圆半径100
t.done()					#停止画笔,但不关闭窗口

如下图所示:这是绘制完成的样子
在这里插入图片描述

3. 使用循环显示四种模式,使用嵌套循环在四个独立的程序中显示下面四种模式。
在这里插入图片描述

print("模式A")
for i in range(1, 7):			#外部循环,控制行数,表示6行输出
    for num in range(1, i + 1):	#内部循环,控制每行打印的数字,从1开始到i结束
        print(num, end=" ")		#循环一次打印一次num的值,并在num后面有个空格
    print()						#换行,循环结束,开始从头循环

print("模式B")
for i in range(6, 0, -1):		#外部循环,控制行数,表示6行输出,i的值将从6-1倒序
    for num in range(1, i + 1):	#内部循环,控制数字,第一行从1开始i结束
        print(num, end=" ")		#循环一次打印一次num的值,并在num后面有个空格
    print()						#换行,循环结束,开始从头循环

print("模式C")
for i in range(1,7):
    for space in range(6-i):	#内部循环,控制空格个数,从0开始到6-i-1
        print(" ",end=" ")
    for num in range(i,0,-1):	#内部循环,控制输出数字,从i开始到1结束,每次递减1
        print(num,end=" ")
    print()

print("模式D")
for i in range(6, 0, -1):
    for space in range(6 - i):	
        print(" ", end=" ")
    for num in range(1, i + 1):	#内部循环,1开始1结束,默认每次+1
        print(num, end=" ")
    print()

执行结果展示:

F:\pythonwork0912\venv\Scripts\python.exe F:\pythonwork0912\for-demoABCD.py 
模式A
1 
1 2 
1 2 3 
1 2 3 4 
1 2 3 4 5 
1 2 3 4 5 6 
模式B
1 2 3 4 5 6 
1 2 3 4 5 
1 2 3 4 
1 2 3 
1 2 
1 
模式C
          1 
        2 1 
      3 2 1 
    4 3 2 1 
  5 4 3 2 1 
6 5 4 3 2 1 
模式D
1 2 3 4 5 6 
  1 2 3 4 5 
    1 2 3 4 
      1 2 3 
        1 2 
          1 

Process finished with exit code 0

4. 在金字塔模式中显示数字,编写一个嵌套for循环来显示下面的输出。
在这里插入图片描述

for i in range(0, 8):
    for space in range(1, 9 - i):  # 控制左侧倒三角空白区域
        print("\t",end="")
    for num_lift in range(0, i + 1):  # 控制左侧数字
        print(2 ** num_lift, end="\t")
    for num_right in range(i, 0, -1):  # 控制右侧数字
        print(2 ** (num_right - 1), end="\t")
    print()

结果为:
在这里插入图片描述

5. 实现求1-100之间的质数

prime_nums = []						#定义一个空列表
for prime_num in range(0,101):		#遍历0-100
    if prime_num <=1:				#过滤2以下的
        TF_prime = False
    else:
        TF_prime =True
    for num in range(2, int(prime_num**0.5)+1):	#循环迭代2到数字的平方根
        if prime_num % num == 0:				#检查是否有因子
            TF_prime = False					#有则设为False
            break
    if TF_prime:		#这句实际是 if TF_prime == True,简写就是这样,bool为真则加入列表
        prime_nums.append(prime_num)
print(prime_nums)

结果为:
在这里插入图片描述

第三章 程序控制流程

3.1 顺序流程

程序的执行顺序:
自上而下的,书写顺序就是执行顺序
一般思路:
初始化变量;数值输入;算法处理;输出。
示例:

#代码执行时会先进入阻塞状态,直到用户输入华氏度或者按下enter
F = int(input("请输入华氏温度:"))
#转换算法
C = 5 / 9 * (F - 32)
#输出结果
print("摄氏温度为:%.2f" % C)

3.2 选择结构

单分支

# 注意python是强缩进语句,一般使用tab进行缩进
if 条件
	#执行语句

双分支

if 条件:
	#执行语句
else:
	#执行不满足的语句

多分支

if 条件1:
    #执行条件1满足的代码 
elif 条件2:
    #执行条件2满足的代码
    …………
elif 条件n
    #执行条件n满足的代码 
else:
     #前面所有条件都不满足的情况
#else不是必须的

3.3 while循环

一般循环用for,while不咋好用。适合不知道循环边界时使用

while 条件:
	循环体
#输出99乘法表
i = 1
while i <= 9:
    j = 1
    while j <= i:
       print("%s X %s = %s " %(i,j,(i*j)),end = "")
       j += 1
    print()
    i += 1

3.4 for循环

for 循环 常用的循环结构,一般使用for in 结构用来遍历容器.

 # 打印0~10
 for i in range(0,11)
 #range 范围:左闭右开默认步长1
 	print(i)

3.5 break和continue关键字

break:终止循环
continue:跳过本次继续下一次循环

for i in range(101):
   if i == 50:
      break #终止循环
   print(i)
else:
   print("break了就不进来了")
print(“循环结束了”)
#此代码只会打印最后一个print,不会进入else
for i in range(101):
    if i == 50:
        continue
    print(i)
else:
    print("break了就不进来了")
print("循环结束了")
#此代码会进入else执行print语句

第四章 内置容器

4.1 列表 list

#列表定义
ls = [2,3,4,5]
ls = list([1,2,"wzh"])
#如何遍历容器
for i in ls:
	print(i)
#while循环
Index = 0
While index < len(ls):
	Print(ls[index])
	Index += 1
方法名含义
append()向列表尾部追加元素
insert(index, object)向指定的位置追加元素
sort()列表排序(只能排Int)字母按照ASCII值进行排序,类型不能混淆
index()查找元素第一次在列表中出现的位置,如果没有这个元素则会报错
reverse()将列表元素顺序翻转
remove()通过元素来移除元素,如果元素不存在则抛出异常
count()统计元素在列表中的个数
clear()清除元素
copy()浅拷贝对象(拷贝) 不等价于 = (引用传递),在堆内存中进行对象拷贝
extend()合并列表
pop()与append()相反,删除列表最后一个元素,并返回值这个元素,要删除指定位置的元素,用pop(i)方法,其中i是索引位置
内存模型:

栈(stack):

​ 先进后出,后进先出

堆(heap):

队列:先进先出,后进后出

4.2 集合 set

集合是无序的,不能重复的
创建集合的方法:

方法含义
s= set()使用全局函数set()创建一个集合
s = set({1,3,4,5})创建集合并赋值
s = {}如果使用空的{}来创建一个对象,改对象是一个字典,不是一个集合
s = {元素}{}至少要有一个元素,此时才是集合

常见使用方法:

方法含义
Clear用于清空集合中的所有元素,使其成为空集合
remove用于从集合中移除指定的元素。如果指定的元素不存在于集合中,它会引发 KeyError 异常
copy用于创建集合的副本。它返回一个新的集合,该新集合包含与原始集合相同的元素。这个方法通常用于在不影响原始集合的情况下进行操作
add添加元素,如果元素重复,不能添加,涉及到hash算法
difference差集
intersection交集
union并集
update更新集合,合并集合
discard移除元素,但是元素如果不存在,则不做任何操作

4.3 元组 tuple

元组的创建:
弱数据类型创建 t = (1,2,3,4)
tuple全局函数创建 t = tuple() t = tuple((元素……))
元组是一个不可变类型,元组的元素一旦定义下来,则无法改变

注意:
虽然元组不可变,如果元组内部元素是可变类型,那么改元组就可变

4.4 字典 dict

 d = {“name”:”zhangsan”,”age”:16,”gender”:”男”}

​       dd = dict()

​       dd = dict({“name”:”zhangsan”,”age”:16,”gender”:”男”})
 通过key来访问对应的值 d[“name”]
​    字典对象[key] 返回key对应的值,如果没有抛出异常
​    字典对象[key] = 新值  
​    字典对象新[key] = 新值   增加新的键值对

常用方法:

方法名说明
clear
copy
get和字典对象[key]类似,通过key值获取值,注意,如果没有该键,则返回none
keys返回所有的键
values返回所有的值
setdefault设置一个默认值
items返回键值对
pop(key)通过键来移除键值对,如果没有,则抛出异常
popitem移除键值对(按照LIFO后进先出的顺序)

4.5 排序算法

冒泡排序

冒泡排序是一种排序算法,通过重复的遍历元素列表,比较相邻的元素并交换他们,如果顺序不正确则一直重复,他的基本思想就是对比两个元素把大的那个往后移,就像气泡那样,不断上升。

#给定一个列表
ls = [9, 54, 3, 6, 8, 10, 66, 99, 30, 44, 28]
# 遍历这个列表,缩小范围,用于将最大的元素冒泡到正确的位置
for i in range(0, len(ls) - 1):
# 用于比较相邻的元素并交换
    for j in range(0, len(ls) - 1 - i):
    #如果ls[j]>ls[j+1]那么交换位置,将大的元素往后移动
        if ls[j] > ls[j + 1]:
            ls[j], ls[j + 1] = ls[j + 1], ls[j]
print(ls)

选择排序

选择排序将未排序的部分中的最大值/最小值,放在已排序的末尾。不断重复,直到排序完成

ls = [9, 54, 3, 6, 8, 10, 66, 99, 30, 44, 28]
# 每次大循环会确定第一个元素为最小值。当序列为n时,比较n -1次即可完成排序
for i in range(0, len(ls) - 1):
    # 每次大循环会确定第一个元素为最小值。
    # 所以比较范围从左不断向右-1
    # 这使得内层循环的左边界为i+1,右边界不变
    for j in range(i + 1, len(ls)):
        if ls[i] > ls[j]:
            ls[i], ls[j] = ls[j], ls[i]
print(ls)

插入排序

插入排序将待排序的列表分成已排序和未排序的部分,从未排序的部分中逐个选择元素,比较和已排序元素的大小并不断向左移动已排序元素来完成。

arr = [8, 3, 2, 6, 1, 4, 9, 7]
#遍历未排序部分,
for i in range(1, len(arr)):
# 用于比较当前元素arr[i]与已排序部分元素arr[j-1],并不断向左移动已排序元素,直到找到适当的位置。
    for j in range(i, 0, -1):
        if arr[j] <= arr[j - 1]:
            arr[j], arr[j - 1] = arr[j - 1], arr[j]
print(arr)

计数排序

计数排序是一种非比较性的排序算法,统计每个元素在待排序序列中出现的次数,然后根据这些统计信息重新给出列表。

  1. 首先找出最大和最小值。
  2. 创建一个计数数组(counting array)来统计每个元素在待排序序列中出现的次数。计数数组的大小是max - min + 1,每个元素的索引对应着待排序元素的取值。初始时,计数数组的所有元素都初始化为0。
  3. 遍历待排序序列,将每个元素的值作为计数数组的索引,并将对应索引的计数加1。
  4. 根据计数数组中的统计信息,重建有序序列。遍历计数数组,根据每个元素出现的次数,依次将元素放回原始序列中。可以根据计数数组的索引来确定元素的值,同时更新计数数组中的统计信息,确保相同元素的位置不会发生冲突。
# 计数排序
ls = [9, 54, 3, 6, 8, 10, 66, 99, 30, 44, 28]
# 找到ls中的最大值
max_v = ls[0]
for i in range(1, len(ls)):
    if max_v < ls[i]:
        max_v = ls[i]
# 找到ls中的最小值
min_v = ls[0]
for i in range(1, len(ls)):
    if min_v > ls[i]:
        min_v = ls[i]
# 根据最大值和最小值生成一个升序的字典,其中每一个key的value 都是记录该key在ls中出现的次数
dc = dict()
for i in range(min_v, max_v + 1):
    dc[i] = 0
for item in ls:
    dc[item] += 1
# 根据字典记录新的列表,如果某个选项出现了n次,则往新列表中添加n个
ls_new = []
for key, value in dc.items():
    for i in range(value):
        ls_new.append(key)
print(ls_new)

4.6 查找算法-二分查找

二分查找是一种高效的查找算法,用于在有序的数组中查找指定元素的位置,每次查找的范围减半,首先确定区间,第一个和最后一个,计算中间的元素的索引,如果找到中间元素==目标元素则完成查找,返回中间的元素索引。

def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    
    while left <= right:
        mid = (left + right) // 2  # 计算中间元素的索引
        
        if arr[mid] == target:
            return mid  # 找到目标元素,返回索引
        elif arr[mid] < target:
            left = mid + 1  # 缩小查找区间为右半部分
        else:
            right = mid - 1  # 缩小查找区间为左半部分
    
    return -1  # 目标元素不在数组中

# 测试二分查找
my_list = [1, 3, 6, 8, 9, 12, 15, 18, 21, 24]
target = 9
result = binary_search(my_list, target)
if result != -1:
    print(f"目标元素 {target} 在列表中的索引为 {result}")
else:
    print(f"目标元素 {target} 不在列表中")

第五章 函数

5.1 函数的基础

函数的定义

在Python中,函数是一段可重用的代码块,用于执行特定的任务。您可以使用def关键字来定义一个函数,并在函数体内编写代码。以下是一个简单的函数定义示例:

def greet(name):
    print(f"Hello, {name}!")

函数的调用

要调用函数,只需使用函数名并传递所需的参数(如果有的话)。例如:

greet("Alice")

这将打印出:Hello, Alice!

参数传递

Python函数可以接受多个参数,参数之间使用逗号分隔。参数可以是任何数据类型,包括整数、字符串、列表、字典等。函数可以根据需要使用这些参数来执行操作。

def add(a, b):
    result = a + b
    return result

sum = add(3, 4)

默认参数

您还可以为函数参数提供默认值,这使得某些参数成为可选的。如果调用函数时没有传递这些参数,将使用默认值。

def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

greet("Alice")  # 输出:Hello, Alice!
greet("Bob", "Hi")  # 输出:Hi, Bob!

可变数量参数

有时候,您不知道函数将接受多少个参数。在这种情况下,您可以使用可变数量参数。使用*前缀的参数将收集所有传递给函数的额外参数,并将它们作为元组传递给函数。

def average(*numbers):
    total = sum(numbers)
    count = len(numbers)
    return total / count

avg = average(1, 2, 3, 4, 5)

5.2 返回值

使用return语句

函数可以使用return语句来返回一个值。返回值可以是任何数据类型。如果函数没有return语句,将默认返回None

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

result = add(3, 4)

多个返回值

Python函数也可以返回多个值,实际上,它返回一个元组(tuple)。这使得您可以方便地返回多个相关的值。

def get_name_and_age():
    name = "Alice"
    age = 30
    return name, age

person_info = get_name_and_age()
>>>('Alice', 30)

函数文档字符串(docstring)

函数文档字符串是一种可选的字符串,用于描述函数的目的、用法和参数等信息。它们通常位于函数定义的顶部,并由三重引号括起来。

def add(a, b):
    """
    这个函数用于计算两个数的和。    
    参数:
    a -- 第一个数
    b -- 第二个数
    返回值:
    两个数的和
    """
    return a + b

可以使用help()函数或在交互式环境中键入函数名来查看函数的文档字符串。

5.3 作用域

全局作用域

在Python中,变量可以具有不同的作用域。全局作用域是在整个程序中可见的作用域,通常在函数外定义的变量具有全局作用域。

x = 10

def print_x():
    print(x)

print_x()  # 输出:10

局部作用域

局部作用域是在函数内部可见的作用域。在函数内定义的变量通常具有局部作用域,不能在函数外部访问。

def print_local_var():
    y = 5
    print(y)

print_local_var()  # 输出:5
# print(y)  # 会引发NameError,因为y是局部变量

global和nonlocal关键字

如果需要在函数内部修改全局变量,可以使用global关键字。类似地,如果在嵌套函数内部修改外部函数的局部变量,可以使用nonlocal关键字。

x = 10

def modify_global():
    global x
    x = 20

modify_global()
print(x)  # 输出:20

5.4 递归函数

什么是递归

递归是一种算法设计技巧,其中一个函数在其自身内部调用。在递归函数中,问题被分解成一个

或多个更小的相似问题,直到达到基本情况,然后开始返回结果并合并答案。

递归示例

一个经典的递归示例是计算阶乘。

def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)

result = factorial(5)  # 计算5的阶乘

递归 vs 迭代

递归是一种强大的技巧,但它可能导致堆栈溢出错误。在某些情况下,迭代可能更有效。因此,在选择使用递归还是迭代时,需要谨慎考虑。

迭代器

迭代器是一种特殊的对象,它允许您逐个访问元素,而不是一次性加载整个数据集。迭代器通常使用iter()和next()函数来实现。

fruits = ["apple", "banana", "cherry"]
iterator = iter(fruits)

print(next(iterator))  # 输出:apple
print(next(iterator))  # 输出:banana
print(next(iterator))  # 输出:cherry

当没有更多的元素可供迭代时,next()函数会引发StopIteration异常。

迭代与递归的比较

迭代和递归都用于处理重复任务,但它们之间有一些重要的区别:

  • 递归是通过函数内部的自我调用来处理任务,而迭代是通过循环执行来处理任务。
  • 递归通常需要更多的内存,因为它会在函数调用栈上创建多个副本,而迭代通常需要较少的内存。
  • 在某些情况下,递归更容易理解和编写,而在其他情况下,迭代可能更有效。

5.5 高级函数技巧

匿名函数(Lambda函数)

Lambda函数是一种轻量级的函数,通常用于临时的、简单的操作。它们可以在不定义具名函数的情况下创建。

add = lambda x, y: x + y
result = add(3, 4)

高阶函数

Python支持高阶函数,这意味着您可以将函数作为参数传递给其他函数,或从函数中返回函数。

def apply(func, x):
    return func(x)

def double(x):
    return x * 2

result = apply(double, 5)

闭包

闭包是包含了自由变量(在函数内部引用但不在函数参数中定义的变量)的函数。它们可以捕获外部函数的状态。

def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

closure = outer_function(10)
result = closure(5)  # 结果是15

装饰器

装饰器是一种高级函数技巧,用于修改其他函数的行为。它们通常用于添加功能,如日志记录、性能测量等,而无需修改原始函数的代码。

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

示例二

  1. 实现扫描全盘的函数
import os  # 导入操作系统模块

# 定义一个函数,用于递归扫描指定目录下的文件和目录,并计算它们的数量
def scan_disk(dir, count=[0, 0]):
    # 获取目录下的所有文件和子目录
    files = os.listdir(dir)
    # 遍历目录下的所有文件和子目录
    for file in files:
        # 使用os.path.join()构建当前文件或目录的完整路径,并规范化路径
        file_path = os.path.join(dir, file)
        file_path = os.path.normpath(file_path)
        # 打印当前文件或目录的路径
        print(file_path)
        # 检查当前项是文件还是目录
        if os.path.isdir(file_path):
            # 如果当前项是目录,增加目录计数,并递归调用scan_disk函数扫描子目录
            count[0] += 1
            scan_disk(file_path, count)
        else:
            # 如果当前项是文件,增加文件计数
            count[1] += 1
    # 返回文件和目录计数的列表
    return count

# 调用函数开始扫描指定目录
result = scan_disk('F:/test001')

# 打印文件数和目录数
print("文件数", result[1])
print("目录数", result[0])

在这里插入图片描述

  1. 编写程序显示前 100个回文素数。每行显示 10个数字,并且准确对齐
def prime_num(n):	#判断是不是素数
    if n <= 1:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True
    
def pali(n): 	#判断是不是回文数
    return str(n) == str(n)[::-1]	#将n转换成字符串,切片反转字符串,比较是不是相等


def find_pp():	#查找前100个
    count = 0
    num = 2
    while count < 100:
        if prime_num(num) and pali(num):	#两个函数都返回true
            print(f"{num:7}", end=" ")		#格式化打印num七个字符宽度
            count += 1
            if count % 10 == 0:				#没十个换行
                print()
        num += 1


find_pp()		# 调用函数

在这里插入图片描述

  1. 编写一个测试程序,读入三角形三边的值,若输人有效则计算面积。否则,显示输入无效
import math	#导入数学模块

a = float(input("请输入边a"))
b = float(input("请输入边b"))
c = float(input("请输入边c"))
if a + b > c and a + c > b and b + c > a:#两边之和大于第三边
    s = (a + b + c) / 2	#计算半周长
    area = math.sqrt(s * (s - a) * (s - b) * (s - c))	#海伦公式
    print(f"面积为:{area}")
else:
    print("无法构成三角形,请重新输入")

在这里插入图片描述

第六章 字符串和切片

字符串对象和常见方法

python字符串的定义方式

  • 由弱数据类型语言的特性决定的:

    • 单引号
    • 双引号
    • 三引号(允许换行)
    • str
    • s = str(“字符串”)

字符串常见方法

方法名说明
capitalize()格式化字符串,将字符串的首字母大写
center(width,[fillchar])之前\t(4个空格)设置字符串按照长度居中(,如果长度小于字符串,不做任何操作整个长度是50的中间,单位是符号位,字符串在50的),fillchar默认是空格,是可选参数
count()统计字符或字符串的出现次数
endswith()判断字符串是否以XXX结尾
startswith()判断字符串是否以XXX开头
index()查找字符或者字符串在字符串第一次出现的位置,如果不存在则抛出异常
rindex从右向左找,查找字符或者字符串在字符串中最后一个的位置
find查找字符或者字符串在字符串第一次出现的位置,如果不存在返回-1
rfind从右向左找,查找字符或者字符串在字符串中最后一个的位置
encode(对应的编码)python3提供将字符串转换为字节的方法(网络传输的时候需要将电信息存储到磁盘上,存储到字符串上是需要二进制数据,在python2中涉及到字符转换非常的麻烦,他不支持中文)(转换的时候需要指定编码集utf-8,转换成功后是字节,type,bxxxx是字节数据)如果字节想转换为字符串?--------decode(对应的的编码)((dir(t) t是字节) 不是字符串的方法) -------字节的方法
format格式化字符串 n =2 nn=3 print(“n={},nn={}”.format(n,nn))
islower判断是否都是小写字母
isupper判断是否都是大写字母
istitle判断字符串是否是标题
isspace判断是不是空格位(不常用,了解就行)
isdigit判断是否为数字(将字符串转换为整数,如果不是数字不能转int)
isalnum不是判断是不是全是数字,判断是否是有效符号(*$%)
isalpha判断是否都是字母
title将字符串转换为标题格式
lower将字符串转换为小写
upper将字符串转换为大写
split(“符号”)按照指定的符号将字符串进行切割(ls = s.split(" ") -----以空格分割),返回一个列表
join按照特定的符号将一个可迭代对象拼接成字符串(" ".jion(ls) ------空格拼,不是列表的方法)
strip清除字符串两侧的空格(java里面有trim()),不能清除字符串中间的空格,例如注册信息的时候,容易打空格,后台接收到的字符串含有很多空格“name ” ,如果用户以"name"登录的时候会登录失败
lstrip清除字符串左侧的空格
rstrip清除字符串右侧的空格
replace(“原字符串”,“新字符串”)替换对应的字符串
ljust左对齐
rjust右对齐

字符串切片

切片操作基本表达式:object[start_index : end_index : step]
step:正负数均可,其绝对值大小决定了切取数据时的“步长”,而正负号决定了****“切取方向,正表示“从左往右”取值,负表示“从右往左”取值。当step省略时,默认为1,即从左往右以增量1取值。“切取方向非常重要!”“切取方向非常重要!”“切取方向非常重要!”,重要的事情说三遍!

start_index:表示起始索引(包含该索引本身);该参数省略时,表示从对象“端点”开始取值,至于是从“起点”还是从“终点”开始,则由step参数的正负决定,step为正从“起点”开始,为负从“终点”开始。

end_index:表示终止索引(不包含该索引本身);该参数省略时,表示一直取到数据”端点“,至于是到”起点“还是到”终点“,同样由step参数的正负决定,step为正时直到”终点“,为负时直到”起点“

对象[start:] 从start位置开始切割字符串,切到末尾,包含strat位置

对象[start:end] 从start位置开始切割字符串,切到end位置为止,包含strat位置,不包含end位置

对象[start:end:step] 从start位置开始切割字符串,切到end位置为止,step为步长,默认值为1,当步长为负数的时候,会反向切割

第七章 内置模块

import xxx就是引用模块

OS模块

方法说明
chdir(path)修改当前工作目录 os.chdir(“c:\”)------os.chdir(“…”) ,一般不会更改
curdir获取当前目录 属性 注意返回的是相对路径 (绝对路径os.path.abspath(os.curdir))
chmod()修改权限 主要用在linux,help(os.chmod)(不做演示)
close关闭文件路径(不做演示)
cpu_count()返回cpu的核对应线程数(2核4线程)
getcwd()获取当前路径,返回的是绝对路径 ,相当于linux的pwd
getpid()获取当前进程的进程编号(任务管理器—详细信息)
getppid()获取当前进程的父进程的进程编号
kill()通过进程编号杀死进程(明白就行)
linesep对应系统下的换行符
listdir()返回对应目录下的所有文件及文件夹(隐藏文件也可以调取出来),返回的是列表
makedirs()创建目录,支持创建多层目录(文件夹)os.makedirs(“a/b/c/d”)
mkdir创建目录,只支持一层创建,不能创建多层
open创建文件,等价于全局函数open (IO流详细讲)
pathsep获取环境变量的分隔符 windows ; linux :
sep路径的分割符 windows \ linux /
remove(文件名或者路径)删除文件 os.remove(b.text)
removedirs()移除目录,支持多级删除,递归删除
system执行终端命令

os.path模块

方法说明
abspath(相对路径)返回路径对应的绝对路径(完整的路径) path.abspath(“.”)
altsep查看python中的各种符号
basename文件名称,shell编程里面也有 path.basename(“路径”)
dirname文件所在的目录,shell编程里面也有
exists判断文件或者目录是否存在(特别有用,使用爬虫爬取数据的时候需要判断是否有这个文件或者文件夹)
getctime创建时间(不做演示)
getmtime修改时间(不做演示)
getsize获取文件的大小,单位是字节
isdir判断path是不是目录(文件夹)
isfile判断path是不是文件
isabs判断是不是绝对路径(不演示)
islink判断是不是连接(不演示)
ismount判断是不是挂载文件(Linux下要用的)(不演示)
join (p1,p2)拼接路径 name=“123.txt” url=“C:/a/b/c” url +“/”+name path.jion(url,name)
sep路径分隔符 url + path.sep +name
split分割路径 path.split(“C://desktop”)
realpath返回真实路径 和abspath一样

UUID模块

UUID是一种标识符,通常用于标识信息或对象的唯一性。

import uuid
# 生成随机的UUID
unique_id = uuid.uuid4()
print(unique_id)

加密模块

hashlib模块
import hashlib
dir(hashlib)
哈希算法
1、 注意:hashlib所有的hash操作起来是一样的,就是你学会一个其它的用法都市一样的,只改变名称就可以,但是在Java里就不一样了,每个算法不一样
cmd窗口:md5 = hashlib.md5()
md5

2、 使用步骤:

创建算法对象(md5 sha256),返回一个算法对象

注意:调用MD5的时候一定要给参数,例如:md5 = hashlib.md5(“12345”),这个错误不是其他错误,需要接收字节数据不能是字符串md5 = hashlib.md5(“12345”.encode(“utf-8”))

如果不做盐值混淆,直接调用hexdigest() md5.hexdigest()

哈希算法的特点:结果唯一、不可逆,哈希算法是无法反向解密的,安全性特别强,因为结果唯一,可以使用碰撞破解,先把MD5的值存下来,下一次遇到的话就可以破解了

解密 这个网站可以对MD5密码解密

在数据校验、安全检查的时候一定不要做盐值混淆(淘宝买东西,订单的10000元可以手动改成1元,所以淘宝会对订单的生成做一个数据校验,价格、数量、时间戳(类似一个随机数)等做一个md5)

在注册账号的时候,需要输入密码和账号存储到数据库中,密码可以铭文存储到数据库吗?不可以,运维人员一定可以看的得到所有人的密码和账号,这样就很不安全,使用密码校验的时候使用的密文校验

3、 盐值混淆

Hash容易碰撞破解,一般建议使用盐值混淆
Md5.update(salt)

md5 = hashlib.md5("12345".encode("utf-8"))

md5.uptate("!@@@@&%hhh".encode("utf-8"))

md5.hexdigest()

hmac模块
hmac也是一个哈希加密库,而且用到了对称加密

参数:第一个参数是要加密的字符串,第二个参数是盐值 ,第三个参数是加密算法

hmac.new(“123456”.encode(“utf-8”),“hahhah”.encode("utf-8),md5)

首先会使用对称加密(密钥就是盐值),之后将加密后的数据再做一次hash加密,盐值混淆,所以整个结果十分安全

第八章 IO及对象序列化

什么是IO stream

  • 什么是IO流

Input output Stream 的缩写
IO流主要是计算机的输入和输出操作
常见的IO操作,一般说的是内存与磁盘之间的输入输出(侠义)
IO流操作是一种持久化操作,将数据持久化在磁盘上(例如淘宝账号和密码是使用数据库持久化,下一次登录不需要输入密码)

  • Python操作IO流

掌握open函数即可
open函数主要作用是打开本地的一个文件

  • open函数的解析(help(open))

第一个参数file 代表要打开或者创建文件的名称或者路径
第二个参数表示打开的模式(默认的是字符输入流)
其他参数
Open的简单使用

from os import path
path.abspath(".")
#在当前路径下建立一个 文件(里面写上一句话)
open("xxx.txt")
open("路径//xxx.txt")
f = open("xxx.txt","r")
dir(f)

f.read()

#打印时文件里面的语句

f.read()

#返回的是空,io流打开是一个指针,open函数的第三个参数
 F = open(path,”r”)
    
 #一般会把读到的数据保存在变量中

 Msg = f.read()
    
 #关闭IO流,操作完成一定要关闭,不然文件删除不了
 f.close()

流的分类

  • IO流的分类:

  • 根据数据流动(站在内存的角度上来说)的方向

输入流
输出流
例子:把数据保存在硬盘里是输入还是输出流?----输出流
根据数据的类型
字节流(存储图片、视频等)
字符流

字符流

f=open("xxx.txt",mode="w")
f.write("哈哈哈哈哈哈,嘿嘿嘿")
#会返回字符的个数
#这个时候打开xxx.txt 没有这一句话,没有关闭,所以没有保存
#会把写入的数据保存到缓存区,缓存区满了才会写入
#第一种方式 关闭流 关闭的时候会自动调用flus 刷新缓存区
f.close()
#不覆盖的写法
f=open("xxx.txt",mode="a")
f.write("哈哈哈哈哈哈,嘿嘿嘿")
f.close()   

在这里插入图片描述

字节流

字符流一般不会设计内存不够用的情况,即使500w字也不会有很大的内存,一个字符一个字节,1024个字=1k
help(open)
b ------------ binary mode
视频、图片、音频、可执行文件都是二进制数据,需要使用字节流
mode=“b” --------------表示字节流操作IO流
注意:字节流操作大数据的时候,不建议一次性读取
字节可以操作任何数据,字符只能操作字符数据

def copy_file(src,dest):
	f = open(src,"rb")
	f2 = open(dest,"wb")
	#不推荐
	#f2.write(f.read())
	while True:
#以M为单位读取
data = f.read(1024*1024)
#字符流读到最后会返回空 字节流b""
if data == b"":
	print("数据读取 完成")
	break
else:
	f2.write(data)
	f.close()
	f2.close()
if __name__ == '__main__':
	copy_file("a.wmv","C:\\Users\wx\\Desktop\\a.wmv")
def copy_file():
	src = input("请输入要备份的数据的路径:")
	dest = input("请输入要保存的路径:")
	f = open(src,"rb")
	f2 = open(dest,"wb")
	#不推荐
	#f2.write(f.read())
	while True:
#以M为单位读取
data = f.read(1024*1024)
#字符流读到最后会返回空 字节流b""
if data == b"":
	print("数据读取 完成")
	break
else:
	f2.write(data)
	f.close()
	f2.close()
if __name__ == '__main__':
	copy_file()

运行过程:python xxx.py
请输入要备份的数据的路径:c:\user\wx\desktop\xxx.mp4
请输入保存备份的路径:c:\user\wx\xxx.mp4
问题:python xxx.py
请输入要备份的数据的路径:c:\user\wx\desktop\xxx.mp4
请输入保存备份的路径:c:\user\wx

对象序列化

列表、字典、集合等是对象,对象都是抽象的,是我们想象的虚拟对象,需要将对象持久化,将它保存到磁盘等,所以需要序列化,
对象序列化:将内存中像对象这种抽象的概念转化为真正的字符或者字节的数据
pickle模块
可以将对象转换为字节数据
import pickle
dir(pickle)
dumps ---------------将对象序列化为字节数据 ls = [1,2,3,4,5,6,7] data = pickle.dumps(ls) f = open(“C:\Users\wx\ls.dat”,“wb”) f.write(data) f.close() 怎么读取?
loads ------------- 将字节数据反序列化为对象 f = open(“c:\ls.dat”,“rb”) show = f.read() show pickle.loads(show)
dump ---------------- 注意将对象序列化为字节数据,并且保存到file中 ls = pickle.loads(show) ls pickle.dump(ls,open(“C:\Users\wx\a.txt”,“wb”))
load ---------------- 将一个file对象反序列化为对象 pickle.load(open(“C:\Users\wx\a.txt”,“rb”))
json模块
注意:json这个模块一般用来序列化字典对象,或者转换json数据,并不是只能用来序列化字典,其他也可以

ls = [1,2,3,4,5,6]

pickle.dumps(ls)

s = json.dumps(ls)

f = open("c:\\aa.txt","w")

f.write(s)

f.close()



json.loads(open("c:\aa.txt").read())

ss = json.loads(open("c:\aa.txt").read())

第九章 面向对象

面向对象编程思想

  • 面向对象就是在编程的时候尽可能的去模拟现实世界,现实世界中,任何一个操作辑的实现都需要一个实体来完成,实体就是动作的支配者,没有实体,就没有动作的发生

  • 思考:上例报名过程中,有哪些动词:提出、提供、缴纳、获得、分配、增加,那么有动词就一定有实现这个动作的实体

  • 分析:

    • 第一步:分析哪些动作是由哪些实体发出的:

      • 学生:提出报名
      • 学生:提供相关资料
      • 学生:缴费
      • 机构:收费
      • 教师:分配教室
      • 班级:增加学生信息
      • 整个过程中,一共有四个实体:学生、机构、教师、班级
    • 第二步:定义这些实体,为其增加相应的属性和功能
      在这里插入图片描述

    • 第三步:让实体去执行相应的功能或动作

      • 学生:提出报名
      • 学生:提供相关资料
      • 教师:登记学生信息
      • 学生:缴费
      • 机构:收费
      • 教师:分配教室
      • 班级:增加学生信息

面向过程向面向对象思想迁移

  • 以前写代码:首先考虑实现什么功能,然后调用函数,之后按部就班的执行
  • 以后写代码:首先考虑应该由什么样的主体去实现什么样的功能,再把该主体的属性和功能统一的进行封装,最后才去实现各个实体的功能
  • 注意:面向对象并不是一种技术,而是一种思想,是一种解决问题的思维方式
  • 面向对象的核心思想是:对调用该功能的主体进行封装,在使用的过程中,先得到对应的主体,再使用主体去实现相关的功能

类与对象

对象

  • 概念:是一个抽象概念,对象是事物存在的实体,如:一个人
  • 每一个现实业务逻辑的一个动作实体就对应着OOP编程中的一个对象
  • 对象分为2部分
    • 静态部分:属性,客观存在,不可忽视,如:人的性别
    • 动态部分:行为,对象执行的动作,如:人跑步
  • 对象使用属性(property)保存数据,对象使用方法(method)管理数据

Python中,采用类(class)来生产对象,用类来规定对象的属性和方法即要得到对象,必须先有类

为什么要引入类的概念?

  • 类本来就是对现实世界的一种模拟,在现实生活中,任何一个实体都有一个类别
  • 类就是具有相同或相似属性和动作的一组实体的集合
  • 所以,在Python中,对象是指现实中的一个具体的实体,由于实体都有一个类别,所以OOP中的对象也都有一个类

类的定义

class Person():
    # 属性
    # 方法(函数)
    def eat(self):
        print('我喜欢吃零食')
    def drink(self):
        print('我喜欢喝可乐')

类的本质也是一个特殊的对象

  • python中一切皆为对象,类是一个特殊的对象即类对象
  • 程序运行时,类也会被加载到内存
  • 类对象在内存中只有一份,可以创建出多个对象实例

类中的self关键字

  • self是Python内置的关键字之一,其指向了类实例对象本身,用于访问类中的属性和方法,在方法调用时会自动传递实际参数self
# 1、定义一个类
class Person():
    # 定义一个方法
    def speak(self):
        print(self)
        print('Nice to meet you!')

# 2、类的实例化(生成对象)
p1 = Person()
print(p1)    # 注意观察地址
p1.speak()

p2 = Person()
print(p2)
p2.speak()

类的属性

创建类的属性:

  • 概念:定义在类中并且在函数体外的属性变量,类属性可以在类的所有实例之间共享值,是公用属性,一般记录这个类的相关特征

  • 类属性可以通过类名或实例名访问

类的方法

类中得变量和方法都叫做类成员

创建_ _ init _ _()方法 (初始化方法)

  • 在Python中,__xxx__()的函数叫做魔术方法,指的是具有特殊功能的函数
  • 思考:人的姓名、年龄等信息都是与生俱来的属性,可不可以在生产过程中就赋予这些属性呢?
  • 类创建后,可以手动创建一个_ _ init _ _()方法,该方法是一个特殊方法,类似java的构造方法,在创建一个对象时默认被调用,不需要手动调用
  • _ _ init _ _()方法必须包含一个self参数,且必须是第一个参数,其指向实例本身,没有写self或位置不对,则会报错
  • _ _ init _ _()方法开头结尾的双下划线(中间没有空格),是一种特殊约定,旨在区分默认方法和普通方法

类的方法

  • 类的成员主要由实例方法和数据成员组成

  • 实例方法本质是类中定义的函数

    • 方法名:一般使用小写字母开头
    • self:必要参数,表示类的实例
    • 其它参数:多个参数使用逗号隔开
    • 方法体:实现具体的功能
  • 实例方法与函数的区别:python函数实现的是某个独立的功能,实例方法是实现类中的一个行为,是类的一部分

  • 使用格式:实例化对象.方法名(实际参数)

创建类的静态方法

  • 作用:在开发时,如果需要在类中封装一个方法,这个方法
    • 既 不需要访问实例属性或者调用实例方法
    • 也 不需要访问类属性或者调用类方法
    • 一般打印提示、帮助等信息
  • 格式:@staticmethod,其用于修饰类中的方法,使其可以再不创建类实例的情况下进行调用,优点是执行效率高,该方法一般被成为静态方法。静态方法不可以引用类中的属性或方法,其参数列表也不需要约定的默认参数self

对象的创建和调用

属性概念:

  • Python中,任何一个对象都应该由两部分组成:属性 + 方法
  • 属性即是特征,比如:人的姓名、年龄、身高、体重…都是对象的属性
  • 对象属性既可以在类外面创建和获取,也能在类里面创建和获取

创建实例属性(默认的对象属性)

  • 概念:定义在类方法中的属性,只作用于当前对象

封装

封装是OOP中的第一个关键概念。它指的是将数据(属性)和操作数据的方法(方法)组合成一个单一的单元,称为类。类是对象的蓝图,它定义了对象的结构和行为。

class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model

    def start_engine(self):
        print(f"{self.make} {self.model}'s engine started.")

在这个例子中,我们创建了一个Car类,它具有makemodel属性以及start_engine方法。属性封装了数据,方法封装了操作。

继承

继承是OOP中的第二个重要概念。它允许您创建一个新的类,从现有的类派生出来,并继承其属性和方法。这使得代码重用和层次结构变得更加容易。

class ElectricCar(Car):
    def __init__(self, make, model, battery_capacity):
        super().__init__(make, model)
        self.battery_capacity = battery_capacity

    def start_engine(self):
        print(f"{self.make} {self.model}'s electric motor started.")

在这个例子中,我们创建了一个ElectricCar类,它继承了Car类的属性和start_engine方法。我们还可以在子类中重写方法,以改变其行为。这允许我们在不影响原始类的情况下创建特定类型的对象。

多态

多态是OOP的第三个关键概念。它允许不同类的对象对相同的方法做出不同的响应。这使得我们能够编写通用的代码,能够处理多种对象类型。

def drive_vehicle(vehicle):
    vehicle.start_engine()

my_car = Car("Toyota", "Camry")
my_electric_car = ElectricCar("Tesla", "Model 3", "75 kWh")

drive_vehicle(my_car)            # 输出:Toyota Camry's engine started.
drive_vehicle(my_electric_car)   # 输出:Tesla Model 3's electric motor started.

在这个例子中,drive_vehicle函数接受任何具有start_engine方法的车辆对象。这展示了多态的强大之处,因为它允许我们在不知道具体对象类型的情况下调用方法。

总结一下,Python的面向对象编程通过封装、继承和多态提供了强大的工具,使代码更模块化、可重用和易于维护。这些概念是Python中创建复杂应用程序和系统的关键。

第十章 异常处理

异常处理是Python编程中不可或缺的一部分。它允许您在程序出现错误或异常情况时采取适当的措施,以确保程序能够继续执行或以优雅的方式失败。

什么是异常?

在编程中,异常是指程序在执行过程中遇到的问题或错误。这些问题可以是语法错误、逻辑错误或运行时错误。Python将异常视为对象,这些对象包含有关问题的信息,如错误消息、行号和堆栈跟踪。

异常的类型

Python提供了许多内置的异常类型,用于处理各种错误情况。以下是一些常见的异常类型:

  • SyntaxError:语法错误,通常是由于代码不符合Python语法规则引起的。
  • TypeError:类型错误,发生在操作不兼容的数据类型时。
  • NameError:名称错误,通常是由于尝试使用未定义的变量或函数引起的。
  • ValueError:值错误,发生在使用正确类型的数据,但其值不合法时。
  • ZeroDivisionError:零除错误,发生在试图除以零时。
  • FileNotFoundError:文件未找到错误,通常在尝试打开不存在的文件时引发。
  • Exception:所有异常的基类,可以用于捕获任何异常。

异常处理的语法

在Python中,异常处理使用tryexcept语句来实现。try块包含可能引发异常的代码,而except块包含在发生异常时要执行的代码。以下是一个简单的异常处理示例:

try:
    # 可能引发异常的代码
    result = 10 / 0
except ZeroDivisionError:
    # 处理特定类型的异常
    print("除以零错误发生了!")

在这个示例中,try块中的除法操作可能引发ZeroDivisionError异常。如果异常发生,程序将跳转到except块,然后打印错误消息。

使用elsefinally

除了tryexcept,Python还提供了elsefinally块:

  • else:在try块中没有发生异常时执行的代码块。
  • finally:无论是否发生异常,都会执行的代码块。
try:
    result = 10 / 2
except ZeroDivisionError:
    print("除以零错误发生了!")
else:
    print(f"结果为:{result}")
finally:
    print("无论如何都会执行这里的代码")

主动引发异常

除了捕获异常,您还可以使用raise语句主动引发异常。这对于在特定条件下引发自定义异常非常有用。

age = -1
if age < 0:
    raise ValueError("年龄不能为负数")

自定义异常

您还可以创建自定义异常类,以便更好地组织和处理程序中的异常情况。自定义异常类通常继承自内置的Exception类。

class MyCustomException(Exception):
    def __init__(self, message):
        super().__init__(message)

try:
    # 某种条件触发自定义异常
    if some_condition:
        raise MyCustomException("自定义异常发生了!")
except MyCustomException as e:
    print(e)

异常处理的最佳实践

  • 明确处理异常:始终尽量明确地处理异常,不要忽略它们。
  • 只处理必要的异常:不要捕获过于宽泛的异常,只捕获您能够处理的异常类型。
  • 记录异常:使用日志记录来记录异常,以便更容易调试和监视应用程序。
  • 使用finally:如果您有需要在无论异常是否发生时都执行的清理代码,使用finally块。

示例三

  1. 设计一套带有界面的可以注册登录的程序
# 导入模块
import os
import hashlib
import uuid

# 定义常量:UI
UI = """
*************
1.注册
2.登陆
*************
"""
# 判断 password.txt是否存在,不存在就创建
if not os.path.isfile("F:/password.txt"):
    open("F:/password.txt", "w").close()

# 生成盐值
def get_salt():
    return str(uuid.uuid4())

# 对密码进行+盐计算
def hash_pass(password, salt):
# 给一个字符串:用户输入的密码+随机盐值
    salt_password = password + salt
    # 通过md5加密字符串,并返回16进制字符串
    hash_password = hashlib.md5(salt_password.encode()).hexdigest()
    return hash_password

# 注册账户
def register():
    username = input("请输入账户")
    password = input("请输入密码")
    #通过get_salt函数获取随机盐值
    salt = get_salt()
    #通过hash_pass函数,传入password和salt
    hash_password = hash_pass(password, salt)
    with open("F:/password.txt", "a") as f:
        f.writelines(f"{username}:{hash_password}:{salt}\n")
    print("注册成功")
    
# 获取密码
def fromPassword():
	# 创建一个字典
    dc = {}
   	#检查文件是否存在
    if os.path.isfile("F:/password.txt"):
    	# 打开文件
        with open("F:/password.txt", "r") as f:
        	#遍历将文件内容给line
            for line in f:
            # 通过:分割字符串,
                username, ha_pass, salt = line.strip().split(":")
                #返回username键对应的值
                dc[username] = (ha_pass, salt)
    return dc
    
# 登录模块
def login():
    username = input("请输入账户")
    password = input("请输入密码")
    # 获取dc返回username键对应的值
    dc = fromPassword()
    # 如果username在dc里面
    if username in dc:
    # 将注册时的加盐密码和盐值取出,重新加密
        ha_pass, salt = dc[username]
        # 对输入的密码加盐加密
        input_hashed_password = hash_pass(password, salt)
        # 如果两个密码一样则登录成功
        if ha_pass == input_hashed_password:
            print('登录成功')
            #不一样就是密码错误
        else:
            print('密码错误')
     # 如果username没读到则账户不存在
    else:
        print("账户不存在")

# 主函数
if __name__ == '__main__':
# 程序阻塞
    while True:
    # 打印UI
        print(UI)
        select = int(input('请输入序号选择功能:'))
        # 如果输入1,执行注册函数
        if select == 1:
            register()
        # 输入2,执行登录函数
        elif select == 2:
            login()

测试结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 创建一个shape类有两个属性center x,center y表示中心坐标 创建一个Rectangle类继承Shape 新增宽高属性 再创建一个circle类继承Shape新增半径属性 矩形和圆形都有一个方法叫做is in(self,x,y) 判断坐标(x,y)是否在图形范围中,如果 (x,y) 在则返回true反之返回false
  • 如何确定x,y在矩形或者圆形范围内
    矩形:确定矩形的左上角和右下角坐标。检查给出坐标是否在这两点之间
    圆形:使用坐标(x,y)和圆心坐标计算与圆心的距离,若小于等于半径,则坐标在圆内。
import math

# 初始化两个图形
class Shape:
    def __init__(self, center_x, center_y):
        self.center_x = center_x
        self.center_y = center_y

# 矩形模块
class Rectangle(Shape):
    def __init__(self, center_x, center_y, width, height):
        super().__init__(center_x, center_y)
        self.width = width
        self.height = height

    def rect_in(self, x, y):
        half_width = self.width / 2
        half_height = self.height / 2
        left = self.center_x - half_width
        right = self.center_x + half_width
        top = self.center_y + half_height
        tail = self.center_y - half_height

        if left <= x <= right and tail <= y <= top:
            return "在矩形内"
        else:
            return None

# 圆形模块
class Circle(Shape):
    def __init__(self, center_x, center_y, r):
        super().__init__(center_x, center_y)
        self.r = r

    def cir_in(self, x, y):
        distance = math.sqrt((x - self.center_x) ** 2 + (y - self.center_y) ** 2)
        if distance <= self.r:
            return "在圆内"
        else:
            return None

#交互,要求用户输入
rect = input("请输入矩形的中心 x 坐标,中心 y 坐标,宽度和高度(以空格分隔):")
rect_values = rect.split()  # 拆分输入值

circle = input("请输入圆形的圆心坐标(x,y)和半径r(以空格分隔)")
circle_values = circle.split()
#检查输入的是否正确
if len(rect_values) != 4 or len(circle_values) != 3:
    print("输入格式不正确,请输入正确的值。")
else:
#map用来返回一个迭代器。相当于rect_center_x = float(rect_values),按顺序给每个变量赋值
    rect_center_x, rect_center_y, rect_width, rect_height = map(float, rect_values)
    circle_center_x, circle_center_y, circle_center_r = map(float, circle_values)
    rect = Rectangle(rect_center_x, rect_center_y, rect_width, rect_height)
    circle = Circle(circle_center_x, circle_center_y, circle_center_r)
    print("矩形已创建。")
    print("圆形以创建")

x = float(input("请输入要测试的 x 坐标:"))
y = float(input("请输入要测试的 y 坐标:"))

rect_result = rect.rect_in(x, y)
circle_result = circle.cir_in(x, y)
#根据函数返回判断点在哪
if rect_result and circle_result:
    print("点" + rect_result + ",点" + circle_result)
    print("点既在矩形内又在圆内")
elif rect_result:
    print("点" + rect_result)
elif circle_result:
    print("点" + circle_result)
else:
    print("不在这两个图形中")
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值