语法规范
- 分行
在 python 中 " 分行 " 表示一个语句的结束,一行代码就是一个语句,与 c 语言、java 不同,python 分行不需要特定的分行符,直接敲击回车即可
需要编写多条语句时,用回车分行
print("hello,world!")
- 缩进
python 中虽然没有特定的分行符,但是用严格的缩进来表示程序的格式框架,缩进是指每一行代码开始前的空白区域,用来表示代码之间的包含和层次关系,一般通过 Tab 键缩进代码
- 注释
增加程序可读性
在 python 中使用 # 来表示单行注释
#这是一个单行注释
从 # 标记开始到本行结束是注释
使用三个单引号开头和结尾 "' 表示对多行语句进行注释
'''这是一个多行注释,一般用于对语句、函数、数据结构或者方法等进行说明'''
pycharm 中会自动将单行注释的内容标注为灰色,多行注释的内容标注为绿色
- 输入法
除字符串内容外,所有其他代码都需要使用英文输入法输入,否则在编译运行时会出现语法错误
- 大小写敏感
python 中对英文输入法输入的大小写字母敏感,A 和 a 表示的含义是不同的
变量
python 中以 "变量" 的形式保存和表示具体的数据值,为了更好地使用变量,需要给程序中使用到的变量命名,称为标识符或变量名
python变量名只能包含以下四种字符:
- 小写字母(a - z)
- 大写字母(A - Z)
- 数字(0 - 9)
- 下划线( _ )
变量名不允许以数字开头
不允许使用各版本下保留的关键字
合法:area_123 iphone11
不合法:123(使用数字开头) for(使用了Python关键字)
数据类型
python 变量在使用时不需要声明,直接使用等号对变量进行赋值
变量名 = 变量值
常见的数据类型有:数值数据类型、布尔数据类型、字符串数据类型
数值数据类型
整数
int 整型 long 长整型
num1 = 34
带小数点的数
float 浮点型数据
num2 = 67.84
布尔数据类型
只有两个值,True 和 False,这种变量一般在条件运算中,程序根据布尔变量的值来判断进行何种操作
#表示将布尔数True赋值给变量flag
flag = True
字符串数据类型
一般指使用双引号、单引号或者三引号包括起来的变量
#表示将字符串"i love you"赋值给变量str1
str1 = 'i love you'
使用三引号进行字符串赋值的数据中,可以包含双引号
"' (包含'') '''
使用双引号进行字符串赋值的数据中,可以包含单引号
''(包含')''
str1 = '''hello ''world'''''
str2 = "hello 'world'"
str3 = 'hello world'
print("str1 = "+st1)
print("str2 = "+st2)
print("str3 = "+st3)
#输出
str1 = hello "world"
str2 = hello 'world'
str3 = hello world
''' 当一条语句以三引号开头时,表示多行注释
当三引号用在变量赋值语句时,表示对字符串数据变量赋值
变量的输入
python 中可以使用变量赋值语句直接赋值,也可以通过与用户之间的交互,由用户对变量进行输入赋值
当需要用户对单个变量进行赋值时,使用带 input 函数的赋值语句完成,可以在 input 函数中给用户提示输入信息
使用以上 input 方式进行变量的输入,所有的输入都会被当作字符串看待
a = input()
b = intput("请输入字符:")
当需要用户输入数值数据类型变量时,使用 eval() 返回字符串的表达式结果
变量名 = eval(input([提示字符串]))
当需要用户输入多个数值型变量时,可以在输入时用逗号,将各个变量值分隔开
a,b,c = eval(input())
#一次性对a,b,c三个数值类型变量进行输入1,2,3
变量的输出
python 变量有直接输出和格式化输出两种方式
直接输出
使用 print(变量名) 可以直接输出单个变量值
#print(变量名)
a = "hello world"
a = print(a)
格式化输出
既可以使用 c 语言传统的 % 方式,也可以使用 format 函数定义格式化输出
print("<模板字符串>".format(<逗号分隔的参数>))
模板字符串包含需要输出的固定内容部分和动态变化部分
动态变化的部分用 { } 占位,每一对 { } 称为槽
槽的内部结构如下:
参数序号 :<填充> <对齐> <宽度> <,> <.精度> <类型>
参数序号从 0 开始计数,参数序号 0 表示在 format 函数中一个需要输出的变量,以此类推
<宽度> 可以设定输出的指定宽度,即字符数
<对齐> 可以选择将需要输出的变量在指定的宽度内进行对齐,其中小于号表示左对齐,大于号表示右对齐,乘方号表示居中对齐
<填充> 使用特定的单个字符,用于填充 当输出变量长度小于指定宽度时的空白区域
a = "hello world"
print("a = {0}".format(a))
使用 format 格式化输出字符串变量 s
参数序号 :<填充> <对齐> <宽度> <,> <.精度> <类型>
0 : ? ^ 10 <,> <.精度> <类型>
槽格式定义了输出格式为输出宽度为 10,变量在指定宽度内居中对齐,且指定宽度剩余空白区域使用问号进行填充
s = "hello"
print("***{0:?^10}***".format(s))
格式控制标记中的后三位标记 用于进行数值输出时对变量进行格式化约束
<,> 在输出数值时,依照西方的数字显示习惯,在整数部分每隔三位数加进一个逗号,即数字的千分位分隔符
<.精度> <类型> 结合在一起使用,<.精度> 表示浮点数输出保留小数的位数,<类型> 表示输出变量数组的类型
字母 f 表示将十进制数格式化为浮点数
字母 e 表示将十进制数格式化为科学计数法形式
槽格式定义了输出格式为显示千分位分隔符,小数点后保留四位小数,右对齐,输出宽度15,使用*填充
num1 = 1234.5678
print("{0:*>15,.4f}".format(num1))
python 变量除了包含加 +,减 - ,乘 * ,除 / 之外,还包括另外四种基本运算符:整数除法,取模,次幂,取负值
x = 7
y = 2
#整数除法
#表示求x与y的商然后取整 结果为3
r1 = x // y
r1 = 3
#取模
#表示求x与y之间商的余数
r2 = x % y
r2 = 1
#次幂
#表示求x的y次幂
r3 = x ** y
r3 = 49
#取负值
#表示求x的负值
r4 = -x
r4 = -7
python 还提供了一些内置数值运算函数
abs():取绝对值
#对-5取绝对值 结果为5
abs(-5)
round():四舍五入取整
#对2.6四舍五入去整后 结果为3.0
round(2.6)
max():求最大值
#返回四个数字中的最大值 结果为9
max(1,5,2,9)
min():求最小值
#返回四个数字中的最小值 结果为-4
min(9,2,-4,2)
pow():求次幂
#计算2的3次幂 结果为8
pow(2,3)
通过内置的数字类型转换函数可以显性地在数字类型间进行转换
#字符转整数
#可以将字符串"5"转换为整数integer 返回结果为整数数值5
int("5")
#浮点转字符
#可以将浮点数2.3转换为字符串string 返回结果为字符串"2.3"
str(2.3)
关系表达式与逻辑表达式
关系运算符用于两个表达式的比较,若比较结果为真,返回 True,若比较结果为假,返回 False,用关系运算符连接的表达式为关系表达式
print(3 < 5) True
print(4 <= 2) False
print(3 > 4) False
print(4 >= 3) True
#一个等号用于表示对变量的赋值
#等于运算符则用于判断语句、循环语句
print(3 == 4) False
print(3 != 4) True
逻辑运算符用于得到一个或多个比较表达式进行逻辑运算后的结果
and 运算符:and 操作两边的结果都是True 时,结果才是True,其他情况都返回 False
print(5 >= 4 and 4 < 3) False
print(12 > 4 and 3 <= 5) True
or 运算符:or 操作两边的结果都是 False 时,结果才是 False,其他情况都返回 True
print(5 >= 4 and 4 < 3) True
print(12 < 4 and 3 >= 5) False
not 运算符:返回与原表达式相反的值
#虽然3 > 5 为假 但是取反之后会返回True
print(not(3 > 5)) True
print(not(3 < 5)) False
库的导入
当需要使用开根号、求立方等更复杂的运算时,可以通过导入 python 提供的内置数学类函数库 math 库解决
math 库支持各类整数和浮点数运算,不过 math 库中的函数不能直接使用,需要首先使用保留字 import 引入该库
python 库的导入有两种方式
方法一
通过 import 直接导入库,在引用导入库内的函数时,需要在函数名前加上即 库名.函数名
import 库名
使用 math 库库中开根号函数 sqrt 计算变量 a 的平方根
#引入math库
import math
a = 4
# 库名.函数名 调用math库中的开根号函数sqrt计算变量a的平方根
print(math.sqrt(a))
方法二
使用 from + import 的方式导入库,在引用导入库内的函数时,可以直接使用函数名,不再需要加库名为前缀
from 库名 import 函数名
#使用from + import方式引入math库中的开根号函数
from math import sqrt
a = 4
# 直接使用开根号函数sqrt计算变量a的平方根
print(sqrt(a))
以上方法适用于任何 pyhton 库的导入
结构化程序设计
顺序结构
指程序按照系统功能进行自上而下的设计,各个功能按照代码块的排列顺序依次执行
提示用户这个程序的功能是计算的 pizza 的面积,用户输入要计算面积的 pizza 的尺寸,程序利用圆的面积公式 S = π * r^2 计算 pizza 的面积,最后输出 pizza 的面积
由于会使用到 math 库中的 pi,需要提前通过 import 关键字导入 math 库
要求输出的宽度为 10 个字符,保留面积小数点后两位
import math
print("这个程序用于计算pizza的面积")
r = eval(input("请输入要计算面积pizza的半径"))
area = math.pi * r * r
print("area is {:10.2f}".format(area))
选择结构与循环结构
春节各大商场打折促销方式如下:
天虹商场:
购物金额在 1000 以内(包括 1000 元),九二折
购物金额在 1000 ~ 3000 元(包括 3000元),八五折
购物金额在 3000 ~ 5000 元(包括 5000元),七八折
购物金额超过 5000 元,七折
友谊新天地:
购物不足 2000 元不予优惠
购物超过 2000 元,超过部分七折优惠
大力发商城:
每满 500 元减 70 元,不足 500 元部分不减免
编写一个程序①依次输入要购买的商品的单价和数量,计算出购物的总价,然后根据商场的促销信息 ②计算折后金额 ③对比选出最便宜的商场,通过对比各个商场的折后金额,选取最小值所在的商场,并输出商场的名称和最终价格
计算总金额功能中,需要顾客重复输入不同商品的单价和数量,直到全部商品输入完毕为止,由于事先并不知道商品的种类,顺序结构无法实现这一功能
计算机中某些语句的重复执行被称为循环:只要写很少的语句,计算机就会反复执行,完成大量的同类操作
循环结构主要由两个语句组成,while 语句和 for 语句
while 语句
通常用于不固定次数的循环语句中
#当条件判断为True时 程序块会被重复执行 当条件为False时 循环终止 执行while语句的后续语句
while(True):
程序块
代码语句1
for 语句
通常用于执行固定次数的循环
#如果列表中有N个变量 程序段将会被执行N次
for N in 列表:
程序块
代码语句1
通过循环语句,用户可以重复从键盘上输入所购物品的单价和数量,并计算购物总金额,直到当价格为 0 时停止
money = 0
price = 1
#从键盘上输入所购物品的单价和数量 并计算购物总金额(当价格为0时停止)
while price != 0:
price = eval(input("请输入所购物品的单价:"))
amount = eval(input("请输入所购物品的数量:"))
money = money + price * amount
计算折后金额功能中,天虹和友谊新天地的折扣,需要根据用户所购商品的金额不同,做出不同决策
计算机中根据不同情况进行不同的操作→ 选择结构
选择结构按照系统功能需求进行设计,但功能程序在运行时,会根据特定的判断条件选择其中一个分支执行
在 python 中使用 if 语句可以实现选择结构
一般而言,选择结构可以细分为:单分支、双分支、多分支
#单分支
if(条件):
语句块1
#当条件表达式的运算结果为True执行语句块1否则不执行
if(True):
语句块1
代码语句2
if(False):
语句块1
代码语句2
#双分支
if(条件):
语句块1
else:
语句块2
#当条件表达式的运算结果为True执行语句块1否则执行语句块2
if(True):
语句块1
else:
语句块2
if(False):
语句块1
else:
语句块2
#多分支
#当条件1表达式的运算结果为True则执行语句块1 当条件2表达式的运算结果为True则执行语句块2 当其他条件都不满足时则执行语句块n
if(True):
语句块1
elif(True):
语句块2
...
else:
语句块n
if(False):
语句块1
elif(True):
语句块2
...
else:
语句块n
使用多分支选择结构计算天虹商场的应付金额,并将折后金额保存在 cash_1 中
if money <= 1000:
cash_1 = money * 0.92
elif money <= 3000:
cash_1 = money * 0.85
elif money <= 5000:
cash_1 = money * 0.78
else:
cash_1 = money * 0.7
使用双分支选择结构计算友谊新天地的应付金额,并将折后金额保存在 cash_2 中
if money >= 2000:
cash_2 = (money - 2000) * 0.6 + 2000
else:
cash_2 = money
直接计算大力发商城的应付金额,并将折后金额保存在 cash_3 中
cash_3 = money - int(money / 500) * 0.7
最后利用嵌套的双分支选择结构,比较 3 个商场的应付金额,得到最终答案
if cash_1 <= cash_2:
if cash_1 <= cash_3:
print("请选择天虹")
else:
print("请选择大力发商城")
else:
if cash_2 < cash_3:
print("请选择友谊新天地")
else:
print("请选择大力发商城")
列表(list)
假设某公司的年终庆典抽奖规则如下:
员工入场时由机器随机选取一组黑白球号码,然后等到了抽奖环节时,开奖确定各获奖等级
编写一个 python 程序用于模拟"黑白球"开奖及机选号码单式投注,生成开奖号码,判断机选号码与开奖号码的中奖情况
抽奖程序需要有明确投注规则和中奖规则才能正确实现抽奖功能
投注规则:
"黑白球"抽奖投注区分为黑色球号码区和白色球号码区,黑色球号码区从1~10中选择,白色球号码从1~5中选择,"黑白球"每注投注号码由 4 个黑色球号码和 1 个白色球号码组成,自选号码单式投注为参加抽奖的员工,自行选择对应的黑白球,机选号码单式投注则由及其随机生成黑白球号码组成为一注投注号码的投注
中奖规则:
"黑白球"奖级设置分为一到六等奖
奖级 中奖规则
黑色球 白色球 中奖说明
一等奖 4 1 中 4 + 1
二等奖 4 中 4 + 0
三等奖 3 1 中 3 + 1
四等奖 3 中 3 + 0
五等奖 2 1 中 2 + 1
六等奖 2 中 2 + 0
如果选取的4个黑色球号码与1个白色球号码跟开奖的结果完全一致,即中 4 + 1,则为一等奖
如果只有 4 个 黑球与开奖结果匹配,白球不匹配,即中 4 + 0,则为二等奖
三 ~ 六等奖随着黑球和白球匹配数量的减少,依次递减
控制台需要输出本次开奖的中奖号码,以及自己的机选号码
计算机不仅要对单个变量表示的数据进行处理,更多情况下,需要对一组数据进行批量处理
在抽奖程序中,无论是开奖号码还是机选号码,都需要有一种数据结构用于存储一组数据进行批量处理,即 4 个黑色球的号码和一个白色球的号码
把投注号码和开奖号码分别存放在列表 mynum 和 lotterynum 中,通过对列表 mynum 和 lotterynum 的比较,判断中奖情况
把抽奖程序分为:1.机选投注 2.开奖号码 3.中奖匹配 4.中奖等级与兑奖
根据投注规则,需要从1 ~ 10 中生成 4 个不同黑色球号码并排序,从 1 ~ 5 中生成 1 个白色球号码,可以把生成的 5 个机选号码存放在 mynum
随机生成一个指定范围内的数值
random 库是是 python 自带标准库,作用是生成随机数,要使用 random 库中的函数需要用 from random import* 导入
包含两个随机数生成函数:randrange() 和 randint()
区别在于生成随机数的范围以生成 1 ~ 10 之间的随机整数为例
#生成1~9之间的随机整数
randrange(1,10)
#生成1~10之间的随机整数
randint(1,10)
机选投注功能实现
#random库的导入
from random import randint
mynum = []
x = 0
while(x < 4)
#注意随机整数生成函数的使用
num = randint(1,10)
if num not in mynum:
mynum.append(num)
x += 1
#升序排序
mynum.sort()
num = rnadint(1,5)
mynum.append(num)
开奖号码功能实现
根据开奖规则,需要从1 ~ 10 中生成 4 个不同黑色球号码,从 1 ~ 5 中生成 1 个白色球号码,可以把生成的 5 个开奖号码存放在 lotterynum,0 ~ 3 号元素为黑色球号码,4号元素为白色球号码
开奖号码功能和机选投注功能一模一样,可以理解为再随机投注,这一注为中奖号码
lotterynum = []
x = 0
while(x < 4)
num = randint(1,10)
if num not in lotterynum:
lotterynum.append(num)
x += 1
num = randint(1,5)
lotterynum.append(num)
中奖匹配功能实现
根据中奖规则,需要判断投注号码中黑色球和开奖号码中黑色球的匹配个数,以及投注号码中白色球与开奖号码中白色球是否相同,用 blackok = 0 记录投注黑色球与开奖号码匹配个数,whiteok = false 用于标注投注白色球是否与开奖号码一致
对开奖号码列表切片,获得开奖号码的黑色球列表 blacklotterynum,迭代投注号码 mynum 中的 0 ~ 3 号元素,查看投注号码中的元素是否存在于开奖黑色球列表 blacklotterynum,如果存在,blackok 的值 + 1
如果投注白色球 mynum[ 4 ] 与 看奖白色球 lotterynum[ 4 ] 的值相同,whiteok = true,标识白色球匹配
range 是一个函数,它返回的是一个可迭代对象,大多使用于for循环中,相当于C/Java 里面的 for (int i = m;i < n;i++)循环
Python for i in range ()用法详解
blackok = 0
whiteok = False
#切片获取黑球的开奖号码
blacklotterynum = lotterynum[0:4]
for i in range(len(mynum) - 1):
x = mynum[i]
if x in blacklotterynum:
blackok += 1
#访问白球投注号码和开奖号码进行匹配
if mynum[-1] == lotternum[-1]:
whiteok = True
中奖等级与兑奖功能实现
一个简单的多分支选择结构,分别罗列从一等奖到六等奖的中奖条件,并将对应中奖等级的字符串赋值给变量prizerank即可,兑奖功能中注意使用 == 判断
if(blackok == 4 and whiteok):
prizerank = "一等奖"
elif(blackok == 4)
prizerank = "二等奖"
elif(blackok == 3 and whiteok):
prizerank = "三等奖"
elif(blackok == 3):
prizerank = "四等奖"
elif(blackok == 2 and whiteok == False):
prizerank = "五等奖"
elif(blackok == 2):
prizerank = "六等奖"
else:
prizerank = "未中奖"
python 中提供了列表(list)来实现一组数据进行批量处理的功能
在列表中的每一个数据称为元素,列表中可以包含多个元素,元素个数没有限制,元素类型也可以不同
1.初始化列表:用于创建一个空列表,或者含有某些元素的列表
2.求列表长度:用于获取列表长度,即列表中的元素个数
3.访问列表元素:用于访问列表中某个特定位置的元素
4.修改/添加列表:用于修改列表中某一个特定位置的元素,或者往列表中添加一个元素
5.判断元素:用于判断某个元素是否是列表元素
6.列表排序:用于将列表中的元素进行从大到小,或者从小到大的进行排序
7.列表切片:用于获取列表中某几个特定元素
8.删除元素:用于删除列表中某个指定元素或者整个列表
列表的基本操作
根据一个班的所有学生的平时(20%)、期中(30%)、期末(50%)计算总评成绩分别需要分配变量,给每个学生分配 4 个变量(通过姓名做标识),一个班(假设有40个学生)就需要分配 4 * 40 ==160个变量
用一个统一的名字 score 来存储学生的成绩,其中每个成绩的访问可以通过位置加以区分,python 中通过了列表来实现这一功能
python 中用 [ ] 表示列表,并使用变量赋值语句初始化列表
表示列表的 [ ] 中既可以没有任何元素:空列表,也可以放置需要在初始化时生成的元素
#初始化了一个变量名为 ls1 的空列表
ls1 = []
#初始化一个含有 90,93,85,96 变量名为 ls2 的列表
ls2 = [90,93,85,96]
print("ls1 = ",ls1)
print("ls2 = ",ls2)
一维列表
ls1 = [ ]
ls2[0] ls2[1] ls2[2] ls2[3]
ls2 = 90 93 85 96
需要创建二维列表时,使得每个列表元素为列表类型
#初始化 ls3 列表,含两个列表元素,每个列表元素为列表类型
ls3 = [["李明",93,85,96],["王军",83,95,91]]
ls3[0][0] ls3[0][1] ls3[0][2] ls3[0][3]
李明 93 85 96
ls3[1][0] ls3[1][1] ls3[1][2] ls3[1][3]
王军 83 95 91
求列表长度
#使用 len(列表名) 的方式可以返回对应列表名中元素的个数即列表长度
ls2 = [90,93,85,96]
#输出变量名为 ls2 的列表长度为 4
print(len(ls2))
访问列表元素
列表中的元素可以通过 列表名[ 索引号 ] 进行访问,列表中的索引号从 0 开始,即列表中第一个元素的索引是 0(而不是 1 ),列表中最后一个元素的索引号既可以是 列表长度 - 1 也可以是 -1,依次类推,倒数第二个元素的索引号可以是 -2. . .
0 1 2 3
ls2 = 90 93 85 96
-4 -3 -2 -1
a = ls2[ 0 ] = 90
c = ls2[ -1 ] = 96
ls2 = [90,93,85,96]
#将 ls2 的第 0 号元素值 90 赋值给变量 a
a = ls2[0]
#将 ls2 的最后一个元素值 96 赋值给变量 c
c = ls2[-1]
print("a = {0},c = {1}".format(a,c))
#输出
a = 90,c = 96
修改 / 添加列表元素
当需要修改列表中的某一个元素时,可以通过赋值语句,访问并修改列表中指定位置的元素
append()方法用于向列表的结尾添加元素
insert() 方法用于在指定位置插入元素
extend() 方法用于将一个列表添加到该列表的尾部
ls2 = [90,93,85,96]
#将 ls2 的第 1 号元素的值由 93 修改为 95
ls2[1] = 95
#使用 列表名.append(元素) 的方式可以向列表的尾部添加元素
#在 ls2 列表末尾添加新元素 88
ls2.append(88)
print(ls2)
#输出
[90,95,85,96,88]
判断元素
使用 in 与 not in 关键字,可以判断某个元素是否存在列表中
ls2 = [90,93,85,96]
#判断 95 是否为 ls2 的元素
x = 95 in ls2 False
y = 95 not in ls2 True
列表排序
当需要对列表中的元素进行排序时,使用 列表名.sort() 与 列表名.sort(reverse = True) 可以分别完成对列表元素的 升序 和 降序 排列
ls2 = [90,93,85,96]
#对 ls2 进行升序排序后 列表中的元素顺序为 85,90,93,96
ls2.sort()
#对 ls2 进行降序排序后 列表中的元素顺序为 96,93,90,85
ls2.sort(reverse = True)
列表切片
使用 列表名[ 起始索引号:结束索引号:步长step ],可以返回列表中某一段区间内的所有元素
步长:从 位置 m 到位置 n,每 step 个位置取一个值
注意:列表切片语法中的切片区域 含头不含尾
ls2 = [90,93,95,97,91,92]
#将 ls2 的 1 - 3 号(即切片区域含头不含尾)元素切给ls3,ls3的元素为93,85,96
ls3 = ls2[1:4]
删除元素
remove() 方法用于删除第一次出现的元素
pop() 方法用于删除指定位置的元素
del() 语句用于删除指定元素或列表
list1 = ['pyhton3',95,'c',2019,95,96,95]
#删除第一次出现的元素95
list1.remove(95)
#list1 = ['pyhton3','c',2019,95,96,95]
#删除并返回最后一个元素95
x = list1.pop()
#list1 = ['pyhton3','c',2019,95,96] x = 95
#删除指定元素
del list1[0]
#['c', 2019, 95, 96]
#删除整个列表 list1不再存在,访问list1将会出现异常
del list1
列表反转
ls2 = [90,93,85,96]
#reverse()用于反转列表元素顺序
ls2.reverse()
#ls2 = [96,85,93,90]
max() 用于求列表中最大的元素,min() 用于求列表中最小的元素
count() 方法用于统计某个元素在列表中出现的次数,index() 方法用于从列表中找出某个值第一个匹配项的索引位置
字符串应用
情报传递的一种方法是使用密码本加密码翻译从而获得情报,假如约定好用一本书作为密码本,发送方需要发送一串数字密码即明码,其中每四位数字代表一个字,接收方根据这四位数到密码本中找对应的字,这四位数代表第几行的第几个字,假定收到一串密码:0022,0529,0920,0121,0204,0729,通过译码规则,可以得到这段情报为 7 个字,分别为密码本中第 0 行 第 22 个字,第 5 行 第 29 个字 . . . 译码后得出的结果为"已暴露快转移"
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
我 和 莫 大 帅 手 拉 着 手 回 到 了 老 房 子 , 我 们 已 经 像 最 平 凡 的 恋 人 一 0
样 手 拉 着 手 , 一 点 也 不 会 感 到 别 扭 , 心 里 充 满 了 快 乐 。 1
转 头 看 见 莫 大 帅 好 笑 地 看 着 我,眼 睛 都 是 宠 溺 。 2
他 带 我 去 了 阁 楼 , 那 间 阁 楼 我 从 未 进 去 过 。 搬 来 的 第 一 天 , 我 便 3
看 到 了 那 上 面 红 色 的 大 锁 。 结 果 莫 大 帅 连 钥 匙 都 没 用 就 打 开 了 锁 , 他 4
举 着 那 把 锁 对 我 说 : " 如 果 你 多 点 好 奇 心 , 你 早 就 会 发 现 , 我 也 会 暴 5
出 更 多 秘 密 。 " 6
阁 楼 古 老 陈 旧 , 木 质 的 地 板 散 发 着 琥 珀 色 的 沉 香 。 莫 大 帅 移 出 角 7
落 里 的 一 个 纸 箱 , 我 好 奇 地 凑 上 去 。 我 打 开 一 本 相 册 , 看 到 了 童 8
年 的 莫 大 帅 。他 的 脸 白 白 净 净 , 发 型 古 怪 , 还 露 出 缺 了 大 门 牙 的 牙 齿 。 9
译码规则中最重要的环节就是根据获得的密码,在密码本中找到对应的文字,涉及到对于文本信息的处理,在编程语言中单个文字被称为字符,由多个字符组成的文本信息,一般被称为字符串(String),字符串是 python中一个重要的数据类型,是由 0 个或者多个字符组成的有序序列,在 python 中字符串可以使用英文输入法下成对的单引号( ' )、双引号( '' )、或者三引号( ''' )括起来,其中三引号括起来的方式保留了字符串中的全部格式信息
译码可以分为初始化和密码译码这两个主要功能,如何在 python 中存储一段文字作为密码本?
AB CD
行号 列号
情报传递中需要有一串由数字组成的字符串作为密码,密码字符串中每四位连续数字 ABCD 代表一个字,代表密码本中第 AB 行的第 CD 个字
虽然已经初始化了 code_book 字符串变量用于存储密码本,但是这个变量并不适用于密码译码。根本原因在于字符串只能通过索引号和切片的方式,对字符串中的一个字符或者子串进行访问,而译码规则要求寻找到密码本中第几行的第几个字,通过索引号并不能根据这一规则,在 code_book 字符串中快速找到对应情报
因此,为了实现情报译码规则,需要将密码本中整段的文字按行进行分隔,使得每一行称为一个单独的字符串,并将这些字符串按顺序存储在列表中,以便按照译码规则在密码本中寻找到对应的明文
想要实现对一个字符串 s 按照特定的分隔符(sep)进行分割并返回一个列表,需要使用到字符串中的 split 方法:s.split(sep)
如果没有指定任何参数,split 方法会把所有空格符(即空格)、制表符(即 \t )、换行符(即 \n ) 等作为分隔符
#初始化密码本
#创建字符串变量来存储这段文字,由于文字跨多行而非单行的字符串,必须使用三引号对code_book字符串变量进行初始化
code_book = ''' 我和莫大帅手拉着手回到了老房子,我们已经像最平凡的恋人一
样手拉着手,一点也不会感到别扭,心里充满了快乐。
转头看见莫大帅好笑地看着我,眼睛都是宠溺。
他带我去了阁楼,那间阁楼我从未进去过。搬来的第一天,我便
看到了那上面红色的大锁。结果莫大帅连钥匙都没用就打开了锁,他
举着那把锁对我说:"如果你多点好奇心,你早就会发现,我也会暴
出更多秘密。"
阁楼古老陈旧,木质的地板散发着琥珀色的沉香。莫大帅移出角
落里的一个纸箱,我好奇地凑上去。 我打开一本相册,看到了童
年的莫大帅。他的脸白白净净,发型古怪,还露出缺了大门牙的牙齿。
'''
print(code_book)
#初始化密码 每四位密码用一个逗号间隔开
code = "0022,0529,0920,0121,0204,0729"
#初始化字符串变量用于存放译码后的情报信息
information = ''
#将密码本按行存储到列表,每行是一个字符串,这些字符串组成一个列表
#打印输出列表的每一个元素
#将密码本字符串code_book按行进行分割并将密码本中的每一行按顺序保存在code_book_list中
code_book_list = code_book.split("\n")
i =0
#使用for循环将密码本按指定格式输出
for item in code_book_list:
print("密码本第{}行是,<{}>".format(i,item))
i += 1
#使用相同的方式对密码字符串code进行分割,使用逗号作为分隔符
code_list = code.split(",")
分割完成后,可以看到字符串 code 变为了长度为 6 的列表 code_list
code_list 中的 6 个元素,每个都是一个由四位密码 ABCD 组成的字符串,即 AB 代表了密码本列表 code_book_list 中的第 AB 个元素,CD代表了 code_book_list[AB] 中的第 CD 个字符
由于这四位密码是字符串,无法直接作为列表中的索引号,需要先对四位密码字符串切片后,后使用 int 函数将字符串强制转换为整型数字
#根据译码规则翻译密码
#使用for循环切片获得密码位于密码本的行row与列column位置,并获得对应的文字
info = ""
for item_c in code_list:
#切片获得前两位密码AB并将其转换为整数变量row
row = int(item_c[0:2])
#用同样方式获得后两位密码CD
column = int(item_c[2:])
#根据变量row 和 column 访问密码本列表中对应的行列信息,获得元素,即情报中的一个字
#对密码字符串中每四个数字密码译码后,拼接为一条完整的情报
info += code_book_list[row][column]
print("最终情报:{}".format(info))
#单引号 (') 括起来的字符串里面可以使用双引号作为字符串的一部分
print('can you program in "python"?')
#双引号 ('') 括起来的字符串里面可以使用单引号作为字符串的一部分
print("can you program in 'python'?")
#三引号 (''') 括起来的字符串里面既可以使用单引号也可以使用双引号作为字符串的一部分
print('''can you
program in
'python' and "java"?''')
#输出
'''can you program in "python"?
can you program in 'python'?
can you
program in
'python' and "java"?'''
利用 python 中的字符串来表示密码本,通过密码在字符串中寻找到对应文字,即可拼接出需要传递的情报,实现情报译码功能,在 python 中,字符串和列表都是有序序列,对列表的序列操作几乎也适用于字符串,但是字符串是不可变的,因此,对列表的元素赋值和切片赋值对字符串是不可用的
pyhton 中对字符串的基本操作主要如下:
1.初始化字符串:用于初始化空字符串,或者含有字符的字符串
2.求字符串长度:用于获取字符串长度,即字符串中的字符个数
3.字符串拼接:用于将两个以上的字符串拼接成一个新的完整的字符串
4.字符串复制:用于复制字符串
5.成员判断:用于判断一个字符串是否是另一个字符串的子串
6.访问字符串中的字符:通过字符索引获得字符串中的某个特定字符
7.字符串切片:用于获取字符串中某几个特定字符
通过单引号、双引号、三引号都可以定义一个字符串变量
字符串中除了正常的字符外,还可以包含转义字符
转义字符 说明
\n 换行
\t 水平制表
\' 单引号
如果单引号括起来的字符串本身含有单引号,可以使用反斜杠( \ ) 进行转义,双引号和三引号的输出亦是如此
print('jacky\'s book')
#输出
jacky's book
初始化字符串
python 中使用变量赋值语句可以对字符串进行初始化
#初始化str0为空字符串
#使用单引号初始化了一个空的字符串变量str0
str0 = ''
#初始化str3,含有11个字符
#使用双引号初始化了一个含有11个字符的字符串变量str3
str3 = "hello mike!"
字符串的初始化往往需要通过用户之间的交互,由用户进行输入初始化
#通过input()函数,将用户输入的内容当作一个字符串
#用户可以在控制台的提示符中输入对应的姓名,并赋值给字符串变量str1
str1 = input("请输入姓名:")
print(str1)
求字符串长度
与求列表长度的方式相同,使用 len(字符串变量名) 的方式,可以返回对应字符串中字符的个数,即字符串的长度
str3 = "hello mike!"
#输出变量名为str3的字符串的长度为11(包括空格和感叹号)
print(len(str3))
字符串拼接
在 python 中使用加号 ( + ) 可以用来拼接(合并)多个字符串
字符串的拼接经常用于 python 的输出语句中,将不同的内容拼接在一个输出语句中
#加号(+)用来拼接(合并)字符串
first_name = "mike"
last_name = "smith"
full_name = first_name + ' ' + last_name
print(full_name)
#打印一个问候的句子
print("hello," + full_name + "!")
#输出
mike smith
hello,mike smith!
#会报错
#加号对于数值类型的数据而言是做算术加法运算
#对于字符串而言是拼接操作所以无法将字符串与数值型数据加在一起
print(full_name + 666)
TypeError: can only concatenate str (not "int") to str
字符串复制
对于字符串而言,可以利用算术运算符中的乘号,进行字符串复制的操作
注意:在使用乘号进行字符串复制时,只能使用整数
print("输入需要显示的内容"*次数)
print("重要的事情说3遍"*3)
#输出
重要的事情说3遍重要的事情说3遍重要的事情说3遍
#会报错
print("重要的事情说3遍"*3.0)
TypeError: can't multiply sequence by non-int of type 'float'
成员判断
在 python 中,使用运算符 in 可以判断一个字符串是否是另一个字符串的子串,返回值为 True 或者 False
因为字符串对于大小写字母敏感,因此最后一个语句中由于 L 没有大写,因此被判定为不是字符串中的子串
badminton_star = "Dan Lin"
#其中L和Dan都是字符串Dan Lin中的一部分 而xie并不是
print("L" in badminton_sta) True
print("Dan" in badminton_sta) True
print("xie" in badminton_sta) False
print("Lin" in badminton_sta) False
访问字符串中的字符
字符串中的字符可以通过字符索引获得,字符串的字符索引有两种方式:
正向索引
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
p y t h o n i s p o p u l a r .
-18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
反向索引
正向索引中字符串里的第一个字符索引号为 0,之后字符的索引号依次递增
反向索引中字符串里的最后一个字符串的索引号为 -1,从后往前的每个字符的索引号依次递减
对于 python is popular 这个字符串而言,p 这个字符在正向索引中的位置是 0,而在反向索引中的位置为 -18
#初始化 message 字符串变量为 "welcome to shenzhen!"
message = "welcome to shenzhen!"
#将 message 的第 0 号字符 w 赋值给变量 char1
char1 = message[0]
#将 message 的最后一个字符 ! 赋值给变量 char_last
char_last = message[-1]
#枚举字符串 message 的所有字符,逐个打印输出
for char in message:
print(char)
字符串切片
字符串切片方法与列表切片方法相同,语法为 字符串[ 开始索引 :结束索引 :步长(可省略)]
0 1 2 3 4 5 6 7 8 9 10 11 12
wish = h e a l t h y , h a p p y
字符串变量 wish 初始化为 "healthy,happy",使用字符串切片的方式打印输出整个字符串,可以将三个参数值全部省略 print(wish[ : : ]) 或者 print(wish[ : ]),即 wish 中只使用一个冒号分隔开 开始索引与结束索引这两个参数默认值
也可以将三个参数值显示列出来即:print( wish[0 : len(wish) : 1]),开始索引为 wish 字符串索引号为 0 的元素,结束索引为 wish 字符串的长度,步长为 1
默认值如下:
开始索引:0
结束索引:字符串长度
步长(可省略):1
wish = "healthy,happy!"
#打印输出整个字符串,三个参数全部省略,默认值分别为0、字符串长度、1
print(wish[ : : ])
print(wish[ : ])
#打印输出整个字符串,三个参数值都显式列出来
print(wish[0 : len(wish) : 1])
#打印输出前7个字符
print(wish[0:7])
类型转换 str()
内置函数 str(x) 返回任意类型 x 所对应的字符串形式
字典与集合
编号 商品 单价
101 签字笔(红) 15RMB
102 签字笔(黑) 15RMB
103 荧光笔 7.9RMB
104 铅笔 17.9RMB
实现购物车功能,需要有一个合适的数据类型用于存储商品的价格
1.提供商品价目表,提示输入商品编号
2.输入所在商品的编号,提示输入购买数量
3.继续输入编号及数量,输入商品编号 -1,提示停止购买商品
4.根据商品价目表,快速查找出该商品编号对应的商品名称及其单价,并计算出所购数量商品的价格小计,最终在控制台输出购买商品的编号,名称,数量,小计及其商品总价
在 python 中有一种叫字典的组合数据类型,可以存放商品价目表
生活中的字典的作用是通过关键字查找其对应的更详细的内容,比如在字典中查找 "典" 的释义,需要在字典中输入关键字"典",从而获得汉字"典"的基本释义
在字典查找过程中,把查找的汉字"典"称为键(key),把通过关键字寻找到的内容称为值(value)
python 中的字典是一种通过"键值对"来存储数据的组合数据类型
"键值对"实际上是一种映射关系,每一个键 key 会指向一个对应的值 value
运用字典这个组合数据类型,可以存储键值对,并通过键快速寻找到对应的值
1.初始化字典:用于创建一个包含键值对的字典
2.创建空字典:创建一个不包含任何初始键值对的字典
3.修改/添加字典:向指定的字典添加键值对,以及修改指定键所对应的值
4.输出字典:用于在控制台输出字典中的所有键值对
5.访问字典元素:用于访问字典中特定的某个键值对
6.字典的删除:用于删除字典中特定的某个键值对、整个字典
7.求字典长度:用于获取指定字典中键值对的数量
8.遍历字典:遍历访问字典中的所有键、所有值、所有键值对
在 python中,字符串、整数等都可以作为键,每个键值对里的键与值之间使用冒号进行分隔,键值对与键值对之间使用逗号进行分隔,整个字典所有的键值对都包括在花括号中
初始化字典变量,以字典名作为变量名,用等号进行赋值,在花括号中添加 N 个键值对,每个键值对间用逗号间隔开
字典名 = { key_1 :value1,key_2 ,. . .,key_N : value_N }
value1 value2 ... ... value_N
对应 对应 对应
key_1 key_2 ... ... key_N
创建一个包含国家和首都对应关系的字典变量sd,该字典初始化了三个键值对
键对应的值 北京 华盛顿 巴黎
对应 对应 对应
键 中国 美国 法国
sd = {"中国" :"北京","美国" :"华盛顿","法国":"巴黎"},用户可以通过国家名快速寻找到对应国家的首都
字典是一个键对一个单值的映射,键必须唯一,但值不需要唯一,键不同,值相同:{"a" :"banana","b" :"banana"} √
不能创建键相同,值不同:{"a" :"apple","a" :"banana"} ×
当需要一个键映射多个值时,需要将多个值放到集合,元组,列表等其他容器中
创建空字典
#表示创建一个字典变量sd
#由于花括号中没有任何初始化的键值对,sd目前是一个空字典
sd = {}
修改 / 添加字典
在添加一个元素时,列表是使用 append 函数,字典没有这样的方法
向指定字典添加键值对,或者修改指定键所对应的值,只需要指定新的键和值就可以了,使用方法与赋值语句类似,在字典名后使用方括号指定特定的键,在等号的右边输入需要添加或者修改元素的值 sd[ ] = " "
注意:添加元素需要指定新的键和值,在字典中的元素是无序的,先添加的数据不一定出现在前面
#修改/添加键值对
#往字典中添加中国-北京的键值对
sd["中国"] = "北京"
sd["美国"] = "华盛顿"
sd["法国"] = "巴黎"
输出字典
在 print 函数参数中指定字典名,即可输出字典内的所有键值对
print(sd)
访问字典元素
在字典名后用方括号指定特定的键,便可以访问到该键所对应的值
print(sd["中国"])
#输出
北京
字典的删除
删除字典中的某个特定元素有两种方式
方式一:字典名.pop("键") 可以删除对应的键值对
#删除字典sd中美国-华盛顿的键值对
sd.pop("美国")
方式二:del(字典名["键"]) 在del函数参数中指定特定的字典名与键,即可删除对应的键值对
#删除字典sd中法国-巴黎的键值对
del(sd["法国"])
删除整个字典也有两种方式
方式一:字典名.clear() 可以直接清除字典中的所有元素
sd.clear()
方式二:del(字典名) 当需要删除整个字典时,del 函数中只需要提供字典名,不需要指定特定的键
del(sd)
求字典长度
使用 len 函数可以求得字典长度,即字典中键值对的数量
print(len(sd))
#输出
3
函数与应用
在编写程序过程中,如果某段代码需要重复使用,需要怎么处理?
遇到需要重复使的代码时,找到之前完成的代码复制粘贴在需要使用的地方,理论可行,但是会造成代码的杂乱无章,而且容易产生 bug,不推荐使用
函数
len 函数,可以用于求字符串长度、列表长度、字典长度,并没有在需要求某一个数据类型的长度重新编写一段代码,而是直接使用 len 函数,在对应参数中给到一个字符串变量或者一个列表变量,len 函数便可以返回我们所需要的结果
函数的操作
1.定义函数
python 中使用 def 保留字用于定义一个函数
函数名称和函数体是一个函数中必须定义的部分,根据函数的要求,确定是否需要参数列表,函数注释,返回值列表
任何传入的参数必须放在圆括号中间
某些函数不需要任何信息就能完成工作,括号可以为空,即没有任何参数
return 返回值列表 结束函数,返回值给调用程序
函数运算后可以同时返回多个结果,使用逗号分隔开
return 结果1,结果2
#括号为空即没有任何参数
del 函数名称():
def 的下一行代码全部缩进直到函数结束
def 的下一行可以选择放注释(#、三个单引号、三个双引号进行注释),描述函数的功能
def 函数名称(参数列表):
#函数注释
函数体
return 返回值列表
2.调用函数
使用函数的目的就是为了在之后可以反复使用函数体中已经完成的代码,减少编码工作量,使得程序看起来更加简洁明了
3.参数传递
每次调用函数时,如果函数规定了需要传递参数,则需要向函数传入数据,函数使用的参数可以是整型数值,字符串,浮点型数值,也可以是列表等其他数据结构
如果有些参数存在默认值,即部分参数不一定需要调用函数传入,可以在定义函数时直接为这些参数指定默认值,当函数被调用时如果没有传入对应的参数值,则使用函数定义时的默认值替代
一个程序中的变量包括全局变量和局部变量
全局变量在函数之外定义,函数 func 里面如果想使用函数外面的全局变量 n,需要在 func() 使用 n 之前,用关键字 global 显式声明该变量是全局变量
def func(a,b):
n = a + b
n = 1
func(3,4)
print("n = {}".format(n))
#输出
n = 1
def func(a,b):
#显式声明该变量是全局变量
global n
n = a + b
n = 1
func(3,4)
print("n = {}".format(n))
#输出
n = 7
局部变量是指在函数内部使用的变量,仅在函数内部有效,当函数结束时变量将不存在,例如以下计算长方形的面积和周长函数里的变量:area 和 perimeter
def rect(a,b):
area = a * b
perimeter = 2 * (a + b)
return area,perimeter
s,p = rect(5,10)
print("面积",s)
print("周长",p)
#输出
面积 50
周长 30
利用 python 绘制五星红旗,需要借助 python 标准库中入门图形绘制函数库 turtle,想象一个一只海龟在窗体正中心,在画布上游走,经过的轨迹形成了绘制的图形,海龟由程序控制,可以变换线条颜色,改变线条宽度,行走方向. . .
红旗的长与高位三与二之比,小五角星的样式和绘制过程相同,可以使用函数完成对应的绘制
通过分析,绘制操作如下:
1.画布设置
setup函数设置窗体的位置和大小
bgcolor函数设置对应的画布窗体的背景颜色
color函数定义画笔的颜色
RGB色彩体系,色彩取值范围为0-255的整数,也可以使用字符串,即颜色的英文名称,white(白色)、yellow(黄色)
import turtle
#定义画布长900像素,高600像素,符合三比二的要求
turtle.setup(900,600,0,0)
#将背景设置为红色
turtle.bgcolor('red')
#把画笔设置为黄色
turtle.color("yellow")
2.定义五角星绘制函数
需要绘制的五角星的画法是类似的,只是起始位置和大小不同,可以通过定义函数,简化代码
#定义huax函数,x、y表示了画笔起始的位置,z表示了每次画笔前进的长度,用于控制绘制五角星的大小
def huax(x,y,z):
#抬笔结束绘制
turtle.up()
#前进到x,y的位置
turtle.goto(x,y)
#落笔准备开始绘制
turtle.down()
#开始填充颜色
turtle.begin_fill():
#选择黄色为填充的颜色
turtle.fillcolor("yellow")
for i in range(5)
#前进z个像素
#别名fd
turtle.forward(z)
#向左旋转144度
#别名lt
turtle.left(144)
#结束填充颜色
turtle.end_fill()
turtle 的空间坐标体系有两种:
绝对坐标 和 海龟坐标,绝对坐标是以屏幕为坐标系,中心位置为(0,0),可以调用turtle.goto(x,y)使海龟从当前位置走到新的坐标(x,y)
海龟坐标是以海龟本身为中心,海龟是坐标系原点(0,0),海龟坐标在转向的操作上很方便,调用函数 turtle.right(45) 来让海龟向右转动45°
调用函数turtle.forward(200) 来让海龟前进200像素的距离
由此我们可以使用绝对坐标以及函数 huax 传递的参数 x,y 控制画笔起始位置,在 for 循环使用海龟坐标控制画笔的转向,完成五角星的绘制
需要注意五星红旗中大的五角星是正的,剩下四颗围绕的五角星是有一定角度的,在 huax 函数基础上,增加 huaxvertical 函数用于绘制正的五角星
与 huax 函数的区别是画笔的转向,如果 for 循环中画笔是向右转向的,则画出的五角星是正的
def huaxvertical(x,y,z):
#抬笔结束绘制
turtle.up()
#前进到x,y的位置
turtle.goto(x,y)
#落笔准备开始绘制
turtle.down()
#开始填充颜色
turtle.begin_fill()
#选择黄色为填充的颜色
turtle.fillcolor("yellow")
for i in range(5):
#前进z个像素
turtle.forward(z)
#向右旋转144度
#别名rt
turtle.right(144)
#结束填充颜色
turtle.end_fill()
3.调用绘制函数
注意调整 huax 的 x,y,z 这三个参数,x,y根据实际情况选择微调,z控制五角星的大小,z = 100 表示绘制大五角星,z = 60 表示绘制小五角星
huaxvertical(-380,180,100)
huax(-230,230,60)
huax(-180,150,60)
huax(-210,75,60)
huax(-270,15,60)
#表示完成绘制,但绘图窗体不关闭,一般是程序的最后一条语句
turtle.done()
面向对象
结构化程序设计:要求设计思路清晰,但适应性和拓展性差,这种设计方式不够直观
面向对象程序设计强调根据事物的本质特征,把它们抽象为系统中的类
一个类一般而言,包含:类名、类的属性及类的功能
一个类可以通过赋予该类中的各个属性的值,实例化一个类的对象
类是对象的抽象,对象是类的实例化
python 支持面向对象的基本功能:封装、继承、多态及其基类方法的重写
面向对象的基本操作主要包括:
1.定义类
2.构造函数
3.定义类的变量
4.定义类的方法
定义类
class 类名:
#pass是空语句没有任何意义,仅为了保持程序结构完整性
#可换成其他内容
pass
构造函数
使用def _ _init_ _()函数,可以定义类的构造函数
类的构造函数也可以称为类的初始化方法
当创建这个类的实例时,会调用该方法,即类的构造函数
class 类名:
def __init__():
定义类的变量
成员变量用于描述类的固有状态或属性
定义公有成员变量,语法格式如下:
公有成员变量在 _ _init_ _( ) 构造函数方法中声明,每个对象都具有该成员变量,self 代表对象实例本身
class 类名:
#创建构造函数
def __init__(self):
self.变量名1 = 值1
self.变量名2 = None
定义私有成员变量,语法格式如下:
私有成员变量在 _ _init_ _( ) 构造函数方法中声明,变量名前面以两个下划线开头,私有成员变量在类的外部不能直接访问,一般是在类的内部使用
或者在类外通过调用公有成员方法来访问
class 类名:
#创建构造函数
def __init__(self):
self.__变量名3 = 值3
self.__变量名4 = None
公有成员变量和私有成员变量是属于对象的数据成员,即每个对象内有这个对象的成员变量,与其他对象无关
需要使用到某个类所有对象,则需要共享使用的数据成员,这种数据成员,称为类的数据成员
类的数据成员不在任何一个成员方法的定义中,通常直接定义在类的定义里
class 类名:
类数据成员名1 = 值1
#创建构造函数
def _init_(self):
self.变量名1 = 值1
self.变量名2 = None
定义类的方法
成员方法用于描述对象的固有行为操作,可以粗略分为四大类:
公有方法:可以通过对象名直接调用
私有方法:名字以两个下划线开头,不能通过对象名直接调用
静态方法:不能访问对象的数据成员和方法,使用 @ staticmethod 修饰器声明,调用时并不需要传递类或者对象实例,也可以通过类或者实例来调用而已
class 类名:
类数据成员名1 = 值1
@ staticmethod #修饰器,声明静态方法
def 静态方法名(): #静态方法
类名.类数据成员1 = 值2
类方法:定义在类中,使用 @ classmethod 修饰器声明,不属于某个具体对象的行为,用于刻画被所有对象共同使用的行为
类方法中不允许使用对象实例的变量和方法,类方法中允许使用类数据成员和类方法,通过第一个参数 cls 进行,对象实例的方法中允许使用类数据成员和类方法
class 类名:
类数据成员名1 = 值1
@ classmethod #修饰器,声明类方法
def 类方法名(cls): #类方法
cls.类数据成员1 = 值2
公有方法、私有方法与公有成员变量、私有成员变量类似,都是属于对象的方法,每个对象都有自己的公有方法和私有方法
类的4种成员方法使用规则:
一、只访问对象成员变量的方法,定义成公有方法或者私有方法
二、只访问类数据成员的方法,定义成类方法
三、既访问对象成员变量,也访问类数据成员的方法,定义成实例方法
四、调用时并不需要传递类或者对象实例,定义成静态方法
实现绘制多边形画笔(绘制三角形、正方形的画笔)项目
使用turtle画笔可以绘制多边形,绘制多边形的画笔具有相同的一些属性和操作,绘制三角形和绘制四边形画笔代码大部分是相同的,具有可重用的基础
要实现绘制多种图形的画笔,需要将画笔绘制,转向,设置颜色,线条粗细等操作封装在一起,组成一个完整的功能,不可分割的整体→ 对象
对于相同功能的对象进行分类和抽象后,可以得出共同的功能和特征→ 类
画笔有共同的特征属性:画笔颜色、填充颜色
正多边形有共同的参数:边长和边数
1.可以为不同形状的多边形画笔设计不同的类,把画笔颜色、填充颜色、边长作为类的成员变量
2.为画笔类定义绘制方法实现正多边形的绘制
3.设置统计对象个数的数据成员 pentotal
定义两个类:
正三角形绘制画笔类和正多边形绘制画笔类
在 python 中,以下划线开头或结束的成员名有特殊含义:
规则说明
_name:保护成员,不能用from module import 导入,只有该类和子类对象可以访问这些成员
_ _name_ _:python 语言的类特殊方法
_ _name:类中私有成员变量或者私有方法,一般只有类对象自己能访问,子类对象也不能访问到这些成员
在构造函数时,实例化一个对象后便将对应的 pentotal 值自增 1
面向对象可以实现代码的复用和设计的复用,实现这种重用的方法之一是通过继承机制:如果一个类 A 继承自另一个类 B,就把这个 A 称为 B 的子类,而把 B 称为 A 的父类,继承可以使得子类具有父类的各种属性数据成员和方法,而不需要再次编写相同的代码
在子类继承父类时,可以重新定义某些属性、数据成员,并重写某些方法,即覆盖父类的原有属性数据成员和方法,使其获得与父类不同的功能,另外,为子类别追加新的属性数据成员和方法也很常见,在 python 中继承语法格式如下:
class 子类名(父类名):
类的内部结构
import turtle
class trianglepen:
pentotal = 0 #类的公有数据成员:用于记录该类的对象总数
def __init__(self,len = 50,fillcolor = 'red'): #构造方法
self.__edgelen = len #对象的私有成员变量:用于记录该类的对象总数
self.__FillColor = fillcolor #对象的私有成员变量:分别记录正三角形边长和填充颜色
trianglepen.pentotal += 1 #pentotal 记录对象个数,加 1
def draw(self): #用于绘制正三角形
turtle.color('red',self.__FillColor) #边框颜色,填充颜色
turtle.begin_fill() #填充颜色开始
for i in range(3):
turtle.fd(self.__edgelen) #画线
turtle.rt(120) #调整角度,向右转动120°
turtle.end_fill() #填充颜色结束
def setedgelen(self,len): #设置边长方法
self.__edgelen = len
def setfillcolor(self,fillcolor): #设置填充颜色方法
self.__FillColor = fillcolor
#创建两个正三角形的实例,并分别设置它们绘制的边长和填充颜色
p1 = trianglepen(100) #创建正三角形画笔对象
p1.draw()
turtle.fd(100) #前进 100 长度
p2 = trianglepen(50) #创建正三角形画笔对象
p2.setfillcolor('yellow')
p2.draw()
print(trianglepen.pentotal) #输出类的数据成员
turtle.exitonclick() #画面停留,点击退出
#输出
#表示创建了两个正三角形画笔对象
2
python 中类继承的一些特点:
1.在继承中父类的构造方法( _ _init_ _ 方法) 在子类没有构造方法的情形下会被自动调用,如果需要在其子类的构造方法中专门调用父类构造方法 super()
2.在调用父类的方法时,有以下三种方式:(1)直接写类名调用
(2)用 super(type,obj).method(arg) 方法调用
(3)在类定义中调用本类的父类方法,可以直接 super().method(arg)
3.python 总是首先查找对应类型的方法,如果它不能在子类中找到对应的方法,它才开始到父类中逐个查找(先在本类中查找调用的方法,找不到才去父类中找)
文件及异常处理
编写程序完成成绩的批量文件转换和修改,成绩转换前的格式为 txt 文本文件,只要确定单个文件如何进行转换,便可以遍历一个目录下所有的文件,完成批量转换文件格式的任务,同理,批量修改文件内容也需要事先将单个文件内容修改的功能定义好
此项目中,考虑文件夹中只含有文件,无文件夹,否则程序可能会报错,比如文件夹的名字中带有 "." 的情况
此项目可分为:
单个文件格式转换、批量文件格式转换、单个文件内容修改、批量文件内容修改
计算机中常见的文件有:txt 文本文件,office 文档,exe 可执行文件,音频 / 视频文件,数据库文件,jpg 图像文件
按内部数据的组织形式,文件可分为文本文件和二进制文件两大类
文本文件:
由若干行以特定编码存储的字符组成,常见编码形式有ASCLL编码、Unicode编码,通常每行以换行符 "\n" 结尾,在Windows系统中,拓展名为 txt,log,ini,py的文件都属于文本文件,可用记事本之类的文本编辑器进行编辑
在 python 中对于普通的文本文件操作,主要包含有:
1.文件的打开:用于打开指定目录下的一个特定文件
2.文件的关闭:用于关闭一个已经不再需要操作的文件
3.文件的读写:用于向指定文件写入数据或者从指定文件中读取数据
4.with语句:用于保证进行操作的文本文件能够被正确关闭
二进制文件:
除文本文件以外的文件都可以称为二进制文件,其信息以字节串形式存储,不能用记事本或普通文字处理软件编辑,打开会是乱码,需要使用相关软件进行解码后读取,常见的如各类 office 文档、音频 / 视频文件、exe 可执行文件. . .
项目中要求批量转换成的Excel格式属于二进制文件,对于 Excel 文件的处理,python 中提供了 openpyxl 库:一个读 / 写 Excel 2010 及更高版本文档的 python 拓展库,主要处理 .xlsx 后缀的 Excel 文档,如果要处理更早格式的 Excel 文档,需要用的额外的库
openpyxl 库:能够同时读取和修改 Excel 文档,其他很多与 Excel 相关的项目基本只支持读或者写 Excel 一种功能
openpyxl 库常用的方法有:
1.创建 Excel 文件:用于创建一个新的 Excel 表格文件
2.Excel 文件添加数据:用于向 Excel 表格中添加一行数据
3.保存文件:用于将对 Excel 文件的修改进行保存
4.读取 Excel 文件:用于读取 Excel 表格中的工作表
5.获取单元格:用于获取 Excel 表格中单元格的内容
6.单元格赋值:用于对Excel表格中某个特定单元格直接进行赋值
7.获取行和列:用于获取工作表中有效的数据行数和列数
8.遍历单元格:用于遍历访问所有单元格的值
python 的标准库中 os 模块提供了大量文件与文件夹操作的方法
os 模块中的 listdir() 方法:用于返回指定的文件夹包含的文件或文件夹的名字的列表→ 对文件路径进行判断
path 模块提供了大量用于路径判断,切分、连接,文件夹遍历的方法
文件的打开
使用 open() 函数可以打开一个文件
常见的打开模式有:
1.模式 r
只读模式(默认,可省略)
文件指针指向文件头,若文件不存在则抛出异常
2.模式 w
写模式
文件指针指向文件头,若文件已存在,则覆盖写入;若文件不存在,则创建
3.模式 x
写模式,创建新文件
文件指针指向文件头,若文件已存在则抛出异常
4.模式 a
追加模式
文件指针指向文件尾,不覆盖文件中原有的内容
5.模式 +
读写模式
与 r / w / x / a 一同使用,如 r +、w +、x +、 a +,在原功能基础上增加同时读写
文件变量名 = open(文件名,打开模式)
#模式选择r,表示打开当前文件路径下的 myfile.txt 的文本文件,打开模式为只读模式
f = open("myfile.txt","r")
文件的关闭
为了安全起见,使用完文件后要对其进行关闭
#关闭文件函数
f.close()
文件的读写
提供或接收数据是文件的基本能力,可用 read() 方法和 write() 方法实现
#以写模式 w 打开当前路径下的文本文件 myfile.txt
f = open("myfile.txt","w")
#往该文件中写入字符串 hello,world!
f.write("hello,world!")
#关闭文件
f.close()
输出 myfile.txt 文件中的内容
#只读模式打开文件
f = open("myfile.txt","r")
#在控制台输出 hello,world!
print(f.read())
#关闭文件
f.close()
文件有四种常用读取方法:read()、read(size)、readline()、readlines()
三种常用写入方法:seek(offset)、write(s)、writeline(l)
read():依次读取文件所有内容,返回字符串
read(size):在 read() 函数中加入 size 参数,则会从文件中读取 size 个字符作为结果返回
readline():从文本文件中读取一行内容作为结果返回
readlines():将文本文件中每行文本作为一个字符串存入列表,返回该列表
seek(offset):将文件指针移到新位置,offset 值有 3 个,0 表示文件开头,1 表示当前位置,3 表示文件结尾
write(s):把字符串 s 的内容写入文件
writeline(l):将元素全为字符串的列表 l 写入文本文件,不添加换行符
with语句
如果文件读 / 写异常,很难保证文件正常关闭,使用上下文管理关键字 with,可以避免这个问题
with 自动关闭资源,可以在代码块执行完毕后还原进入该代码块时的现场,无论何种原因跳出 with 块,总能保证文件被正确关闭
with 代码语句
代码语句1
代码语句2
代码语句3
可以利用 with 语句打开文件,一次读入,分行打印,如果在执行过程中出现异常,也能保证文件被正确关闭
with open("myfile.txt","r") as fo:
for line in fo.readlines():
print(line)
使用 openpyxl 库,可以实现从 txt 文件转换到 excel 文件的操作
Py之openpyxl:openpyxl库的简介、安装、使用方法之详细攻略
1.创建 excel 文件
需导入 Workbook 类,创建 Workbook 类的一个对象,并返回到第一张表
from openpyxl import Workbook
#创建一个workbook类的对象wb
wb = Workbook()
#可以返回其中的第一张表
ws = wb.worksheets[0]
workbook 对象提供了很多属性和方法,大部分方法都与 sheet 表有关
active:获取当前活跃的 worksheet
worksheets:以列表的形式返回所有的 wooksheets (表格)
read_only:判断是否以 read_only 模式打开 Excel 文档
sheetnames:获取工作簿中的表(列表)的名称
2.添加数据
使用 append() 函数可向表格中添加一行数据
#向ws表中添加一行abcde的数据
row = ["a","b","c","d","e"]
ws.append(row)
3.保存文件
使用工作簿名.save(指定路径 + 文件名) 的方式,可以保存对应操作完成的 excel 文件
注意:在路径的前面需要加上 r,否则执行时会出现 Unicode error
#将上述wb保存到指定的路径下
wb.save(r"data/myexcel.xlsx")
4.读取 excel 文件
#需要导入load_workbook类
from openpyxl import load_workbook
#读取文件 定位到第一张工作表
wb = load_workbook(r"data/myexcel.xlsx")
#工作表序号从0开始
ws = wb.worksheets[0]
5.获取单元格内容
使用 表名[单元格位置].value 的方式,可以获取对应单元格内的内容
#获取excel表格中,A1单元格内的值
a1 = ws["A1"].value
print(a1)
6.单元格赋值
在赋值语句中,可以对 表名[单元格位置] 的内容直接进行赋值
ws["A1"] = 10
也可以使用 cell() 函数,指定表中的行、列和值
A B C
1
2 20
ws.cell(row=2,column=1,value=20)
将表格 ws 中第二行第一列的单元格赋值为 20
注意: 操作后需要保存文件
7.获取行和列
使用 工作表名.max_row 和 工作表名.max_column 可以分别获取工作表中有效的数据行数和列数
print(ws.max_row)
print(ws.max_column)
8.遍历所有单元格
使用双重循环,第一重循环遍历表格中的行,第二重循环遍历表格中的列,即遍历打印所有单元格的值
for r in range(ws.max_row):
for c in range(ws.max_column):
print(ws.cell(row=r+1,column=c+1).value)
批量文件转换项目实现
利用 python 的文件操作,先实现对单个文件格式的转换和修改,再完成批量文件格式转换与修改
单个文件格式转换功能实现
实现对源文件的拓展名重新变更,保留其文件名,创建 excel 文件,利用字符串的相关方法将内容添加到单元格中
首先,自定义一个函数 change,该函数的功能是实现单个文件转换,函数的参数为一个文本文件 txtFileName,在函数体中定义新的 excel 文件名,即原文件名 txtFileName + 后缀名 xlsx
from openpyxl import Workbook
import os
def change(txtFileName):
#原文件名 txtFileName + 后缀名xlsx
new_XlsxFileName = txtFileName[:-3] + 'xlsx'
#利用 openpyxl 创建一个新的工作簿 wb
wb = Workbook()
#在工作簿 wb 中创建一张新的工作表 ws
ws = wb.worksheets[0]
#为了避免文件关闭错误 使用 with 语句打开原文本文件并赋值给文件变量 fp
with open(txtFileName) as fp:
#使用 for 循环遍历文件 fp 中每一行并将数据加入 excel 文件的 ws 表中
for line in fp:
#通过字符串的 strip() 去空格方法 split() 分割方法 将原数据形成新的列表 line
line = line.strip().split(',')
#将列表 line 的数据加入 excel 文件的 ws 表中
ws.append(line)
#保存新文件
wb.save(new_XlsxFileName)
批量文件格式转换功能实现
利用上述单个文件格式转换功能,通过 os 库的相关方法结合字符串处理相关方法,实现批量文件格式转换
os.listdir() 方法:可以用于返回指定的文件夹包含的文件或文件夹的名字的列表,列表元素为字符串
语法格式如下:
file_list = os.listdir(某个目录)
import os
path = r"file"
file_list = os.listdir(path)
for file in file_list:
#可以列出 file 目录下的所有文件和文件夹
print(file)
#查找该目录下的所有txt文件 批量转换-> 使用 os 库中 listdir 函数列出当前目录下的所有文件
file_list = os.listdir(".")
for filename in file_list:
#遍历该列表中的每个文件名 使用 python 字符串中的 rindex 函数获取文件名字符串中"."的位置
pos = filename.rindex(".")
#判断"."后面的所有字符是否等于字符串"txt"
if filename[pos+1:] == "txt":
#若相等 则调用上面的自定义函数 change 进行单个文件格式转换
change(filename)
单个文件内容修改功能实现
通过 openpyxl 库的相关方法找到需要修改的单元格
首先,自定义函数 modifyExcel 用于实现单个文件内容修改,该函数的参数为需要修改的 excel 文件名
from openpyxl import load_workbook
import os
#打开 excel 文件修改内容
def modifyExcel(xlsxFileName):
#导入需要修改的 excel 文件赋值给变量 wb
wb = load_workbook(xlsxFileName)
#在工作簿 wb 中定位到第一张工作表 即下标为 0 的 ws
ws = wb.worksheets[0]
#使用双重遍历 遍历工作表 ws 中的每一个单元格
for r in range(ws.max_row):
for c in range(ws.max_column):
#判断每个单元格内容是否等于"小白"
if ws.cell(row=r+1,column=c+1).value == "小白":
#若等于则重新赋值为"大白"
ws.cell(row=r+1,column=c+1).value == "大白"
#保存文件
wb.save(xlsxFilename)
批量文件内容修改功能实现
利用上述单个文件修改功能,通过 os 库的相关方法结合字符串处理相关方法,实现批量文件修改
首先,列出当前目录下的所有文件及文件夹
#查找该目录下所有 excel 文件 批量修改
file_list = os.listdir(".")
print(file_list)
#遍历该列表中的每个文件名
for filename in file_list:
#获取文件名字符串中"."的位置
pos = filename.rindex(".")
print(pos)
#判断"."后面的所有字符是否等于字符串"xlsx"
if filename[pos+1:] == "xlsx":
#若相等 则调用上面的自定义函数进行单个文件内容修改
modifyExcel(filename)
注意:没有考虑任何异常情况的发生,要打开文件不存在怎么办? 要读取的文件出现乱码怎么办?编辑文件时出现各种语法错误怎么办?→ 任何一种情况都会导致程序的终止,因此必须在程序中添加异常处理结构来解决这个问题
异常处理是程序编写过程中一个非常重要的环节,前面实现了学生成绩从文本文件到 excel 文件的批量转换和 excel文件中相同单元格内容的批量修改,但整个过程没有考虑任何异常情况的发生
打开一个 excel 文件,在最后一行添加一行数据,整个过程会出现哪些异常?
1.文件名错误或文件路径不对
2.在哪张工作表中添加数据,下标是否越界
3.添加数据时,参数类型是否正确
4.编辑文件时,文件是否已经关闭
什么是异常?
程序运行时引发的错误:除0、下标越界、文件不存在、参数类型不匹配、网络异常. . .
异常若不及时处理,程序就会用回溯 traceack 一种错误信息,终止程序执行,因此需要使用异常处理结构,使程序更健壮、容错性更高
从用户层面来说,使用异常处理结构可为用户带来友好的提示,避免因用户误操作而导致程序崩溃
常见的异常类型如下:
除 0 异常
算术计算出现除以 0 的操作,程序运行过程中会出现 ZeroDivisionError,即除 0 错误
print(3/0)
操作数类型异常
如果在程序中强行将无法操作的变量进行运算,运行时会出现 TypeError
想要要将字符 'b' 和整数 5 相加,便会出现操作数类型异常
print('b'+5)
命名异常
当使用没有定义的变量时,程序运行会出现 NameError
在程序编写时,要特别注意所使用的每个变量是否在使用前已经定义
print(x)
文件不存在异常
在进行文件操作时,如果想要打开不存在的文件,程序运行会出现 FileNotFoundError
fp = open(r"d:\myfile.txt")
下标越界异常
对于列表、字符串等数据类型,当使用索引号访问其中某个元素时,经常有可能由于操作时不慎操作 index error,即下标越界异常
#初始化列表变量mylist 包含1,2,3,4 四个元素
mylist = [1,2,3,4]
#使用print语句想要访问mylist中的第五个元素时 便会出现下标越界异常
print(mylist[4])
参数类型异常
在程序中,如果传递给函数的参数与函数定义的参数类型不相符,便会出现 type error
print(len(5))
根据项目的描述,需要添加相应的异常处理结构处理以下几个异常:文件找不到、下标越界、参数类型错误、文件未关闭. . .
使用 try - except - else 异常捕获结构,设计异常捕获条件
try:
#可能会引发异常的代码
#Exception 为异常类型
except Exception:
#若try中的代码抛出异常且被 except 语句捕获,则执行相应的异常处理代码,而不执行 else 中的代码,其中 else 部分可以省略
else:
#若try中的代码没有抛出异常,则执行 else 语句块中的代码
from openpyxl import load_workbook
try:
#载入test.xlsx文件
wb = load_workbook("test.xlsx")
#定位到第0张工作表
ws = wb.worksheets[0]
#在该工作表最后添加一行数据
ws.append([1,2,3,4,5])
wb.save("test.xlsx")
#except 文件不存在异常:若载入的文件名不存在 在此处被捕获
except FileNotFoundError:
#打印异常信息
print("文件不存在")
except IndexError:
print("工作表下标越界")
except TypeError:
print("参数类型错误")
except PermissionError:
print("文件未被关闭")
else:
#打印正常信息
print("文件正常打开并添加了数据")
使用 try - except - finally 异常捕获结构
finally 子句通常用来做一些清理工作,释放资源等
若 try 引发的异常没能被 except 捕获,或 except 子句 / else 子句中的代码也抛出了异常,则这些异常都将在 finally 子句执行后再次抛出,finally 子句中的代码也可能引发异常,则在系统继续抛出
try:
#可能会引发异常的代码
#Exception 为异常类型
except Exception:
#若try中的代码抛出异常且被 except 语句捕获,则执行相应的异常处理代码,而不执行 else 中的代码,其中 else 部分可以省略
finally:
#无论 try 中代码是否发生异常,或者异常是否被 except 语句捕获,都会执行 finally 中的代码
数据格式化及格式转换
虽然 python 使用变量时,没有显式的声明其类型,但是变量是有其类型的,通常需要对数据类型进行转换,从而满足场景需求
#字符串'4.03'不能参与数值运算
str num1 = '4.03'
#需要将类型转成float 浮点类型4.03才能计算
num1 = float(num1)
print("num1 + 2 = ",num1 + 2)
python 数据转换主要分为:
(1)使用内置转换函数
int(x,[,base]) 将 x 转换为一个整数
long(x,[,base]) 将 x 转换为一个长整数
float(x,[,base]) 将 x 转换为一个浮点数
complex(real [,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
repr(x) 将对象 x 转换为表达式字符串
eval(x) 用来计算在字符串中的有效 python 表达式,并返回一个对象
tuple(s) 将序列 s 转换为一个元组
. . .
(2)外部包函数
python 绝大多数的外部包都包含数据类型转换的相关函数,所以涉及的外部包和函数种类很多
time 包里面用于将字符串转换为日期类型的函数 strptime() 函数
字符串转日期
import datetime #使用 datetime 包
#初始化a变量为"2020/10/2"
a = "2020/10/2"
#使用 strptime() 函数按格式转换%Y代表年份的位置,%m代表月份的位置,%d代表日的位置
date1 = date.datetime.strptime(a,"%Y/%m/%d")
print(date1) #结果为 2020 - 10 - 02 00:00:00
#按格式输出日期
date2 = date1.strftime('%Y{y}%m{m}%d{d}').format(y = '年',m = '月',d = '日')
print(date2) #结果为 2020 年 10 月 02 日
json 包里面用于将符合字典语法的字符串转换为字典 loads() 函数
基本数据类型转换
#字符串转整数
#将字符串 2019 转成整数的 2019
i = int('2019')
#字符串转浮点数
#将字符串 20.19 转成浮点数 20.19
f = float(20.19)
列表、集合、字典的转换
#创建列表
ls = [90,93,85,93]
#将列表转换为集合,使用 set 函数将列表作为参数传进去直接转换
S = set(ls)
#将列表转换成字典,字典有键和值
#首先创建一个键列表
k = ['k1','k2','k3','k4']
#再创建一个值列表
v = ['v1','v2','v3']
#用zip函数将键列表和值列表组合,从而创建字典 当两个列表长度不一致时,多出的元素 k4 将被忽略
z = zip(k,v)
#用zip函数 将键列表k和值列表v组合成一个字典
d = dict(z)
#创建字典,直接使用字典的声明方式用{}将键值对括起来
d2 = {'name':'zhangsan',
'age':'22',
'gender':'male',
'address':'shanghai'}
#将字典的key转换成列表,可以直接将字典 d2 传进 list 函数里面,就会将d2的键值转成列表
lst1 = list(d2)
#输出键值
print(lst1) #['name','age','gender','address']
#将字典的值转换成列表,使用 values() 函数,然后把它放到 list 函数中,把它转成列表
lst2 = list(d2.values())
print(lst2) #['zhangsan','22','male','shanghai']
由字符串创建字典列表
首先这个字符串要符合字典的语法,也就是用 { } 将键值对括住,并且使用逗号分隔,满足字典的格式
#符合字典语法的字符串
str = "{'股票名称':'福建高速',
'今开':'3.32',
'成交量':'5.37万手',
'最高':'3.34','涨停':'3.66',
'成交额':'1779.96万'}"
#使用 eval 函数将这个字符串转成字典
d3 = eval(str)
print(d3.keys())
#dict_keys(['股票名称','今开','成交量','最高','成交额'])
整数不同进制间的转换,整数不同进制的转换是计算机领域处理整数编码时经常要遇到的问题,可以使用内置的 int()、bin()、format() 函数解决这个问题
#将字符串101的十六进制数转成十进制数 结果为257
i = int('101',16)
#将字符串101的八进制数转成十进制数 结果为65
i = int('101',8)
#将字符串101的二进制数转成十进制数 结果为5
i = int('101',2)
#十进制转十六进制数,将2019转换为十六进制数 结果为7e3
s = hex(2019)
#十进制转八进制数,将2019转换为八进制数 结果为3743
s = oct(2019)
#十进制转二进制数,将2019转换为二进制数 结果为11111100011
s = bin(2019)
股票交易数据项目
采集到的数据以文本格式存储的,符合字典格式语法的数据,需要将它转换为嵌套字典的结构,外层字典的 key 为股票名称,内层字典 key 为成交额、总股本等这些股票信息
{'股票名称':"福建高速",'成交量':'5.37万手','成交额':'1778.96万','委比':'-18.43%'}
{'股票名称':"楚天高速",'成交量':'10.52万手','成交额':'3669.72万','委比':'34.69%'}
1.逐行读入单支股票
需要注意文件存放的路径
#逐行读入单支股票
#打开文本文件 StockData.txt
with open('StockData.txt','r') as fp:
#读入多行文本放到字符串列表lines中
lines = fp.readlines()
#print(len(lines))
print(lines)
2.利用字典存储单支股票信息
为了统计数据方便,对成交量中的 "万手",成交额中的"万元",这些中文字去掉,并将相应的数字乘以 1 w,同时去掉 "委比" 的 %,并转成对应的数值
#利用字典存储多支股票信息
StockDict = list() #创建列表
for S in lines: #利用for 语句遍历 lines列表里每行的字符串S
dict1 = eval(S) #使用eval函数将此行的字符串转换为字典
StockDict.append(dict1)
cjl = dict1['成交量'][:-2]
if(cjl.strip()!=''):
dict1['成交量']=float(cjl) * 10000
else:
#删除'成交量'这个关键字
del dict1['成交量'];
cje=dict1['成交额'][:-2]
if(cje.strip()!=''):
dict1['成交额']=float(cje) * 10000
print(dict1)
else:
del dict1['成交额'];
wb=dict1['委比'][:-1]
print(wb)
#特别处理空字符串和单个减号
if(wb.strip()!='' and wb.strip()!='-'):
dict1['委比']=float(wb)/100
else:del dict1['委比'];
3.利用嵌套字典存储多支股票信息
提取 Stocklist 里面的每一项股票代码,并以此作为关键字建立字典,形成嵌套字典
#利用字典存储多支股票信息
#初始化空字典
StockDict = dict()
#遍历列表StockDict里面的每个字典dic
for dic in StockList:
#在字典dic中获取股票名称name 设置关键字name对应的值为字典dic
StockDict[dic['股票名称']] = dic
#.keys()
print(StockDict)
输出信息如下:
2
['{\'股票名称\':"福建高速",\'成交量\':\'5.37万手\',\'成交额\':\'1778.96万\',\'委比\':\'-18.43%\'}\n',
'{\'股票名称\':"楚天高速",\'成交量\':\'10.52万手\',\'成交额\':\'3669.72万\',\'委比\':\'34.69%\'}']
{'股票名称': '福建高速', '成交量': 53700.0, '成交额': 17789000.0, '委比': '-18.43%'}
-18.43
{'股票名称': '楚天高速', '成交量': 105200.0, '成交额': 36697000.0, '委比': '34.69%'}
34.69
{'福建高速': {'股票名称': '福建高速', '成交量': 53700.0, '成交额': 17789000.0, '委比': -0.1843},
'楚天高速': {'股票名称': '楚天高速', '成交量': 105200.0, '成交额': 36697000.0, '委比': 0.3469}}
4.将股票信息保存到文件
#股票信息保存到文件
#载入第三方包pickle
import pickle
#二进制格式写入文件
output = open('股票信息字典.pkl','wb')
#存储函数:将StockDict保存到股票名为"股票信息字典.pkl文件"中
pickle.dump(StockDict,output)
科学计算与可视化
科学计算需要用到两个常用的第三方库:Numpy库、Pandas库
Numpy 模块主要用于数学 / 科学计算,不但能够完成科学计算任务,而且能够高效处理多维数据,以及存储和处理大型矩阵
Pandas 模块主要用于快速分析数据,以及数据清洗和准备等工作
Numpy 是一个 python 的开源的第三方库,代表 "Numeric Python",是由一个多维数组对象和用于处理数组的函数集合组成的库
1.Numpy 模块的导入、创建数组
2.Numpy 对象的创建
Numpy库 array() 函数可以创建一维或多维数组
创建一维数组时,传入的参数写法,跟列表写法是一致的
创建二维数组时,是列表里面的嵌套列表的写法
#导入Numpy模块
#为了引用函数方便 使用as关键字把numpy引用为np-> np作为numpy的别名
import numpy as np
#创建一个一维数组
arr1 = np.array([1,2,3,4,5,6,7,8,9])
print("创建的数组为:",arr1)
#创建一个二维数组
arr2 = np.array([[1,2,3,4],[5,6,7,8,9]])
print("创建的数组为:",arr2)
#输出
创建的数组为: [1 2 3 4 5 6 7 8 9]
创建的数组为: [list([1, 2, 3, 4]) list([5, 6, 7, 8, 9])]
3.Numpy 数组的访问
Numpy 库对数组的访问,与列表中访问元素类似
①可以直接下标访问
②使用切片器访问
print("数组第4至第6个元素为:",arr[3:6])
表示取出的是下标3至5的元素,也就是数组中第4个到第6个的元素
#一维数组的访问
arr = np.array([1,2,3,4,5,6,7,8,9])
print("数组arr为:",arr)
#直接下标访问
print("数组中第6个元素为:",arr[5])
#使用切片器访问
print("数组第4至第6个元素为:",arr[3:6])
print("数组中倒数第2个元素为:",arr[-2])
print("数组中所有下标为奇数的元素:",arr[1::2])
#输出
数组arr为: [1 2 3 4 5 6 7 8 9]
数组中第6个元素为: 6
数组第4至第6个元素为: [4 5 6]
数组中倒数第2个元素为: 8
数组中所有下标为奇数的元素: [2 4 6 8]
二维数组有两个维度,可以在每个维度中使用下标或者切片器
#二维数组的访问
arr = np.array([[1,2,3,4,5],[4,5,6,7,8],[7,8,9,10,11]])
print("创建的二维数组为: \n",arr)
print("数组中第1行中第3列和第4列的元素为:",arr[0,2:4])
print("数组中第2行和第3行中的3-5列的元素为:",arr[1:,2:])
#选取一列中所有元素怎么写? :代表选取此维度所有元素
print("数组中第2列的元素:",arr[:,1])
#输出
创建的二维数组为:
[[ 1 2 3 4 5]
[ 4 5 6 7 8]
[ 7 8 9 10 11]]
数组中第1行中第3列和第4列的元素为: [3 4]
数组中第2行和第3行中的3-5列的元素为: [[ 6 7 8]
[ 9 10 11]]
数组中第2列的元素: [2 5 8]
4.Numpy 数组数值运算
import numpy as np
#创建一个二维数组
arr = np.array([[1,2,3,4,5],[4,5,6,7,8],[7,8,9,10,11]])
print("创建的二维数组为: \n",arr)
#利用数值运算函数sum函数求和
print("数组的和为:",np.sum(arr))
#axis=0指定求纵向的平均值
print("数组纵轴的和:",np.sum(arr,axis=0))
print("数组横轴的和为:",np.sum(arr,axis=1))
print("数组均值为:",np.mean(arr))
print("数组纵轴的均值为:",np.mean(arr,axis=0))
print("数组的标准差为:",np.std(arr))
print("数组的方差为:",np.var(arr))
print("数组的最小值为:",np.min(arr))
print("数组的最大值为:",np.max(arr))
#输出
创建的二维数组为:
[[ 1 2 3 4 5]
[ 4 5 6 7 8]
[ 7 8 9 10 11]]
数组的和为: 90
数组纵轴的和: [12 15 18 21 24]
数组横轴的和为: [15 30 45]
数组均值为: 6.0
数组纵轴的均值为: [4. 5. 6. 7. 8.]
数组的标准差为: 2.8284271247461903
数组的方差为: 8.0
数组的最小值为: 1
数组的最大值为: 11
5.Numpy 文件的读写
学会文件读写是利用 Numpy 进行数据处理的基础
二进制格式文件读 / 写
文本格式文件读 / 写
import numpy as np
#创建一个二维数组
arr = np.array([[1,2,3,4,5],[4,5,6,7,8],[7,8,9,10,11]])
#savetxt()函数将arr数组保存到arr.txt文件 %d表示为整数类型 delimiter表示分隔符 这里使用逗号分隔
np.savetxt("arr.txt",arr,fmt="%d",delimiter=",")
#loadtxt()函数从文件中读入数据 这里指明了分隔符是逗号
load_data = np.loadtxt("arr.txt",delimiter=",")
print("读取的数组为:\n",load_data)
Pandas 也是一个 Python 的开源第三方库,被广泛用于快速分析数据,以及数据清洗和准备等工作
Pandas == Panel + data
1.Pandas 模块导入
2.Pandas 数据读取和写入
import pandas as pd
#Pandas提供了read_excel()函数读取Excel格式文件
data=pd.read_excel('data/tips.xls')
#读入后可以直接输出到控制台
print(data)
可以看到:多了序号列、标题行
total_bill:总费用
tip:小费金额
sex:性别
smoker:是否吸烟
day:周几
time:时间
size:用餐人数
Pandas 支持将数据写入到 Excel,将 data1 的数据写入 tips_new.xls
import pandas as pd
data1=pd.read_excel('data/tips.xls',usecols=[0,1,2])
print(data1)
#sheet_name代表工作表的名字为'小费数据' index设置为False表示不需要序列号
#默认为True有序号列
data1.to_excel("tips_new.xls",sheet_name='小费数据',index=False)
写入效果如下:
3.Pandas 数据存储结构
主要分为两种:
①Series
类似于一维数组的对象,由一组数据和与之相关的数据标签组成
import pandas as pd
#利用一组数据就可以产生最简单的Series
obj=pd.Series([4,7,-5,3])
print(obj)
#输出
序号列 数组内容
0 4
1 7
2 -5
3 3
显示类型为64位整数
dtype: int64
②Dataframe
是一个表格型的数据结构,含有一组有序的列,每列可以是不同的值类型:数值、字符串、布尔值等
Dataframe既有行索引。也有列索引
用行序号1进行索引
也可以使用省份进行索引:data[1]["省份"] 它的值就是广东
import pandas as pd
#通过字典创建Dataframe类型数据
data = {'省份':['江西','广东','福建','浙江','上海'],
'姓名':['小白','大白','小黑','大黑','小红'],
'age':[23,24,25,27,28]}
frame = pd.DataFrame(data)
print(frame)
#输出
省份 姓名 age
0 江西 小白 23
1 广东 大白 24
2 福建 小黑 25
3 浙江 大黑 27
4 上海 小红 28
4.Pandas 数据常用属性
Pandas 可以统计当前存储结构中的行索引
import pandas as pd
data = pd.read_excel('data/tips.xls')
print('小费统计表的索引为:',data.index)
print('小费统计表的所有值为:',data.values)
print('小费统计表的列名为:',data.columns)
print('小费统计表的元素个数为:',data.size)
print('小费统计表的维度数为:',data.ndim)
print('小费统计表的形状为:',data.shape)
#输出
小费统计表的形状为: (244,7) 表示有244行和7列数据
5.Pandas 数据访问
访问 Pandas 数据有两种方式:
①使用字典访问方式获取数据 data['name']
#使用pandas常规方法访问数据
import pandas as pd
data = pd.read_excel("data/tips.xls")
#获取total_bill这一列数据
total_bill = data["total_bill"]
print("每个账单总金额为:",total_bill)
data2 = data['total_bill'][2:6]
print("每个账单总金额数据中,行索引从2到6的数据为:",data2)
#用 data[["total_bill","tip"]] 表示总金额和小费这两列 切片器[2:6]表示从序号第2行到第5行
data3 = data[["total_bill","tip"]][2:6]
#获取行索引从2到6的每个账单中总金额和小费这两列数据
print("每个账单总金额和小费这两列中,行索引从2到6的数据为:",data3)
②使用属性访问方式获取数据 data.name 不建议使用:容易和面向对象以及库的数据成员弄混
Matplotlib 是 python 中最常用的可视化工具之一,可以很方便地创建各种类型的 2D 图表和 3D 图表:柱状图、饼图、3d曲面图
Matplotlib 库的使用
Matplotlib 库中应用最广的是 matplotlib.pyplot 模块,基于 pyplot 模块可视化绘图大致分为四个步骤:
1.绘图数据准备
import numpy as np
import matplotlib.pyplot as plt
#使用Numpy包的array和arange创建绘图数据
arr_temp = np.array([3,9,5,12,7,8,5,10,11,9,5,1])
arr_month = np.arange(1,13)
#这里用array()创建了12个月的温度
print('月份',arr_month)
print('温度',arr_temp)
#print(range(1,11))
#输出
月份 [ 1 2 3 4 5 6 7 8 9 10 11 12]
温度 [ 3 9 5 12 7 8 5 10 11 9 5 1]
2.设定图表类型
#设定图表类型为折线图 使用plot()函数
plt.plot(arr_month,arr_temp)
#设定图表类型为柱状图 使用bar()函数
plt.bar(arr_month,arr_temp)
3.设置图表属性
首先要设置 rcParams 指定字体,解决中文显示乱码问题
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['font.sans-serif']=['Arial Unicode MS']
设置图表的标题,x轴、y轴名称
plt.title('深圳5月的温度')
plt.xlabel('月份')
plt.ylabel('温度')
#使用show()函数显示出绘制的图表
plt.show()
4.绘制显示图表
注意:Matplotlib 库绘制的图表可任意改变长宽比例不会变形,还可以保存成多种图片格式
餐饮小费数据统计和分析项目
做数据统计分析一般按照以下基本流程:
问题定义
数据获取
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#使用read_excel()函数读取数据
tips = pd.read_excel("data/tips.xls") #读入小费数据集
#查看数据
#打印前六行数据
print(tips.head(6))
#打印列名
print(tips.columns)
#了解行数
print("数据行数",len(tips))
#了解数据基本信息
print(tips.info())
数据查看
数据统计
使用 loc() 函数选取出男性和女性、烟民和非烟民给小费的数据,使用 mean() 函数统计出均值,最后使用 groupby() 分组进行统计
#计算男性和女性就餐者给出小费的均值
tip_male=tips.loc[tips['sex']=="Male","tip"].mean()
tip_female=tips.loc[tips['sex']=="Female","tip"].mean()
print("男性和女性就餐者给出的小费均值分别\
为: {:.2f}和{:.2f}".format(tip_male,tip_female))
#计算吸烟者和非吸烟者给出小费的均值
tip_male=tips.loc[tips['smoker']=="Yes","tip"].mean()
tip_female=tips.loc[tips['smoker']=="No","tip"].mean()
print("烟民和非烟民给出的小费均值分别\
为: {:.2f}和{:.2f}".format(tip_male,tip_female))
#按性别分组统计就餐人数的平均值
tip_grp_sex=tips.groupby(by="sex")
print(tip_grp_sex["size"].mean())
#是否吸烟分组统计就餐人数的平均值
tip_grp_smoker=tips.groupby(by="smoker")
print(tip_grp_smoker["size"].mean())
可视化展示
使用折线图和散点图对数据进行可视化展示
plt.plot(tips["tip"],color="red",linestyle="-",linewidth=0.5) #绘制小费数据的折线图
plt.show() #显示图形
plt.scatter(x=tips["total_bill"],y=tips["tip"],marker="o",c="red",s=tips["size"])
#设置标签
plt.xlabel("total_bill")
plt.ylabel("tip")
plt.show()
分析结论
网站信息爬取
网站信息爬取的预备知识:爬取网页数据和解析数据的程序,一般称为 "网络爬虫",就是模拟客户端发送网络请求,接收响应,按照一定的规则自动化地爬取互联网信息的程序
只要浏览器能够做的事情,原则上爬虫都能爬取到
网站爬取的流程一般为初始化 URL 队列,判断队列是否为空,如果为空则结束运行,如果不为空代表还有要爬取的 URL,就从队列中选取一个 URL,发送页面请求,如果请求不成功,则重新放入队列等以后再爬取,如果成功则解析页面内容,并存储数据
需要安装 request 库和 beautifulsoup4 库
利用 request 库爬取网页:
使用pycharm 安装第三方库 这里以request 为例子
利用 beautifulsoup4 库解析网页:基于pycharm的beautifulsoup4库使用
利用 request 库爬取网页
import requests
url = "https://baike.baidu.com/item/c/22337?fr=aladdin"
#使用 gets 函数发送网页请求
r = requests.get(url)
#设置编码格式,否则中文会显示乱码
r.encoding = 'utf-8'
print(r.text)
从运行结果可以看出,已经获取到网页的源代码
利用 beautifulsoup4 库解析网页
将爬取下来的源代码,字符串 r.text 创建一个 beautifulsoup 对象 soup
from bs4 import BeautifulSoup
import requests
url = "https://www.baidu.com/index.php?tn=monline_3_dg"
#使用 gets 函数发送网页请求
r = requests.get(url)
#设置编码格式,否则中文会显示乱码
r.encoding = 'utf-8'
soup = BeautifulSoup(r.text,'html.parser')
#自动解析出 title 标签和第一个 a 标签
print(soup.title)
print(soup.a)
常用的查找函数:
find_out(): 返回所有满足条件的标签
find(): 与 find_out() 函数类似,差异在于只返回第一个符合条件的标签
爬取一个网站首页:网易财经-有态度的财经门户,然后使用 beautifulsoup 库对内容进行解析,最后输出新闻标题
在浏览器中右键点击查看页面源代码,新闻标题的数据位于:
from bs4 import BeautifulSoup
import requests
# Fetch the page and create a Beautiful Soup object
page = requests.get("https://money.163.com/")
soup = BeautifulSoup(page.content.decode('utf-8','ignore'), "html.parser")
ul = soup.find("div",class_='topnews_ad channel_relative_2016')
for region in ul.find_all('a'):
print(region.string)
爬取所有的地方名,地方名的数据位于:人民网_网上的人民日报
from bs4 import BeautifulSoup
import requests
# Fetch the page and create a Beautiful Soup object
page = requests.get("https://www.people.com.cn/")
soup = BeautifulSoup(page.content.decode('gb2312','ignore'), "lxml")
ul = soup.find("ul",class_='df')
for region in ul.find_all('a'):
print(region.text)
项目的任务:爬取序号、电影名、豆瓣评分
查看网页源代码,在源代码中定位电影的信息,发现在 class 属性为 grid_view 的 ol 标签中,class 属性为 title 的 span 是电影的名字,class 属性为 rating_num 的 span 是豆瓣评分
由于许多网站出于安全考虑会阻止爬虫对上面的信息进行爬取,一种绕过这种安全防护的方式是设置 header 伪装成浏览器,利用 requests() 库里面的 get() 函数传入 headers 来绕过安全检测
from bs4 import BeautifulSoup
import requests
url = "https://movie.douban.com/top250"
#使用gets函数发送网页请求
myheader = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"'
'(KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'
}
#绕过安全检测
r = requests.get(url,headers = myheader)
#设置编码格式,否则中文会显示乱码
r.encoding = 'utf-8'
#利用 BeautifulSoup 库通过标签查找定位电影信息
order = 0
soup = BeautifulSoup(r.text,'html.parser')
myitems = soup.find_all('div',attrs={"class":"item"})
for item in myitems:
#class属性为title的span是电影名
myspan = item.find('span',{'class':'title'})
print(order,myspan.text,end='\t')
#class属性为rating_num的span是豆瓣评分
scoreitem = item.find('span',{'class':'rating_num'})
print(scoreitem.text)
order +=1
运行程序输出爬取到的电影名字和豆瓣评分
AI应用
百度AI:人脸识别-百度AI开放平台-全球领先的人工智能服务平台-百度AI开放平台
创建应用并保存以下信息
安装 python SDK:
pip install baidu-aip
pip install opencv-python
pip install numpy
基于百度 Al 的人脸检测,检测合影图片文件,检测出人脸信息,并给与显示,实现流程分为以下四个部分:
百度在线人脸识别API简单实现教程_辣鸡博主已停更的博客_百度人脸识别
一、创建 Airface 客户端,填写 APPID,API Key,Secret Key 的账号信息
https://ai.baidu.com/ai-doc/FACE/yk37c1u4t
二、读取图片并转码,读取合影图片并使用 BASE64 编码
三、调用百度AI,获取人脸区域,设置参数调用人脸检测的 API
四、用矩形标出人脸区域,使用 OpenCV 在图片上人脸区域绘制矩形框以标出人脸
0.素材
1.读取图片
#导入cv模块
import cv2 as cv
#读取图片
img = cv.imread('file\heying.jpg')
cv.imshow('read_img',img)
#等待:填入0无限等待 填入具体数字,具体数字达到后会关闭
cv.waitKey(0)
#释放内存
cv.destroyWindows()
2.灰度转换
#灰度转换 要转换的图片 要转换成什么颜色的图片
gray_img = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#显示灰度图片
cv.imshow('gray',gray_img)
#保存灰度图片
cv.imwrite("gray_face.jpg",gray_img)
#显示图片:只显示一下 要显示的名字 显示的图片
3.修改尺寸
#修改尺寸 需要改变的图像 需要改成多大的:改为 1440//2 * 1080//2
resize_img = cv.resize(img,dsize = (1440//2,1080//2))
#让原图大小和修改后的图片大小进行直观对比
#显示原图
cv.imshow('img',img)
#显示修改后的
cv.imshow('resize_img',resize_img)
#打印原图尺寸大小
print('未修改:',img.shape)
#打印修改后图片大小
print('修改后:',resize_img.shape)
#输出
未修改: (1080, 1440, 3)
修改后: (540, 720, 3)
4.检测退出
#检测到键盘按下'q'就退出-> 注意是英文输入法的'q'
while True:
if ord('q') == cv.waitKey(0):
break
5.在修改后的图片上画框框、或者画圆圈,需要画在人脸上,绘制矩形
#坐标
#起始点
x,y,w,h = 100,100,100,100
#绘制矩形 需要在哪张图片上画矩形 (起始点 宽 高) 颜色 BGR 宽度
cv.rectangle(img,(x,y,x + w,y + h),color=(0,0,255),thickness=5)
#绘制圆形 需要在哪张图片上画圆形 圆心 半径 颜色 宽度
cv.circle(img,center=(x+w,x+h),radius=100,color=(255,0,0),thickness=5)
#显示
cv.imshow('re_img',img)
6.人脸检测
分类器的位置:注意把路径的符号改为 /
#导入cv模块
import cv2 as cv
def face_detect_demo():
#把图片转换为灰度
resize_img = cv.resize(img, dsize=(1080 // 2, 1226 // 2))
gray_img = cv.cvtColor(resize_img, cv.COLOR_BGR2GRAY)
#加载一个分类器:快速做出人脸识别的关键-> 调用 OpenCV 中自带的,别人已经训练好的分类器,不用自己训练就可以直接使用
face_detect = cv.CascadeClassifier('D:/OPENCV(WIN)/opencv/sources'
'/data/haarcascades/haarcascade_frontalface_alt2.xml')
#face = face_detect.detectMultiScale(gray_img)
#放入的图像 每次遍历之后的缩放倍数 确定的次数:检测5遍都有人脸才确定 默认值0 在图片中的人脸最小有多小 最大有多大
face = face_detect.detectMultiScale(gray_img,1.01,5,0)
for x,y,w,h in face:
cv.rectangle(resize_img,(x,y),(x+w,y+h),color=(0,0,255),thickness=2)
cv.imshow('result',resize_img)
#读取图像
img = cv.imread('file\Face.jpg')
#检测函数
face_detect_demo()
#等待:填入0无限等待 填入具体数字,具体数字达到后会关闭
cv.waitKey(0)
#释放内存
cv.destroyWindows()
出现检测失败的情况:由于缩放倍数改变导致
通过限制大小后也可以找到人脸
#最小是 100*100 的像素框中不可能有人脸 超过 200*200 的框中也不可能有人脸
face = face_detect.detectMultiScale(gray_img,1.01,5,0,(100,100),(200,200))
7.检测多个人脸
只需要调整限制大小就可以找到人脸,如果检测效果不明显,可以修改分类器,或者把 detectMultiScale() 中的参数省略
#导入cv模块
import cv2 as cv
def face_detect_demo():
#把图片转换为灰度
resize_img = cv.resize(img, dsize=(810, 540))
gray_img = cv.cvtColor(resize_img, cv.COLOR_BGR2GRAY)
#加载一个分类器:快速做出人脸识别的关键-> 调用 OpenCV 中自带的,别人已经训练好的分类器,不用自己训练就可以直接使用
face_detect = cv.CascadeClassifier('D:/OPENCV(WIN)/opencv/sources'
'/data/haarcascades/haarcascade_frontalface_alt2.xml')
face = face_detect.detectMultiScale(gray_img, 1.01, 5, 0, (80, 80), (200, 200))
for x,y,w,h in face:
cv.rectangle(resize_img,(x,y),(x+w,y+h),color=(0,0,255),thickness=2)
cv.imshow('result',resize_img)
#读取图像
img = cv.imread('file\hezhao.jpg')
#检测函数
face_detect_demo()
while True:
if ord('q') == cv.waitKey(0):
break
#释放内存
cv.destroyWindows()
8.视频检测
这里就不展示了hhh
#导入cv模块
import cv2 as cv
def face_detect_demo(img):
#把图片转换为灰度
resize_img = cv.resize(img, dsize=(810, 540))
gray_img = cv.cvtColor(resize_img, cv.COLOR_BGR2GRAY)
#加载一个分类器:快速做出人脸识别的关键-> 调用 OpenCV 中自带的,别人已经训练好的分类器,不用自己训练就可以直接使用
face_detect = cv.CascadeClassifier('D:/OPENCV(WIN)/opencv/sources'
'/data/haarcascades/haarcascade_frontalface_alt2.xml')
face = face_detect.detectMultiScale(gray_img)
for x,y,w,h in face:
cv.rectangle(resize_img,(x,y),(x+w,y+h),color=(0,0,255),thickness=2)
cv.imshow('result',resize_img)
#读取摄像头图像 默认的摄像头0 数据改变就是外接摄像头
cap = cv.VideoCapture(0)
#循环
while True:
#本身:有视频内容时self返回值为Ture,img为当前帧的图像
#cap.read()
flag,frame = cap.read()
#如果播放完毕
if not flag:
break
#一直播放-> 有值就让它识别frame
face_detect_demo(frame)
if ord('q') == cv.waitKey(1):
break
#释放内存
cv.destroyWindows()
#释放摄像头
cap.release()
读取一个视频:后续需要的时候可以改为网页中的视频或者别的设备上的摄像头,实现一种远程控制的效果
#读取摄像头图像 默认的摄像头0 数据改变就是外接摄像头
cap = cv.VideoCapture('file/win.mp4')
9.信息录入
把要识别的人脸提前录入,下一次识别的时候计算机就知道 ta 是谁,把所有的照片保存到文件夹中,后序就可以把这些照片的特征提取出来(通过提取特征的方式,把人的面部特征提取出来,提取出来的人的面部特征在下一次被识别到的时候,可以把这个人的名字显示出来)
#读取摄像头图像 默认的摄像头0 数据改变就是外接摄像头
cap = cv.VideoCapture('file/win.mp4')
falg = 1
num = 1
#检测摄像头是否为开启状态
while(cap.isOpened()):
#得到每帧图像
ret_flag,Vshow = cap.read()
#显示图像
cv.imshow("Capture_Test",Vshow)
#按键判断:检测到键盘按下's' 就把当前图像保存到指定路径
k = cv.waitKey(1) & 0xFF
#保存
if k == ord('s'):
#文件夹的命名规则:路径+编号+提前录入的人的名字-> 让人的名字和序号保存到某一个文件中
cv.imwrite("D:/Files/"+str(num)+".name"+".jpg",Vshow)
print("success to save"+str(num)+".jpg")
print("-------------------")
num += 1
#按下空格退出循环
elif k == ord(' '):
break
10.数据训练
前面九步找到人脸的过程,下面把人脸和人脸的 ID 对应起来
下面的二维列表中储存人脸部分的灰度值,颜色越浅的地方越小,颜色越深的地方越大,把第一个人脸和身份信息对应起来了
识别过程中需要调用 yml 文件来进行识别,把所需要识别的人的信息和 ID 先保存到一个文件里面,利用这个训练好的文件拿到别的地方去,这个文件就可以帮助你识别出这个人和 ID 的对应关系了
可能遇到的问题及解决办法:
可以看到自动生成的 .yml 文件
#导入cv模块
import os
import cv2 as cv
import sys
from PIL import Image
import numpy as np
def getImageAndLabels(path):
#存储人脸数据
facesSamples=[]
#存储姓名数据
ids=[]
#存储图片信息:通过路径存储在列表中
imagePaths=[os.path.join(path,f) for f in os.listdir(path)]
#加载分类器
face_detector= cv.CascadeClassifier('D:/OPENCV(WIN)/opencv/sources'
'/data/haarcascades/haarcascade_frontalface_alt2.xml')
#遍历列表中的图片:对保存的全部图像一一遍历,把身份信息保存起来
for imagePath in imagePaths:
#打开图片,以灰度化的方式 PIL有九种不同模式:1:黑白 有像素为1 无像素为0
#L:灰度:把每个像素点变成 0 ~ 255 的数值 颜色越深、数值越大 P,RGB,RGBA,CMYK,YCbCr,I,F
PIL_img=Image.open(imagePath).convert('L')
#把图片的每个像素点变成一个数值-> 将图像转换为数值为了让计算机看懂 计算机看不懂整张图片
img_numpy = np.array(PIL_img,'uint8')
#用分类器获取图片的人脸特征-> 人脸那一部分数组
faces = face_detector.detectMultiScale(img_numpy)
#获取每张图片的id和姓名-> 提取文件名前面的.前面的东西
id = int(os.path.split(imagePath)[1].split('.')[0])
#预防无面容照片
for x,y,w,h in faces:
#把 id 添加到 ids 列表中
ids.append(id)
#同一个人的向量下的特征
facesSamples.append(img_numpy[y:y+h,x:x+w])
#打印脸部特征和id
print('id:',id)
print('fs:',facesSamples)
return facesSamples,ids
if __name__ == '__main__':
#把图片拿进来 找到图片路径
path = './file/py/'
#获取图像数组、id标签数组、姓名-> 通过某个函数把人脸特征和姓名拿出来-> 读取到每个人的信息和身份信息
faces,ids = getImageAndLabels(path)
#加载识别器-> 把面部和身份消息通过训练整合在一起,面部信息和身份信息一一对应 最后保存在文件中
recognizer = cv.face.LBPHFaceRecognizer_create()
#训练
recognizer.train(faces,np.array(ids))
#写入文件-> 识别过程中调用关系文件实现人脸识别
recognizer.write('trainer/trainer.yml')
11.人脸识别
如果一个人长时间在我的摄像头下徘徊,并且我不认识 ta,我的手机就会收到一条短信,从而我知道有一个陌生人
#导入模块
import cv2
import numpy as np
import os
# coding=utf-8
import urllib
import urllib.request
import hashlib
#加载训练数据集文件-> 导入训练数据
recogizer=cv2.face.LBPHFaceRecognizer_create()
recogizer.read('trainer/trainer.yml')
#列表用于存储1.后面的名字
names=[]
#当摄像头检测到不是我们之前录入的人员-> 黑名单:发出警报-> 发送一条短信提醒
#报警全局变量
warningtime = 0
#md5对短信平台的账号和密码加密
def md5(str):
import hashlib
m = hashlib.md5()
m.update(str.encode("utf8"))
return m.hexdigest()
#短信反馈
statusStr = {
'0': '短信发送成功',
'-1': '参数不全',
'-2': '服务器空间不支持,请确认支持curl或者fsocket,联系您的空间商解决或者更换空间',
'30': '密码错误',
'40': '账号不存在',
'41': '余额不足',
'42': '账户已过期',
'43': 'IP地址限制',
'50': '内容含有敏感词'
}
#报警模块
def warning():
#借用短信宝api 发送报警短信
smsapi = "http://api.smsbao.com/"
# 短信平台账号
user = '13******10'
# 短信平台密码
password = md5('*******')
# 要发送的短信内容
content = '【报警】\n原因:检测到未知人员\n地点:xxx'
# 要发送短信的手机号码
phone = '*******'
data = urllib.parse.urlencode({'u': user, 'p': password, 'm': phone, 'c': content})
send_url = smsapi + 'sms?' + data
response = urllib.request.urlopen(send_url)
the_page = response.read().decode('utf-8')
print(statusStr[the_page])
#准备识别的图片
def face_detect_demo(img):
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#导入图片转换为灰度
#加载分类器进行检测:把整张图片的人脸部分框起来
face_detector=cv2.CascadeClassifier('D:/OPENCV(WIN)/opencv/sources'
'/data/haarcascades/haarcascade_frontalface_alt2.xml')
face=face_detector.detectMultiScale(gray,1.1,5,cv2.CASCADE_SCALE_IMAGE,(100,100),(300,300))
#face=face_detector.detectMultiScale(gray)
for x,y,w,h in face:
cv2.rectangle(img,(x,y),(x+w,y+h),color=(0,0,255),thickness=5)
cv2.circle(img,center=(x+w//2,y+h//2),radius=w//2,color=(0,255,0),thickness=5)
# 人脸识别-> 对人脸部分预测、评分
ids, confidence = recogizer.predict(gray[y:y + h, x:x + w])
#print('标签id:',ids,'置信评分:', confidence)
if confidence > 80:
global warningtime
#如果 confidence 比较大就不可信 警报变量 + 1
warningtime += 1
#警报次数达到一定次数,说明不是我们所录入的人员,就发送一个警报
if warningtime > 100:
warning()
warningtime = 0
cv2.putText(img, 'unknow', (x + 10, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)
else:
#评分比较小,是可信人员,就需要把 ta 的姓名打到人脸框上
cv2.putText(img,str(names[ids-1]), (x + 10, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)
cv2.imshow('result',img)
#print('bug:',ids)
def name():
path = './file/py/'
#names = []
imagePaths=[os.path.join(path,f) for f in os.listdir(path)]
for imagePath in imagePaths:
name = str(os.path.split(imagePath)[1].split('.',2)[1])
names.append(name)
cap=cv2.VideoCapture('file/win.mp4')
name()
while True:
flag,frame=cap.read()
if not flag:
break
face_detect_demo(frame)
if ord(' ') == cv2.waitKey(10):
break
cv2.destroyAllWindows()
cap.release()
#print(names)
12.网页视频
通常情况下的摄像头不可能离主机很近,一般就是离家2Km. . .之外有一个摄像头,实时识别这个摄像头中的数据就需要借助互联网,了解 rtmp 协议,通过这种协议,可以让视频流从机器摄像头与主机进行数据的传输,基本上现在的摄像头都是支持 rtmp 协议的,使用时只要把 "rtmp://58.200.131.2:1935/livetv/hunantv" 改成我们需要的地址即可
import cv2
class CaptureVideo(object):
def net_video(self):
# 获取网络视频流
#cam = cv2.VideoCapture("rtmp://192.168.0.10/live/test")
cam = cv2.VideoCapture("rtmp://58.200.131.2:1935/livetv/hunantv")
while cam.isOpened():
sucess, frame = cam.read()
cv2.imshow("Network", frame)
cv2.waitKey(1)
if __name__ == "__main__":
capture_video = CaptureVideo()
capture_video.net_video()