Gritty 坚韧不拔之志|Python Everywhere|Python Only Not Enough|本人也第一次接触编程,难免出错,大家多多包容|
第零周:Pycharm 使用技巧
1.Pycharm 快捷键
代码回退: command(Ctrl)+z
多选:长按 command+光标选中
2.网站资源
GitHub · Build and ship software on a single, collaborative platform
PyPI · The Python Package Index
3.补充
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
4.常见报错
TypeError:类型错误
SyntaxError:语法错误
IndentationError:表示缩进错误,也就是表明这里的代码没有顶格
invalid syntax:是无效语法,说明变量定义出错了
IndexError:索引错误
indentation:缩进错误
第一周:Python基本语法元素
1.代码高亮
编程的色彩辅助体系,不是代码要求
2.缩进
(1)一行代码开始前的空白区域,表示程序的格式框架
(2)有单层缩进和多层缩进之分
(3)(严格明确)缩进是代码的一部分
(4)(所属关系)表达代码间包含和层次关系的唯一手段
(5)(长度一致)程序内一致即可,一般用4个空格或一个tab;也不一定非得4个,但单一程序内缩进必须相同
(6)Python 中不同层级的代码之间强制要求缩进,并且相同层级的代码要求缩进的空格数量一致。
3.注释
(1)用于提高代码可读性的辅助性文字,不被执行
(2)单行注释,以#开头
(3)多行注释,开头结尾都有三个单引号'''
'''
xxxxx
'''
4.变量
(1)用来表示和保存数据的标识符号
(2)变量采用标识符(名字)来表示,关联标识符的过程叫命名TempStr是变量名字
(3)可以使用=来向赋值或修改值,=被称为赋值符号
(4)TempStr="82F"#向变量TempStr赋值"82F"
(5)变量定义时必须顶格
5.命名
(1)命名规则:大小写字母、数字、下划线和汉字等字符及组合
(2)注意:大小写敏感(即字母大小写不同,表义不同)、首字母不能是数字、不与保留字相同
6.保留字(关键字)共35 个
(1)被编程语言内部定义并保留使用的标识符
eg:if,elif,else,in
(2)大小写敏感
and | elif | import | raise | global |
as | else | in | return | nonlocal |
assert | except | is | try | True |
break | finally | lambda | while | False |
class | for | not | with | None |
continue | from | or | yield | asyne |
def | if | pass | del | await |
7.数据类型
(1)供计算机理解的数据形式
(2)程序设计语言不允许存在语法歧义,需要定义数据的形式
eg:10,101,010关联一种计算机可以理解的形式
(3)程序设计语言通过一定方式向计算机表达数据的形式
eg:"123"表示字符串123,123则表示数字123
(4)10,011,100的三种数据类型表示
(1)整数类型:整型直接通过数字来表示,且无需添加引号eg:10011100
(2)字符串类型:"10,011,100"
(3)列表类型(相当于三个数字):[10,011,100]
(4)布尔类型:Ture/False且不加引号
#哈希函数hash(),能够进行哈希运算的类型是不可变类型,并产生一个整数哈希值
>>>hash("python is popular")
-7425766840899008624
>>>hash(["python",123])
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
hash(["python",123])
TypeError: unhashable type: 'list'
8.字符串类型
(1)由0个或多个字符组成的有效字符序列
(2)字符串由一对单引号或一对双引号表示或三个单引号
eg:""/'' eg:''' '''
为什么有那么多种:使得单引号和双引号可以包含到字符串内
(3)字符串是字符的有序序列,可对字符串进行索引
eg:"请"是"请输入带有符号的温度值:"的第0个字符
(4)字符串的序号
9. 字符串的使用
(1)使用[]获取字符串的一个或多个字符
(2)索引:通过序号访问字符串所包含字符的过程,返回字符串中的单个字符 <字符串>[M]
eg:"请输入带有符号的温度值:"[0] 或者 TempStr[-1]
(3)切片:通过序号组合访问字符串某个区间的过程,返回字符串中一段字符子串 <字符串>[M:N]
eg:"请输入带有符号的温度值:"[1:3]意思是从第一个开始,不到第三个,即'输入'
或者TempStr[0:-1]意思相当于把字符串的最后一个值去掉
TempStr[1:]表示字符串除首字符外的所有字符
(4)字符串切片的高级用法
<字符串>[M:N],M缺失表示至开头,N缺失表示至结尾
"零一二三四五六七八九十"[:3]结果为"零一二"
<字符串>[M:N:K],根据步长K对字符串切片
"零一二三四五六七八九十"[1:8:2]结果是"一三五七"
倒序技巧:"零一二三四五六七八九十"[::-1]结果是"十九八七六五四三二一零"
>>>s = "python语言程序设计"
>>>s[3:0:-1]#从序号0开始到3,以步长为1取反
'hty'
(5)字符串的特殊字符
转义符\ 即表达字符的本义
转义符表达特殊字符的本义
"这里有个双引号(\")"结果为这里有个双引号(")
转义符形成一些组合,表达一些不可打印的含义
"\b"表示回退、"\n"表示换行(光标移到下行首)、"r"回车(光标移到本行首)
10. 字符串操作符
由0个或多个字符组成的有序字符序列
操作符及使用 | 描述 |
x + y | 连接两个字符串x和y,返回新的字符串 |
n*x 或 x*n | 复制n次字符串x,返回新的字符串 |
x in s | 如果x是s的子串,返回Ture,否则返回False |
x == y | 如果 x 是 s 的子串,返回 True,否则 False |
问题: 获得输入的一个字符串s,以字符减号(-)分割s,将其中首尾两段用加号(+)组合后输出。
s = input()
ls = s.split("-")
print("{}+{}".foemat(ls[0],ls[-1]))
#WeekNamePrintv1.py
WeekStr = "星期一星期二星期三星期四星期五星期六星期日"
WeekID = eval(input("请输入星期数字(1-7):"))
pos = (WeekID - 1)*3
print(WeekStr[pos:pos+3])
#WeekNamePrintv2.py
WeekStr = "一二三四五六日"
WeekID = eval(input("请输入星期数字(1-7):"))
print("星期"+WeekStr[WeekID-1])
11. 字符串处理函数
一些以函数形式处理字符串功能
函数及使用 | 描述 |
len(x) | 长度,返回字符串x的长度,也可返回组合数据类型的元素个数 len("一二三456")结果为6 |
str(x) | 任意类型x所对应的字符串形式 str(1.23)结果为"1.23" str([1,2])结果为"[1,2]" #str与eval相当于相反操作 |
hex(x) | 整数x的十六进制小写形式字符串 hex(425)结果为"0x1a9" |
oct(x) | 八进制小写形式字符串,oct(425)结果为"0o651" |
bin(x) | 将数字 x 转换为其二进制形式,且为字符串类型 |
chr(u) | u为Unicode编码,返回其对应的字符 u 的取值范围为0~1114111(即十六进制 0x10FFFF) |
ord(x) | x为字符,返回其对应的Unicode编码整数 |
12.Unicode编码
Python字符串的编码方式:统一字符编码,即几乎覆盖所有字符的编码方式;从0到1114111(0x10FFFF)空间,每个编码对应一个字符;Python字符串中每个字符都是Unicode编码字符
"1+1=2"+chr(10004)
#'1+1=2✔'
"这个字符♉的Unicode值是:"+ str(ord("♉"))
#这个字符♉的Unicode值是:9801
for i in range(12):
print(chr(9800 + i),end="")#end等于空,end输出之后不换行
#♈♉♊♋♌♍♎♏♐♑♒♓
13.ASCII 码表
ASCII码表 | |||||||
ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 |
0 | NUT | 32 | (space) | 64 | @ | 96 | 、 |
1 | SOH | 33 | ! | 65 | A | 97 | a |
2 | STX | 34 | " | 66 | B | 98 | b |
3 | ETX | 35 | # | 67 | C | 99 | c |
4 | EOT | 36 | $ | 68 | D | 100 | d |
5 | ENQ | 37 | % | 69 | E | 101 | e |
6 | ACK | 38 | & | 70 | F | 102 | f |
7 | BEL | 39 | , | 71 | G | 103 | g |
8 | BS | 40 | ( | 72 | H | 104 | h |
9 | HT | 41 | ) | 73 | I | 105 | i |
10 | LF | 42 | * | 74 | J | 106 | j |
11 | VT | 43 | + | 75 | K | 107 | k |
12 | FF | 44 | , | 76 | L | 108 | l |
13 | CR | 45 | 77 | M | 109 | m | |
14 | SO | 46 | 78 | N | 110 | n | |
15 | SI | 47 | / | 79 | 0 | 111 | o |
16 | DLE | 48 | 0 | 80 | P | 112 | p |
17 | DCI | 49 | 1 | 81 | Q | 113 | q |
18 | DC2 | 50 | 2 | 82 | R | 114 | r |
19 | DC3 | 51 | 3 | 83 | X | 115 | s |
20 | DC4 | 52 | 4 | 84 | T | 116 | t |
21 | NAK | 53 | 5 | 85 | U | 117 | u |
22 | SYN | 54 | 6 | 86 | V | 118 | V |
23 | TB | 55 | 7 | 87 | W | 119 | W |
24 | CAN | 56 | 8 | 88 | X | 120 | X |
25 | EM | 57 | 9 | 89 | Y | 121 | y |
26 | SUB | 58 | : | 90 | Z | 122 | Z |
27 | ESC | 59 | ; | 91 | [ | 123 | { |
28 | FS | 60 | < | 92 | / | 124 | |
29 | GS | 61 | = | 93 | ] | 125 | } |
30 | RS | 62 | > | 94 | ^ | 126 | ~ |
31 | US | 63 | ? | 95 | 127 | DEL |
14. 字符串处理方法
"方法"在编程中是一个专有名词
"方法"特指<a>.<b>()风格中的函数<b>(),a 为对象,b 为方法
方法本身也是函数,但与<a>有关,<a>.<b>风格使用
字符串及变量也是<a>,存在一些方法
一些方法形式提供的字符串处理方法 12 个
方法及使用 | 描述 |
str.title() | 首字母大写 |
str.lower() | 返回字符串的副本,全部字符小写 "AbCdEfGh".lower()结果为"abcdefgh" |
str.upper() | 返回字符串的副本,全部字符大写 |
str.islower() | 当 str 所有字符都是小写时,返回 True,否则返回 False |
str.isnumeric() | 当所有字符都是数字时,返回 Ture,否则 False |
str.split(sep=None) | 返回一个列表,由 str 根据 sep 被分隔的部分组成 "A,B,C".split(",")结果为 ['A','B','C'] |
str.join(iter) | 将序列中的元素(如列表、元组、集合等)以指定的字符连接生成一个新的字符串 ",".join("12345")结果为"1,2,3,4,5"#主要用于字符串分隔等 |
str.count(sub) | 返回子串 sub 在 str 中出现的次数 "an apple a day".count('a')结果为 4 |
str.replace(old,new) | 返回字符串 str 副本,所有 old 子串被替换为 new "python".replace("n","n123.io")结果为"python123.io" |
str.center(width[,fillchar]) | 字符串 str 根据宽度 width 居中,fillchar (填充内容)可选 "python'.center(20,"=")结果为'=======python=======' |
str.strip(chars) | 从 str 中去掉在其左侧和右侧 chars 中列出的字符 "= python=".strip(" =np")结果为"ytho" |
str.lstrip() | 除去左端字符,默认空格 |
str.rstrip() | 除去右端字符,默认空格 |
str.format() | 返回字符串 str 的一种排版格式 |
str.find(sub) | 返回 sub 子串在 str 中的最低出现序号,不存在返回-1 |
#lower和upper对非英文字符形态不改变
#islower不判断非英文形态
#isnumeric判断的数字是0~9,不包括小数(点)、正负号
#old和new的长度可以不同,当new为空字符串时,相当于删除了old部分
#center(width,fillchar)当width小于字符串长度时,返回str(即不发生改变),fillchar是单个字符
#find返回的数字为正整数,即正向索引,故不会有-1的出现
#strip方法只是去掉str左右两侧chars中列出的字符,不影响字符串内部
#split方法若不加内容,sep默认是空格,sep可字符或字符串,若sep出现在字符串两侧,则会在两侧产生一个空字符串
>>>"hththth".split('t')
['h', 'h', 'h', 'h']
#join方法于split方法互逆
15. 作业
#CaesarCodeEn.py
ptxt = input("请输入明文:")
for p in ptxt:
if 'a'<=p<='z':
print(chr(ord("a") + (ord(p) - ord("a") - 3) % 26),end='')
else:
print(p,end='')
16. 字符串类型的格式化
格式化是对字符串进行格式表达的方法,用于解决字符串与变量融合的格式安排问题
字符串格式化使用.format()方法,用法如下:
<模版字符串>.format(<逗号分隔的参数>)
"{}:计算机{}的CPU占用率为{}%".format("A","B","C")
#默认012按序填充
#"{1}:计算机{0}的CPU占用率为{2}%".format("A","B","C")
#也可指定填充
#可嵌套使用
>>>"圆周率{{{1}{2}}}是{0}".format("无理数","3.1415926","...")
'圆周率{3.1415926...}是无理数'
槽内部对格式化的配置方式
{<参数序号>:<格式化控制标记>}
参数序号的作用:
1.指定占位符的索引:冒号前的数字表示占位符的索引。例如,{1:x<4}
中的 1
表示使用第二个参数进行格式化(在Python3.6之后就不需要用这种难看的形式了)
2.指定变量名:冒号前可以使用变量名来指定占位符的内容。例如,{name:x^4}
中的 name
是一个变量名,表示使用该变量的值进行格式化
3.定义格式化选项:冒号后的部分可以定义格式化选项,如对齐方式、填充字符、宽度等。例如,{:<4}
表示左对齐,宽度为4
4.省略索引和格式化选项:如果冒号前后的内容都省略,则按顺序将元组中的内容以字符串格式显示
5.嵌套槽:在某些情况下,冒号前还可以嵌套其他槽,用于更复杂的格式化需求
#
print("{0:=^20}".format("PYTHON"))
#=======PYTHON=======
print("{0:*>20}".format("BIT"))
#*****************BIT
print("{:10}".format("BIT"))
#BIT,填充默认为空格,对齐为左对齐
>>>Money = input()
>>>Money = Money[:-4]
>>>print(Money)
1234567
123
>>>Money = input("请输入带有符号的货币值:")
>>>Money = Money[-4:]
>>>print(Money)
1234567
4567
#总结:冒号没数的一端代表到此端头
#默认填充为空格,对齐为左对齐
#如果字符串超过长度3,则以字符串长度显示
<类型>
整数<类型> | |
b | 输出整数的二进制方式 |
c | 输出整数的 Unicode 字符 |
d | 输出整数的十进制方式 |
o | 输出整数的八进制方式 |
x | 输出整数的小写十六进制方式 |
X | 输出整数的大学十六进制方式 |
浮点数<类型> | |
e | 输出浮点数对应的小写字母 e 的指数形式 |
E | 输出浮点数对应的小写字母 E 的指数形式 |
f | 输出浮点数的标准浮点形式 |
% | 输出浮点数的百分形式 |
print("{0:b},{0:c},{0:d},{0:o},{0:x},{0:X}".format(425))
#110101001,Ʃ,425,651,1a9,1A9
#b二进制表示形式、cUnicode编码形式、d 十进制表示形式、o八进制、x小写十六进制、X大写十六进制
print("{0:e},{0:E},{0:f},{0:%}".format(3.14))
#3.140000e+00,3.140000E+00,3.140000,314.000000%
#e、E使用科学计数法e、E形式表示浮点数;f为以通常的非科学计数法形式表示浮点数;以%形式表示浮点数
#精度的两种含义,对浮点数,表示小数位数(四舍五入);对字符串,表示输出的最大长度
>>>"{0:.4}".format("PYTHON")
'PYTH'
#英文的半角形式,中文的全角形式
#中文以字符形式表示,不可用作语法的一部分
17.数字类型
(1)整数
数学中的整数,包括正数和负数
(2)浮点数
数学中的实数,包含小数部分
eg:1.0
>>>type(123)
<class'int'>
18.数字
(1)浮点型:它通过数字和小数点来表示,无需添加引号。
(2)整数类型:整型直接通过数字来表示,且无需添加引号。
(3)
数据类型 | + | - | * | / |
整型和整型 | 整型 | 浮点型 | ||
整型和浮点型 | 浮点型 | |||
浮点型和浮点型 | 浮点型 |
(4)数字运算符
运算符 | 描述 |
x + y | x 与 y 的和 |
x - y | x 与 y 的差 |
x * y | x 与 y 的积 |
x / y | x 与 y 的的商 |
x // y | x 与 y 的整数商 |
x % y | x 与 y 的商的余数,也称模运算 |
-x | x 的负值 |
+x | x 本身 |
x**y | x 的 y 次幂 |
(1)+ - * / == !=
(2)//取整 %取余(模)
(3)遵循“先乘除取整取模,后加减”的运算顺序,取整取模和乘除是同一等级,都会优先参与运算。
(4)逻辑运算:and且 or或 not非
(5)运算结果按宽的输出,即使下移类型
(5)字符串运算
(1)整型和字符串相乘,整型*字符串,输出的结果,是将字符串重复几次拼接在一起。
#整型*字符串
print(5*"123")#123123123123123
print("hello"*5)#hellohellohellohellohello
(2)字符串+字符串,输出的结果,是这几个字符串的拼接。
print("123"+"123")#123123
19.列表类型
(1)由0个或多个数据组成的有序序列
列表用[]表示采用,分隔各元素
eg:['F','f']表示两个元素'F'和'f'
(2)使用保留字in判断一个元素是否在列表中
TempStr[-1] in ['C','c']判断前者是否于列表中的一个元素相同
(3)里面用单引号或者双引号都可以
20.赋值语句
(1)由赋值符号构成的一段代码
(2)
C = (eval(TempStr[0:-1] -32)/1.8#右侧变量结果赋值给变量C
(3)
TempStr = input("")#input("")返回一个字符串,TempStr也是字符串
(4)
name = "Downey"
name = "Tony"
print(name)
#Tony,当我们放入别的东西时,原来的会被丢掉
(5)赋值数字不加引号,赋值汉字、英文加引号
(6)== 表示 "等于",in 表示成员包含且一般用在列表['','']
21.分支语句
(1)由判断条件决定程序运行的方向
(2)
if TempStr [-1] in ['F','f']:#如果if后为Ture则执行:后的语句,否则跳过
(3)每个保留字所在的行存在一个:,这是语法的一部分
冒号及后续缩进用来表示后续语句于条件的所属关系
(4)在判断语句中,对非零值判断为真;对数字0的判断为假;对 None 的判断为假。
22.函数
(1)根据输入参数参数不同输出的功能过程
类似数学y=f(x)
print("格式输入有误")#打印输出"格式输入有误"
(2)函数采用<函数名>(<参数>)方法使用
eval(TempStr[0:-1])#TempStr[0:-1]是参数
(3)input
从控制台获得用户的输入
格式:<变量> = input("提示信息字符串") #用户输入的信息以字符串的形式保存在变量中
TempStr = input("请输入")#TempStr用来保存用户的输入
(4)print
以字符的形式向控制台输出结果的函数
格式:print("拟输出的字符串或字符串变量")#其中的引号不做输出
print("转换后的温度是{:.2f}C".format(C))
#{}称为槽,后续变量C填充到槽中{:.2f}表示将变量C填充到这个位置时取小数点后两位
name = "Downey"
print(f"My name is {name}")
print(f"{name} is a good boy")
print(f"{name} likes playing football")
#f表示格式化输出
#My name is Downey
#Downey is a good boy
#Downey likes playing football
注意:输出的为变量时不用加引号
name = "Downey"
print(name)
#Downey
name = "Downey"
print("name")
#Error
(5)eval评估函数
去掉参数最外层引号并执行余下语句的函数
eval()函数将字符串转换成数字,不能省略,比例input得到字符串,eval才得到数字类型
格式:eval(<字符或字符串变量>)
eval("1")#1
eval("1+2")#3
eval('"1+2"')#'1+2'
eval('print("Hello")')#Hello
23.转义字符
(1)加上\(反斜杠),改变字符原有的含义
(2)eg:
\\ | 反斜线字符 |
\' | 单引号字符 |
\" | 双引号字符 |
\a | 蜂鸣,响铃 |
\b | 回退,向后退一格 |
\r | 移动当前位置到本行开头 |
\n | 移动当前位置到下一行开头(换行) |
\t | 水平制表符(tab) |
\f | 换页 |
\v | 垂直制表 |
\0 | NULL,什么都不做 |
#续行符\,在程序以多行显示,输出为单行
#换行符\n,在程序以单行显示,输出为多行
#原来是多行,想写在一行,用分号隔开;s=[1,2,3,4,5,6,7,8,9];random.shuffle(s);print(s)
24.实例一:温度转换
#TempConvertV1.py
TempStr = input("请输入带有符号的温度值:")
if TempStr[-1] in ['F','f']:
C = (eval(TempStr[0:-1]) - 32)/1.8
print("转换后的温度是{:.2f}C".format(C))
elif TempStr[-1] in ['C','c']:
F = 1.8*eval(TempStr[0:-1]) + 32
print("转换后的温度{:.2f}F".format(F))
else:
print("输入格式错误")
#TempConvert2.py
def TempConverter(TempStr):
if TempStr[-1] in ["F","f"]:
C = (eval(TempStr[0:-1])-32)/1.8
return "转换后的温度是{:.2f}C".format(C)
elif TempStr[-1] in ['C','c']:
F = 1.8*eval(TempStr[0:-1]) + 32
return "转换后的温度是{:.2f}F".format(F)
else:
return "输入格式错误"
value = input("请输入带有符号的温度值:")
print(TempConverter(value))
第二周:Python基本图形绘制
1.import
引入代码之外的功能,即引入了一个绘图库,名字叫turtle海龟
2.Python计算生态
Python计算生态=标准库+第三方库
标准库:随解释器直接安装到操作系统的功能模块
第三方库:需要经安装才能使用的功能模块
库Library、包Package、模块Module统称模块
3.turtle库的使用
(1)窗体布局
setup()设置窗口大小及位置
eg:turtle.setup(width,heught,startx,starty)宽度、高度、起始点(窗口左上)x,y坐标。其中x,y可选,setup函数也可选
(2)turtle空间坐标体系
(1)绝对坐标
起始位置为画布中心,方向为右
import turtle
import.goto(100,100)
import.goto(100,-100)
import.goto(-100,100)
import.goto(-100,100)
import.go(0,0)
goto()只改变位置,不改变方向
(2)海龟坐标
以海龟自身为坐标点
turtle.fd(d)#正前方向
turtle.bk(d)#正后方向
turtle.circle(r,angle)#海龟左侧一点为圆心,曲线运行
(3)turtle角度坐标体系
(1)绝对角度
turtle.seth(45)#绝对角度,就是一个坐标系,海龟视为一个质点
(2)海龟角度
turtle.left(angle)#向左
turtle.right(angle)#向右
(4)RGB色彩体系
RGB的每色取值范围为0-255的整数,或0-1的小数
turtle库默认使用小数,但也可以切换
turtle.colormode(mode)
#小数值1.0模式
#整数值255模式
#把1.0或255换为mode,再接着写pencolor()
英文名称 | RGB整数值 | RGB小数值 | 中文名称 |
white | 255,255,255 | 1,1,1 | 白色 |
yellow | 255,255, 0 | 1,1,0 | 黄色 |
magenta | 255,0,255 | 1,0,1 | 洋红 |
cyan | 0,255,255 | 0,1,1 | 青色 |
blue | 0,0,255 | 0,0,1 | 蓝色 |
black | 0,0,0 | 0,0,0 | 黑色 |
seashell | 255,245,238 | 1,0.96,0.93 | 海贝色 |
gold | 255,215,0 | 1,0.84,0 | 金色 |
pink | 255, 192, 203 | 1,0.75,0.80 | 粉红色 |
rown | 165,42,42 | 0.65,0.16,0.16 | 棕色 |
purple | 160, 32, 240 | 0.63,0.13,0.94 | 紫色 |
tomato | 255,99,71 | 1, 0.39,0.28 | 番茄色 |
4.库引用和import
(1)库引用:扩充Python语言功能的方式,使用import保留字完成,import<库名>,采用<库名>.<函数名>(<函数参数>)
(2)import的更多引用:使用import和from保留字共同完成
from<库名>import<函数名>
from<库名>import*
<函数名>(<函数参数>)
(3)两种方式的比较
一:
import<库名>
<库名>.<函数名(<函数参数>)
这种方法不会出现函数名重名问题
#PythonDraw.py
import turtle
turtle.setup(650,350,200,200)
turtle.penup()
turtle.fd(-250)
turtle.pendown()
turtle.pensize(25)
turtle.pencolor("purple")
turtle.seth(-40)
for i in range(4):
turtle.circle(40,80)
turtle.circle(-40,80)
turtle.circle(40,80/2)
turtle.fd(40)
tuetle.circle(16,180)
turtle.fd(40*2/3)
turtle.done()
二:
from<库名>import<函数名>
from<库名>import*
<函数名>(<函数参数>)
这种方法不会出现函数名重名问题
#PythonDraw.py
from turtle import*
setup(650,350,200,200)
penup()
fd(-250)
pendown()
pensize(25)
pencolor("purple")
seth(-40)
for i in range(4):
circle(40,80)
circle(-40,80)
circle(40,80/2)
fd(40)
circle(16,180)
fd(40*2/3)
done()
(4)更好的方式
使用import和as保留字共同完成
import<库名>as<库别名>
<库别名>.<函数名>(<函数参数>)
即给外部关联的一个库使用一个更短,好认的名字
#PythonDraw.py
import turtle as t
t.setup(650,350,200,200)
t.penup()
t.fd(-250)
t.pendown()
t.pensize(25)
t.pencolor("purple")
t.seth(-40)
for i in range(4):
t.circle(40,80)
t.circle(-40,80)
t.circle(40,80/2)
t.fd(40)
t.circle(16,180)
t.fd(40*2/3)
t.done()
5.布尔表达式
只要运算结果是True或False,这样的运算式,都被统一称为布尔表达式
and运算:两边均为Ture结果才为Ture
or运算:只要当or左右两边的布尔数有一个为True时,运算结果就为True
not运算:对这个布尔数进行取反
当涉及多个条件时,在Python中常会将比较运算和逻辑运算混合使用。,在此时,Python会优先执行比较运算,再按从左到右的顺序执行逻辑运算,可用括号更改
6.turtle画笔控制函数
画笔操作后一直有效,一般成对出现
(1)turtle.penup() 别名turtle.pu()
抬起画笔,海龟飞行
(2)turtle.pendown() 别名turtle.pd()
落下画笔,海龟爬行
(3)turtle.pensize(widyh) 别名turtle.width(width)
画笔宽度,海龟的腰围
(4)turtle.pencolor(color) color为颜色字符串或RGB值
画笔颜色,海龟在涂装
turtle.pencolor("purple")
turtle.pencolor(0.63,0.13,0.94)
turtle.colormode(255)
turtle.pencolor(255, 0, 0)
7.运动控制函数
走直线&曲线
(1)turtle.forword(d) 别名turtle.fd(d)
向前行进,海龟走直线,d为行进距离,可以为负数
(2)turtle.circle(r,extent=None)
根据半径r绘制extent角度的弧形
r:默认圆心在海龟左侧r距离的位置,当值为负数时,在右侧
extent:绘制角度,默认360度是整圆
8.方向控制函数
控制海龟面对方向:绝对角度&海龟角度
不控制海龟运动
(1)绝对角度
turtle.setheading(angle) 别名turtle.seth(angle)
angle:改变海龟行进方向,角度
(2)海龟角度
turtle.left(angle) 海龟向左转
turtle.right(angle) 海龟向右转
angle:旋转方向的角度
9.其他函数
turtle.write()
#用于在绘图窗口写入文本
#以下是一些参数补充
turtle.write(arg, move=False, align="left", font=("Arial", 8, "normal"))
#arg要写入的内容
#move布尔值,决定写完文本后是否移动画笔,如果为 True,画笔会移动到文本的右下角;如果为 False,画笔位置不变
#align:文本的对齐方式,可以是 "left"、"center" 或 "right"
#font:一个三元组,指定字体名称、字号和字形(如 "normal正常"、"bold粗体"、"italic斜体" 等)
turtle.hideturtle()#隐藏海龟
turtle.speed()#控制海龟速度,数字越小越快
10.循环语句
(1)for<变量>in arnge(<参数>)
被循环执行的语句
<变量>表示循环的计数,0到<计数>-1
for i in arnge(5):
print("Hello:",i)
#Hello 0
#Hello 1
#Hello 2
#Hello 3
#Hello 4
#print用逗号分隔打印为空格
(2)range函数
产生循环计数序列
range(N) 产生0到N-1个整数序列,共N个
range(M,N) 产生M到N-1的整数序列,共N-M个
11.空值
空值,又叫 NULL 值,在 Python 中写作 None。None 是关键字。它代表这个数值不是整型,不是字符串,不是浮点型,表示没有值。注意,它和 0 不一样,因为 0 的值是 0,而空值的值是None。
12.实例二:蟒蛇绘制
#PythonDraw.py
import turtle#引用turtle库
turtle.setup(650,350,200,200)#建立一个窗口长、宽、相对左上点坐标
turtle.penup()#提起画笔
turtle.fd(-250)#直线倒退250像素
turtle.pendown()#放下画笔
turtle.pensize(25)#设置画笔大小
turtle.pencolor("purple")#设置画笔颜色
turtle.seth(-40)#绝对角度-40
for i in range(4):#循环4次以下语句
turtle.circle(40,80)#海龟左侧半径40,转80度
turtle.circle(-40,80)#海龟右侧半径40,转80度
turtle.circle(40,80/2)#海龟左侧半径40,并转半个40度
turtle.fd(40)#直线行驶40
turtle.circle(16,180)#海龟左侧半径16,转180度
turtle.fd(40*2/3)#直线行驶刚刚行驶40的2/3
turtle.done()#使程序运行完不关闭窗口
13.气人的作业
#WindWheel.py
import turtle as t
t.pensize(2)
for i in range(4):
t.seth(90*i)
t.fd(150)
t.right(90)
t.circle(-150, 45)
t.goto(0,0)
第三周:基本数据类型
1.整数类型 integer
(1)与数学中整数的概念一致,可正可负,没有整数限制
pow(x,y)函数:计算x的y次方,想算多大算多大,可以套用
(2)进制表示
十进制:正常数字
二进制:0b或0B开头
八进制:0o或0O开头
十六进制:0x或0O开头或h结尾
2.浮点类型 float
(1)与数学中的实数一致,带有小数点及小数的数字
(2)浮点数的取值范围和小数精度都存在限制,但常规计算可忽略
(3)浮点数间运算存在不确定尾数,不是bug
0.1+0.3#0.4
0.1+0.2#0.3000000000004,这就是不确定尾数,原因为计算机内部有关计算机小数的存储为二进制近似表示
0.1+0.2==0.3#False
round(0.1+0.2==0.3,1)#Ture
#准确的浮点数运算的标准库decimal
>>>from decimal import *
>>>Decimal('0.1')+Decimal('0.2')
Decimal('0.3')
#使用Decimal库,Decimal('数字')是基本表达形式,及这样表示依旧为数字
(4)浮点数间运算不确定尾数
round(x,d):对x四舍五入,d是小数截取位数
浮点数间运算及比较用round()函数辅助
>>>round(123.456789,3)
123.457
(5)浮点数的科学计数法
#使用e或E作为幂的符号,以10为基数,格式如下:
<a>e<b>(<a>E<b>)表示a乘上10的b次方
4.3e-3为0.0043 9.6E5(9.6E+5)为960000.0
#若小数或整数部分0,则可保留小数点并省略为0的部分
-77. .123 99.
(6)浮点数精度
>>>import sys
>>>sys.float_info
sys.float_info(max=1.7976931348623157e+308, max_exp=1024,
max_10_
exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_
exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16,
radix=2, rounds=1)
>>>sys.float_info.max
1.7976931348623157e+308
3.复数类型
复数在Python中以字符串'complex'表示其类型
与数学中复数的概念一致
定义j=√-1,等价为数学里的i,a+bj为复数,a为实部,b为虚部,a,b 均为浮点数类型
z=a+bj 实部:z.real 虚部:z.image
>>>type(1.23e-4+5.67e+89j)
<class'complex'>
>>>(1.23e-4+5.67e+89j).real
0.000123
>>>(1.23e-4+5.67e+89j).imag
5.67e+89
4. 真假无值
Ture 和 False 构成 bool 类型,严格讲,它们属于数值,Ture==1,False==0
None()表示无
>>>a = print("Hello World")
>>>a == None
True
#print函数运行后不返回任何内容
5. 整数序列
整数序列是数字类型的一种重要延伸,由 range()函数生产
#第一种,生成丛0开始的递增整数序列
#产生的整体为range类型,可通过遍历循环逐一获得序列整数,若b<0,则不产生
>>>for i in range(10):
print(i,end"")
0 1 2 3 4 5 6 7 8 9
#第二种,生成a到b-1的递增的整数序列
>>>for i in range(10,20):
print(i,end"")
10 11 12 13 14 15 16 17 18 19
#第三种,带有步长的
>>>for i in range(0,20,2):
print(i,end"")
0 2 4 6 8 10 12 14 16 18
#总结:生成数字个数为末-初,有则除以步长,步长可以看作每次加几
6.数值运算操作符
(1)二元数字运算符
+、-、*、/(结果为浮点数)、//(整除得整数部分)、%(取余)、**(幂运算)
(2)增强赋值运算符
功能为对两个数进行运算之后,去更改其中的一个数
x op=y
eg:x +=y、x -=y、x *=y、x /=y、x //=y、x %=y、x **=y
x **=3等价为x=x**3,s += count 等于 s 等于 s+count
(3)类型间进行混合运算时,生成结果为最宽类型
整数<浮点数<复数
eg:123+4.0=127.0
7.数值运算函数
函数及使用 | 描述 |
abs(x) | 绝对值,x的绝对值 abs(-10.01)结果为10.01 |
divmod(x,y) | 商余,(x//y,x%y),同时输出商和余数 divmod(10,3)结果为(3,1),属于元组类型,可通过赋值方式将结果同时传递给两个变量 |
pow(x,y[,z]) | 幂余,(x**y)%z,[..]表示参数z可省略 pow(3,pow(3,99),10000)结果为4587,为数字类型 |
round(x[,d]) | 四舍五入,d是保留小数位数,默认值为0 round(-10.123,2)结果为-10.12 |
max(x1,x2,x3,...,xn) | 最大值,返回x1,x2,x3,...,xn中的最大值,n不限 max(1,9,5,4,3)结果为9 |
mix(x1,x2,x3,...,xn) | 最小值,返回x1,x2,x3,...,xn中的最小值,n不限 min(1,9,5,4,3)结果为1 |
int(x) | 将x变成整数,舍弃小数部分 int(123.45)结果为123;int("123")结果为123 |
float(x) | 将x变为浮点数,增加小数部分 float(12)结果为12.0;float("1.23")结果为1.23 |
complex(re,[,im]) | 将x变为复数,增加虚数部分,re 为实数,im 为虚数 complex(4)结果为4+0j |
#abs()也可以计算复数的绝对值,输出为二维坐标系中复数位置到坐标原点的距离
>>>ans(-3+4j)
5.0
#divmod()输出商和余数属于元组类型,可通过赋值方式将结果同时传递给两个变量
#pow(x,y[,z])的速度快,如pow(3,pow(3999))%10000慢于pow(3,pow(3999),10000),因为后者是同时进行运算的
#模运算个好东西,n%m的结果映射到[0,m-1]的区间内
#round()的四舍五入按平等价值划分,即奇进偶不进,并非所有的Y.5都进位,看Y的奇偶得
#复数不能直接转换为其他数字类型,可通过.real和.imag将复数的实部和虚部分别转换
>>>float((10+99j).image)
99.0
8.实例三:天天向上的力量
#DayDayUpQ1.py
dayup =pow(1.001,365)
daydown =pow(0.999,365)
print("向上:{:.2f},向下:{:.2f}".format(dayup,daydown))
#向上:1.44,向下:0.69
dayfactor = 0.005
dayup = pow(1+dayfactor,365)
daydown = pow(1-dayfactor,365))
print("向上:{.2f},向下:{.2f}".format(dayup,daydown))
#当前能力为N时,进步则N*(1+0.01),反之N*(1-0.01)
dayup = 1.0
dayfactor = 0.01
for i in range(365):
if i % 7 in [6,0]:#牢记工作日于周末的遍历方法
dayup = dayup*(1-dayfactor)
else:
dayup = dayup*(1+dayfactor)
print("工作日的力量:{.2f}".format(dayup))
def dayup(df):#def定义一个函数,df是个占位符,用来表示dayfactor的缩写
dayup = 1
for i in range(365):
if i % 7 in [6,0]:
dayup = dayup*(1-0.01)
else:
dayup = dayup*(1+df)
return dayup
dayfactor = 0.01
while dayup(dayfactor) < 37.78:
dayfactor += 0.001
print("工作日的努力参数为:{:.3f}".foemat(dayfactor))
#工作日的努力参数为0.019
#根据df参数计算工作日力量的函数,参数不同,代码可共用,def保留字用于定义函数
#while保留字判断条件是否成立,条件成立时执行循环
9.字符串类型及操作
(1)字符串类型的表示(二类四种)
由一对单引号或双引号表示,仅表示单行字符串
eg:"请" '请'
由一对三单引号或三双引号表示,可表示多行字符串
'''Python
语言'''
注意:三单引号形成的是字符串,只是它的作用可以当成注释
如何把单、双引号当做字符?
'这里有个双引号(")'或者"这里有个单引号(')"
如果希望字符串中出现单引号和双引号的组合?
'''这里既有单引号(')又有(")双引号'''
10.time库
(1)time库是python中处理时间的标准库;计算机时间的表达;提供获取系统时间并格式化输出功能;提供系统级精确功能,用于程序性能分析
import time
time.<b>()
(2)包含的三类函数
时间获取:time()、ctime()、gmtime()
时间格式化:strftime()、strptime()
程序计时:sleep()、perf_counter()
函数 | 描述 |
time() | 获取当前时间戳,单位为 s,浮点数 >>>time.time() 1536727223.63191689#从 1970.1.1 开始至今 |
ctime() | 获取当前时间并以易读方式表示,返回字符串 >>>time.ctime 'Fri Jan 26 12:11:16 2018'(星期,月份,日,时,分,秒,年) |
gmtime() | 返回当前时间戳对应的 struct_time 类型时间,获取当前时间,表达为计算机可处理的时间格式 >>>time.gmtime time.struct_time(tm_year=2018,tm_mon=1, time_mday=26,tm_hour=4,tm_ser=16, tm_wday=4,tm_yday=26,tm_isdst=0) |
11.gmtime 和 localtime 区别
在Python中,localtime
和gmtime
是两个用于获取时间信息的函数,它们的主要区别在于处理时区的方式。
localtime
函数:
-
localtime
函数将一个时间戳转换为本地时间,返回的是一个包含本地时间信息的struct_time
对象。- 该函数考虑了当前系统的时区,因此返回的时间是根据本地时区调整后的。
- 如果不传入参数,
localtime
会使用当前时间作为转换标准。
gmtime
函数:
-
gmtime
函数将一个时间戳转换为UTC时间(世界标准时间),即不考虑时区的时间。- 该函数返回的时间是基于格林尼治标准时间(GMT)的,不进行任何时区调整。
- 如果不传入参数,
gmtime
也会使用当前时间作为转换标准。
localtime
返回的是本地时间,考虑了时区的影响;而gmtime
返回的是UTC时间,不考虑时区的影响。这两个函数在处理时间时需要根据具体需求选择使用,以确保时间信息的准确性。
(3)时间格式化
将时间以合理的方式展示出来
格式化:类似字符串格式化,需要有展示模版
展示模板需要由特定的格式化控制符组成
strftime(tpl,gt) | tpl是格式化模版字符串,用来定义输出效果 gt 是 struct_time 类型的时间,即 gmtime 所的 >>>t = time.gmtime() >>>time.strftime("%y-%m-%d %h:%m:%s,t") '2018-01-26 12:55:20' |
strptime() | 与 strftime 函数刚好相反,用于提取字符串 str 中时间要素,生成一个 strut_time 类型的时间值 |
>>>timeString = '2023-09-02 13:26:22'
>>>strptime(timeString,"%Y-%m-%d %H:%M:%s")
time.struct_time(tm_year=2024, tm_mon=9, tm_mday=29, tm_
hour=20, tm_min=27, tm_sec=49, tm_wday=6, tm_yday=273, tm_isdst=-1)
格式化字符串 | 日期/时间说明 | 值范围和实例 |
%Y | 年份 | 0000~9999,例如:2024 |
%m | 月份 | 01~12,01~12 例如:08 |
%B | 月份名称 | January~December,例如:April |
%b | 月份名称缩写 | Jan~Dec,例如:Apr |
%d | 日期 | 01~31,例如:25 |
%A | 星期几 | Monday~Sunday,例如:Wednesday |
%a | 星期缩写 | Mon~Sun,例如:Wed |
%H | 小时(24h制) | 00~23,例如:12 |
%I | 小时(12h制) | 01~12,例如:7 |
%p | 上/下午 | AM,PM,例如:PM |
%M | 分钟 | 00~59,例如:26 |
%S | 秒 | 00~59,例如:26 |
%x | 日期 | 月/日/年,09/29/2024 |
%X | 时间 | 时/分/秒,18/29/11 |
月份 | 全称 | 缩写 |
一月 | January | Jan |
二月 | February | Feb |
三月 | March | Mar |
四月 | April | Apr |
五月 | May | May |
六月 | June | Jun |
七月 | July | Jul |
八月 | August | Aug |
九月 | September | Sep |
十月 | October | Oct |
十一月 | November | Nov |
十二月 | December | Dec |
英文全称 | 缩写形式 |
Monday | Mon. |
Tuesday | Tue. |
Wednesday | Wed. |
Thursday | Thu. |
Friday | Fri. |
Saturday | Sat. |
Sunday | Sun. |
>>>t = time.gmtime()
>>>time.strftime("%Y-%m-%d %H:%M:%S",t)
'2018-01-26 12:55:20'
>>>timeStr = '2018-01-26 12:55:20'
>>>time.strtime(timeStr,"%Y-%m-%d %H:%M:%S")
(4)程序计时
程序计时时间广泛;程序计时指测量起止动作所经历时间的进程
测量时间:perf_counter()
产生时间:sleep()
函数 | 描述 |
perf_counter() | 返回英国CPU级别的精确时间计数值,单位为秒 由于这个计数值起点不确定,连续调用差值才有意义,并且差值是基于最开始调用之后,而非上一次 >>>start = time.perf_counter() 318.66599499718114 >>>end = time.perf_counter() 341.3905185375658 >>>end - start 22.724523540384666 |
sleep(s) | s拟休眠的时间,单位是秒,可以是浮点数 >>>def waite()#定义一个函数 waite time.sleep(3.3) >>>wait() #当调用 waith 函数时程序将等待3.3秒后再退出 |
12. 实例四.文本进度条
(1)单行动态刷新
刷新的本质:用后打印的字符覆盖原来的字符
不能换行:print()需要被控制
要能回退:打印后光标退回到之前的位置\r
#TextProBarv1.py
import time
for i in range(101):#0到100共101个数
print("\r{:3}%").format(i),end()="")#end()=""使原来print的换行变为停留在当前光标,\r为在打印字符串之前,将光标退回到行首
time.sleep(0.1)
(2)完整效果
#TextProBarV3.pу
import time
scale = 50
print("执行开始".center(scale//2,"-"))#利用字符串的填充处理功能
start = time.perf_counter()#确定一个开始时间
for i in range(scale+1):
a ='*'*i
b= '.' * (scale - i)
c= (i/scale)*100
dur = time.perf_counter() - start#程序到此的时间差
print("\r{:^3.0f}%[{}->{}{:.2f}s".format(c,a,b,dur),end='')#光标回到开头,并结束换行
time.sleep(0.1)
print("\n"+"执行结束".center(scale//2,'-'))
(3)课本高级版
#tqdmBar.py
from tqdm import tqdm
from time import sleep
for i in tqdm(range(1,100)):
sleep(0.01)
#100%|██████████| 99/99 [00:01<00:00, 88.26it/s]
13.作业
在一个周期内,连续学习 3 天能力值不变,从第 4 天起到休息前,能力每天比前一天增长 1%,若中断学习,周期从头计算,问当每 10 天或 15 天休息一天后,365 天后的能力值是多少?
dayup = 1#能力初始值
dayfactor = 0.01#进步百分数
period = [4,5,6,0]#当为周四五六日时
decrease = 0#
for j in range(1,366):#进行365次循环
temp = j - decrease
tom = temp % 7#得到当前按程序讲的星期,而非实际的
if j%10 == 0:#当连续学习10天时
decrease += j - (tom - 1)
tom = 1
if tom in period:#
dayup = dayup * (1 + dayfactor)
print('%f the result is %.2f'%(dayfactor,dayup))
ability = 1.0
T = 365//11
for j in range(T):
for i in range(1,12):
if i in [1,2,3]:
ability = ability
print(ability)
elif i in [4,5,6,7,8,9,10]:
ability = ability*1.01
print(ability)
else:
ability = ability
i = 1
print(ability)
第四周:程序的控制结构
顺序、循环、分支结构=控制结构
1.单分支结构
根据判断条件结果而选择不同向前路径的运行方式
if <条件>:
<语句块>
guess = eval(nput())
if guess == 99:
print("猜对了!")
if Ture:
print("条件正确")
确定列表不是空的
requested_toopings = []
if requested_toopings:
for requested_tooping in requested_toopings:
print("Add "+requested_tooping+".")
print("\nFinished making your pizza!")
else:
print("Are you sure you want a plain pizza?")
'''
if语句将在列表名用在条件表达式中时,Python将在列表至少包含一个元素时返回True,否则False
'''
2.二分支结构
根据判断条件结果而选择不同向前路径的运行方式
if<条件>:
<语块一>:
else:
<语块二>
紧凑形式:适用于简单表达式的二分支结构
<表达式1> if <条件> else <表达式2>
#条件满足时执行表达式一,否则执行表达式二;表达式一般基本数据类型及其简单运算
guess = eval(input())
print("猜{}了!".format("对" if guess==99 eval "错"))
#注意这里的条件判断放到了format方法里了
注意:表达式是语句的一部分,前者不正常等号的赋值形式
3.多分支结构
score = eval(input())
if score >= 60:
grade = "D"
elif score >= 70:
grade = "C"
elif score >= 80:
grade = "B"
elif score >= 90:
grade = "A"
print("输入的成绩级别为{}".format(grade))
#显然此程序出现问题,出在代码的先后关系及包含关系出现问题,需要注意
#注意多条件之间的包含关系
#注意变量取值范围的覆盖
#寻找第一个结果为True的条件,执行该条件下的语句块,结束后跳过整个if-elif-else结构,执行后面的语句
#如果没有任何条件成立,else下面的语句块将被执行
备注:
else 不是必须的,因为它包罗万象。仅仅使用 if-elif 即可,而且这样条件会更清晰。
测试多个条件时,也可以只使用 if 语句。
若使用 if-elif-else 但有一个条件满足这会跳出检查。
4.异常处理
Python 通过 try、except、else、finally 保留字提供程序异常处理功能
num eval(input("请输入一个整数:"))
print(num**2)
#假如输入abc则会显示错误,及abc没有被定义
Traceback#异常回溯标记 (most recent call last):
File "/Users/chuji/Desktop/个人/计算机/Python/课内/ts.py"#异常文件路径, line 1#异常代码行数, in <module>
num = eval(input())
^^^^^^^^^^^^^
File "<string>", line 1, in <module>
NameError#异常类型: name 'NO' is not defined#异常内容提示
异常带来程序非预期执行或退出,但异常与错误不同
try:
<语块1>
except:
<语块2>
#当try发生异常时,执行except
try:
<语块1>
except<异常类型>:
<语块2>
#当try出现异常且符合except的错误类型时,才会执行语块2
try:
num = eval(input("请输入一个整数:"))
print(num**2)
except:
print("输入的不是整数")
#其二
try:
num eval(input("请输入一个整数:"))
print(num**2)
except NameError:
print("输入的不是整数")
#标记异常类型后,仅响应该异常,异常类型名字等同于变量,是Python内部自定义的
try:
<语句块1>
except <异常类型A>:
<语句块A>
...
except <异常类型Z>:
<语句块Z>
except:
<语句块2>
#A到Z都指定了异常类型,则仅可满足类型的执行,最后的except语句没有指定任何类型,表示它对应的语句可以处理所有的其他异常
异常处理的高级使用
try:
<语块1>
except:
<语块2>
else:
<语块3>
finally:
<语块4>
#finally对应的语块4一定执行
#else对应的语块3在不发生异常时执行
#except还是当对应异常处理时执行
Python 的异常处理一般用来检测输入数据的合规性,并不在程序中大量出现
5. 异常类型
Python 对每个异常都进行了定义,称为异常类型
>>>25/0
Traceback (most recent call last):
File "/Users/chuji/Desktop/个人/计算机/Python/课内/ts.py", line 1, in <module>
25/0
~~^~
ZeroDivisionError: division by zero
#除数是0
>>>4+a
Traceback (most recent call last):
File "/Users/chuji/Desktop/个人/计算机/Python/课内/ts.py", line 1, in <module>
4+a
^
NameError: name 'a' is not defined
#变量a没有赋值
>>>4+'25'
Traceback (most recent call last):
File "/Users/chuji/Desktop/个人/计算机/Python/课内/ts.py", line 1, in <module>
4+'25'
~^~~~~
TypeError: unsupported operand type(s) for +: 'int' and 'str'
#整数与字符串的加法操作,但这种操作尚未被定义
6.实例五:身体质量指数 BMI
BMI:Body Mass Index
国际上常用的衡量人体肥胖和健康程度的重要标准,主要用于统计分析
定义;BMI = 体重 (Kg)/身高 2(m2)
世界卫生组织 WHO:World Health Organization
分类 | 国际BMI值(kg/m**2) | 国内BMI值(kg/m**2) |
偏瘦 | <18.5 | <18.5 |
正常 | 18.5~ 25 | 18.5~ 24 |
偏胖 | 25~30 | 24~28 |
肥胖 | > 30 | >28 |
#CalBMIv3.py
height,weight = eval(input("请输入身高(米)和体重(千克)[逗号隔开]:"))
bmi = weight/height**2
print("BMI的值为:{:.2f}".format(bmi))
who,nat = "",""
if bmi < 18.5:
who,nat = "偏瘦","偏瘦"
elif 18.5 <= bmi < 24:
who,nat = "正常","正常"
elif 24 <= bmi < 25:
who,nat = "正常","偏胖"
elif 25 <= bmi < 28:
who,nat = "偏胖","偏胖"
elif 28 <= bmi < 30:
who,nat = "偏胖","肥胖"
else:
who,nat = "肥胖","肥胖"
print("BMI的指标为:国际{0},国内{1}".format(who,nat))
注意:关注多分支条件的组合
多分支条件之间的覆盖是重要问题
程序可运行,但不正确,要注意多分支
分支结构是程序的重要框架,读程序先看分支
7.循环结构
python 通过 for,while 等保留字提供遍历循环和条件循环两种方式,循环可分为确定次数循环和非确定次数循环
8.遍历循环
Python 通过保留字 for 实现"遍历循环"
遍历某个结构形成的循环运行方式
for <循环变量> in <遍历结构>:
<语句块>
#只要后面的遍历结构有多个元素,即可依次产生遍历,遍历次数和元素个数有关
#由保留字 for 和 in 组成,完整遍历所有元素后结束
#每次循环,从遍历结构中逐一提取元素,所提取元素放在循环变量中,并执行一次语句块
#for循环中的遍历结构可以是字符串、文件、组合数据类型或range()函数等
(1)计数循环(N 次)
for i in range(N):
<语句块>
0 1 2 3 4
遍历由 range()函数产生数字序列(0--N-1),产生循环
for i in range(5):
print("Hello:",i)#注意这里的逗号不显示
for i in range(M,N,K):
<语句块>
#从M开始到N,以K为步长,遍历range()函数产生的序列,产生循环
for i in range(1,6,2):
print(i)#1 3 5
(2)字符串遍历循环
for c in s:
<语句块>
s是字符串,遍历字符串每个字符,产生循环
for c in "Python123":
print(c,end=",")
#P,y,t,h,o,n,1,2,3,
(3)列表遍历循环
for item in ls:
<语句块>
#ls是一个列表,遍历其每个元素,产生循环
for item in [123,"py",456]:
print(item,end',')
#123,py,456
(4)文件遍历循环
for line in fi:
<语句块>
#fi是一个文件标识符(文件句柄),遍历其每行,产生循环
(5)总结
for i in range(N):
<语句块>
#计数循环(N次)计数循环(特定次)字符串遍历循环 列表遍历循环 元组类型进行遍历循环 字典类型
9.条件循环
由条件控制的循环运行方式,不再是遍历某个结构,而是根据这个条件来进行循环
while <条件>:#条件与分支结构的判断条件一样,结果为True或False
<语句块>
#反复执行语句块,直到条件不满足时结束
a = 3
while a>0:
a=a-1
print(a)
#210
10.循环控制保留字
break:跳出并结束当前整个循环,执行循环后的语句,当多层循环嵌套时,它只跳出内层,外层循环依然有效
for c in "PYTHON":
if c == "T":
break
print(c,end="")
#PY
for s in "BIT":
for i in range(5):
print(s,end="")
if s == "T"
break
#BBBBBITTTTT
continue:结束当次循环,继续执行后续次数循环
for c in "PYTHON":
if c == "T":
continue
print(c,end="")
#PYHON
注意:一个当前,一个当次
区别:continue 语句只结束本次循环,而不终止整个循环的执行;back 语句则是结束整个循环过程,不再判断执行循环的条件是否成立
s = "PYTHON"
while s !="":
for c in s:
print(c,end="")
s = s[:-1]#切片操作,从开头到-1,但-1的位置不取,故相当于去掉最后一个字符
#PYTHONPYTHOPYTHPYTPYP
#解释:首先3,4行在唱双簧,直至字符串索引完,执行第5行,此是s变量少了一个字符,然后循环
s = "PYTHON"
while s !="":
for c in s:
if c == "T":
break
print(c,end="")
s = s[:-1]
#PYPYPYPYPYP
11.循环的扩展 else
因为循环可能被 break 提前终止,for 循环和 while 循环都有一个 else 扩展用法
当循环没有被 break 语句退出时,执行 else 语句块,即使 continue 了一下也没关系
else 语句块作为完成正常循环的一种"奖励"
这里的 else 用法与异常处理中的 else 相似
#扩展遍历循环
for <循环变量> in <遍历结构>:
<语句块1>
else:
<语句块2>
#扩展条件循环
while <条件>:
<语句块1>
else:
<语句块2>
for c in "PYTHON":
if c == "T":
continue
print(c,end="")
else:
print("正常退出")
#PYHON正常退出
for c in "PYTHON":
if c == "T":
break
print(c,end="")
else:
print("正常退出")
#PY
12.逻辑运算
Python 常用逻辑运算和比较运算作为分支或循环的判断条件
True 和 False 二元数值构成了基本的真假逻辑
Python 将所有非 0 值数字都等价为 True
运算符 | 描述 |
and | x and y,"与"操作 |
or | x or y,"或"操作 |
not | not x,"非"操作 |
"与"操作:当 x 和 y 都是 True 是,结果为 True,当 x 或 y 其一为 False 时,结果为 False;可以在数字及 True 或 False 之间进行逻辑运算;其中只有 0 值表示 False,其他值均等价于 True
"或"操作:当 x 和 y 都是 False 时,结果为 False,当 x 或 y 其一为 True 时,结果为 True;可以在数字及 True 或 False 之间进行逻辑运算
"非"操作:对 x 进行取反
备注:and和or均为二元操作,not 为一元操作;逻辑运算可使用小括号优先运算,否则按照自左到右运算
位层次上的逻辑运算:
x | y | x AND y | x | y | x OR y | x | NOT x | x | y | x XOR y | |||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | |||
0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | |||
1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | |||||
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
13.比较运算
比较运算适用于数字,字符串,列表等多种类型数据的比较,结果为 True 或 False
条件判断的操作符:
操作符 | 数学符号 | 描述 |
< | < | 小于 |
<= | ≤ | 小于等于 |
>= | ≥ | 大于等于 |
> | > | 大于 |
== | = | 等于 |
!= | ≠ | 不等于 |
备注:涉及复数类型的比较只能判断是否相等,不能比较大小,即只能使用==和!=,否则报错
3+4j == 3+4j
True
3+4j < 4+4j
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
3+4j < 4+4j
TypeError: '<' not supported between instances of 'complex' and 'complex'
#本质上是字符串对应Unicode编码的比较,两个字符串比较采用从左到右依次比较字符的方式
>>>"123"=="123"
True
>>>"123"=="321"
False
>>>"python"<="python123"
True
14.random 库
random 库是使用随机数的 Python 标准库,直接使用 import 调用
伪随机数:采用梅森旋转算法(Mersenne twister)生成的(伪)随机序列中的元素
random 库主要用于生产随机数
使用 random 库:import random
random 库包含两类函数,常用的共 8 个
基本随机数函数:seed(),random()
扩展随机数函数:randint(),getrandbits(),uniform(),randrange(),choice(),shuffle()
15.基本随机数函数
随机数种子唯一确定了随机序列的产生
函数 | 描述 |
seed(a=None) | 初始化给定的随机数种子,默认为当前系统时间 即当不调用 random.seed()时 >>>random.seed(10) #产生种子 10 对应的序列 |
random() | 生产 [0.0,1.0) 之间的随机小数 >>>random.random() 0.57578276782 |
import random
random.seed(10)
random.random()
0.5875327887
random.random()
0.8375376283
#种子只需使用一次,往后随机数即可一直调用
#使用随机数种子有可能再现随机数,但如果不调用,用的即是系统时间,精确到微秒,几乎不再现
import random
random.seed(10)
random.random()
0.5714025946899135
random.seed(10)
random.random()
0.5714025946899135
#后续只要调用random()函数的顺序只要相同,那么产生的随机数也是相同的
函数 | 描述 |
randint(a,b) | 生成一个 [a,b] 之间的整数 >>>random.randint(10,100) 64 |
uniform(a,b) | 生成一个 [a,b] 之间的随机小数 >>>random.uniform(10,100) 13.9876456876524634 #Python 浮点数的取值范围为小数点后 16 位 |
randrange(m,n[,k]) | 首先生成一个 [m,n)间以 k 为步长的随机整数序列,然后随机选择一个整数输出 >>>random.randrange(10,100,10) 80 |
getrandbits(k) | 生成一个 k 比特长的随机整数,为 10 进制 >>>random.getrandbits(16) 37885(有时不正确好像) |
choice(seq) | 从序列 seq 中随机选择一个元素,序列类型包括列表 、字典、字符串等 >>>random.choice([1,2,3,4,5,6,7,8,9]) 8 |
shuffle(seq) | 将序列 seq 中元素随机排列,返回打乱后的序列 >>>s=[1,2,3,4,5,6,7,8,9];random.shuffle(s);print(s) [3,2,4,6,8,9,7,1,5] #一般上述代码分行放置,如需一行,则分号分隔 |
sample(pop,k) | 从 pop 序列类型中随机选取 k 个元素,以列表类型返回,序列类型包括:列表、字符串、字典等 >>>sample("123456",3) ['1','2','4'] |
#randint和uniform括号里的a于b可以相等
#列表类型的新奇用法,question:从列表[...]中随机选取一个字符串
print([...][random(0,3)])
16:实例六:圆周率的计算
利用蒙特卡洛方法(random sampling)
圆周率的近似计算公式(BBP 公式)
#CalpiV1.py
pi = 0#定义pi的初始值
N =100#假设无穷大是100
for k in range(N):
pi += 1/pow(16,k)*(\
4/(8*k+1) - 2/(8*k+4) - \
1/(8*k+5) - 1/(8*k+6))
print("圆周率的值为:{}".format(pi))
#\代表换行,其意义与写在一行是一致的
#CalpiV2.py
from random import random#库名+函数名调用
from time import perf_counter#添加计时
DARTS = 1000*1000#在当前区域中抛撒点的总数量
hits = 0.0#目前在圆的内部点的数量
start = perf_counter()
for i in range(1,DARTS+1):
x,y = random(),random()#random随机生成0到1的小数值,而方形恰为单位方形
dist = pow(x**2 + y**2,0.5)
if dist <= 1.0:
hits = hits+1
pi = 4*(hits/DARTS)
print("圆周率的值为:{}".format(pi))
print("运行时间是{:.5f}:".format(perf_counter() - start))
注意:程序运行的时间大部分都在循环上,如果需要优化,可产生 perf_counter 测量是否是循环耗时
17.作业
(1)"水仙花数"是指一个三位整数,其各位数字的3次方和等于该数本身。
例如:ABC是一个"3位水仙花数",则:A的3次方+B的3次方+C的3次方 = ABC。
请按照从小到大的顺序输出所有的3位水仙花数,请用"逗号"分隔输出结果。
s = ""
for i in range(100,1000):
t = str(i)
if pow(eval(t[0]),3)+pow(eval(t[1]),3)+pow(eval(t[2]),3) == i:
s +="{},".format(i)
print(s[:-1])
(2)给用户三次输入用户名和密码的机会,要求如下:
1)如输入第一行输入用户名为‘Kate’,第二行输入密码为‘666666’,输出‘登录成功!’,退出程序;
2)当一共有3次输入用户名或密码不正确输出“3次用户名或者密码均有误!退出程序。”。
count = 0
while count < 3:
name = input()
password = input()
if name=='Kate' and password =='666666':
print("登录成功!")
break
else:
count += 1
if count == 3:
print("3次用户名或者密码均有误!退出程序。")
(3)100 以内素数之和
求100以内所有素数之和并输出。
素数指从大于1,且仅能被1和自己整除的整数。
提示:可以逐一判断100以内每个数是否为素数,然后求和。
#Prime
def is_prime(n):
for i in range(2,n):
if n%i == 0:
return False
return True
sum = 0
for i in range(2,100):
if is_prime(i):
sum += i
print(sum)
18.课内作业
num = 502
guess = 0.0
count = 0
while guess != num:
guess = eval(input("请输入你要猜的数字(0~1000):"))
count = count +1
if guess < num:
print("猜小了!")
elif guess > num:
print("猜大了!")
else:
print("猜对了!")
print("总共猜了{}次。".format(count))
#from random import *
chr = input("请输入一行字符:")
#ls = sample(chr,len(chr))
num,eng,kong,other = 0,0,0,0
for i in chr:
if i in "0,1,2,3,4,5,6,7,8,9":
num += 1
elif i in "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z":
eng += 1
elif i in [" "]:
kong += 1
else:
other += 1
print("数字:{}\n英文:{}\n空格:{}\n其他:{}".format(num,eng,kong,other))
#不过没有用到这节课的东西
a,b=eval(input("请输入两个整数并用逗号隔开:"))
max = max(a,b)
min = min(a,b)
n = 10
while n!=0:
n = max % min
max = min
min = n
print(max,end="")
from random import *
sum = randint(0,1001)
guess = -1
while guess != sum:
guess = eval(input("请输入你猜测的数字(0~1000):"))
if guess < sum:
print("猜小了!")
elif guess > sum:
print("猜大了!")
else:
print("猜对了!")
from random import *
sum = randint(0,1001)
guess = -1
while guess != sum:
try:
guess = eval(input("请输入你猜测的数字(0~1000):"))
if guess < sum:
print("猜小了!")
elif guess > sum:
print("猜大了!")
else:
print("猜对了!")
except:
print("输入内容必须为整数!")
year = eval(input("请输入年份以判断是否为闰年:"))
if year%400 == 0:
print("是闰年。")
else:
print("不是闰年。")
while True:#这是一个无限循环
try:
# 提示用户输入一个整数
user_input = input("请输入一个全数字的十进制整数: ")
# 尝试将输入转换为整数
number = int(user_input)
# 如果转换成功,跳出循环
break
except ValueError:#值错误
# 如果转换失败,提示用户重新输入
print("输入无效,请输入一个全数字的十进制整数。")
# 输出用户输入的整数user_input
print(f"您输入的整数是: {number}")
#如果eval了,对于象12a这种输入,会出现SyntaxError语法错误
while True:
try:
num = float(input("请输入一个带有小数点的浮点数(不使用科学计数法):"))
if num.is_integer():#integer是整形
print("您输入的是一个整数。请重新输入一个带有小数点的浮点数。")
else:
print("您输入的小数是:", num)
break
except ValueError:
print("输入无效。请确保您输入的是一个小数,不使用科学计数法。")
在这个程序中,我们使用了一个无限循环(while True:
),直到用户输入了符合要求的浮点数才退出循环。使用try
和except
语句来捕获用户输入可能引发的ValueError
异常。如果用户输入不能转换为浮点数(例如输入了字符串或其他非数字字符),程序将捕获异常并提示用户重新输入。
在try
块中,我们首先尝试将用户输入转换为浮点数(num = float(input(...))
)。如果转换成功,我们检查这个浮点数是否为整数(num.is_integer()
)。如果用户输入的是一个整数,我们提示用户重新输入。如果用户输入的是一个带有小数点的浮点数,且不是整数,程序将打印出用户输入的小数,并退出循环。
请注意,这个程序没有限制用户输入小数的范围,也没有处理可能的其他异常情况,如输入无穷大或NaN(非数字)。根据实际需求,可能需要对程序进行进一步的修改和优化。
while True:
try:
user_input = input("请输入带有小数点的浮点数:")
if int(eval(user_input)) == eval(user_input):
print("你的输入为整数,请重新输入!")
else:
print("您输入的小数为:{}".format(float(user_input)))
break
except:#因为可能出现NameError、ValueError、SyntaxError
print("格式不正确,请重新输入!")
19.列表解析
squares = []
for value in range(1,11):
squares.append(value**2)
print(squares)
square = [value**2 for value in range(1,11)]
print(square)
20.使用 while 循环来处理列表和字典
#首先,创建一个待验证的用户列表
#和一个用于存储已验证用户的空列表
unconfirmed_users = ['alice','brian','candace']
confirmed_users = []
#验证每个用户,知道没有未验证用户为止
#将每个经过验证的列表都移到已验证的列表中
while unconfirmed_users:#但凡此列表不为空,便会一直循环
current_user = unconfirmed_users.pop()#弹出原列表的最后一个元素
print("Verifying user: "+current_user.title())
confirmed_users.append(current_user)
#显示所有已验证的用户
print("\nThe following users have been confirmed:")
for confirmed_user in confirmed_users:
print(confirmed_user.title())
'''
Verifying user: Candace
Verifying user: Brian
Verifying user: Alice
The following users have been confirmed:
Candace
Brian
Alice
'''
responses = {}
#设置一个标志,指出调查是否继续
polling_active = True
while polling_active:
#提示输出被调查者的姓名及回答
name = input("What's your name?")
response = input("Which mountain would you like to climb someday?")
#将答卷存储在字典中
responses[name] = response
#看看是否还有人要继续参与竞答
repeat = input("Would you like to let another person responday?(yes/no)")
if repeat == "no":
polling_active = False
#调查结束,打印结果
print("\n---Poll Resulte---")
for name,response in responses.items():
print(name + "would like to climb" + response + ".")
'''
---Poll Resulte---
张文博would like to climb珠穆朗玛峰.
'''
21.函数与while循环
def get_formatted_name(first_name,last_name):
"""返回整洁的姓名"""
full_name = first_name + " " + last_name
return full_name.title()
while True:
print("\nPlease tell me your name:")
print("(enter 'q' at any time to quit)")
f_name = input("First_name:")
if f_name == 'q':
break
l_name = input("Last_name:")
if f_name == 'q':
break
formatted_name = get_formatted_name(f_name,l_name)
print("\nHello"+formatted_name+"!")
第五周:函数和代码复用
1. 函数的理解和调用
函数是一段代码的表示,是一段具有特定功能的,可重用的语句组,一种功能的抽象,一般函数表达特定功能,由保留字 def 和 return 定义
python 解释器自带一些函数,称为 python 的标准函数,如:abs(),pow(),len()
作用:降低编程难度和代码复用
def <函数名>(<参数列表>):#参数列表也称形参,相当一个占位符,代指输入的数据,当函数被调用时,实际传递给函数内部的值,称为实参
<函数体>#这是函数执行的代码
return<返回值列表>#需要返回值列表时写入,没有可以省略
#函数名符合python命名规则
#参数列表是调用函数时输入的值,可以有零个或多个,当传递多个参数时用逗号隔开,没有参数时也要保留圆括号
#执行return语句或函数体结束后,程序的控制权返回到调用函数的位置
def f():
pass
#pass仅占位,不表任何操作
def isprime(n):
if n < 2:
return False
for i in range(2,n//2 +1):
if n % i == 0:
return False
return True
#前7行不直接执行,解释器会记录isprime()的位置,为后续调用作准备
#当一个函数被调用时,此时执行的程序会暂停执行
count = 0
for i in range(1,10000):
if isprime(i):
count += 1
print(count)
#神奇的是在line4,自[n//2+1,n)都不会被整除,故将n//2+1换成n也行,只不过遍历的时间更长
def fact(n):
s = 1
for i in range(1,n+1):
s *= i
return s
#调用 a = fact(10)\print(a)
y=f(x)
函数定义时,所指的参数是一种占位符,如果不经过调用,不会被执行,参数是输入,函数体是处理,结果是输出(IPO)
2. 函数参数的传递
函数可以有参数,也可以没有,但必须保留括号
当给形参指定默认值时,等号两边不要有空格
#函数定义时可以为对某些参数指定默认值,构成可选参数
#如果参数定义了默认值,当函数被调用时,若没有传入对应的参数值,则使用默认值
def <函数名> (<非可选参数>,<可选参数>):
<函数体>
return(返回值)
>>>def dup(str,times=2):#str为非可选参数,times为可选参数
print(str*times)
>>>dup("knnock~")
knock~knock~
>>>dup("knock~",4)
knock~knock~knock~knock~
#可选参数必须在非可选参数之后
def get_formatted_name(first_name,last_name,middle_name=""):
"""返回整洁的姓名"""
if middle_name:#当middle_name不为空时解读为True
full_name = first_name + " " + middle_name + " " + last_name
else:
full_name = first_name + " " + last_name
return full_name.title()
musician = get_formatted_name('jimi','hendrix')
print(musician)
musician = get_formatted_name('join','hooker','lee')
print(musician)
def fact(n,m=1):
s = 1
for i in range(1,n+1):
s *= i
return s//m
#m给值即值,否则视为1
'''
Python将实参封装到一个元组中
'''
def make_pizza(*toppings):
"""打印顾客点的所有配料"""
print(toppings)
make_pizza('peppoeroni')
make_pizza('mushroom','green peppers','extra cheese')
'''
('peppoeroni',)
('mushroom', 'green peppers', 'extra cheese')
'''
#函数定义时可以设计可变数量参数,即不确定参数总数量
def <函数名>(<参数>,*b):
<函数体>
return<返回值>
def make_pizza(size,*toppings):
"""打印顾客点的需求"""
print("\nMake a "+str(size)+
"-inch pizza with the following toppings:")
for topping in toppings:
print("-"+topping)
make_pizza(16,'peppoeroni')
make_pizza(12,'mushroom','green peppers','extra cheese')
'''
Make a 16-inch pizza with the following toppings:
-peppoeroni
Make a 12-inch pizza with the following toppings:
-mushroom
-green peppers
-extra cheese
'''
def build_profile(first,last,**user_info):#**两个星号指让python创建一个字典
"""创建一个字典,其中包含我们知道的有关用户的一切"""
profile = {}
profile['first_name'] = first
profile['last_name'] = last
for key,value in user_info.items():
profile[key] = value
return profile
user_profile = build_profile('albert','einstein',
laocation='princeton',field='physics')
print(user_profile)
def fact(n,*b):
s = 1
for i in range(1,n+1):
s *= i
for item in b:
s *= item
return s
>>>fact(10,3)
10886400#先算出10的阶乘,再乘3
>>>fact(10,3,5,8)#这里的可变参数被当作元组类型
435456000#先算出10的阶乘,再乘3乘5乘8
#对标准函数max(x1,x2,x3...)这种不确定参数数量的,可利用可变参数的函数
函数调用时,参数可以按照位置或名称方式传递
>>>func(x1,y1,z1,x2,y2,z2)
return(x1*x2 + y1*y2 + z1*z2)
result = func(1,2,3,4,5,6)
#<函数名>(<参数名> = <实际值>)
>>>result = func(x1=1,x2=2,y1=2,y2=5,z1=3,z2=6)
3. 函数的返回值
return 语句可将函数处理的结果返回到调用函数的代码行
函数可以返回 0 或多个结果
return 保留字用来退出函数执行并传递返回值
函数可以有返回值,也可以没有,可以有 return,也可以没有
return 可以传递 0 个返回值,也可以传递任意多个返回值,此时多个值以元组类型返回
>>>def func(a,b):
return a*b
>>>s = func("knock~",2)
>>>print(s)
knock~knock~
>>>def func(a,b)
return b,a
>>>s = func("konck",2)
>>>print(s,type(s))
(2,'konck')<class'tuple'>
def fact(n,m=1):
s = 1
for i in range(1,n+1):
s *= i
return s//m,s,m
>>>fact(10,5)
(725760,3628800,5)#元组类型
>>>a,b,c = fact(10,5)
print(a,b,c)
725760 3628800 5
def build_person(first_name,last_name,age=""):
"""返回一个字典"""
person = {'first':first_name,'last':last_name}
if age:
person['age']=age
return person
musician = build_person('jimi','hendrix',age=18)
print(musician)
'''
总结:一般对于可选参数,都是用等于空字符串代替
'''
4. 局部变量和全局变量
n,s = 10,100#n和s是全局变量
def fact(n):
s = 1#fact中的n和s是局部变量,函数参数也是局部变量
for i in range(1,n+1):
s *= i
return s
print(fact(n),s)#n和s是全局变量
>>>3628800 100
规则 1:局部变量和全局变量是不同变量
局部变量是函数内部的占位符,与全局变量可能重名但不同
函数运算结束后,局部变量被释放
可以使用 global 保留字在函数内部对全局变量赋值或重新创建
n = 2#n在函数外部,可认为是全局变量
def func(a,b):
global n
n = a*b
return a*b
print(func("knock~",2))
knock~knock~
print(n)
knock~knock~
n = 2
def fucn(a,b):
return a*b*n
print(fucn("knock~",2))
knock~knock~knock~knock~
规则 2:局部变量为组合数据类型且未创建,等同于全局变量
ls = ["F","f"]#通过使用[]真实创建了一个全局变量列表ls
def func(a):
ls.append(a)#此时ls是列表类型,未真实创建则等同于全局变量
return
func("C")#全局变量ls被修改
print(ls)
>>>['F''f''C']
#原因是组合数据类型有创建和引用的区别,只有使用赋值或list创建才有真实,否则为之前创建的一次引用
#函数内不存在变量ls的创建过程,此时func()函数专属的内存空间中没有已经创建过且名称为ls的列表,
#因此,fucn()函数进一步去寻找全局内存空间,自动关联外部列表变量ls,并修改对应值
ls = ["F""f"]
def func(a):
ls = []
ls.append(a)
return
func("C")
print(ls)
>>>['F''f']
总结:
- 函数内变量无论是否与全局变量重名,若在函数内部创建,函数退出后变量被释放,如与全局变量重名,全局变量的值不变
- 全局变量可以不用 globle 声明,直接在函数内部使用
- 当需要在函数内部对全局变量赋值或重新创建时,使用保留字 global 在函数内部声明全局变量
- 对于组合数据类型,如列表类型,当组合数据类型采用引用方式使用,不采用 global 声明时,函数内可以通过方法或操作函数等方式改变全局变量
扩展(指针和引用):
- 指针是保存内存地址的变量
- 引用是某一变量的别名,用这个名字可以对变量进行操作
- 区别:指针直接指向内存地址,说明对象已经生成,而引用只是别名,需要真实创建对象才能操作对象
5.lambda(匿名)函数
lambda 函数返回函数名作为结果
使用 lambda 保留字定义,函数名是返回结果
lambda 函数用于定义简单、能够在一行内表示的函数
<函数名> = lambda<参数>:<表达式>#紧凑形式
#普通形式
def <函数名>(<参数列表>):
<函数体>
return<返回值>
>>>f = lambda x,y:x+y
>>>f(10,15)
25
>>>f = lambda : "lambda函数"
>>>print(f())
lambda函数
谨慎使用 lambda 函数
lambda 函数主要用于一些特定函数或方法的参数
lambda 函数有一些固定使用方式,建议逐步掌握
一般情况,建议使用 def 定义普通函数
6.map()函数
#map(f,iters)它用于将函数功能f逐一作用于组合类型参数iters的各元素
>>>"".join(map(lambda i:i*2,"123"))
'112233'
>>>list(map(lambda i:i*2,[1,2,3,4,5]))
[2,4,6,8,10]
#map函数的第一个参数为函数名,一般由lambda()函数表达
7. 实例七:七段代码管绘制
__A__
| |
F B
|__G__ |
| |
E C
|__D__ |
#绘制顺序:GCDEFAB
import turtle
def drawLine(draw):#绘制单段数码管
turtle.pendown() if draw else turtle.penup()
turtle.fd(40)
turtle.right(90)
def drawDigit(digit):#根据数字绘制七段数码管
drawLine(True) if digit in [2,3,4,5,6,8,9] else drawLine(False)
drawLine(True) if digit in [0,1,3,4,5,6,7,8,9] else drawLine(False)
drawLine(True) if digit in [0,2,3,5,6,8,9] else drawLine(False)
drawLine(True) if digit in [0,2,6,8] else drawLine(False)
turtle.left(90)
drawLine(True) if digit in [0,4,5,6,8,9] else drawLine(False)
drawLine(True) if digit in [0,2,3,5,6,7,8,9] else drawLine(False)
drawLine(True) if digit in [0,1,2,3,4,7,8,9] else drawLine(False)
turtle.left(180)
turtle.penup()#为绘制后续数字确定位置
turtle.fd(20)#为绘制后续数字确定位置
def drawDate(date):#获得输出的数字
for i in date:
drawDigit(eval(i)) #通过eval函数将数字变为整数
def main():
turtle.setup(800,350,200,200)
turtle.penup()
turtle.fd(-300)
turtle.pensize(5)
drawDate('2024917')
turtle.hideturtle
turtle.done()
main()
import turtle,time
def drawGap():
turtle.penup()
turtle.fd(5)
def drawLine(draw):#绘制单段数码管
drawGap()
turtle.pendown() if draw else turtle.penup()
turtle.fd(40)
drawGap()
turtle.right(90)
def drawDigit(digit):#根据数字绘制七段数码管
drawLine(True) if digit in [2,3,4,5,6,8,9] else drawLine(False)
drawLine(True) if digit in [0,1,3,4,5,6,7,8,9] else drawLine(False)
drawLine(True) if digit in [0,2,3,5,6,8,9] else drawLine(False)
drawLine(True) if digit in [0,2,6,8] else drawLine(False)
turtle.left(90)
drawLine(True) if digit in [0,4,5,6,8,9] else drawLine(False)
drawLine(True) if digit in [0,2,3,5,6,7,8,9] else drawLine(False)
drawLine(True) if digit in [0,1,2,3,4,7,8,9] else drawLine(False)
turtle.left(180)
turtle.penup()#为绘制后续数字确定位置
turtle.fd(20)#为绘制后续数字确定位置
def drawDate(date):#获得输出的数字
turtle.pencolor("red")
for i in date:
if i =='-':
turtle.write("年",font=("Arial",18,"normal"))
turtle.pencolor("green")
turtle.fd(40)
elif i == '=':
turtle.write("月",font=("Arial",18,"normal"))
elif i == '+':
turtle.write("日", font=("Arial", 18, "normal"))
else:
drawDigit(eval(i))
def main():
turtle.setup(800,350,200,200)
turtle.penup()
turtle.fd(-300)
turtle.pensize(5)
drawDate(time.strftime("%Y-%m=%d+",time.gmtime()))
drawDate('2024917')
turtle.hideturtle
turtle.done()
main()
无论每段数码管是否被绘制出来,画笔都会走过每一段,根据紧凑形式判段数字是否符合绘制
扩展:
计算机硬件时钟,断电时间的准确性问题,主板上有纽扣电池,有必要时操作系统会从硬件时钟中读出时间放入内核给应用软件使用
7. 抽象和代码复用
抽象是一种代码定义,用来赋予代码含义,主要包括函数和对象两种方式
分别对应面向过程(过程式)和面向对象(对象式)编程思想
代码复用:把代码当成资源进行复用
代码资源化:程序代码是一种用来表达计算的" 资源"
代码抽象化:使用函数等方法对代码赋予更高级别的定义
代码复用:同一份代码在需要时可以被重复使用
函数和对象是代码复用的两种主要形式
函数:将代码命名;在代码层面建立了初步抽象
对象:属性和方法;<a>.<b>和<a>.<b>()在函数之上再次组织进行抽象
8. 模块化设计:分而治之
通过函数或对象封装将程序划分为模块及模块之间的表达;具体包括主程序,子程序和子程序之间的关系;分而治之是一种分层抽象、体系化的设计思想;七段数码管绘制就是最好的体现
#DrawSevenSegDisplay.py
import turtle as t
import time
def drawGap():#绘制数码管间隔
t.penup()
t.fd(6)
def drawLine(draw):#绘制单段数码管
drawGap()#这样产生数码管的效果(空格),否则仅仅为完整的线
t.pendown() if draw else t.penup()#紧凑形式<表达式1> if <条件> else <表达式2>
t.fd(40)
drawGap()#这样数码管两边都会有空隙,不会很突兀
t.right(90)
def drawDight(d):#根据数字绘制单段的数码管
drawLine(True) if d in [2,3,4,5,6,8,9] else drawLine(False)
drawLine(True) if d in [0,1,3,4,5,6,7,8,9] else drawLine(False)
drawLine(True) if d in [0,2,3,5,6,8,9] else drawLine(False)
drawLine(True) if d in [0,2,6,8] else drawLine(False)
t.left(90)
drawLine(True) if d in [0,4,5,6,8,9] else drawLine(False)
drawLine(True) if d in [0,2,3,5,6,7,8,9] else drawLine(False)
drawLine(True) if d in [0,1,2,3,4,7,8,9] else drawLine(False)
t.left(180)
t.penup()
t.fd(20)
def drawDate(date):#遍历日期字符串
t.pencolor("red")
for i in date:
if i == "-":
t.write("年",font=("Arial",18,"normal"))
t.pencolor("blue")
t.fd(40)
elif i == "=":
t.write("月",font=("Arial",18,"normal"))
t.pencolor("green")
t.fd(40)
elif i == "+":
t.write("日",font=("Arial",18,"normal"))
pass#啥也不干
else:
drawDight(eval(i))#记得去引号,将字符串变数字
def main():
t.setup(800,350,200,200)
t.penup()
t.fd(-300)
t.pensize(5)
drawDate(time.strftime("%Y-%m=%d+",time.gmtime()))#gmtime()返回当前时间戳对应的 struct_time 类型,\
# strftime时间式化模版字符串,用来定义输出效果
t.hideturtle()#隐藏海龟图标,虽然放在这里没啥用
main()
t.done()
'''
采用函数封装后,理解程序的第一层不再是直接阅读一行行语句,而是通过函数阅读程序框架
理解函数所表达的功能及调用关系,当需要了解具体函数内部实现时,再进一步理解函数内部语句
'''
模块化设计以功能块为基本单位,一般有以下俩个基本要求:
紧耦合:两个部分之间交流很多,无法独立存在,尽可能合理划分功能块,功能块内部耦合紧密
松耦合:两个部分之间交流和少,可以独立存在,模块间关系尽可能简单,功能块之间耦合度低
模块内部紧耦合,模块之间松耦合
9. 函数递归
函数定义中调用函数自身的方式,例如 n!
n! = n(n-1)(n-2)....1 <=> n(n-1)!
函数在定义中调用自身的方式称为递归调用,简称递归。包含递归调用的函数称为递归函数。
两个关键特性:
递归链条:递归链条在函数中表达递归调用关系,所有递归链条均以一个或多个基例结尾
递归基例:是不需要再次递归的确定值或确定表达式。可能存在一个或多个基例,例如 0!= 1
递归的实现:函数+分支语句
if <基例条件>:
<返回:基例值>
else:
<构造:递归链>
#参考下面
- 1基例值 n=0基例条件
n!|
- n(n-1)!递归链 其他
递归本身是一个函数,需要函数定义方式描述
函数内部,采用分支语句对输入参数进行判断
基例和链条,分别编写对应代码
def fact(n):
if n == 0:
return 1
else:
return n*fact(n-1)
n = eval(input("请输入数字"))
print(fact(n))
递归不提高程序执行效率,每次函数调用时,函数参数独立存储,递归中各次函数相互没有影响
任何递归程序都可以通过堆栈或队列变成非递归程序(这是程序的高级应用)
10. 函数递归实例解析
将字符串 s 反转后输出
>>>s[::-1]
def rvs(s):#得到递归变量为字符串s及其长度n
if s =="":#完成递归基例的设置
return s#一般来说,能够直接获得结果的情况都可以作为递归基例,所有递归基例不止一个
else:
return rvs(s[1:])+s[0]#这里又调用了rvs函数,实现了函数的递归
str = input("请输入一个字符串:")
print(rvs(str))
#故根据line3注释,认为当只有最后一个字符时,其反转也为自身,相当于一个基例
def reverse():
if len(s) <= 1:
return s
else:
return reverse(reverse(1:) + s[0])
str = input("请输入一个字符串:")
print(reverse(str))
#定义F(0)=1,F(1)=1,F(n)=F(n-2)+F(n-1),n>=2
#第一章的代码
a,b = 1,1
while a < 1000:
print(a,end="")
a,b = b,a+b
#F(n)=F(n-1)+F(n-2)
def F(n):
if n < 2:
return 1
else:
return F(n-1) + F(n-2)
n = eval(input("请输入数字:"))
for i in range(n):
print(F(i),end=" ")
count = 0
def hanoi(n,src,dst,mid):#src源柱,dst目标柱,mid过渡柱
global count#声明全局变量,才能使用,函数里面的只有括号里定义的以及函数内产生的变量
if n==1:#当只有一个圆盘时
print("{}:{}->{}".format(1,src,dst))#圆盘尺寸:从源柱搬到目标柱
count += 1
else:#即盘数>=2时
hanoi(n-1,scr,mid,dst)#再次调用汉诺塔,以除最下面圆盘外的为目标,此时相当于重置汉诺塔问题,要求为从源柱向过渡柱搬运,目标柱反而为"过渡柱"
print("{}:{}->{}".format(n.src,dst))#n为圆盘尺寸,相当于特指那个盘,n越大圆盘尺寸越大
count += 1
hanoi(n-1,mid,dst,src)#当进行完n-1数量的圆盘搬运后,再以中间柱为源柱向目标柱搬运,源柱相当于过渡柱
hanoi(3,"A","C","B")
print("总步数为:",count)
'''
请输入圆盘总数:3
1:A->C
2:A->B
1:C->B
3:A->C
1:B->A
2:B->C
1:A->C
总步数为: 7
'''
11.Python标准函数
3.13.0 Documentation Python文档
Python 提供 71 个标准函数,这些函数可以直接调用
A | B | C | D | E |
abs() *aiter() all() *anext() any() ascii() | bin() bool() *breakpoint() *bytearray() bytes() | *callable() chr() *classmethod() *compile() complex() | *delattr() dict() *dir() divmod() | enumerate() eval() exec() |
F | H | L | M | N |
filter() float() format() *frozenset() | *hasattr() hash() *help() hex() | len() list() *locals() | map() max() *memoryview() min() | *next() |
O | P | R | S | T |
object() oct() open() ord() | pow() print() *property() | range() repr() reversed() round() | set() *setattr() *slice() sorted() *staticmethod() str() sum() super() | tuple() type() |
V | Z | _ | ||
*vars() | zip() | *__import()__ |
12.PyInstaller 库
概述:
Pyinstaller 库是一个将 Python 源文件打包成可执行文件的第三方库,可用于多种操作系统,好处是不用配置环境
pip install pyinstaller#安装
pip install --upgrade pyinstaller#更新
PyInstaller Manual — PyInstaller 6.11.0 documentation 此库地址
pyinstaller -F <文件名.py>
#实际上不需要在终端输入<>
之后的目录下会多出三个文件:_pycache_;build;dist 前两个可以放心删除,在 dist 中,可以看到与原文件名相同的 exe 文件,这个便是我们打包的文件
build 目录是 pyinstaller 储存临时文件的目录,可以删除。最终打包程序在 dist 内部的 xx 中。目录中的其他文件是 xx 执行所需的动态链接库。
扩展:动态链接使程序在运行时调用不属于其程序的代码,进而程序会十分简洁,Windows 提供大量动态链接库,一般以 dll 或 ocx 为扩展名
注意:文件路径不能出现空格和英文句号;源文件必须为 UTF-8 编码
程序打包:
参数 | 描述 |
-F,--onefile | 在 dist 文件夹中只生成独立的打包文件,不依赖库文件 |
-D DIR--onedir | 默认值,生成 dist 目录 --distpath |
-i<.ico or .icns> | 指定打包程序使用的图标(icon)文件 |
-h,--help | 查看帮助 |
--clean | 清理打包过程中的临时文件 |
-v,--version | 查看 pyinstaller 版本 |
对于我能用的
-F#打包文件
--distpath#默认目录
--icon icon.icns#icon指图标,icon后面的表示自己的icns文件名
对我的注意:不知道为什么,-D 在我这里总是错误,换成--distpath 就行了
在线生成 ico 文件:https://www.bitbug.net/
不过苹果是 icns 文件
#不知道为什么我的设置不行,以下是我的解决方案
pyinstaller --onefile --windowed --icon icon.icns --name testApp main.py
--onefile参数表示生成一个单独的可执行文件,
--windowed参数表示生成一个无控制台窗口的应用程序(对于GUI应用程序很有用),
--icon参数后面紧跟图标文件的名称(如果图标文件与脚本在同一目录下),
--name参数用于指定生成的应用程序的名称。testApp 为更改后的文件名,main.py为要更改的文件
13. 实例八:科赫雪花小包裹
分形几何:一种迭代的几何图形,广泛存在于自然界中
#DrawKoch.py
import turtle as t
def koch(size,n):
if n==0:
t.fd(size)
else:
for angle in [0,60,-120,60]:
t.left(angle)
koch(size/3,n-1)
def main():
rank = 3#阶数
t.setup(800,400)
t.speed(-20)#控制画笔速度,0最快,1-10数字大速度快
t.penup()
t.goto(-300,-50)
t.pendown()
t.pensize(2)
koch(600,rank)#绘制曲线
t.hideturtle()#隐藏海龟
main()
t.done()
#DrawKochV1.py
import turtle
def koch(size,n):
if n == 0:
turtle.fd(size)
else:
for angle in [0,60,-120,60]:
turtle.left(angle)
koch(size/3,n-1)
def main():
turtle.setup(600,600)#默认生成窗口在中央,仅仅设置了宽高
turtle.penup()
turtle.goto(-200,100)
turtle.pendown()
turtle.pensize(2)
level = 4
koch(400,level)
turtle.right(120)
koch(400,level)
turtle.right(120)
koch(400,level)
turtle.hideturtle()
main()
14.作业
def drawsq(n):
line=3*n+1#这相当于于循环打配合,搞定用户输入于行数的打印关系
for i in range(1,line+1):
if i%3 == 1:#当是第1,4,7...行时,打印的是横排连着的样式
print(n*"+----",end="")#几阶便打印多少个
print("+")
else:
print("| "*n,end="")
print("|")
def main():
n=eval(input("请输入您要的阶数:"))
drawsq(n)
main()
def isOdd(n):
try:
if n % 2 == 0:
return False
if type(n) == type(0.):#因为输入float并不会报错,当它并不属于我们的需要类型
return False
else:
return True
except:
print("输入格式错误!")
print(isOdd(4))
print(isOdd(3))
print(isOdd(-1))
print(isOdd('str'))
print(isOdd(3.))
print(isOdd(str))
'''
False
True
True
输入格式错误!
None
False
输入格式错误!
None
'''
def isPrime(num):
import math
try:
if type(num) == type(0.):
raise TypeError#raise是保留字,手抛异常类型
r = int(math.floor(math.sqrt(num)))#math.floor()向下取整;sqrt()计算平方根
except TypeError:
print('不是一个有效的整数')
return None
if num == 1:
return False
for i in range(2,r+1):
if num % i == 0:#num逐步取余,为0则i为num的因数
return False
return True
#TypeError类型错误,将float也归于此类中,以此排除float、str的干扰
#num为1不符合素数定义
#for循环遍历判断是否为素数
print(isPrime(2))
print(isPrime(44))
print(isPrime('str'))
print(isPrime(1))
print(isPrime(3.3))
print(isPrime(0x18))
'''
素数:在大于1的自然数中,只有1和它本身两个因数
判断素数的平方根技巧
假设我们有一个整数 n,我们要判断它是否为素数。最直观的方法是检查从 2 到 n−1 的
所有整数是否能整除 n。如果没有任何一个数能整除 n,那么 n 就是素数。
但是, 对于较大的 n 来说非常低效.我们可以利用一个重要的数学性质来优化这个过程:
如果 n有一个大于根号n的因子,那么它必定有一个小于或等于根号n的因子。
因此,我们只需要检查从 2 到 根号n的所有整数即可。
'''
def PrimeList(N):
def is_prime(num):
if num <= 1:
return False
for i in range(2, int(num**0.5) + 1):
if num % i == 0:
return False
return True
primes = []
for num in range(2, N):
if is_prime(num):
primes.append(num)#ls.append()向列表中加入元素
return ' '.join(map(str, primes))#map(f,iters)它用于将函数功能f逐一作用于组合类型参数iters的各元素
N = eval(input("请输入N值:"))
print(PrimeList(N))
#line2~8是判断一个数是否为质数的函数
def isNum(s):
try:
# 尝试将字符串转换为复数类型
complex(s)
return True
except ValueError:
return False
def multi(i,*b):#可变参数b被当作元组类型遍历
for n in b:
i *= n
return i
print(multi(1,3,4))
'''
def multi(*args):
sum = 1
count = 1
for i in args:
if type(i) is type(1) or type(i) is type(1.):#使用type(i) is type(1) 和 type(i) is type(1.) 来检查参数 i 是否为整数或浮点数
sum *= i
else:
print("第{}项不是一个有效的整数!".format(count))
return;
count += 1
return sum;
print(multi(2,3,1.0,5,4.99))
print(multi(2,1,'str'))
print(multi())
'''
def FabN(n):
# 基本情况:当n为0或1时,直接返回n
if n == 0:
return 0
elif n == 1:
return 1
# 递归情况:返回前两项的和
else:
return FabN(n-1) + FabN(n-2)
#不得不说递归是懵中带着神奇
def isType(value):
if isinstance(value, int):
return "整数"
elif isinstance(value, float):
return "小数"
elif isinstance(value, complex):
return "复数"
elif isinstance(value, str):
return "字符串"
elif isinstance(value, list):
return "列表"
elif isinstance(value, dict):
return "字典"
elif isinstance(value, set):
return "集合"
elif isinstance(value, tuple):
return "元组"
else:
return "未知类型"
# 示例使用
print(isType(123)) # 输出: 整数
print(isType(123.45)) # 输出: 小数
print(isType(1+2j)) # 输出: 复数
print(isType("hello")) # 输出: 字符串
print(isType([1, 2, 3])) # 输出: 列表
print(isType({"a": 1})) # 输出: 字典
print(isType({1, 2, 3})) # 输出: 集合
print(isType((1, 2, 3))) # 输出: 元组
'''
isinstance() 是 Python 中的一个内置函数,用于检查一个对象是否属于指定的类型或其子类。
它的语法是 isinstance(object, classinfo),
其中 object 是要检查的对象,classinfo 是要检查的类型或类型元组。
如果 object 是 classinfo 的实例或子类的实例,则返回 True,否则返回 False
'''
15.math 库
math库是Python标准库
from math import *
1.基本数学运算
sqrt(x)#计算x的平方根
pow(x,y)#计算x的y次方
floor(x)#向下取整
ceil(x)#向上取整
fabs(x)#返回x的绝对值
2.三角函数
sin()#计算x的正弦值
cos(x)#计算x的余弦值
tan(x)#计算x的正切值
asin(x)#计算x的反正弦
acos(x)#计算x的反余弦
atan(x)#计算x的反正切
3.对数和指数函数
math.log(x):计算x的自然对数。
math.log10(x):计算x的以10为底的对数。
math.exp(x):计算e的x次方。
4.其他常用函数
math.pi:返回圆周率π的值。
math.e:返回自然对数的底e的值。
math.fmod(x, y):返回x除以y的余数。
5.特殊函数
math.gamma(x):计算x的伽玛函数。
math.erf(x):计算x的误差函数。
math.erfc(x):计算x的互补误差函数。
6.角度转换
math.degrees(x):将弧度转换为角度。
math.radians(x):将角度转换为弧度。
7.统计函数
math.factorial(x):计算x的阶乘。
8.常量
math.inf:表示正无穷大。
math.nan:表示非数值(NaN)
16.禁止函数修改列表
def print_models(unprinted_desings,completed_models):
"""
模拟打印每个设计,直到没有未打印的设计为止
打印每个设计后,都将其移到列表completed_models中
"""
while unprinted_desings:
current_design = unprinted_desings.pop()
#模拟根据设计制作3D打印模型的过程
print("Printing model: " + current_design)
completed_models.append(current_design)
def show_completed_models(completed_models):
"""显示打印好的所有模型"""
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
unprinted_desings = ['iphon case','robot pendant','dodecahedron']
completed_models = []
print_models(unprinted_desings,completed_models)
show_completed_models(completed_models)
'''
假如即便打印所有设计后,也要保留原来未打印的设计列表,以供备案,可以使用以下方法
print_modles(unprinted_designs[:],completed_models)
这样便创建了一个副本以供使用
'''
第六周:组合数据类型
组合数据类型是一组数据的表达,可以分为三类:集合类 、序列类和映射类
组合数据类型能够将多个同类型或不同类型的数据组织起来,通过单一的表示使数据操作更有序
集合类是元素集合,元素之间无序,相同元素在集合中唯一存在
序列类是元素向量,元素之间有序,通过序号访问,元素之间不排他
映射类是"键值对"集合,每个键值对表示为(key,value),用 key 访问 value
1. set 集合类型
集合是 0 个或多个元素的无序组合,每个元素唯一,不存在相同元素
集合类型和数学中的集合类型一致
集合元素不可变,不能是可变数据类型,因为可能改变后于其他元素相同
非可变数据类型:整数,浮点数,复数,字符串类型,元组类型...
可变数据类型:列表、字典、集合
#通过hash函数判断一个类型是否可变
>>>hash("python")
3337818790016917955
>>>hash(123)
123
>>>hash([1,2,3])
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
hash([1,2,3])
TypeError: unhashable type: 'list'
'''
哈希运算可以将任意长度的二进制值映射为较短的固定长度的二进制值,这个转换后的值便是哈希值
哈希值与哈希前的内容无关,也和这些内容的组合无关,算是在另一个数据维度的体现
'''
集合用{}表示,用逗号分隔
集合创建:
建立集合类型用{}或 set(),其元素可以动态增加或删除,建立空集合类型,必须用 set()
>>>A = {"python",123,("python",123)}#使用{}建立集合
{123,'python',('python',123)}
>>>set = ("python123")#使用set建立集合
{'1','p','2','3','y'}
>>>C = {"python",123,"python",123}
{'python',123}#由于集合元素的独一无二,故重复的元素能被过滤掉
#由于集合元素无序,故定义效果可能与展示效果不一致
>>>w = set("apple")
{'e','p','l','a'}
>>>v = set(["cat","dog","tiger","human"])
{'cat','human','dog','tiger'}
#set(x)通过遍历组合类型x的元素创建集合
2.集合操作符
集合的互操作:
操作符及应用 | 描述 |
S|T | 返回一个新集合,包括在S和T中的所有元素 |
S-T | 返回一个新集合,包括在S但不在T中的元素 |
S&T | 返回一个新集合,包括同时在S和T中的元素 |
S^T | 返回一个新集合,包括S和T中的非相同元素 |
S-=T | 更新集合S,包括在S但不在T中的元素 |
S&=T | 更新集合S,包括同时在S和T中的元素 |
S^=T | 更新集合S,包括S和T中的非相同元素 |
S|=T | 更新集合S,包括在S和T中的所有元素 |
S.isdisjoint(T) | 如果集合 S 与 T 没有相同元素,返回 False |
S<=T 或 S<T | 返回 Ture 或 False,判断 S 和 T 的子集关系 |
S>=T 或 S>T | 返回 Ture 或 False,判断 S 和 T 的包含关系 |
集合间的比较操作:
操作符 | 描述 |
S >T | 如果 S 是 T 的真超集,返回 True,否则 False |
S >= T | 如果是S 与 T 相同或 S 是是 T 的超集,返回 True,否则 False |
S < T | 如果 S 是 T 的真子集,返回 True,否则 False |
S <= T | 如果是S 与 T 相同或 S 是是 T 的子集,返回 True,否则 False |
S == T | 如果 S 于 T 相同,返回 True,否则 False |
S != T | 如果 S 与 T 不相同,返回 True,否则 False |
>>>A = {"p","y","123"}
>>>B = set{"python123"}
>>>A - B
{123}
>>>B - A
{'3','1','2'}
>>>A | B
{'1','2','p','y','3','123'}
>>>A & B
{'p','y'}
>>>A ^ B
{'1','2','123','3'}
3.集合的处理方法
集合可对其元素进行增删、复制、清空、归属等维护操作
操作函数及方法 | 描述 |
S.add(X) | 如果x不在集合S中,将x增加到 S |
S.discard() | 删除S中的x,如果x不在S中,不报错 |
S.remove() | 移除 S 中的x,如果x 不在集合S中,产生 KeyError 异常 |
S.clear() | 删除S中所有元素 |
S.pop() | 随机取出S的一个元素,更新S,若S为空,则产生KeyError 异常 |
S.copy() | 返回集合S的一个副本 |
len(S) | 返回集合S的元素个数 |
x in S | 判断S中的x,x在集合S中,返回Ture,否则 False |
x not in S | 判断S中的x,x不在集合S中,返回Ture,否则 False |
set(x) | 将其他变量x转变为集合类型 |
>>>s = {425,"BIT",(10,"cs"),424}
>>>s.add("123")
>>>s.discard("BIT")
>>>s
{424,425,'BIT',(10,"CS")}
>>>t = s.copy()
>>>t
{424,425,'BIT',(10,"CS")}
>>>s.clear()
>>>s
set()
#归属操作
>>>424 in s
True
>>>123 in s
False
>>>A = {"p","y","123"}
for item in A:
print(item,end"")
p123y
>>>A
{'p','y','123'}
try:
while True:
prinr(A.pop(),end="")
except:
pass
4.集合类型应用场景
分组操作、成员检测、元素去重
- 分组操作:根据应用需求,进行元素分类分组,形成集合,在集合间通过互操作及比较运算,实现元素的分类维护及分组操作
- 成员检测:将一组无序元素形成集合后,可以利用集合的元素操作,检测成员归属,实现元素分组检测
- 元素去重:利用集合元素的不重复特性,对一组元素进行去重操作,快速实现元素差异化
>>>p in {"p","y","123"}
True
>>>{"p","y"} >= {"123","p","y"}
False
>>>ls = ["p","p","y","y","123"]
>>>s = set(ls)#利用集合中无重复元素的特点
{'p','y','123'}
>>>lt = list(s)#将集合转换为列表
['p','y','123']
5.列表类型
列表是 0 个或多个元素组成的有序序列,没有长度限制,可以自由增删元素
(对比元组来讲:元组是 0 个或多个数据项的不可变序列组合。元组创建后是固定的,其中任何元素都不能替换或删除)
序列是具有先后关系的一组元素,序列是一维元素向量,元素类型可以不同
元素间由序号引导,通过下标访问序列的特定元素
序列是一种基类类型,一般使用其衍生类型,如:字符串类型,元组类型,列表类型
序列操作适用于列表类型、元组类型、字符串类型
序号的定义:
列表创建
#列表必须通过中括号[]或函数list()创建
>>>ls = [425,"BIT",1024]#创建列表对象
>>>lt = ls#lt是ls所对应数据的引用,lt并不包含真实数据
>>>ls[0] = 0
>>>lt
[0,'BIT',1024]
6.序列处理函数及方法
操作符及应用 | 描述 |
x in s | 如果 x 是序列 s 的元素,返回 Ture,否则 False |
x not in s | 如果 x 是序列 s 的元素,返回 False,否则 Ture |
s + t | 连接两个序列 s 和 t |
s*n 或 n*s | 将序列 s 复制 n 次 |
s[i] | 索引,返回 s 中的第 i 个元素,i 是元素的序号 |
s[i:j] 或 s[i:j:k] | 切片,返回 s 中第 i到 j 以 k 为步长的元素子序列,步长可以看作每次加几 |
>>>ls = ["python","123",".io"]#列表类型
>>>ls = [::-1]
['.io','123','python']
>>>s = "python123.io"#字符串类型
>>>s[::-1]
'oi.321nohtyp'
#高级哈,还能怎么玩
>>>ls = [425,"BIT",[10,"CS"],425]
>>>ls[2][-1][0]
'C'
#先到[10,"CS"],然后"CS",最后'C'
函数及方法 | 描述 |
len(s) | 返回序列 s 的长度即元素个数 |
min(s) | 返回序列 s 中的最小元素,s 中元素可比较 |
max(s) | 返回序列 s 中的最大元素,s 中元素可比较 |
s.index(x)或 s.index(x,i,j) | 返回序列s 从 i 位置到 j 位置第一次出现 x 的位置 |
s.count(x) | 返回序列 s 中 x 出现得总次数 |
>>>ls = ["python","123",".io"]
>>>len(ls)
3
>>>s = python123.io
>>>max(s)
'y'#按照字母序比较
7. 扩展:数组和列表
每种编程语言都提供一个或多个表示一组元素的方法,如 C 中的数组,Py 中的列表,但有不同点
- 数组需要预先分配大小,而列表不需要。创建数组时,必须指定数组大小,即它能容纳元素的个数。如果不知道有多少个元素,必须假设一个最大的可能值,再按照这个最大值分配数组。列表则没有预分配大小的要求和限制,创建列表变量时不需要知道元素个数,可以在使用中动态插入任何数量的元素。
- 数组要求元素类型一致,而列表不需要。数组要求每个元素具有相同的数据类型。列表则没有上述限制,列表中不同元素的类型可以相同,也可以不同,甚至,列表中的元素也可以是列表
8.列表类型及操作
列表是序列类型的一种扩展,十分常用,创建后可以随意被修改
使用方括号 [] 或 list()创建,元素间用逗号分隔
列表中各元素可以不同,无长度限制
>>>ls = ["cat","dog","tiger",1024]
>>>ls
['cat','dog','tiger',1024]
>>>lt = ls
>>>lt
['cat','dog','tiger',1024]
#[]方括号真正创建一个列表,赋值仅传递引用,相当于不同名字
函数及方法 | 描述 |
ls[i] = x | 替换 ls 第 i 个元素为 x |
ls[i:j:k] = lt | 将 lt 替换为 ls 中的切片 |
del ls[i] | 删除列表 ls 中的第 i 个元素,等价 ls[i]=[] |
del ls[i:j:k] | 删除列表 ls 中从 i 到 j 以 k 为步长的元素 |
ls += lt 或 ls.extend() | 更新列表 ls,将列表 lt 中的元素增加的 ls 中元素之后 |
ls *= n | 更新列表 ls,其元素重复 n 次 |
ls[0:-1:2] = [0,'q','w','e']
ls
[0, 2, 'q', 4, 'w', 6, 'e', 8, 9]
>>>ls = ["cat","dog","tiger",1024]
>>>ls[1:2] = [1,2,3,4]
['cat','1','2','3','4','tiger','1024']
>>>del = ls[::3]
['cat','1','2','4','tiger']
>>>ls * 2
['cat','1','2','4','tiger','cat','1','2','4','tiger']
函数及方法 | 描述 |
ls.append(x) | 在列表 ls 最后增加一个元素 x |
ls.clear() | 删除列表 ls 中所有元素 |
ls.copy() | 生成一个新列表,赋值 ls 中所有元素 |
ls.insert(i,x) | 在列表 ls 的第 i 位置增加元素 x,x 变为 i 位置元素,原元素后移 |
ls.pop(x) | 将列表 ls 中第 i 位置元素弹出该元素 |
ls.remove() | 将列表 ls 中出现的第一个元素 x 移除 |
ls.reverse() | 将列表 ls 中的元素反转 |
ls.sort(reverse=False) | 默认将列表 ls 中的元素按照从小到大顺序重新排列(永久性),出现非法操作即报错TypeError,如 str 与 int or float 组合输入 |
ls.sorted(reverse=False) | 默认将列表 ls 中的元素按照从小到大顺序重新排列(临时性),出现非法操作即报错TypeError,如 str 与 int or float 组合输入 |
motorcycles = ['honda','yamaha','suzuki']
print(motorcycles)
popped_motorcycle = motorcycles.pop()
print(motorcycles)
print(popped_motorcycle)#弹出的元素进入到新的列表中
'''
['honda', 'yamaha', 'suzuki']
['honda', 'yamaha']
suzuki
'''
#del是删除后不再使用,而pop是弹出原来的列表,pop后跟索引
motorcycles = ['honda','yamaha','suzuki','ducati']
print(motorcycles)
too_expensive = 'ducati'
motorcycles.remove(too_expensive)
print(motorcycles)
print("\nA " + too_expensive.title()+"is too_expensive for me.")
'''
['honda', 'yamaha', 'suzuki', 'ducati']
['honda', 'yamaha', 'suzuki']
A Ducatiis too_expensive for me.
'''
#del是删除后不再使用,pop是根据索引弹出,remove是根据值移出,后两个均可重用
#但一次remove只能删除一个值,除非用循环
>>>ls = ["cat","dog","tiger",1024]
>>>ls.append(1234)
['cat','dog','tiger',1024,1234]
>>>ls.insert(3,"human")
['cat','dog','tiger','human',1024,1234]
>>>ls.reverse()
[1234,1024,'human','tiger','dog','cat']
#对列表进行更改时,列表长度不一致的问题
>>>ls = [0,"BIT","computer","python",4]
>>>ls[1:3] = ["new_bit","new_computer",123]
>>>ls
[0,"new_bit","new_computer",123,"python",4]
>>>ls[1:3]=["fewer"]
[0,"fewer",123,"python",4]
9.序列类型的应用场景
数据管理、元素遍历、有序操作
- 数据管理:数据表示、增删查找、成员检测;当需要动态数据时,列表类型是首选
ls = []
s = input("请输入,空止:")
while s:#条件循环,s为True进入
ls.append(s)
s = input("请输入,空止:")
print(ls)
- 元素遍历
for item in ls:#列表类型
<语句块>
#甚至可以
>>>ls = list(range(5))
>>>ls
[0,1,2,3,4]
for item in tp:#元组类型
<语句块>
- 有序操作:对一组数据进行排序。使用 ls.sort()方法或 sorted()函数
#ls.sort(reverse=False) 或 sorted()
#其中,当reverse参数为默认值False时,从小到大排,否则,从大到小
#ls.sort()会改变列表ls的元素顺序,sorted()函数根据列表ls排序后返回一个新列表
>>>ls = ['Python123','数字中国','强国建设','Python']
>>>sorted(ls)
['Python','Python123','强国建设','数字中国']#根据Unicode和ASCII码值
>>>ls
['Python123','数字中国','强国建设','Python']#即不更改原列表
- 其他
元组用于元素不改变的应用场景,更多用于固定搭配场景
#如果不希望数据被程序所改变,转换成元组类型
>>>ls = ["cat","dog","tiger",1024]
>>>lt = tuple(ls)
>>>lt
('cat','dog','tiger',1024)
对于列表的比较,为元素逐一比较,不行之后看列表长度
使用多个列表
available_toppings = ['mushrooms','olives','green peppers','pepperoni','pineapple','extra cheese']
requested_toppings = ['mushrooms','french fries','extra cheese']
for requested_topping in requested_toppings:
if requested_topping in available_toppings:
print("Add "+requested_topping+".")
else:
print("Sorry,we don't have "+requested_topping)
print("\nFinished making pizza!")
10.实例九:基本统计值计算
对给出的一组数据,对他们有一个概要理解,如:总个数、求和、平均数、方差 、 中位数...
总个数:len()
求和:for...in
平均值:求和/总个数
方差:各数据与平均值差的平方和的平均数
中位数:排序,然后...奇数找中间 1 个,偶数找中间两个取均值
#CalStats.py
def grtNum():#获取用户输入函数
nums = []
istr = input("请输入数字(回车退出):")
while istr != "":
nums.append(eval(istr))
istr = input("请输入数字(回车退出):")
return nums#返回包含输入值的列表
def mean(numbers):#计算均值,形参用number表示
s = 0.0
for num in numbers:
s = s + num
return s/len(numbers)#返回均值计算结果
def dev(numbers,mean):#根据方差的公式知道,计算方差需要每个数据和平均数,因为要做差
sdev = 0.0
for num in numbers:
sdev = sdev + (num-mean)**2
return pow(sdev/len(numbers),0.5)
def median(numbers):#计算中位数
new = sorted(numbers,reverse=True)#sorted是一种默认从小到大的排序,反之则reverse=True
size = len(numbers)
if size%2 == 0:
med = (new[size//2-1]+new[size//2])/2
else:
med = new[size//2]#试试就知道了,整除2之后按0索引得到的即是中位数
return med
n = grtNum()
m = mean(n)
print("平均值是:{},标准差为:{:.2f},中位数为:{}".format(m,dev(n,m),median(n)))
print("最大值是:{},最小值是:{}".format(max(n),min(n)))
11.元组(tuple)类型及操作
元组是序列类型的一种扩展,一旦创建就不能被修改,有序,故可以索引
使用小括号 ()或 tuple()创建,其实也可以不用,元素间用逗号,分隔,可以使用或不使用小括号
def func():
return 1,2#我们认为返回两个值1和2,实际上计算机认为返回一个元组类型
>>>creature = "cat","dog","tiger","human"
>>>creature#这就直接创建了元组类型
('cat','dog','tiger','human')
>>>color = (0x001100,"blue",creatrue)#十六进制转了十进,自动的
>>color
(4352,'blue',('cat','dog','tiger','human'))
元组继承了序列类型的全部通用操作
元组因为创建后不能修改,因此没有特殊操作
>>>creature = "cat","dog","tiger","human"
>>>creature[::-1]
('human','tiger','dog','cat')#并不改变原有creature的值,而是生成一个新的元组值
>>>color = (0x001100,"blue",creatrue)
>>>color[-1][2]#有趣,先索引到元组,再索引到其中的值
'tiger'
"修改元组变量"
dimensions = (200,50)
print("Original dimensions:")
for dimension in dimensions:
print(dimension)
dimensions = (400,100)
print("\nModified dimensions:")
for dimension in dimensions:
print(dimension)
'''
Original dimensions:
200
50
Modified dimensions:
400
100
'''
12.hash计算
hash 运算可以用来判断数据可变与否,能产生 hash 值即为不可变量,否则为可变
元组具有不可变性,能够进行 hash 运算
>>>creature = "cat","dog"
>>>hash(creature)
-2936790823811548117
>>>ls = [1,2]
>>>hash(ls)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
hash(ls)
TypeError: unhashable type: 'list'
13.元组的应用场景
主要应用于:语法要素、元素遍历
语法要素:Python 语法要素中隐含用到很多需要元组类型的场景,如函数返回多值、多变量同时赋值
def func():
return x,x**3#函数返回多值
a,b = 'dog','tiger'#多变量同时赋值
a,b = (b,a)#多变量同时赋值,括号可省略
元素遍历:元组类型在表达一组固定数据后,可以采用遍历循环(for-in)对元素进行遍历。同列表类型一样
for <变量名> in <元组名>:
<语句块>
补充:对元组使用 sorted(),得到的是列表类型的返回值
12.字典(dict)类型的定义
字典是 0 个或多个键值对的集合,采用大括号{}或函数 dict()创建
映射:是一种键(索引)和值(数据)的对应
键值对:键是数据索引的扩展
字典是键值对的集合,键值对之间无序,用来表达映射关系,包含 0 个或多个键值对,可以根据键索引值的内容
键(key)表示一个属性,也可以理解为一个属性或类别,用于索引;值(value)是属性的内容或数据
采用大括号{}和 dict()创建,键值对用冒号:表示
{<键值1>:<值1>,<键值2>:<值2>,...}
#键和值通过冒号连接,不同键值对通过逗号隔开
#由于集合同样使用{}表示,因此字典也具有与集合相似的性质,即键值对之间没有顺序且不能重复
#由于line3的说明,直接使用大括号{}生成一个空字典,而不是集合,生成空集合需要set函数
#因为字典之间没有顺序之分,当获取字典元素元素时,是按照创建时键值对的插入顺序取出
<字典变量> = {<键1>:<值1>,<键2>:<值2>,...,<键n>:<值n>}
<值> = <字典变量>[<键>] <字典变量>[<键>] = <值>
[]用来向字典变量中索引或增加元素
<值> = <字典变量>[<键>]#字典变量后跟的一定是键
>>>DC = {"中国":"北京","美国":"华盛顿","法国":"巴黎"}
>>>DC['中国']='大北京'
>>>print(DC)
{"中国":"大北京","美国":"华盛顿","法国":"巴黎"}
>>>DC['英国']='伦敦'
>>>print(DC)
{"中国":"大北京","美国":"华盛顿","法国":"巴黎","英国":"伦敦"}
>>>d = {"中国":"北京","美国":"华盛顿","法国":"巴黎"}
>>>d
{'中国':'北京','美国':'华盛顿','法国':'巴黎'}
>>>["中国"]
'北京'
>>>de = {};type(de)
<class'dict'>
补充:字典要求键是非可变类型,值可以是任意数据类型,也好理解,键如果可变就不好访问
13.字典处理函数及方法
相对于元组,字典就更为灵活,字典元素可以动态增删
函数或方法 | 描述 |
del d[k] | 删除字典 d 中键 k 对应的键值对 |
k in d | 判断键 k(k 是索引) 是否在字典 d 中,如果在返回 True,否则 False |
d.keys() | 返回字典 d 中所有的键信息 |
d.values() | 返回字典 d 中所有的值信息 |
d.items() | 返回字典 d 中所有的键值对信息 |
>>>d = {"中国":"北京","美国":"华盛顿","法国":"巴黎"}
>>>"中国" in d
True
>>>d.keys()
dict_keys(['中国','美国','法国'])
>>>d.values()
dict.values(['北京','华盛顿','巴黎'])
#返回的依旧是字典类型
函数及方法 | 描述 |
d.get(k,<default>) | 键 k 存在,则返回相应值,不在则返回默认值<default>值,default=默认 |
d.pop(k,<default>) | 键 k 存在,则取出相应值,不在则返回<default>值 |
d.popitem() | 随机从字典 d 中取出一个键值对,以元组类型返回 |
d.clear() | 删除所有的键值对 |
d.len() | 返回字典 d 中元素的个数 |
>>>d = {"中国":"北京","美国":"华盛顿","法国":"巴黎"}
>>>d.get("中国","伊斯兰堡")#中国在字典中,则返回对应的值
‘北京’
>>>d.get("巴基斯坦","伊斯兰堡")#巴基斯坦不在字典中,返回我们输入的伊斯兰堡即default值
‘伊斯兰堡’
#定义空字典d
>>>d = {}
#向d中新增两个键值对
>>>d["a"] = 1;d["b"] = 2
#修改第2个元素,记住字典没有顺序
>>>d["b"] = 3
#判断字符“c”是否是d的键
>>>"c" in d
#计算d的长度
>>>len(d)
#清空d
>>>d.clear()
总结:使用<字典变量>['键'] 和 get 方法都可以获得值,但 get 方法会在搜寻值时若找不到则会返回默认值,实际中的却很有用
for <变量名> in <字典名>:
<语句块>
#由于键值对的键相当于索引,因此,for循环返回的变量名时字典元素的键
>>>for key in DC:
print(key,DC[key])
14.字典类型应用场景
应用场景:映射表达和个数统计
映射表达:映射无处不在,键值对无处不在
例如:统计数据出现的次数,数据是键,次数是值
最重要作用:表达键值对数据,进而操作它们
个数统计:对一组元素,统计各元素的个数时,字典能够发挥很大作用
ls = [1,2,4,6,3,6,7,3,5,2,4,2,5,2]
DC = {}
for i in ls:
DC[i] = DC.get(i,0)+1#若键存在则返回值并+1,否则返回默认值并+1
print(DC)
'''
{1: 1, 2: 4, 4: 2, 6: 2, 3: 2, 7: 1, 5: 2}
'''
15.jieba 库
jieba 是优秀的中文分词第三方库,需要额外安装
中文文本需要通过分词获得单个的词语,以列表形式返回
原理:构建一个中文词库,从左到右将待分词的内容与词库进行比对,通过图结构和动态规划方法找到具备最大概率的最左侧词组,分离;除了分词,jieba 库也可以增加自定义词组
jieba 库提供三种分词模式,最简单最需要掌握一个函数
精确模式:把文本精确的切分开,不存在冗余单词,适合文本分析
全模式:把文本中所有可能的词语都扫描出来,有冗余
搜索引擎模式:在精确模式基础上,对长词再次切分
函数 | 描述 |
jieba.cut(s) | 精确模式,返回一个可迭代的数据类型 |
jieba.cut(s,cut_all=True) | 全模式,输出文本 s 中所有可能的单词 |
jieba.cut_for_search(s) | 搜索引擎模式,适合搜索引擎建立索引的分词结果 |
jieba.lcut(s) | 精确模式,返回一个列表类型的分词结果 >>>jieba.lcut("中国是一个伟大的国家") ['中国','是','一个','伟大','的','国家'] |
jieba.lcut(s,cut_all=True) | 全模式,返回一个列表类型的分词结果,存在冗余 >>>jieba.lcut("中国是一个伟大的国家",cut_all=Ture) >>>['中国','国是','一个','伟大','的','国家'] |
jieba.lcut_for_search(s) | 搜索引擎模式,返回一个列表类型的分词结果,存在冗余 >>>jieba.lcut_for_search("中国人民共和国是伟大的") >>>['中华','华人','人民','共和','共和国','中华人民共和国','是','伟大','的'] #其实这是先精确模式,然后因为"中华人民共和国"太长,故再分解 |
jieba.add_word(w) | 向分词词典增加新词 w >>>jieba.add_word("蟒蛇语言") |
注意:jieba.lcut(s,cut_all_True)是相当于全模式,有冗余的;而 jieba.lcut_for_search()是先进行搜索引擎模式然后在此基础上进行全模式,两者的分词结果不同
16.实例十:文本词频统计
文本处理是一项基本能力,是针对中英文本进行清洗、提取、分词、统计、文件读写等操作的基本能力
碰巧的是:词频统计是累加计算,即对文档中每个词设计一个计数器,相关词出现一个,即加一;如果词语为键,计数器为值,构成<词语>:<出现次数>的键值对
'''
第一步:分解并提取英文文章的词语,但对于同一个单词的存在,会有大小写,
故使用txt.lower()将字母变成小写;其次,统一分隔符,利用txt.replace(old,new)方法
第二步:词语计数,两种方式
if word in count:
counts[word] = counts[word]+1
else:
count[word] = 1
或者
counts[word] = counts.get(word,0)+1,word指返回word对应的值
第三步:对统计值从高到低排序
首先因为字典无序,故需转换为列表,利用sort(reverse=True)自大到小排序
ltems = list(count.items)#字典转换为记录列表
dict = {"中国":"北京","美国":"华盛顿","法国":"巴黎"}
dict_items([('中国', '北京'), ('美国', '华盛顿'), ('法国', '巴黎')])#dict.item
items = list(dict.items())
[('中国', '北京'), ('美国', '华盛顿'), ('法国', '巴黎')]
items = sort(key=lambda x:x[1],reverse=True)#以记录第二列排序
#sort()方法有两个参数,第二个控制升降序,第一个用来指定一个获取排序元素的函数
#lambda x:x[1]函数说明,排序变量x的序号1元素进行
'''
#CalHamletV1.py
'''excludes = {"the","and","of","you","a","i","my","in"}#排出的词汇库'''
def getText():
txt = open("hamlet.txt","r").read()#打开hamlet文件
txt = txt.lower()#所有字母变小写
for ch in '!"#$%&()*+,-./:;<=>?@[\\]^_‘{|}~':
txt = txt.replace(ch,"")#将以上符号替换为空格
return txt#之后仍然保持在txt文本中
hamletTxt = getText()#利用刚刚定义的函数读取并进行归一化
words = hamletTxt.split()#以列表形式返回
#单词和出现次数构成一种映射,字典类型
counts = {}#定义一个字典类型
for word in words:
counts[word] = counts.get(word,0) + 1
#get方法,用来从字典中获得某一个键对应的值,如果这个键不存在在字典中,给出默认值
#counts.get函数指用当前的某一个英文单词为作为键索引字典,如果它在里面,就返回它的次数并加1,如果不在,那么就赋值为0,并加1
'''for word in excludes:
del(counts[word])'''#字典的删除方法
items = list(counts.items())#将字典类型变成列表类型
items.sort(key=lambda x:x[1],reverse=True)#有精力学习列表类型的sort方法,这里解释为从大到小的排序,并保存在items中
'''
在给定的代码中,lambda函数的作用是定义一个匿名函数,用于在排序时指定排序的依据。
具体来说,items.sort(key=lambda x:x[1], reverse=True) 这一行代码中,
lambda x:x[1] 定义了一个匿名函数,该函数接受一个参数 x,并返回 x 的第二个元素 x[1]。
这个匿名函数被用作 sort 方法的 key 参数,
表示排序时应该根据每个元组的第二个元素(即字典中每个键值对的值)来进行排序。
'''
for i in range(10):
word,count = items[i]
print("{0:<10}{1:>5}".format(word,count))#打印出单词及次数,对齐方式及宽度
'''
the 1137
and 963
to 736
of 669
you 546
i 540
a 527
my 513
hamlet 459
in 435
'''
'''
to 754
hamlet 462
it 416
that 391
is 340
not 314
lord 309
his 296
this 295
but 269
'''
#ThreeKingdomsHumans.py
excludes = {"将军","却说","荆州","二人","不可","不能","如此"}
import jieba
txt = open("threekingdoms.txt","r",encoding='utf-8').read()
words = jieba.lcut(txt)
counts = {}
for word in words:
if len(word)==1:#排出单个字符
continue
elif word=="诸葛亮" or word=="孔明曰":
rword = "孔明"
elif word=="关公" or word=="云长":
rword = "关羽"
elif word =="玄德" or word=="玄德曰":
rword = "刘备"
elif word=="孟德" or word=="丞相":
rword = "曹操"
else:
rword = word
counts[rword] = counts.get(rword,0)+1
items = list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(5):
word,count = items[i]
print("{0:<10}{1:>5}".format(word,count))
'''
'''
17.作业
#我的
import random
count = 0
all = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u'\
,'v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N'\
,'O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9']
while count<10:
for j in range(8):
i = random.randint(0,61)
print(all[i],end="")
count += 1
print()
#答案
from random import randint#可以生成指定范围内的整数,双闭
def rancre():
mi=''
for i in range(8):#循环8次,以确保得到8个字符
u = randint(0,62)
if u>=10:#对于大于10的u,我们用于转换为字符
if 90<(u+55)<97:#这属于小写与大写之间的杂符
mi+=chr(u+62)#u从35开始
else:#这属于65-90间,对应A-Z,即u在10-35间
mi+=chr(u+55)
print("{}".format(u+55),end="")
else:#对于小于10的数字,直接输出其值
mi+='%d'%u
return mi
def main():
for i in range(1,11):
print("生成的第{}个密码是:{}".format(i,rancre()))
main()
'''
rancre 函数:
使用 randint(0,62) 随机生成一个整数 u,范围在 [0, 62] 之间。
如果 u 大于等于 10,表示将选择一个字母(大写或小写)作为密码的一部分。这里通过 u + 55 或 u + 62 来计算对应的 ASCII 值,并转换为字符。
对于 u + 55,当 u 在 [10, 35] 范围内时,结果会落在 [65, 90] 之间,对应大写字母 A-Z。
当 u 在 [36, 61] 范围内时,u + 55 会落在 [91, 116] 之间,但是因为有额外的条件检查 (u+55) < 97,所以当 u 在 [36, 41] 范围内时,u + 62 会被用来确保生成的是小写字母 a-f。
如果 u 小于 10,则直接使用数字作为密码的一部分。
函数最终返回一个长度为 8 的字符串,该字符串由数字和/或字母组成。
main 函数:
循环调用 rancre 函数 10 次,每次生成一个密码,并
'''
#其实我感觉答案有问题
from random import randint
def rancre():
mi=''
for i in range(8):
u = randint(0,62)
if u>=10:
if 65<=(u+55)<=90:
mi+=chr(u+55)
else:
mi+=chr(u+61)
else:
mi+='%d'%u
return mi
def main():
for i in range(1,11):
print("生成的第{}个密码是:{}".format(i,rancre()))
main()
#列表元素可以重复,但set集合就不能重复了,故考虑两者的长度是否相等
def main():
num=[]
n = input("请输入一组数字(按下回车结束):")
while n!="":#在基本统计值那里有与此类似的操作
num.append(n)
n = input("请输入一组数字(按下回车结束):")
else:
print("正在鉴定,请稍后!")
judge(num)
def judge(m):
if len(m)==len(set(m)):
print("True")
else:
print("有重复元素,共计{}个".format(len(m)-len(set(m))))
main()
#英文文本,大小写转换、标点统一(replace去除函数,split按符号分隔成列表函数)、计数(字典)
txt = input("请输入你的文本信息:")
txt.lower()
for ch in '!"#$%&()*+,-./:;<=>?@[\\]^_‘{|}~':
txt.replace(ch,"")
txt = txt.split(" ")
counts = {}#创建新字典
for word in txt:
counts[word] = counts.get(word,0)+1
items = list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(5):
word,count = items[i]
print("{0:<10}{1:>5}".format(word,count))
#中文文本
import jieba
txt = input("请输入你的文本信息:")
txt = jieba.lcut(txt)
counts = {}#创建新字典
for word in txt:
if len(word) == 1:
continue
else:
counts[word] = counts.get(word,0)+1
items = list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(5):
word,count = items[i]
print("{0:<10}{1:>5}".format(word,count))
#需要注意的是,对于英文文本,需要遍历以去除符号;对于中文文本,引入jieba库、分词后默认产生
#列表类型,其次,对于符号的去处,使用len(word)==1方法
from random import *
def randbirth():#定义生日函数
mon=randint(1,12)#得到月份的整数随机表示
if mon in [1,3,5,7,8,10,12]:
day = randint(1,31)#在大月有31天
elif mon==2:
day = randint(1,28)#二月28天
else:
day = randint(1,30)#其余月份有30天
return mon*100+day#相当于加了两位空格以存放日,现在就设定好了一个随机生成生日的模块
def randNum(personNum):#用人数作为参数,以遍历几次,列表中就含有几个人的生日元素
ls=[]#定义空列表以添加生日
for i in range(personNum):#人数多少,遍历几次,人数的int在try中定义
ls.append(randbirth())#将生日逐步加入列表中
if len(ls) == len(set(ls)):#当没有生日相同时,同样的,set会自动排出重复元素
return False
else:#即有人生日相同的情况下
return True
try:#try-except异常处理
personnum = eval(input("请输入房间人数:"))#人就是person
poss = 0#
mean = 0.0#
for n in range(1000,11000,1000):#共循环10次,n为1000、2000...10000
for i in range(n):#开始上算力了,因为n值就很大,故i也要循环好多次,而且n的值还有多个
if randNum(personnum) == True:#将参数人数填入randNum函数,此函数内部再调用randbirth函数,当有人生日相同时执行if语句
poss += 1#当有人生日相同时poss+1
mean += poss*100/n#
poss = 0#
finally:
print("当房间人数为{}时,至少有两个人生日相同的概率是{:.2f}%".format(personnum,mean/10))
#这个从line25往后就有点懵了
#差不多这个样式,可以自己修改名称数量
excludes = {"却说","二人","不可","不能","如此","什么","一个","我们","那里","如今","你们","说道","知道","起来","姑娘","这里"}
import jieba
txt = open("红楼梦.txt","r",encoding='utf-8').read()
words = jieba.lcut(txt)
counts = {}
for word in words:
if len(word)==1:#排出单个字符
continue
elif word == "老太太":
rword = "贾母"
else:
rword = word
counts[rword] = counts.get(rword,0)+1
for word in excludes:
del(counts[word])
items = list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(5):
word,count = items[i]
print("{0:<10}{1:>5}".format(word,count))
第七周:文件和数据格式化
1.文件的使用
文件是数据的抽象和集合,就想函数是程序的集合和抽象,文件是储存在辅助储存器上的数据序列,文件是数据存储的一种形式
文件展现形态:文本文件和二进制文件(二进制存储,展现形态多元)区别主要在于是否有统一的字符编码
文本文件:由单一特定编码组成的文件,如 UTF-8 编码,由于存在编码,也被看作是存储着长的字符串(.py 或.txt)
二进制文件:直接由比特 0 和 1 的组织结构,没有统一字符编码,一般存在二进制 0 和 1 的组织结构,即文件格式(.png 或.avi)
#文本形式打开文件
tf = open("f.txt","rt")
print(tf.readline())
tf.close()
>>>中国是个伟大的国家!
#二进制形式打开文件
bf = open("f.txt","re")
print(bf.readline())
bf.close()
>>>b'\xd6\xd0\xb9\xfa\xca\xc7\xb8\xf6\xce\xb0\xb4\xf3\xb5\
xc4\xb9\xfa\xbc\xd2\xa3\xa1
'''
文本方式读取文件,文件经过编码形成字符串;二进制方式打开,文件被解析为比特Byte流。
由于存在编码,字节流中每个字节采用十六进制表示,其中,\xd6表示一个字节。
由于中文采用UTF-8编码,每个中文字符由两个字节表示
'''
2.文件的打开与关闭
文件处理的步骤:打开-操作-关闭
文件的存储状态和占用状态必在其一(唯一的、排它的)
操作有读文件(输入)和写文件(输出)
读文件函数 | 写文件函数 |
a.read(size) | a.write(s) |
a.readline(size) | a.writelines(lines) |
a.readlines(hint) | a.seek(offest) |
<变量名> open(<文件名>,<打开模式>)
#文件名:文件路径和名称,源文件同目录可省路径
#打开模式:文本了or二进制,读or写
#变量名:文件句柄
#关于路径:D:\PYE\f.txt可写成D:/PYE/f.txt或D:\\PYE\\f.txt(绝对路径)
#./PYE/f.txt或f.txt(相对路径)
#需要注意的是,对于mp3文件,直接使用open函数是播放不了的,需要安装第三方库,但以二进制打开还是可以的
bf = open('music.mp3','rb')#读取二进制文件的打开模式
#open()函数存在第三个参数,可以指定读取文件的字符编码
<变量名> = open(<文件名>,<打开模式>,encoding=None)#encoding编码
#若系统当前编码与文本编码不同,文件将产生字符编码错误,可使用指定文件解析编码
<变量名> = open(<文件名>,<打开模式>,encoding='utf-8')
打开模式 | |
文件的打开模式 | 描述 |
'r' | 只读模式,默认值,如果文件不存在,返回 FileNotFoundError,可以使用 try except 捕捉这个异常并处理 |
'w' | 覆盖写模式,文件不存在则创建,存在则完全覆盖 |
'x' | 创建写模式,文件不存在则创建,存在则返回 FileExistsError,可以使用 try except 捕捉这个异常并处理 |
'a' | 追加写模式,文件不存在则创建,存在则在文件最后追加内容 |
'b' | 二进制文件模式 |
't' | 文本文件模式,默认值 |
'+' | r/w/x/a 可以与'b'、't'、'+'组合使用,形成即表达读写又表达文件模式的方式 |
f = open("f.txt")#文本形式、只读模式、默认值
f = open("f.txt","rt")#文本形式、只读模式、同默认值
f = open("f.txt","w")#文本形式,覆盖写模式
f = open("f.txt","a+")#文本形式,追加写模式+读文件,若是a则只能写,不能读
f = open("f.txt","x")#文本形式,创建写模式
f = open("f.txt","b")#二进制形式、只读模式
f = open("f.txt","wb")#文本形式,覆盖写模式
'''
文件使用结束后要用close()方法关闭,释放文件的使用授权
'''
<变量名>.close()#变量名是文件句柄
#文本形式打开文件
tf = open("f.txt","rt")
print(tf.readline())
tf.close
#文本形式关闭文件
bf = open("f.txt","rb")
print(bf.readline())
bf.close()
#使用保留字with和as以及open()函数,可以简化文件打开,无须显示关闭
#扩展:保留字with和as组合使用,形成一种“上下文管理器”的特殊功能
with open(<文件名>,<打开模式>) as f:
<文件操作>
#在文件操作部分,不用关闭文件,当程序退出with区域代码执行时,将自动关闭所打开的文件f
#挺类似with循环的退出的
#现在对上述代码进行with改写
with open("7A.txt","rt") as tf:
print(tf.readline())
with open("7A.txt","rb") as bf:
print(bf.readline())
#相对
with open('text_files/pi_digits.txt') as file_object:
contents = file_object.read()
print(contents.rstrip())
#绝对
"""不管要进行任何操作,打开文件都是必须的"""
"""使用while能避免使用close"""
file_path = '/Users/chuji/Desktop/个人/计算机/Sublime Text/pi_digits.txt'
with open(file_path) as file_object:
contents = file_object.read()
print(contents.rstrip())
3.文件内容的读写
操作方法 | 描述 |
<f>.read(size=-1) | 读入全部内容,如果给出参数,读入前 size 长度的字节流或字符流 >>>s = f.read(2)#中国是个伟大的国家 中国 |
<f>.readline(size=-1) | 读入一行内容,如果给出参数,读入前size 长度的字节流或字符流 >>>s = f.readline() 中国是一个伟大的国家! |
<f>.readlines(hint=-1) | 读入文件所有行,以每行为元素形成列表,如果给出参数,读入 hint 行 如果给出参数,读入前 hit 行 >>>s = f.readlines() ['中国是一个伟大的国家!'] |
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line)
"""
3.1415926535
8979323846
2643383279
"""
#之所以有空行,是因为源文件每行末都有\n
#改进
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line.rstrip())
"""
因为使用with时,open()返回的对象只在with内可用,若想在外面使用,可利用列表为中介
"""
filename = 'pi_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
for line in lines:
print(line.rstrip())
4.数据的文件写入
文件打开后,可以用 write(),writelines()函数写入数据,通过 seek()函数控制文件写入的位置
操作方法 | 描述 |
<f>.write(s) | 向文件写入一个字符串或字节流 >>>f.write("中国是一个伟大的国家!") |
<f>.writelines(lines) | 将一个列表元素组合后写入文件 >>>ls = ["中国","法国","美国"] >>>f.writelines(ls) 中国美国法国 |
<f>.seek(offset,w=0) | 改变当前文件操作指针的位置,offest 表示偏移量,读写指针会被设定到 w+offset 位置,w 表示基地址 0-文件开头;1-当前位置;2-文件结尾 >>>f.seek(0)#回到文件开头 |
fname = input("请输入要写入的文件:")
f = open(fname,"w+")#覆盖写模式
ls = ["唐诗","宋词","元曲"]
f.writelines(ls)#将列表元素组合后写入文件,这里并不会把每一行写入时也单独成行,实际上其不增加换行
#f.seek(0)在此加入即可实现输出
for line in fo:
print(line)
f.close()
'''
这个并不会print,因为写操作后文件操作指针在写入内容的后面,line5-7从指针开始向后读出并打印
想要实现打印操作只需指针回退即可,即f.seek(0)
'''
filename = 'pi_digits.txt'
with open(filename,'a') as file_object:
file_object.write("\nI also happy")
filename = 'pi_digits.txt'
with open(filename,'w') as file_object:
file_object.write("\nI also happy")
5.文件遍历
使用 for-in 遍历循环能够遍历文件内容
文件的全文本操作
fname = input("请输入要打开的文件名称:")
fo = open(fname,"r")
txt = fo.read()
#对全文本txt进行处理
fo.close()
#一次读入,全部处理,缺点是对大文件读入耗内存
fname = input("请输入要打开的文件名称:")
fo = open(fname,"r")
txt = fo.read(2)#指从文件中读入两个字节
while txt != "":#只要读入的信息不为空就持续处理
#对txt进行处理
txt = fo.read(2)
fo.close()
#按数量读入,逐步处理
文件的逐行操作
fname = input("请输入要打开的文件名称:")
fo = open(fname,"r")
for line in fo.readlines():#遍历每一行,以行的方式生成一个列表。每行是列表的一个元素
print(line)
fo.close()
#一次读入,分行处理
fname = input("请输入要打开的文件名称:")
fo = open(fname,"r")
for line in fo:
print(line)
fo.close()
#分行读入,逐行处理,这可以占用更少的内存,以防文件过大的情况
6.政府工作报告词云
基本思路:
读取文件、分词整理;设置并输出词云;观察结果、优化迭代
#GovRptWordCloudv1.py
import jieba
import wordcloud
f = open("2024年中央一号文件.txt","r",encoding="utf-8")
t = f.read()#使用f.read一次性将文本读入变量t
f.close()
ls = jieba.lcut(t)#将文本进行分词
txt = " ".join(ls)#用空格将ls的每一个用空格连接起来
w = wordcloud.WordCloud(font_path = "STHeiti Light.ttc",width=1000,height=700,background_color="white")
w.generate(txt)#加载这段文本
w.to_file("2024年中央一号文件词云.png")
#若要限制词的输出,在line9括号内加入max_words=15即可
若想生成更有形的,前提准备一个背景是白色的形状图片
#GovRptWordCloudv1.py
import jieba
import wordcloud
from scipy.misc import imread
mask = imread("fivestart.png")#imread方法能够读取一个图片文件并且变成一个图片文件表达的内部变量
f = open("2024年中央一号文件.txt","r",encoding="utf-8")
t = f.read()#使用f.read一次性将文本读入变量t
f.close()
ls = jieba.lcut(t)#将文本进行分词
txt = " ".join(ls)#用空格将ls的每一个用空格连接起来
w = wordcloud.WordCloud(font_path = "STHeiti Light.ttc",mask = mask,width=1000,height=700,background_color="white")
w.generate(txt)#加载这段文本
w.to_file("2024年中央一号文件词云.png")
#其实这个输出有问题,在引入scipy.misc库的imread函数方面
7. 实例十一.中央一号文件词云
#DrawRptOne.py
import jieba
import wordcloud
fname = "倚天屠龙记.txt"
with open(fname,'r',encoding='utf-8') as f:#以utf-8编码打开文件,文件句柄为f
ls = jieba.lcut(f.read())#只读方式打开,lcut分词返回为列表类型
w = wordcloud.WordCloud(width = 1000,height = 700,background_color = "white",font_path = "STHeiti Light.ttc")
#ttc文件为字体文件
txt = " ".join(ls)#将列表ls重组为空格分隔的字符串
w.generate(txt)#wordcloud的函数,进行根据字符串进行词云绘制
w.to_file("RptOneWordle01.png")#输出为png格式,并命名
缺点是有很多单个字,中文里单个字基本不表含义
#DrawRptOne.py
import jieba
import wordcloud
fname = "2024年中央一号文件.txt"
with open(fname,'r',encoding='utf-8') as f:
ls = jieba.lcut(f.read())
for item in reversed(ls):#用于返回一个反向迭代器,该迭代器可以遍历序列 ls 中的元素,但顺序是反向的。这个函数不会生成新的序列副本,因此在处理大型序列时非常高效。
if len(item) == 1:
ls.remove(item)
w = wordcloud.WordCloud(width = 1000,height = 700,background_color = "white",font_path = "STHeiti Light.ttc")
txt = " ".join(ls)
w.generate(txt)
w.to_file("2024年中央一号文件.png")
注意:对列表内容进行判断删除时,要采用列表的逆序遍历
#正序遍历
ls = [5,4,4,2,1]
for item in ls:
if item == 4:
ls.remove(item)
print(ls)
>>>[5,4,2,1]
'''
主要是因为,当列表元素删除后,他们的索引也会有些许变化
当删除的一个4后,该检查索引为2的了,但新列表[5,4,2,1]的索引2为2,出现逻辑错误
'''
#逆序遍历
ls = [5,4,4,2,1]
for item in ls:
if item == 4:
ls.remove(item)
print(ls)
>>>[5,2,1]
'''
原因为自后向前删除,并不会改变前面的索引
'''
一组文件词云:os 库可以对文件夹下的文件进行遍历,从而处理一组文件
os 库:标准库,遍历操作系统目录
#DrawRptOne.py
import jieba
import wordcloud
import os
def GenWordle(dirname,fname):
with open(dirname+"//"+fname,"r",encoding="utf-8") as f:
ls = jieba.lcut(f.read())
w = wordcloud.WordCloud(width = 1000,height = 700,background_color = "white",font_path = "STHeiti Light.ttc")
txt = " ".join(ls)
w.generate(txt)
w.to_file("Worlde"+fname[:4]+".png")
dirname = "金庸小说"
for fname in os.listdir(dirname):#os.listdir(<dirname>)能够返回目录名<dirname>内部的所有文件,结合for-in简直般配
GenWordle(dirname,fname)
'''
GenWordle()将生成词云的功能封装为函数,通过遍历目录,对文件逐一调用
'''
8.数据组织的维度
根据数据的关系不同,数据组织可以分为一维数据、二维数据和高维数据
一维数据:由对等关系的有序或无序数据构成,采用线性方式组织
3.14,3.15,1.34,125...
对应列表、数组和集合等概念
二维数据:也称表格数据,由多个一维数据(关联关系数据)构成,采用表格方式组织
类似数学中矩阵的概念,表格是典型的二维数据,表头是二维数据的一部分
多维数据:由一维或二维数据在新维度上扩展形成,例如在中国大学排行榜上加入时间维度
高维数据:仅利用最基本的二元关系展示数据间的复杂结构,例如键值对,最灵活
高维数据在网络系统中十分常用,HTML、XML、JSON 等都是高维数据组织的语法结构
{
"firstName":"Liang"
"lastName":"Zhang"
"address":{
"streeAddr":"中关村南大街"
"city":"北京市"
"zipcode":100081
},
"professional":["Compyter Networking","Security"]
}#像是多个键值对的套用
'''
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,具有易读易写的特点,
广泛应用于Web开发和数据传输领域。
它起源于JavaScript语言,但已成为一种独立于编程语言的格式,
易于人阅读和编写,同时也易于机器解析和生成。
JSON采用完全独立于编程语言的文本格式来表示数据,可以跨语言、跨平台使用。
JSON的数据结构主要包含两种基本类型:对象和数组。
JSON对象以大括号{}表示,内部由一系列键值对组成,键和值之间用冒号分隔,键值对之间用逗号分隔;
JSON数组以中括号[]表示,内部由一系列值组成,值之间用逗号分隔。
JSON支持的数据类型有字符串、数字、布尔值、数组、对象、null等。
JSON的设计目标是简洁、可移植、文本格式且为JavaScript的子集,使得不同编程语言之间可以交换数据。
'''
数据的操作周期(数据格式化)
存储<->表示<->操作
9.一维数据的表示
列表或集合类型可以表示一维数据
如果数据间有序:使用列表类型 [, ,]
for 循环可以遍历数据,进而对每个数据进行处理
如果数据间无序:使用集合类型{, ,}
集合的缺点就是不能直接索引元素,但可以遍历
for 循环可以遍历数据,进而对每个数据进行处理
>>>s = {123,321,213}
>>>s
{123,321,213}
>>>for i in s:
print(i,end="")
321,123,213#无序输出
10.一维数据的读写
存储方式一:空格分隔
中国 美国 日本 德国 法国 英国 意大利
使用一个或多个空格分隔进行存储,不换行
缺点:数据中不能存在空格
txt = open(fname).read()
ls = txt.split()#这里也可以是'$'
f.close()
>>>ls
['中国','美国','日本','德国','法国','英国','意大利']
ls = ['中国','美国','日本']
f = open(fname,'w')
f.write(' '.join(ls))#join方法,将join前的字符串分隔放置到后面的join参数中的各个元素之间
f.close()
存储方式二:逗号分隔
中国,美国,日本,德国,法国,英国,意大利
使用英文的半角逗号分隔数据进行存储,不换行
with open(fname) as f:
txt = f.read()
ls = txt.split(",")
with open(fname,'w') as f:
f.write(','.join(ls))
存储方式三:其他方式
中国$美国$日本$德国$法国$英国$意大利
使用其他符号或符号组合分隔,建议采用特殊符号
11.二维数据的表示
CSV 格式用于存储二维数据,使用列表类型,二维列表(本身是个列表,而列表中的每一个元素又是一个列表)
使用两层 for 循环遍历每个元素,外层列表中每个元素可以对应一行,也可以对应一列
12.CSV格式与二维数据的存储
CSV:Comma-Separated Values:由逗号分隔的值
这是国际通用的一二维数据存储格式,一般以.csv 扩展名
规则:
- 纯文本格式,通过单一编码表示字符
- 以行为单位,开头不留空行,行之间没有空行
- 每行代表一个一维数据,多行表示二维数据
- 以逗号(英文,半角)分隔每列数据,列数据为空也要保留逗号
- 对于表格数据,可以包含或不包含列名,包含时列名放置在文件第一行
Excle 和一般的编辑软件都可以读入或另存为 csv 文件,下图右方即二维数据采用 CSV 格式存储后的内容
按行存或按列存都可以,具体由程序决定
一般索引习惯:ls[row][column],先行后列#英文:排,列
扩展:
Python 的 csv 标准库,可以通过 import csv 语句使用。csv 库包含操作 CSV 格式最基本的功能,如 csv.reader()和 csv.writer()。但对于一般程序而言,还是使用自己编写的 CSV 格式函数更为重要,对于商业性质的,采用标准库函数
13.二维数据的处理
从 CSV 格式的文件中读入数据
fo = open(fname)
ls = []
for line in fo:#读入数据的每一行
line = line.replace("\n","")#将每行的回车替换为空字符串
ls.append(line.split(","))#将每行的元素,按照逗号分隔形成列表,并把这个列表增加到ls列表中
fo.close()
将数据写入 CSV 格式的文件
ls = [[],[],[]]#二维列表
f = open(fname,'w')#覆盖写模式
for item in ls:
f.write(','.join(item) + '\n')#在每一行的中间加入逗号,并在每一行的最后增加回车进行下一行的写入
f.close()
ls = [[1,2],[3,4],[5,6]]#二维列表
for row in ls:
for column in row:
print(column)
ls[1][1]#之要注意到嵌套关系,理解先后索引关系即可
4
书上示例:
ls = []
with open("price2024-10-19.csv",encoding='utf-8') as f:
for line in f:
line = line.replace("\n","")
ls.append(line.split(","))
print(ls)
'''
[['\ufeff城市', '环比', '同比'], ['北京', '99.9', '101.3'], ['上海', '100.4', '104.2'], ['广州', '99.2', '96.4'], ['深圳', '99.3', '95.9'], ['沈阳', '99.4', '98.6']]
'''
'''
"\ufeff" 是一个 Unicode 字符,称为字节顺序标记(Byte Order Mark,BOM)。
在 UTF-8 编码中,"\ufeff" 通常用于指示文本文件的字节顺序。
具体来说,它是一个字节序列,用于在处理文本文件时识别文件的编码格式。
'''
ls = []
with open("price2024-10-19.csv",encoding='utf-8') as f:
for line in f:
line = line.replace("\n","")
lls = line.split(",")
txt = ""
for i in lls:
txt += "{}\t".format(i)
print(txt)
'''
城市 环比 同比
北京 99.9 101.3
上海 100.4 104.2
广州 99.2 96.4
深圳 99.3 95.9
沈阳 99.4 98.6
'''
ls = []
fw = open("price2024-10-19.csv", "w")
with open("price2024-10-19.csv", encoding='utf-8') as fr:
for line in fr: # 读入二维数据
line = line.replace("\n","")
ls.append(line.split(","))
for i in range(len(ls)): # 计算浮动百分比
for j in range(len(ls[i])):
if ls[i][j].replace(".","").isnumeric():
ls[i][j] = "{:.2}%".format(float(ls[i][j])-100)
for row in ls: # 打印并写入 CSV 文件
for col in row:
print(col, end="\t")
print()
fw.write(",".join(row)+"\n")
fw.close()
#这部分代码其实我也蛮懵的
14.实例十二:自动轨迹绘制
"软件引擎"是共性软件功能的结合,与所需数据分离,可以达到更为灵活的效果。
实际上就是将软件与数据的紧耦合转换为分离形式
需求:根据脚本来绘制图形,不是写代码而是写数据绘制轨迹,数据脚本是自动化最重要的一步
基本思路:
定义接口:定义数据文件格式(接口),算是程序和数据的一种规范
数据接口定义,非常具有个性色彩,实现软件功能和数据的分离
300,0,144,1,0,0
300,1,144,0,1,0
#行进距离;转向判断,0左转,1右转;转向角度;RGB三个通道颜色0~1的浮点数
#定义后的软件接口是一个二维数据,可以采用二维数据处理方法读入和表示
实现引擎:根据接口定义,编写程序获取并解析数据,进而实现对应功能
#AutoTracDraw.py
import turtle as t
t.title('自动轨迹绘制')
t.setup(800,600,0,0)
t.pencolor("red")
t.pensize(5)
dls=[]
with open("data.txt") as f:
for line in f:
line = line.replace("\n","")
dls.append(list(map(eval,line.split(","))))
for i in range(len(dls)):
t.pencolor(dls[i][3],dls[i][4],dls[i][5])
t.forward(dls[i][0])
if dls[i][1]:
t.right(dls[i][2])
else:
t.left(dls[i][2])
编制数据:根据绘制需求编制数据文件,实现数据驱动的自动轨迹绘制
#AutoTracDraw.py
import turtle as t
t.title("自动轨迹绘制")#设置绘制窗口的标题栏信息
t.setup(800,600,0,0)
t.pencolor("red")#设置初始画笔的颜色
t.pensize(5)
#数据读入
datals = []
f = open("data.txt")
for line in f:#打开文件并遍历每一行
line = line.replace("\n","")#将文段最后的换行符转换为空字符串
#遍历每一行时得到的是字符串,而我们要解析为真实的数字
#line.split(",")将长字符串按逗号分隔成多个字符串
#map函数是python的内嵌函数,即无需import,功能为将第一个参数的功能作用于第二个参数的每一个元素,第一个参数是一个函数的名字,第二个是迭代类型
datals.append(list(map(eval,line.split(","))))
f.close()
#自动绘制
for i in range(len(datals)):
#获得当前datals的一个元素,并找到元素的第三个参数,第三个元素是R值,依次是GB
t.pencolor(datals[i][3],datals[i][4],datals[i][5])
t.fd(datals[i][0])#等价于forward
if datals[i][1]:#这里加上==1亦可
t.right(datals[i][2])
else:
t.left(datals[i][2])
t.done()
'''
备注:
再次对.split方法做个示例
"1,2,3,4".split(",")
['1','2','3','4']
map(<函数>,<可迭对象>),用于将函数应用于可迭代对象的每一个元素之后
需要注意的是,map(eval,line.split(","))得到的是<map object at 0x106d1c6d0>,这是map对象的内存地址
But,对map函数前加入list()即可得到[1,2,3,4]纯数字组成的列表
'''
自动化思维:数据和功能分离,数据驱动的自动运行
接口化设计:格式化设计接口,清晰明了
二维数据应用:应用维度组织数据,二维数据最常用
扩展接口设计,增加更多控制接口,扩展功能设计,增加弧形等更多功能,扩展应用需求,发展自动轨迹绘制到动画绘制
软件引擎化可以封装为专业计算功能,将程序设计变为数字文件进行编制
15.wordcloud 库
WordCloud 库采用 WordCloud 对象表示一个词云,采用像素覆盖方法控制词云形状
白色像素部分不填充单词,非白色像素部分填充单词
wordcloud 库是优秀的词云展示第三方库
词云以词语为基本单位,更加直观和艺术的展示文本
wordcloud 库把词云当作一个 WordCloud 对象
wordcloud.WordCloud()代表一个文本对应的词云
可以根据文本中词语出现的频率等参数绘制词云
绘制词云的形状、尺寸和颜色都可以设定
pip inastall -U wordcloud
-U 表示 update 更新
w = wordcloud.WordCloud()
#以WordCloud对象为基础;配置参数、加载文本、输出文本
#下面的一堆方法,其实都是加载到WordCloud里进行参数配置的
方法 | 描述 |
w.WordCloud() | WordCloud 库功能主要通过设置 wordcloud.Wordcloud()函数的参数实现 |
w.generate(txt) | 向 WordCloud 对象 w 中加载文本 txt, >>>w.generate("python and WordCloud") |
w.to_file(filename) | 将词云输出为图像文件,.png 或.jpg 格式 >>>w.to_file("outfile.png") |
步骤一:配置对象参数
步骤二:加载词云文本
步骤三:输出词云文件
import wordcloud
c = wordcloud.WordCloud(<配置对象>)#生成一个词云对象赋给变量c
c.generate("wordcloud by python")#空格分隔单词构成的字符串
c.to_file("pywordcloud.png")#将词云效果输出到pywordcloud.png文件中,输出词云对象文件名
#默认生成宽400高200的图片
原理:
1.分隔:以空格分隔单词
2.统计:单词出现次数并过滤
3.字体:根据统计配置字号
4.布局:颜色环境尺寸
备注:
对于文本,会过滤掉非实义词
配置对象参数 | |
参数 | 描述 |
width | 指词云对象生成词云宽度,默认 400 像素 >>>w=wordcloud.WordCloud(width=600) |
hight | 指词云对象生成词云高度,默认 200 像素 >>>w=wordcloud.WordCloud(hight=400) |
min_font_size | 指定词云中字体的最小字号,默认四号 >>>w=wordcloud.WordCloud(min_font_size=10) |
max_font_size | 指定词云中字体的最大字号,根据高度自动调节 >>>w=wordcloud.WordCloud(max_font_size=20) |
font_step | 指定词云中字体字号的步进间隔,默认为 1 >>>w=wordcloud.WordCloud(font_setp=2) |
font_path | 指定字体文件的路径,默认为 None >>>w=wordcloud.WordCloud(font_path="msyh.ttc") |
max_words | 指定词云显示的最大单词数量,默认 200 >>>w=wordcloud.WordCloud(max_words=20) |
stop_words | 指定词云的排出词列表,即不显示的单词列表 >>>w=wordcloud.WordCloud(stop_words={"python"}) |
mask | 指定词云形状,默认为长方形,需要引入 imread()函数 >>>from scipy.misc import imread() >>>mk=imread("pic.png") >>>w=wordcloud.WordCloud(mask=mk) |
background_color | 指定词云图片的背景颜色,默认为黑色 >>>w=wordcloud.WordCloud(background_color="white") |
include_numbers | 指定词云图是否包含数字,默认为 False |
import jieba
import wordcloud
txt = "程序设计语言是计算机能够理解和识别用户操作意图的一种交互体系,\
它按照特定规则组织计算机指令,使计算机能够自动进行各种运算处理。"
w = wordcloud.WordCloud(width=1000,font_path="STHeiti Light.ttc",height=700)
w.generate(" ".join(jieba.lcut(txt)))#将这段文本进行分词,lcut会生成一个列表变量
w.to_file("pyttwcloud.png")
#生成中文词云图时,建议指定中文字体文件,对于ttc文件,请尝试自己下载,因为文件有点大,不好传附件
图形设计:
采用 imread()函数,可以辅助生成任意形状词云
pip install -U imageio
使用格式:pixels = imread(<图形文件名>)
import jieba
import wordcloud
from imageio.v3 import imread
mask = imread("五角星.jpg")
txt = "程序设计语言是计算机能够理解和识别用户操作意图的一种交互体系,\
它按照特定规则组织计算机指令,使计算机能够自动进行各种运算处理。"
w = wordcloud.WordCloud(width=1000,height=1000,mask=mask,\
font_path="STHeiti Light.ttc",background_color="white")
w.generate(" ".join(jieba.lcut(txt)))
w.to_file("五角星形词云.png")
16.作业
#哎,第一题都被难着了
import keyword
stopwords = '\t\n\r:()'
functionwords = '.('
word = []
output = ''
lastAvailable = ['from','import']
last = False
def readFile(path):
file = open(path,'r',encoding = 'utf-8')
string = file.read()
return string[1:]
def parse(string):
global word
global output
for i in string:
if i in stopwords:
wd = ''.join(word)
res = isKeyWord(wd)
if res == False:
if i not in functionwords and last == False:
wd = wd.upper()
if wd in lastAvailable():
last = True
else:
last = False
output += wd
output += i
word = []
else:
word.append()
def isKeyWord(string):
if string in keyword.kwlist:
return True
return False
def outPutFile():
file = open('D:\\12.8.py','w',encoding = 'utf-8')
file.write(output)
string = readFile('D:\\12.7.py')
parse(string)
outPutFile()
import jieba
import wordcloud as w
f = open("2024年中央一号文件.txt",'r',encoding='utf-8')
t = f.read()
f.close()
w = w.WordCloud(width=1000,height=1000,max_words=100,\
font_path="STHeiti Light.ttc")
w.generate(" ".join(jieba.lcut(t)))
w.to_file("7.2.png")
import turtle as t
t.pensize(10)
t.pencolor("red")
t.setup(800,800,0,0)
t.title("圆形轨迹绘制")
dls = []
with open("圆形轨迹绘制.txt") as f:
for line in f:
line = line.replace("\n","")
dls.append(list(map(eval,line.split(","))))
for i in range(len(dls)):
t.circle(dls[i][0],dls[i][1])
17.利用 JSON 存储数据
import json
number = [2,3,5,7,11,13]
filename = 'numbers.json'
with open(filename,'w') as f_obj:
json.dump(number,f_obj)
import json
filename = 'numbers.json'
with open(filename) as f_obj:
numbers = json.load(f_obj)
print(numbers)
18.重构
代码能够正常运行,但可做进一步修改,将代码划分为一系列完成具体工作的函数--重构
import json
#如果以前存储了用户名,就加载它
#否则就提示用户输入用户名并存储它
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
username = input("What your name? ")
with open(filename,'w') as f_obj:
json.dump(username,f_obj)
print("We'll remember you when you come back, "+username+"!")
else:
print("Welcome back, "+username+"!")
import json
def greet_user():
"""问候用户,并指出名字"""
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
username = input("What is your name? ")
with open(filename,'w') as f_obj:
json.dump(username,f_obj)
print("We'll rember you when you come back, " + username + "!")
else:
print("Welcome back, "+ username+" !")
greet_user()
import json
def get_stored_username():
"""如果存储了用户名,就获取它"""
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
return None
else:
return username
def greet_user():
"""问候用户,并指出其名字"""
username = get_stored_username()
if username:
print("Welcome back, "+username+"!")
else:
username = input("What is your name?")
filename = 'username.json'
with open(filename,'w') as f_obj:
json.dump(username,f_obj)
print("We'll remember you when you come back, "+username+"!")
greet_user()
import json
def get_stored_username():
"""如果存储了用户名,就获取它"""
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
return None
else:
return username
def get_new_username():
"""提示用户输入用户名"""
username = input("What is your name?")
filename = 'username.json'
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
def greet_user():
"""问候用户,并指出其名字"""
username = get_stored_username()
if username:
print("Welcome back, " + username + "!")
else:
username = get_new_username()
print("We'll remember you when you come back, "+username+"!")
greet_user()
第八周:程序设计方法学
程序设计是一种面向功能的人机交互方法,兼具功能性、方法性和艺术性
#这个没见过,了解一下
>>>evens = [x for x in range(1,11)if x%2==0]
>>>print(evens)
[2, 4, 6, 8, 10]
>>>keys = ['a','b','c']
>>>values = [1,2,3]
>>>d = {k:v for k,v in zip(keys,values)}
#zip()函数将两个列表中的元素一一对应组成元组,生成一个迭代器
#遍历这个迭代器,并将每个元组的第一个元素作为key,第二个最为value,生成新的字典
>>>print(d)
{'a': 1, 'b': 2, 'c': 3}
#map()是老熟人了,可以对列表中的每个元素进行相同的计算
>>>squared = list(map(lambda x:x**2,range(1,6)))
>>>print(squared)
[1, 4, 9, 16, 25]
1.实例十三:体育竞技分析
用计算机模拟 N 场比赛,N 很大时结果更为收敛
比赛规则:
- 双人击球比赛:A&B,回合制,5局3胜
- 开始时一方先发球,直至判分
- 球员只能在发球局得分,15分胜一局
框架+自定义函数:
- 打印程序的介绍性信息式
-printInpo()
- 获得程序运行参数:proA,proB,n
-getIupts()
- 利用球员 A 和 B 的能力值,模拟 n 局比赛
-simNGames()
- 输出球员 AB 的获胜比赛场次及概率
-printSummary()
def main():
printIntro()
probA,probB,n = getInputs()
winsA,winsB = simNGames(n,probA,probB)
printSummary(winsAmwinsB)
def main():#框架
printIntro()#打印介绍信息,提升用户体验
proA,proB,n = getInputs()#输入两者能力值及比赛场次
winsA,winsB = simNGames(n,probA,probB)#得到两者获胜场次
printSummary(winsA,winsB)#打印获胜场次
def printIntro():
print("这个程序模拟两个选手A和B的某种竞技比赛")
print("程序运行需要A和B的能力值(0-1之间的小数表示)")
def getInputs():
a = eval(input("请输入选手A的能力值:"))
b = eval(input("请输入选手B的能力值:"))
n = eval(input("模拟比赛场次:"))
return a,b,n#返回一个元组类型,对应三个输入
def printSummary(winA,winB):
n = winsA + winsB
print("竞技分析开始,共模拟{}场比赛".format(n))
print("选手A获胜{}场比赛,占比{:0.1%}".format(winsA,winsA/n))
print("选手B获胜{}场比赛,占比{:0.1%}".format(winsB,winsB/n))
#将simNGames分解为N次的单局比赛
def simNgame(n,probA,probB):#核心函数
winsA,winsB = 0,0
for i in rnage(n):
soreA,soreB = simOneGame(probA,probB)
if scoreA >scoreB:
winsA += 1
else:
winsB += 1
return winsA,winsB
def simOneGame(probA,probB):
scoreA,scoreB = 0,0
serving = "A"#A发球
while not gameOver(scoreA,scoreB):
if serving =="A":
if random() < probA:
scoreA += 1
else:
serving == "B"
else:
if random() < probB:
scoreB += 1
else:
serving == "A"
return scoreA,scoreB
def GameOver(a,b):
return a==15 or b==15
自左向右执行
确定事件的重要特征而忽略其他细节的过程称为抽象
#MatchAnalysis.py
from random import random
def printIntro():
print("这个程序模拟两个选手A和B的某种竞技比赛")
print("程序运行A和B的能力值(用0到1之间的小数表示)")
def getInputs():
a=eval(input("请输入选手A的能力值(0-1):"))
b=eval(input("请输入选手B的能力值(0-1):"))
n=eval(input("模拟比赛的场次:"))
return a,b,n
def simNGame(n,probA,probB):
winsA,winsB = 0,0
for i in range(n):
scoreA,scoreB = simOneGame(probA,probB)
if scoreA>scoreB:
winsA += 1
else:
winsB += 1
return winsA,winsB
def gameOver(a,b):
return a==15 or b==15
def simOneGame(probA,probB):
scoreA,scoreB = 0,0
serving = 'A'
while not gameOver(scoreA,scoreB):
if serving=="A":
if random()<probA:
scoreA += 1
else:
serving = "B"
else:
if random()<probB:
scoreB += 1
else:
serving = "A"
return scoreA,scoreB
def printSummary(winsA,winsB):
n = winsA+winsB
print("竞技分析开始,共模拟{}场比赛".format(n))
print("选手A获胜{}场比赛,占比{:0.1%}".format(winsA,winsA/n))
print("选手B获胜{}场比赛,占比{:0.1%}".format(winsB,winsB/n))
def main():
printIntro()
probA,probB,n = getInputs()
winsA,winsB = simNGame(n,probA,probB)
printSummary(winsA,winsB)
main()
'''
可以用IDLE调用,不知道为什么控制台输入有问题
'''
import MatchAnalysis
MatchAnalysis.gameOve(15,10)
True#或运算,单个为真即为真
MatchAnalysis.simOneGame(.45,0.5)
(9,15)
2.自顶向下和自底向上(函数)
自顶向下(设计):将一个总问题表达为若干个小问题组成的形式,使用同样方法进一步分解问题,直至可以用计算机简洁的解决
自低向上(执行):逐步组建复杂系统的有效测试方法,分单元测试,逐步组装(和递归类似)
python 程序设计思维:
- 计算思维:抽象计算过程和自动化执行
- 计算生态:竞争发展、相互依存、快速更迭
- 用户体验:进度展示、异常处理等
IPO、自顶向下、模块化、配置化、应用开发的四个步骤
3.第三方库安装
PyPI · The Python Package Index
1.pip 安装方法
安装:pip install <第三方库名>
安装到本地并更新:pip install -U <第三方库名>
卸载:pip uninstall <第三方库名>
下载但并不安装:pip download <第三方库名>
,文件一般以.whl 为扩展名
列出详细信息:pip show <第三方库名>
根据关键词搜索第三方库:pip search <关键词>
列出系统已安装的第三方库:pip list
2.集成安装方法
结合特定的 Python 开发工具,批量的安装一批库,eg:Anaconda,是 python 数据处理方面的 IDE
Anaconda | The Operating System for AI
3.文件安装方法
有的第三方库可下载,但不可以安装,因为它提供的并不是可执行文件,而是源代码,需编译后使用
视频提供的链接不可用,以后需要时再找吧
4.OS 库
这个库我们在一组词云绘制时使用过
os 库提供通用的、基本的操作系统交互功能
路径操作:os.path 子库,处理文件路径及信息(path=路径)
os.path 子库以 path 为入口,用于操作和处理文件路径
import os.path
import os.path as op
函数 | 描述 |
os.path.abspath(path) | 返回 path 在当前系统中的绝对路径 >>>os.path.abspath("file.txt") 'c:\\Users\\Tian Song\\python36-32\\file.txt' |
os.path.normpath(path) | 归一化 path 的表示形式,用 \\ 统一分隔路径 >>>os.path.normpath("D://PYE//file.txt") 'D:\\PYE\\file.txt' |
os.path.relpath(path) | 返回当前程序与文件之间的相对路径(relative path) >>>os.path.relpath("C://PYE//file.txt") '..\\..\\..\\..\\PYE\\file.txt' |
os.path.dirname(path) | 返回 path 中目录的名字 >>>os.path.dirname("D://PYE//file.txt") 'D://PYE' |
os.path.basename(path) | 返回 path 中最后的文件名 >>>os.path.basename("D://PYE//file.txt") 'file.txt' |
os.path.join(path,*paths) | 组合 path 与 pyths,返回一个路径字符串 >>>os.path.join("D:/","PYE/file.txt") 'D:/PYE/file.txt' |
os.path.exists(path) | 判断 path 对应文件或目录是否存在,返回 True 或 False >>>os.path.exists("D://PYE//file.txt") False |
os.path.isfile(path) | 判断 path 所对应是否为已存在文件,返回 True 或 False >>>os.path.isfile("D://PYE//file.txt") True |
os.path.isdir(path) | 判断 path 所对应是否为已存在目录,返回 True 或 False >>>os.path.isdir("D://PYE//file.txt") False |
os.path.getsize(path) | 返回 path 对应文件的大小,以字节为单位 >>>os.path.getsize("D://PYE//file.txt") 124583 |
os.path.getatime(path) | 返回 path 对应文件或目录上一次的访问时间 >>>os.path.getatime("D://PYE//file.txt") 1236571356371.9736218 |
os.path.getmtime(path) | 返回path 对应文件或目录上一次的修改时间 >>>os.path.getatime("D://PYE//file.txt") 1236571356371.9736218 |
os.path.getctime(path) | 返回path 对应文件或目录上一次的创建时间 >>time.ctime(os.path.getctime("D://PYE//file.txt")) 'Sum Feb 11 21:43:54 2024' |
a=access 访问 m=modify 修改 c=create 创建 |
进程管理:启动系统中其他程序
os.system(command)
'''
执行程序或命令command
在Windows系统中,返回值为cmd的调用返回信息
'''
#可通过增加参数来控制程序打开相应的文件
import os
os.syatem("C:\\windows\\System32\\mspaint.exe D:\\PYECourse\\grwordcloud.png")
#空格来分隔要打开的文件
#检查文件权限:首先,使用 ls -l 命令查看文件的权限设置。例如:
#ls -l 命令以长格式显示当前目录中的文件和目录的详细信息
ls -l /Users/chuji/Desktop/个人/计算机/Python/课内/2024年中央一号文件.txt
#修改文件权限:使用 chmod 命令为文件添加执行权限。例如:
chmod +x /Users/chuji/Desktop/个人/计算机/Python/课内/2024年中央一号文件.txt
#再次尝试执行
环境参数:获得系统软硬件信息等环境参数
函数 | 描述 |
os.chdir(path) | 修改当前程序操作的路径 >>>os.chdir("D:") |
os.getcwd() | 返回程序当前路径 >>>os.getcwd() 'D:\\' |
os.getlogin() | 获得当前系统登陆用户名称 >>>os.getlogin() "ZhangLiang" |
os.cpu_count() | 获得当前系统的 CPU 数量 >>>os.cpu_count() 8 |
os.urandom(n) | 获得 n 个字节长度的随机字符串,通常用于加解密运算 >>>os.urandom(10) b'\xef\xddK]\x7f\xa3\xdd\xf6\x16\xa6' 有些字符串不能有效的打印出来,故使用十六进制表示 |
5. 实例十四:第三方库安装脚本
mind:利用 pip 指令,实现对列表的调用,逐一安装
库名 | 用途 | pip 安装指令 |
Numpy | N 维数据表示和运算 | pip install numpy |
Matplotlib | 二维数据可视化 | pip install matplotlib |
PIL | 图像处理 | pip install pillow |
Scikit-Learn | 机器学习和数据挖掘 | pip install sklearn |
Requtsts(请求) | HTTP 协议访问及网络爬虫 | pip install requests |
jieba | 中文分词 | pip install jieba |
Beautiful Soup | HTML 和 XML 解析器 | pip install wheel |
Pyinstaller | 打包 Python 源文件为可执行文件 | pip install pyinstaller |
Django | Python 最流行的 Web 开发框架 | pip install diango |
Flask | 轻量级 Web 开发框架 | pip install flask |
WeRoBot | 微信机器人开发框架 | pip install werobot |
SymPy | 数学符号计算工具 | pip install sympy |
Pandas | 高效数据分析和计算 | pip install pandas |
Networkx | 复杂网络和图结构的建模和分析 | pip install networkx |
PyQt5 | 基于 Qt 的专业级 GUI 开发框架 | pip install pyqt5 |
PyOpenGl | 多平台 OpenGL 开发接口 | pip install pyopengl |
PyPDF2 | PDF 文件内容提取和处理 | pip install pypdf2 |
docopt | Python 命令行解析 | pip install docopt |
PyGame | 简单小游戏开发框架 | pip install pygame |
#BatchInstall.py
#函数os.system()能够启动操作系统中已有的程序并进行自动执行
import os
libs = {"numpy","matplotlib","pillow","sklearn","requests","jieba","beautifulsoup4","wheel","networkx",\
"sympy","pyinstaller","djando","flask","werobot","pyqt5","pandas","pyopengl","pypdf2","docopt","pygame"}
try:
for lib in libs:
print("开始安装{}".format(lib).center(20,'-'))
os.system("pip install "+lib)
print("全部安装成功".center(20,'-'))
except:
print("未能全部安装成功".center(20,'-'))
自动化脚本:编写各种自动化运行程序的脚本,调用已有程序
扩张应用:安装更多第三方库,增加配置文件,变成引擎加配置的模式
扩展异常检测:捕获更多异常类型,程序更稳定友好
6.Python 之蝉
#IDLE输入import this
import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
7.Pillow 库和图像处理
Pillow 是 PIL 库的一个扩展
Pillow 库是 Python 图像处理重要的第三方库,包含丰富的像素、色彩操作,以及图像归档和批量处理
pip install -U pillow
Image 是 Pillow 最重要的类,它代表一张图片
在 pillow 中,任何一个图像文件都可以用 Image 对象表示
Image 类图像的读取和创建方法
属性 | 描述 |
Image.open(filename) | 根据参数加载图像文件 |
Image.new(mode,size,color) | 根据给定参数创建一个新的图像 |
Image.open(StringIO.StringIO(buffer)) | 从字符串中获取图像 |
Image.frombytes(mode,size,data) | 根据像素点 data 创建图像 |
Image.verify() | 对图像文件的完整性进行检查,返回异常 |
from PIL import Image
im = Image.open("霍兰德人格分析雷达图.png")
im.show()
im.close()
print(img.format,img.size,img.mode)
Image 类的常用属性
属性 | 描述 |
Image.format | 标识图像格式或来源,如果图像不是从文件中读取,值为 None |
Image.mode | 图像的色彩模式,"L"为灰度图像、"RGB"为真彩色图像、"CMYK"为出版图像 |
Image.size | 图像宽度和高度,单位是像素(px),返回值是二元元组 |
Image.palette | 调色板属性,返回一个 ImagePalette 类型 |
Image 还能读取序列类图像文件,如 GIF\FLI\FLC\TIFF
方法 | 描述 |
Image.seek(frame) | 跳转并返回图像中的指定帧 |
Image.tell() | 返回当前帧的序号 |
from PIL import Image
im = Image.open("动态地球.gif")
try:
im.save("picfram{:02d}.png".format(im.tell()))
while True:
im.seek(im.tell()+1)
im.seve("picfram{:02d}.png".format(im.tell()))
except:
print("处理结束!")
Image 类的图像转换和保存方法
方法 | 描述 |
Image.save(filename,format) | 将图像保存为 filename 文件名,format 是图片格式 |
Image.convert(mode) | 使用不同参数,将图像转换为新的模式 |
Image.thumbnail(size) | 创建图像的缩略图,size 是缩略图尺寸的二元元组 |
from PIL import Image
im = Image.open("霍兰德人格分析雷达图.png")
im.thumbnail((128,128))#size是缩略图的二元元组
im.save("霍兰德人格分析雷达图缩略图.png",'png')
Image 类的图像缩放和旋转方法
方法 | 描述 |
Image.resize(size) | 按 size 大小调整图像,生成副本 |
Image.rotate(angle) | 按 angle 角度逆时针旋转图像,生成副本 |
Image 类的图像像素和通道处理方法
方法 | 描述 |
Image.point(func) | 根据函数 func()的功能对每个元素元素进行计算,返回图像副本 |
Image.split() | 提取 RGB 图像的每个颜色通道,返回图像副本 |
Image.merge(mode,bands) | 合并通道,其中,mode 表示颜色,bands 表示新的色彩通道 |
Image.blend(im1,im2,alpha) | 将两幅图片 im1 和 im2 按照如下公式插值后生成新的图像: im1*(1.0-alpha)+im2*alpha |
from PIL import Image
im = Image.open("夜色下的鸟巢.jpeg")
r,g,b = im.split()
om = Image.merge("RGB",(b,g,r))
om.save("夜色下的鸟巢颜色反转.jpeg")
from PIL import Image
im = Image.open("夜色下的鸟巢.jpeg")
r,g,b = im.split()
newg = g.point(lambda i:i*0.9)#根据函数 func()的功能对每个元素元素进行计算,返回图像副本
newb = b.point(lambda i:i < 100)
om = Image.merge(im.mode,(r,newg,newb))#合并通道
om.save("夜色下的鸟巢光线消除.jpeg")
PIL 库中的 ImageFilter 类和 ImageEnhance 类提供了过滤图像和增强图像的方法
ImageFilter 类的预定义过滤方法
方法 | 描述 |
ImageFilter.BLUR | 图像的模糊效果 |
ImageFilter.CONTOUR | 图像的轮廓效果 |
ImageFilter.DETAIL | 图像的细节效果 |
ImageFilter.EDGE_ENHANCE | 图像的边界加强效果 |
ImageFilter.EDGE_ENHANCE_MORE | 图像的阈值边界加强效果 |
ImageFilter.EMBOSS | 图形的浮雕效果 |
ImageFilter.FIND_EDGES | 图形的边界效果 |
ImageFilter.SMOOTH | 图形的平滑效果 |
ImageFilter.SMOOTH_MORE | 图像的阈值平滑效果 |
ImageFilter.SHARPEN | 图像的锐化效果 |
利用 Image 类的 filter() 方法可以使用 ImageFilter 类
Image.filter(ImageFilter.fuction)
from PIL import Image
from PIL import ImageFilter
im = Image.open("夜色下的鸟巢.jpeg")
om = im.filter(ImageFilter.CONTOUR)
om.save("夜色下的鸟巢轮廓获取.jpeg")
ImageEnhance 类的图像增强的滤镜方法
方法 | 描述 |
ImageEnhance.enhance(factor) | 对选择属性的数值增强 factor 倍 |
ImageEnhance.Color(im) | 调整图像的颜色平衡 |
ImageEnhance.Contrast(im) | 调整图像的对比度 |
ImageEnhance.Brightness(im) | 调整图像的宽度 |
ImangeEnhance.Sharpness(im) | 调整图像锐度 |
from PIL import Image
from PIL import ImageEnhance
im = Image.open("夜色下的鸟巢.jpeg")
om = ImageEnhance.Contrast(im)
om.enhance(20).save("夜色下的鸟巢锐化版.jpeg")
8.作业
pip install you-get -i Simple Index
-i 指的是指定包的安装源,如果在开头就永久配置了从源,这里就可以不用再次配置
GitHub - soimort/you-get: :arrow_double_down: Dumb downloader that scrapes the web
from PIL import Image
from PIL import ImageFilter
im = Image.open("夜色下的鸟巢.jpeg")
om = im.filter(ImageFilter.EMBOSS)
om.save("夜色下的鸟巢浮雕效果.jpeg")
from PIL import Image
from PIL import ImageFilter
im = Image.open("夜色下的鸟巢.jpeg")
om = im.filter(ImageFilter.BLUR)
om.save("夜色下的鸟巢模糊效果.jpeg")
第九周:对象式编程
1.万物皆对象
对象是一种相对独立的存在,类是描述某一类对象的统称,对象是类的实例
类由属性和方法来描述,对应变量和函数
类 = {属性} + {方法}
如果类是<C>,其派生的对象是<O>,属性是<A>,方法是<B>,那么访问方法结构如下:
属性访问:<O>.<A>
方法访问:<O>.<B>()
对象是类的实例化结果,每次实例化会创建一个对象
Python 语言所有数据类型和语法结构都是类,每个变量都是对象
txt = "Hello,Python!"
txt_upper = txt.upper()
print(txt_upper)
ends_with_python = txt_upper.endswith("PYTHON!")#检查字符串末尾是否包含特定字符串
print(ends_with_python)
'''
HELLO,PYTHON!
True
'''
面向对象程序设计一种编程思想,重点在于建立面向对象的高阶抽象
面向对象程序设计有三大基本特征:封装、继承、多态
对象构造法是一种通过构建对象及对象间交互关系解决问题的计算方法
对象构造法要求对象具备三个特征:独立性、功能性、交互性
对象构造法定义对象在软件系统中的表现和相互作用
2.类的创建
类在创建时需要定义构造函数、属性和方法,在使用时通常需要实例化
Python 语言通过保留字 class 定义一个类
clsaa <类名>:#类名建议采用首字母大写的单词组合
<语句块>
clsaa DemoClass:
pass
class <类名>:
def__int__(self,<参数列表>):#self表示类实例自身,在类内部
<语句块>
<语句块>
#构造函数,固定采用__int__()作为名字,由双下划线开始和结束
#构造函数的作用:当用类生成对象时,接收参数,执行构造函数的内容,完成初始操作,实现一次"实例化"
<对象名> = <类名>([<参数>])
#实例化后的对象,可通过某种方法访问方法和属性
<对象名>.<属性名>
<对象名>.<方法名>
#例如定义一个包含构造函数的DemoClass类、
class DemoClass:
def __init__(self,name):
print(name)
dc1 = DemoClass("小王")
dc2 = DemoClass("小李")
小王
小李
3.属性和方法
Python 类的属性总体包括两种:类属性和实例属性
类属性是所有实例共享,实例属性由实例名独享
class <类名>:
<类属性变量名> = <类属性初值>
def __int__(self,<参数列表>)
self.<实例属性变量名> = <实例属性初值>
class DemoClass:
count = 0
def __init__(self,name,age):
self.name = name
self.age = age
DemoClass.count += 1
dc1 = DemoClass("小王",23)
dc2 = DemoClass("小李",21)
print("总数:",DemoClass.count)
print(dc1.name,dc2.name)
总数: 2
小王 小李
属性根据名称前是否包含两个下划线(__)分为:公开属性和私有属性
防止外部代码直接访问对象内部的状态,对于私有属性,直接在属性名前加上 __,如 __count.
设定为私有属性后,不能通过<对象名>.<实例属性名>或<类名>.<类属性>方式直接访问
class DemoClass:
__count = 0
def __init__(self,name,age):
self.__name = name
self.__age = age
DemoClass.__count += 1
dc1 = DemoClass("小王",23)
dc2 = DemoClass("小李",21)
print("总数:",DemoClass.__count)
print(dc1.__name,dc2.__name)
Traceback (most recent call last):
File "/Users/chuji/Desktop/个人/计算机/Python/课内/ts1.py", line 10, in <module>
print("总数:",DemoClass.__count)
^^^^^^^^^^^^^^^^^
AttributeError: type object 'DemoClass' has no attribute '__count'
Python 类的方法主要有 3 种:类方法、实例方法、保留方法
类方法是所有实例对象可以共享使用的方法;实例方法是实例对象使用的方法,由实例对象独享
class<类名>:
@classmethod#装饰器,标记符
def<方法名>(cls,<参数列表>)#至少包含一个参数,表示类对象
#<类名>.<方法名>(<参数列表>)或<对象名>.<方法名>(<参数列表>)
class DemoClass:
count = 0
def __init__(self,name):
self.name = name
DemoClass.count += 1
@classmethod
def getChrCount(cls):
s = "零一二三四五六七八九十多"
idx = cls.count if cls.count<10 else 10
return s[idx]
dc1 = DemoClass("小王")
dc2 = DemoClass("小李")
print(dc1.getChrCount())
print(DemoClass.getChrCount())
二
二
实例方法格式定义
class<类名>:
def<方法名>(self,<参数列表>)#至少包含一个参数self,用于索引实例属性
#使用:<对象名>.<方法名>(<参数列表>)
class DemoClass:
def __init__(self,name):
self.name = name
def lucky(self):
s = 0
for c in self.name:
s += ord(c)%100
return s
dc1 = DemoClass("小王")
dc2 = DemoClass("小李")
print(dc1.name,"的幸运数字是:",dc1.lucky())
print(dc2.name,"的幸运数字是:",dc2.lucky())
小王 的幸运数字是: 146
小李 的幸运数字是: 113
保留方法
class<类名>:
def <保留方法名>(<参数列表>)
……
class DemoClass:
count = 0
def __init__(self,name):
self.name = name
DemoClass.count += 1
def __len__(self):
return len(self.name)
dc1 = DemoClass("小王")
dc2 = DemoClass("小李")
print(len(dc1))
print(len(dc2))
2
2
4.类的实例化
类的实例化由构造函数和析构函数组成
class Dog:
"""首字母大写创建类,括号内是空的,因为我们要从空白创建这个类"""
"""一次模拟小狗的简单尝试"""
"""def后定义的我们称为方法"""
def __init__(self,name,age):#每当根据Dog类创建新实例时,Python都会自动运行它
"""初始化属性name和age"""
"""三个形参,self必备并位于开头"""
self.name = name
#引用name属性
self.age = age
"""以self为前缀的变量都可供类中所有方法使用,我们还可以通过类的任何实例来访问这些变量"""
"""self.name = name获取存储在形参name中的值,并将其存储在变量name中,然后该变量被关联到当前创建的实例"""
"""这样可通过实例访问的变量称为属性"""
def sit(self):
"""模拟小狗被命令时蹲下"""
print(self.name.title()+ " is now sitting.")
def roll_over(self):
"""模拟小狗被命令时打滚"""
print(self.name.title()+ " rolled over")
"""访问属性同时创建一个实例my_dog"""
my_dog = Dog('willie',6)
"""创建一个your_dog实例"""
ypur_dog = Dog('lucy',3)
"""调用Dog类中的方法"""
my_dog.sit()
my_dog.roll_over()
print("My dog's name is " + my_dog.name.title() + '.')
#访问属性:my_dog.name先找到my_dog的实例,再查找与此实例相关的属性name
print("My dog's is " + str(my_dog.age) + " years old.")
"""
Willie is now sitting.
Willie rolled over
My dog's name is Willie.
My dog's is 6 years old.
"""
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self,make,model,year):
"""初始化描述汽车的属性"""
"""类中的每个属性必须有默认值"""
self.make = make
self.model = model
self.year = year
#添加一个新的属性
self.odometer_reading = 0
def get_descriptive_name(self):
"""返回简洁的描述性信息"""
long_name = str(self.year)+' '+self.make+' '+self.model
return long_name.title()
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print("This car has "+str(self.odometer_reading)+" miles on it.")
def update_odometer(self,mileage):
"""将里程表读数设置为指定的值"""
"""并禁止任何人将里程数往回调"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self,miles):
"""将里程表读数增加指定的量"""
self.odometer_reading += miles
my_new_car = Car('audi','a4',2016)
print(my_new_car.get_descriptive_name())
#直接修改属性的值
# my_new_car.odometer_reading = 23
#通过方法修改属性的值
my_new_car.update_odometer(23500)
my_new_car.read_odometer()
#通过方法对属性的值进行递增
my_new_car.increment_odometer(100)
my_new_car.read_odometer()
"""
2016 Audi A4
This car has 23500 miles on it.
This car has 23600 miles on it.
"""
实例化包括对象创建和对象删除,前者由构造函数负责,后者由析构函数负责
class DemoClass:
def __init__(self,name):
self.name = name
def __del__(self):
print("再见",self.name)
dc1 = DemoClass("小王")
del dcl
print(dcl.name)
Traceback (most recent call last):
File "/Users/chuji/Desktop/个人/计算机/Python/课内/ts1.py", line 9, in <module>
print(dc1.name)
^^^
NameError: name 'dc1' is not defined
再见 小王
将实例用作属性
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self,make,model,year):
"""初始化描述汽车的属性"""
"""类中的每个属性必须有默认值"""
self.make = make
self.model = model
self.year = year
#添加一个新的属性
self.odometer_reading = 0
def get_descriptive_name(self):
"""返回简洁的描述性信息"""
long_name = str(self.year)+' '+self.make+' '+self.model
return long_name.title()
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print("This car has "+str(self.odometer_reading)+" miles on it.")
def update_odometer(self,mileage):
"""将里程表读数设置为指定的值"""
"""并禁止任何人将里程数往回调"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self,miles):
"""将里程表读数增加指定的量"""
self.odometer_reading += miles
class Battery():
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self,battery_size=70):
"""初始化电瓶的属性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一条描述电瓶容量的消息"""
print("This car has a "+str(self.battery_size)+"-KWh battery.")
def get_range(self):
"""打印一条消息,指出电瓶的续航里程"""
if self.battery_size == 70:
range = 240
elif self.batter_size ==85:
range = 270
message = "This car can go approximately "+str(range)
message += " miles on a full change."
print(message)
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self,make,modle,year):
"""
初始化父类的属性,再初始化电动汽车的特有属性
"""
super().__init__(make,modle,year)
self.battery = Battery()#添加一个新属性,让Python创建一个新的Battery实例
my_tesla = ElectricCar('tesla','modle s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
"""
2016 Tesla Modle S
This car has a 70-KWh battery.
This car can go approximately 240 miles on a full change.
"""
5.实例十五:简单图书借阅系统
#LibraryMangeSystem.py
class Book:#Book类的属性包括id,title,suthor,is_borrowed;方法包括borrow,return_book,statue
def __init__(self,idx,title,author):
self.id = idx
self.title = title
self.author = author
self.is_borrowed = False
def borrow(self):
if not self.is_borrowed:
self.is_borrowed = True
return True
else:
return False
def return_book(self):
if self.is_borrowed:
self.is_borrowed = False
return True
else:
return False
def status(self):
return "可借阅" if not self.is_borrowed else "已借阅"
class Library:#属性包括books;方法包括add_book(book),borrow_book(book_id),return_book(book_id),list_books()
def __init__(self):
self.books = {}
def add_book(self,book):
self.books[book.id] = book
def borrow_book(self,book_id):
if book_id in self.books and self.books[book_id].borrow():
print("图书{}借阅成功".format(self.books[book_id].title))
else:
print("图书{}无法借阅".format(self.books[book_id].title))
def return_book(self,book_id):
if book_id in self.books and self.books[book_id].return_book():
print("图书{}归还成功".format(self.books[book_id].title))
else:
print("图书归还出错")
def list_books(self):
for book in self.books.values():
print("ID:{:4},书名{:20},作者:{:15},状态:{:10}".format(book.id,book.title,book.author,book.status()))
library = Library()
library.add_book(Book(1,"The Littel Prince","Antoine"))
library.add_book(Book(2,"1984","George Orwell"))
library.list_books()
library.borrow_book(1)
library.list_books()
library.return_book(1)
library.list_books()
6.类的继承
继承是面向对象程序设计的精髓,是代码复用的高级抽象
继承是能够完全拥有一个类的属性和方法,并可自由扩展的过程
一个子类可以继承多个父亲,称为多继承;Python 最基础的类是 object 类。
扩展:Python 对象的三个要素:标识、类型、值
派生类可以直接使用基类的属性和方法,通常在定义时声明继承关系
class <类名>(<基类名>):
def__init__(self,<参数列表>)
<语句块>
...
class DemoClass:
count = 0
def __init__ (self,name):
self.name = name
DemoClass.count += 1
def getName(self):
return self.name
class HumanNameClass(DemoClass):
def printName(self):
return str(DemoClass.count) + self.name + "同志"
dc1 = HumanNameClass("小王")
print(dc1.getName())
print(dc1.printName())
'''
小王
1小王同志
HumanNameClass继承了DemoClass
'''
与继承关系判断相关的 Python 标准函数(只能基类的公开属性和方法)
函数 | 描述 |
isinstance(obj,cls) | 判断对象 obj 是否是类 cls 的实例或子类实例,返回 True/False |
issubclass(cls1,cls2) | 判断类 cls1 是否是类 cls2 的子类,返回 True/False |
重载(override)是派生类对基类属性或方法的再定义
步骤一:优先使用派生类重定义的属性和方法
步骤二:若步骤一未命中,寻找基类的属性和方法
步骤三:若步骤一和步骤二均未命中,寻找超类的属性和方法
class DemoClass:
count = 0
def __init__(self,name):
self.name = name
DemoClass.count += 1
class HumanNameClass(DemoClass):
count = 99
def __init__(self,name):
self.name = name
HumanNameClass.count -= 1
def printCount(self):
return str(HumanNameClass.count) + self.name
dc1 = HumanNameClass("小王")
print(dc1.printCount())
'''
98小王
'''
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self,make,model,year):
"""初始化描述汽车的属性"""
"""类中的每个属性必须有默认值"""
self.make = make
self.model = model
self.year = year
#添加一个新的属性
self.odometer_reading = 0
def get_descriptive_name(self):
"""返回简洁的描述性信息"""
long_name = str(self.year)+' '+self.make+' '+self.model
return long_name.title()
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print("This car has "+str(self.odometer_reading)+" miles on it.")
def update_odometer(self,mileage):
"""将里程表读数设置为指定的值"""
"""并禁止任何人将里程数往回调"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self,miles):
"""将里程表读数增加指定的量"""
self.odometer_reading += miles
"""类的继承"""
"""创建子类时,父类必须包含在当前文件中,且置前"""
class ElectricCar(Car):#括号中指定父类的名称
"""电动汽车的独特之处"""
"""初始化父类的属性,再初始化电动汽车的特有属性"""
def __init__(self,make,model,year):
"""初始化父类属性"""
super().__init__(make,model,year)#超类,将子类与父类关联起来
self.battery_size = 70
def describe_battery(self):
"""打印一条描述电瓶容量的信息"""
print("This car has a "+str(self.battery_size)+"-KWh battery.")
"""重写父类方法,假设Car类中有fill_gas_tank的方法"""
def fill_gas_tank(self):
"""电动汽车没有油箱"""
print("This car doesn't need a gas tank!")
#如此一来,Python只会关注子类中的方法
my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
my_tesla.fill_gas_tank()
# my_new_car = Car('audi','a4',2016)
# print(my_new_car.get_descriptive_name())
# #直接修改属性的值
# # my_new_car.odometer_reading = 23
# #通过方法修改属性的值
# my_new_car.update_odometer(23500)
# my_new_car.read_odometer()
# #通过方法对属性的值进行递增
# my_new_car.increment_odometer(100)
# my_new_car.read_odometer()
"""
2016 Tesla Model S
This car has a 70-KWh battery.
This car doesn't need a gas tank!
"""
7.类的运算
Python 运算符包括算术、比较、逻辑、位、赋值、特殊、函数等运算类别
操作数 运算符 操作数
算术运算符:+ - * / // % **
比较运算符:== != < > <= >=
逻辑运算符:and or not
位运算符:& | ^ ~ << >>
赋值运算符:= += -=
特殊运算符:is is not in not in
函数操作符:一些用于计算的 Python 标准函数
Python 将运算符关联保留函数,自定义类可以重载运算符功能
二元算术运算符的保留方法:
保留方法 | 操作符操作 | 描述 |
.__neg__(self) | -obj | 定义对象取负的操作逻辑 |
.__pos__(self) | +obj | 定义对象取正的操作逻辑 |
.__abs__(self) | abs(obj) | 定义对象绝对值的运算逻辑 |
.__invert__(self) | ~obj | 定义对象取反的操作逻辑 |
.__add__(self,other) | obj + other | 定义两个对象加厚的运算逻辑 |
.__sub__(self,other) | obj - other | 定义两个对象减法的运算逻辑 |
.__mul__(self,other) | obj + other | 定义两个对象乘法的运算逻辑 |
.__truediv__(self,other) | obj / other | 定义两个对象除法的运算逻辑 |
.__floordiv__(self,other) | obj // other | 定义两个对象整数除的运算逻辑 |
.__mod__(self,other) | obj %other | 定义两个对象模的运算逻辑 |
.__divmod__(self,other) | divmod(obj,other) | 定义两个对象除模的运算逻辑 |
.__pow__(self,other) | obj**other | 定义对象幂的运算逻辑 |
.__lshift__(self,other) | obj<<other | 定义对象左移的运算逻辑 |
.__rshift__(self,other) | obj>>other | 定义对象右移的运算逻辑 |
.__and__(self,other) | obj&other | 定义两个对象位与的运算逻辑 |
.__xor__(self,other) | obj^other | 定义两个对象位异或的运算逻辑 |
.__or__(self,other) | obj | other | 定义两个对象位或的运算逻辑 |
class NewList(list):
def __add__(self, other):
result = []
for i in range(len(self)):
try:
result.append(self[i] + other[i])
except:
result.append(self[i])
return result
ls = NewList([1,2,3,4,5,6])
lt = NewList([1,2,3,4])
print(ls+lt)
'''
[2, 4, 6, 8, 5, 6]
'''
比较运算符的保留方法
保留方法 | 操作符操作 | 描述 |
.__It__(self,other) | obj < other | 两个对象的比较操作 |
.__le__(self,other) | obj <= other | |
.__eq__(self,other) | obj == other | |
.__ne__(self,other) | obj != other | |
.__gt__(self,other) | obj > other | |
.__ge__(self,other) | obj >= other |
成员运算符的保留方法
保留方法 | 操作符操作 | 描述 |
.__getitem__(self,key) | obj[k] | 定义获取对象中序号 k 元素的运算逻辑,k 为整数 |
.__setitem__(self,key,v) | obj[k] = v | 定义赋值对象中序号 k 元素的运算逻辑 |
.__delitem__(self,key) | del obj[k] | 定义删除对象中序号 k 元素的运算逻辑 |
.__reversed__(self) | obj.reversed() | 定义对象逆序的运算逻辑 |
.__contains__(self,item) | item in obj | 定义 in 操作符对应的运算逻辑 |
其他常用运算符的保留方法
保留方法 | 操作符操作 | 描述 |
.__int__(self) | int(obj) | 定义对象整数转换的运算逻辑 |
.__float__(self) | float(obj) | 定义对象浮点数转换的运算逻辑 |
.__complex__(self) | complex(obj) | 定义对象复数转换的运算逻辑 |
.__repr__(self) | repr(obj) | 定义对象可打印字符串的运算逻辑 |
.__str__(self) | str(obj) | 定义对象字符串转换操作的运算逻辑 |
.__len__(self) | len(obj) | 定义对象长度操作的运算逻辑 |
.__round__(self) | round(obj) | 定义对象四舍五入的运算逻辑 |
.__bytes__(self) | bytes(obj) | 定义对象字节串转换的运算逻辑 |
.__bool__() | bool(obj) | 定义对象布尔运算的运算逻辑 |
.__format__(self,spec) | obj.format() | 定义对象格式化输出的运算逻辑 |
8.实例十六:图像的四则运算
# ImageOperations.py
import numpy as np
from PIL import Image
#总体定义了ImageObject类
class ImageObject:
def __init__(self, path=""):
self.path = path
try:
self.data = np.array(Image.open(path))
except:
self.data = None
def __add__(self, other):
image = ImageObject()
try:
image.data = np.mod(self.data + other.data, 255)
except:
image.data = self.data
return image
def __sub__(self, other):
image = ImageObject()
try:
image.data = np.mod(self.data - other.data, 255)
except:
image.data = self.data
return image
def __mul__(self, factor):
image = ImageObject()
try:
image.data = np.mod(self.data * factor, 255)
except:
image.data = self.data
return image
def __truediv__(self, factor):
image = ImageObject()
try:
image.data = np.mod(self.data // factor, 255)
except:
image.data = self.data
return image
def saveImage(self, path):
try:
im = Image.fromarray(self.data)
im.save(path)
return True
except:
return False
a = ImageObject("earth.jpg")
b = ImageObject("gray.png")
(a + b).saveImage("result_add.png")
True
(a - b).saveImage("result_sub.png")
True
(a * 2).saveImage("result_mul.png")
True
(a / 2).saveImage("result_div.png")
True
9.模块
模块和程序包是组织和重用代码的重要结构
模块封装:模块是一个命名空间,对应单独的.py 文件
module_var = 1
class module_class:
mc_classattr = 1
def __init__(self,mc_instattr = 1):
self.mc_classattr = mc_instattr
def mc_func(self):
return "Method with a count of {}".format(self.mc_classattr)
def module_func():
print("Module Function")
print("Module Statement")
>>>import m
Module Statement
>>>print(m.module_var)
1
>>>mc = m.module_class(99)
>>>print(mc.mc_func())
Method with a count of 99
10.程序包
程序包通过 __init__.py 文件实现命名空间的组织,本质上属于目录
程序包包含了多重命名空间,import 可以引入任何一级命名空间
import pkg.pkg1
import pkg.pkg2.m1
程序包在组织程序逻辑上十分有用,可将所有有关的类和函数放在一个模版中
game_engine/
| __init__.py
| graphics.py
| audio.py
#当需要时可分别导入这些模块
from game_engine import graphics
from game_engine import audio
11.从模版中导入类
from <文件名> import <类名>
"""一个可用于表示汽车的类"""
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self,make,model,year):
"""初始化描述汽车的属性"""
"""类中的每个属性必须有默认值"""
self.make = make
self.model = model
self.year = year
#添加一个新的属性
self.odometer_reading = 0
def get_descriptive_name(self):
"""返回简洁的描述性信息"""
long_name = str(self.year)+' '+self.make+' '+self.model
return long_name.title()
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print("This car has "+str(self.odometer_reading)+" miles on it.")
def update_odometer(self,mileage):
"""将里程表读数设置为指定的值"""
"""并禁止任何人将里程数往回调"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self,miles):
"""将里程表读数增加指定的量"""
self.odometer_reading += miles
class Battery():
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self,battery_size=70):
"""初始化电瓶的属性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一条描述电瓶容量的消息"""
print("This car has a "+str(self.battery_size)+"-KWh battery.")
def get_range(self):
"""打印一条消息,指出电瓶的续航里程"""
if self.battery_size == 70:
range = 240
elif self.batter_size ==85:
range = 270
message = "This car can go approximately "+str(range)
message += " miles on a full change."
print(message)
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self,make,modle,year):
"""
初始化父类的属性,再初始化电动汽车的特有属性
"""
super().__init__(make,modle,year)
self.battery = Battery()#添加一个新属性,让Python创建一个新的Battery实例
from car import Car,ElectricCar
my_tesla = ElectricCar('tesla','modle s',2024)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
12.字典兼具列表的属性
"""从模版collections中导入OrderedDict类"""
"""
之所以用这个模版,是因为普通的遍历字典,是无序的,Python只关注对应关系
而这种方式保证字典兼具列表的属性
"""
from collections import OrderedDict
favorite_languages = OrderedDict()#创建一个实例
favorite_languages['jen'] = 'python'
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'python'
for name,language in favorite_languages.items():
print(name.title()+"'s favorite language is "+language.title()+'.')
第十周:网络爬虫和信息提取
1.简介
网络爬虫,Web Spider 或 Web Crawler,是一种自动访问 Web 页面提交数据的自动化程序
网络爬虫应用可以采用 Requests 和 Beautiful Soup 库
Sitemap: https://pypi.org/sitemap.xml
网站地图: https://pypi.org/sitemap.xml
User-agent: *
Disallow: /simple/
Disallow: /packages/
Disallow: /_includes/
Disallow: /pypi/*/json
Disallow: /pypi/*/*/json
Disallow: /pypi*?
Disallow: /search*
用户代理: *
不允许:/simple/
不允许:/packages/
不允许:/_includes/
不允许:/pypi/*/json
不允许:/pypi/*/*/json
不允许:/pypi*?
禁止:/search*
2.Request 库
Request 库是一个简洁且简单的处理 HTTP 请求的第三方库
Request 库总体根据 HTTP 协议处理方式设计其功能函数
HTTP:万维网访问的基本协议
Request 库的网页请求函数:
函数 | 描述 |
get(url [, timeout=n]) | 对应于 HTTP 的 GET 方式,是获取网页最常用的方法,可以增强 timeout=n 参数,设定每次请求时间为 n 秒 |
post(url, data = {'key':'value'}) | 对应于 HTTP 的 POST 方式,其中,字典用于传递客户数据 |
delete(url) | 对应 HTTP 的 DELETE 方式 |
head(url) | 对应 HTTP 的 HEAD 方式 |
options(url) | 对应 HTTP 的 OPTIONS 方式 |
put(url, data = {'key':'value'}) | 对应 HTTP 的 PUT 方式,其中,字典用于传递客户数据 |
Request 库的 get()函数用于访问网页,返回内容保存为 Request 对象
import request
r = request.get("http://www.baidu.com")#使用get方法打开百度链接
type(r)#返回Response对象
<class 'requests.models.Response'>
Request 对象的属性
属性 | 描述 |
status_code | HTTP 请求的返回状态,整数,200 表示链接成功,404 表示失败 |
text | HTTP 响应内容的字符串形式,即 url 对应的页面内容 |
encoding | HTTP 响应内容的编码形式 |
content | HTTP 响应内容的二进制形式 |
>>>import requests
>>>r = requests.get("heep://www.baidu.com")
>>>r.status_code#返回状态
200
>>>r.text#观察返回的内容,中文字符是否能正常显示
...
>>>r.encoding#默认编码方式不对,所以中文为乱码
'ISO-8859-1'
>>>r.encoding = 'utf-8'#更改编码方式
>>>r.text#更改成功后,中文即可正常显示
Request 对象的方法
方法 | 描述 |
json() | 如果 HTTP 响应内容包含 JSON 格式数据,则该解析 JSON 数据 |
raise_for_status() | 如果不是 200,则产生异常 [ 之后就可以用 try-except 捕获异常 ] |
受限于网络条件,使用 Request 库功能可能会触发异常:ConnectionError HTTPError Timeout……
import requests
def getHTMLText(url):
try:
r = requests.get(url,timeout=30)#url是地址,timeout为请求超时时间
r.raise_for_status()#如果状态不是200,引发异常
r.encoding='utf-8'
return r.text
except:
return ""
url = "http://www.baidu.com"
print(getHTMLText(url))
扩展(HTTP 的 GET 和 POST):
定义了客户端与服务器交互的不同方法,一般而言,GET 可以根据某链接获得内容,POST 用于发送内容。然而,GET 也可以向链接提交内容,区别如下:
- GET 方式可以通过 URL 提交数据,待提交数据是 URL 的一部分;采用 POST 方式。待提交数据放置在 HTML HEADER 内
- GET 方式提交的数据最多不超过 1024 字节,POST 没有对提交内容的长度限制
- 安全性问题。使用 GET 时参数会显示在 URL 中,而 POST 不会。所以,如果这些数据是非敏感数据,那么使用 GET;如果提交数据是敏感数据,建议采用 POST 方式
3.实例十七:关键词搜索爬虫
向搜索引擎自动提交关键词并查询,是个技术活
<div ... data-tools= '{"title":"...","url":"..."}'>...</div>
'''
利用beautifulsoup4库找到data-tools属性值,提取带有title的字符串
data-tool内部由{}形成的数据是典型的JSON格式,可用json库将其转换为字典
'''
扩展(CAPTCHA 验证码):
"全自动区分计算机和人类的图灵测试"
4.HTML 标识和 Web 页面
HTML(hypertext markup language)是超文本标记语言,它是专门为 Web 页面组织内容而创建的语言
HTML 语言本质上是键值对的标识,采用<key>value</key>方式表达键 key 对应的值 value
<!DOCTYPE HTML>
<html>
<body>
<meta charset=gb2312>
<h2 align=center>2024 年 1 月部分大中城市新建商品住宅销售价格指数 </h2>
<table border='1' align="center" width=70%>
<tr bgcolor='orange'>
<th width="40%">城市</th>
<th width="30%">环比</th>
<th width="30%">同比</th>
</tr>
<tr><td align="center">北京</td><td align="center">99.9</td><td align="center">101.3</td></tr>
<tr><td align="center">上海</td><td align="center">100.4</td><td align="center">104.2</td></tr>
<tr><td align="center">广州</td><td align="center">99.2</td><td align="center">96.4</td></tr>
<tr><td align="center">深圳</td><td align="center">99.3</td><td align="center">95.9</td></tr>
<tr><td align="center">沈阳</td><td align="center">99.4</td><td align="center">98.6</td></tr>
</table>
</body>
</html>
解释:HTML 语法中,由<table>表格内容</table>形成的是一个表格,<tr>表格的一行</tr>表示表格的一行。<tr>标签中<th>表头列</th>表示表格表头的一列;<td>内容列</td>表示表格行中的一列。
扩展(Web 前端开发):
Web 前端指开发基于 HTML 的展示效果,经历静态网页制作、动态网页制作和 Web2.0 开发等几个阶段。开发语言主要是 HTML5、CSS、JavaScript
#CSV2HTML.py
seg1 = '''
<!DOCTYPE HTML>\n<html>\n<body>\n<meta charset=gb2312>
<h2 align=center>2024 年 1 月部分大中城市新建商品住宅销售价格指数 </h2>
<table border='1' align="center" width=70%>
<tr bgcolor='orange'>\n '''
seg2 = "</tr>\n"
seg3 = "</table>\n</body>\n</html>"
def fill_data(locls):
seg = '<tr><td align="center">{}</td><td align="center">' + \
'{}</td><td align="center">{}</td></tr>\n'
seg = seg.format(*locls)
return seg
with open("price202401.csv", encoding='utf-8') as fr:
ls = []#将CSV文件读入列表ls
for line in fr:
line = line.replace("\n","")#格式化字符串方法将ls中内容写入HMTL文件
ls.append(line.split(","))
with open("price202401.html", "w",encoding='utf-8') as fw:
fw.write(seg1)
seg = '<th width="40%">{}</th>\n<th width="30%">{}</th>\n'+\
'<th width="30%">{}</th>\n'
fw.write(seg.format(*ls[0]))
fw.write(seg2)
for i in range(len(ls)-1):
fw.write(fill_data(ls[i+1]))
fw.write(seg3)
#限于技术有限,我的编码不太对
5.HTML 语言概述
- 标签(Tags) :HTML文档由各种标签组成,每个标签用于定义文档的不同部分。标签通常成对出现,包括开始标签和结束标签。例如,
<p>
和</p>
分别表示段落的开始和结束。有些标签是自闭合的,如<br>
或<img>
,它们不需要结束标签。 - 元素(Elements) :元素是由开始标签、内容和结束标签组成的整体。例如,
<p>这是一个段落。</p>
就是一个元素,其中<p>
是开始标签,</p>
是结束标签,中间的内容是元素的内容。 - 属性(Attributes) :属性提供了关于元素的额外信息。属性通常出现在开始标签内,格式为
属性名="属性值"
。例如,<a href="[http://www.example.com](http://www.example.com) ">这是一个链接</a>
中的href
是一个属性,指定了链接的目标地址。 - 注释(Comments) :注释用于在HTML代码中添加说明,不会被浏览器解析。注释的格式是
<!-- 这是一个注释 -->
。 - 文档类型声明(DOCTYPE) :文档类型声明是HTML文档的第一行,用于告诉浏览器文档使用的HTML版本。例如,
<!DOCTYPE html>
声明这是一个HTML5文档。 - 基本结构:一个标准的HTML文档通常包含以下几个部分:
-
<!DOCTYPE html>
:文档类型声明。<html>
:HTML文档的根元素。<head>
:包含文档的元数据,如标题、字符集等。<title>
:定义文档的标题,显示在浏览器的标题栏或标签页上。<body>
:包含文档的实际内容,如文本、图像、链接等。
- 特殊字符和实体(Entities) :HTML中有一些特殊字符需要使用实体来表示,例如
<
表示小于号<
,>
表示大于号>
。 - 嵌套和层次结构:HTML元素可以嵌套,形成层次结构。例如,一个段落可以包含多个句子,每个句子可以包含单词和标点符号。
- 大小写不敏感:HTML标签和属性名不区分大小写,例如
<p>
和<P>
是相同的。
通过这些基本语法形式,可以构建出复杂的网页结构和内容。
6.Beautiful Soup 库
Beautiful Soup 库能够用来解析 HTML 和 XML 的第三方库,也称 beautifulsoup4 或 bs4
使用 Request 库获取 HTML 页面并将其转换成字符串后,需要进一步解析 HTML 页面格式,提取有效信息,这需要处理 HTML 和 XML 的函数库
pip install -U beautifulsoup4
from bs4 import BeautifulSoup
从库中引入 BeautifulSoup 类
Beautiful Soup库采用 BeautifulSoup 对象表示一个页面
import requests
from bs4 import BeautifulSoup
r = requests.get("http://www.baidu.com")
r.encoding = 'utf-8'
soup = BeautifulSoup(r.text)
type(soup)
'''
<class 'bs4.BeautifulSoup'>
'''
soup.head
'''
<head><meta content="text/html;charset=utf-8" http-equiv="content-type"/><meta content="IE=Edge" http-equiv="X-UA-Compatible"/><meta content="always" name="referrer"/><link href="http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/><title>百度一下,你就知道</title></head>
'''
title=soup.title
type(title)
'''
class 'bs4.element.Tag'>
'''
soup.p
'''
<p id="lh"> <a href="http://home.baidu.com">关于百度</a> <a href="http://ir.baidu.com">About Baidu</a> </p>
'''
BeautifulSoup 对象的常用属性
属性 | 描述 |
head | HTML 页面的<head>内容 |
title | HTML 页面标题,在<head>之中,由<title>标记 |
body | HTML 页面的<body>内容 |
p | HTML 页面中第一个<p>内容 |
strings | HTML 页面所有呈现在 Web 上的字符串,即标签的内容 |
stripped_strings | HTML 页面所有呈现在 Web 上的非空格字符串 |
<a class="mnav" href="http://www.nuomi.com">糯米</a>
'''
<>中的是标签的名字name,其他项是sttrs,尖括号间的内容是string
'''
>>>soup.a
<a class="mnav" herf="http://www.nuomi.com">糯米</a>
>>>soup.a.name
'a'
>>>soup.a.attrs
{'href':'http://www.nuomi.com','class':['mnav']}
>>>soup.a.string
'糯米'
>>>title.name#title变量在上段例子中已经定义
'title'
>>>title.string
'百度一下,你就知道'
>>>soup.p.contents
……
标签对象的常用属性:
属性 | 描述 |
name | 字符串,标签的名字,比如 div |
attrs | 字典,包含了原来页面 Tag 所有的属性,比如 href |
contents | 列表,这个 Tag 下所以子 Tag 的内容 |
string | 字符串,Tag 所包围的文本,网页中真实的文字 |
String 属性的返回遵循如下原则:
- 如果标签内部没有其他标签,string 属性返回其中的内容
- 如果标签内部还有其他标签,但只有一个标签,string 属性返回最里面标签的内容
- 如果标签内部有超过 1 层嵌套的标签,string 属性返回 None(空字符串)
按照条件返回标签内容:
BeautifulSoup.find_all(name,attrs,recursive,string,limit)
name:按照 Tag 标签名字检索,名字用字符串形式表示,例如,div、li。
sttrs:按照 tag 标签属性值检索,需要列出属性名称和值,采用 JSON 表示
recursive:设置查找层次,只查找当前标签下一层时使用 recursive=False
string:按照关键字检索 string 属性内容,采用 string=开始
limit:返回结果的个数,默认返回全部结果
正则表达式:
正则表达式(Regular Expression,简称regex或regexp)是一种强大的文本处理工具,用于在字符串中查找、匹配和替换特定的模式。它由普通字符(如字母、数字)和特殊字符(称为元字符)组成,能够描述复杂的字符串匹配规则。正则表达式广泛应用于编程、数据验证、文本处理等领域,是处理字符串的强大武器。
7.实例十八:中国大学排名爬虫
采用网络爬虫技术,从网页上获取中国大学排名数据
allUniv=[]
def fillUnivList(soup):
data = soup.find_all('tr')
for tr in data:
singleUniv = []
ltd = tr.find_all('td')
singleUniv.append(ltd[0].string.strip("\n "))
singleUniv.append(list(ltd[1].strings)[1].strip("\n "))
singleUniv.append(list(ltd[2].strings)[0].strip("\n "))
singleUniv.append(list(ltd[3].strings)[0].strip("\n "))
singleUniv.append(ltd[4].string.strip("\n "))
allUniv.append(singleUniv)
allUniv=[]#存储全部表格数据,二维列表
def fillUnivList(soup):
singleUniv = []
ltd = tr.find_all('td')
if len(ltd)==0:
continue
singleUniv.append(ltd[0].string.strip("\n "))
singleUniv.append(list(ltd[1].strings)[1].strip("\n "))
singleUniv.append(list(ltd[2].strings)[0].strip("\n "))
singleUniv.append(list(ltd[3].strings)[0].strip("\n "))
singleUniv.append(ltd[4].string.strip("\n "))
allUniv.append(singleUniv)data = soup.find_all('tr')
#CrawUnivRanking.py
import requests
from bs4 import BeautifulSoup
from prettytable import PrettyTable
allUniv = []
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = 'utf-8'
return r.text
except:
return ""
def fillUnivList(soup):
data = soup.find_all('tr')
for tr in data:
singleUniv = []
ltd = tr.find_all('td')
if len(ltd)==0:
continue
singleUniv.append(ltd[0].string.strip("\n "))
singleUniv.append(list(ltd[1].strings)[1].strip("\n "))
singleUniv.append(list(ltd[2].strings)[0].strip("\n "))
singleUniv.append(list(ltd[3].strings)[0].strip("\n "))
singleUniv.append(ltd[4].string.strip("\n "))
allUniv.append(singleUniv)
def printUnivList(num):
tb = PrettyTable();
tb.field_names = [" 排名 "," 学校名称 "," 省市 "," 类型 "," 总分 "]
for i in range(num):
tb.add_row(allUniv[i])
print(tb)
def main(num):
url = 'https://www.shanghairanking.cn/rankings/bcur/2023'
html = getHTMLText(url)
soup = BeautifulSoup(html, "html.parser")
fillUnivList(soup)
printUnivList(num)
main(10)
'''
+--------+------------------+--------+--------+--------+
| 排名 | 学校名称 | 省市 | 类型 | 总分 |
+--------+------------------+--------+--------+--------+
| 1 | 清华大学 | 北京 | 综合 | 1004.1 |
| 2 | 北京大学 | 北京 | 综合 | 910.5 |
| 3 | 浙江大学 | 浙江 | 综合 | 822.9 |
| 4 | 上海交通大学 | 上海 | 综合 | 778.6 |
| 5 | 复旦大学 | 上海 | 综合 | 712.4 |
| 6 | 南京大学 | 江苏 | 综合 | 676.2 |
| 7 | 中国科学技术大学 | 安徽 | 理工 | 608.6 |
| 8 | 华中科技大学 | 湖北 | 综合 | 606.2 |
| 9 | 武汉大学 | 湖北 | 综合 | 599.1 |
| 10 | 西安交通大学 | 陕西 | 综合 | 572.6 |
+--------+------------------+--------+--------+--------+
'''
8.PrettyTable 库与格式化展示
PrettyTable 库是一个在终端生成简洁格式化文本的第三方库
pip install -U prettytable
from prettytable import PrettyTable
table = PrettyTable()
table.field_names = ["City","Area (sq km)","Population"]
table.add_row(["Adelaide",1295,115829])
table.add_row(["Brisbane",5905,1857954])
table.align = "l"
print(table)
'''
+----------+--------------+------------+
| City | Area (sq km) | Population |
+----------+--------------+------------+
| Adelaide | 1295 | 115829 |
| Brisbane | 5905 | 1857954 |
+----------+--------------+------------+
'''
PrettyTable 库的主要函数:
函数 | 描述 |
PrettyTable() | 创建一个 PrettyTable 对象 |
field_names() | 设置或获取表格的字段名称,即列的名字 |
add_row() | 向表格中添加一行数据 |
add_column() | 向表格中添加一整列数据 |
align() | 设置指定列的对齐方式,左对齐"I"、居中"c"、右对齐"r" |
del_row(row_indes) | 删除指定索引的行 |
clear() | 清空表格中的所有行数据 |
sortby() | 设置排序依据的列名 |
创建表格,增加一行数据:
from prettytable import PrettyTable
table = PrettyTable(["Name","Age","City"])
table.add_row(["Alice",30,"New York"])
print(table)
'''
+-------+-----+----------+
| Name | Age | City |
+-------+-----+----------+
| Alice | 30 | New York |
+-------+-----+----------+
'''
增加新列 Occupation,设置第一行对应该列的值为 Engineer:
table.add_column("Occupation",["Engineer"])
print(table)
'''
+-------+-----+----------+------------+
| Name | Age | City | Occupation |
+-------+-----+----------+------------+
| Alice | 30 | New York | Engineer |
+-------+-----+----------+------------+
'''
设置各列对齐方式:
table.align["Name"] = "l"
table.align["Age"] = "c"
table.align["City"] = "r"
print(table)
'''
+-------+-----+----------+------------+
| Name | Age | City | Occupation |
+-------+-----+----------+------------+
| Alice | 30 | New York | Engineer |
+-------+-----+----------+------------+
'''
增加数据,设置根据年龄排序:
table.add_row(["Charlie",25,"Chicago","Artist"])
table.sortby = "Age"
print(table)
'''
+---------+-----+----------+------------+
| Name | Age | City | Occupation |
+---------+-----+----------+------------+
| Charlie | 25 | Chicago | Artist |
| Alice | 30 | New York | Engineer |
+---------+-----+----------+------------+
'''
第十一周:Python 计算生态概览
从数据处理到人工智能:
数据表示->数据清洗->数据统计->数据可视化->数据挖掘->人工智能
数据表示:采用合适方式用程序表达数据
数据清洗:数据归一化、数据转换、异常值处理
数据统计:数据的概要理解、数量、分布、中位数
数据可视化:直观展示数据内涵的方式
数据挖掘:从数据分析获得知识,产生数据外的价值
人工智能:数据/语言/图像/视觉等方面深度分析与决策
1.Python 库之数据分析
Numpy:表达 N 维数组的最基础库
Python 接口使用,C 语言实现,计算速度优异
Python 数据分析及科学计算的基础库,支撑 Pandas 等
提供直接的矩阵运算、广播函数、线性代数等功能
Pandas:Python 数据分析高层次应用库
pandas - Python Data Analysis Library
提供了简单易用的数据结构和数据分析工具
理解数据类型与索引的关系,操作索引即操作数据
Python 最主要的数据分析功能库,基于 Numpy 开发
Series = 索引 + 一维数据
DataFrame = 行列索引 + 二维数据
Scipy:数学、科学和工程计算功能库
提供了一批数学算法及工程数据运算功能
类似 Matlab,可用于如傅立叶变换、信号处理等应用
Python 最主要的科学计算功能库,基于 Numpy 开发
2.Python 库之数据可视化
Matplotlib:高质量的二维数据可视化功能库
Matplotlib — Visualization with Python
提供了超过 100 种数据可视化展示效果
通过 matplotlib.pyplot 子库调用各可视化效果
Python 最基本的数据可视化功能库,基于 Numpy 开发
Seaborn:统计类数据可视化功能库
提供了一批高层次的统计类数据可视化展示效果
主要展示数据间分布、分类和线性关系等内容
基于 Matolotlib 开发,支持 Numpy 和 Pandas
Mayavi:三维科学数据可视化功能库
Mayavi: 3D scientific data visualization and plotting in Python — mayavi 4.8.2 documentation
提供了一批简单易用的 3D 科学计算数据可视化展示效果
目前版本是 Mayavi2,三维可视化最主要的第三方库
支持 Numpy、TVTK、Traits、Envisage 等第三方库
3.Python 库之文本处理
PyPDF2:用来处理 PDF 文件的工具集
提供了一批处理 PDF 文件的计算功能
支持获取信息、分隔/整合文件、加密解密等
完全 Python 语言实现,不需要额外依赖,功能稳定
from PyPDF2 import PdfFileReader,PdfFileMerger
merger = PdfFileMerger()
input1 = open("document1.pdf","rb")
input2 = open("document2.pdf","rb")
merger.append(fileobj = input1,pages = (0,3))
merger.merge(position = 2,fileobj = input2,pages = (0,1))
output = open("document-output.pdf","wb")
merger.write(output)
NLTK:自然语言文本处理第三方库
NLTK :: Natural Language Toolkit
提供了一批简单易用的自然语言文本处理功能
支持语言文本分类、标记、语法句法、语义分析等
最优秀的 Python 自然语言处理库
from nltk.corpus import treebank
t = tree.bank.parsed_sents('wsj_0001.mrg')[0]
t.draw()
Python-docx:创建或更新 Microsoft Word 文件的第三方库
python-docx — python-docx 1.1.2 documentation
提供创建或更新.doc .docx 等文件的计算功能
增加并配置段落、图片、表格、文字等、功能全面
from docx import Document
document = Document()
document.add_handing('Document Title',0)#标题
p = document.add_paragraph('A plain paragraph having some')#段落
document.add_page_break()#分页符
document.save('demo.docx')
4.Pythpn 之机器学习
Scikit-learn:机器学习方法工具集
提供一批统一化的机器学习方法功能接口
提供聚类、分类、回归、强化学习等计算功能
机器学习最基本且最优秀的第三方库
TensorFlow:AlphaGo 背后的机器学习框架
谷歌公司推动的开源机器学习框架
将数据流图作为基础,图节点代表运算,边代表张量
应用机器学习的一种方式。支撑谷歌人工智能应用
import tensorflow as tf
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
res = sess.run(result)
print("result:",res)
MXNet:基于神经网络的深度学习计算框架
Apache MXNet | A flexible and efficient library for deep learning.
提供可扩展的神经网络及深度学习计算功能
可用于自动驾驶、机器翻译、语言识别等众多领域
Python 最重要的深度学习计算框架
5.实例十九:霍兰德人格分析
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
# 指定字体文件路径
font_path = '/System/Library/Fonts/STHeiti Light.ttc' # 替换为您的字体文件路径
# 加载字体文件
font_prop = fm.FontProperties(fname=font_path)
# 设置全局字体
plt.rcParams['font.family'] = font_prop.get_name()
plt.rcParams['font.sans-serif'] = [font_prop.get_name()] # 可选:确保中文显示正确
radar_labels = np.array(['研究型(I)', '艺术型(A)', '社会型(S)',
'企业型(E)', '常规型(C)', '现实型(R)'])
data = np.array([
[0.40, 0.32, 0.35, 0.30, 0.30, 0.88],
[0.85, 0.35, 0.30, 0.40, 0.40, 0.30],
[0.43, 0.89, 0.30, 0.28, 0.22, 0.30],
[0.30, 0.25, 0.48, 0.85, 0.45, 0.40],
[0.20, 0.38, 0.87, 0.45, 0.32, 0.28],
[0.34, 0.31, 0.38, 0.40, 0.92, 0.28]
])
data_labels = ('艺术家', '实验员', '工程师', '推销员', '社会工作者', '计事员')
angles = np.linspace(0, 2 * np.pi, len(radar_labels), endpoint=False).tolist()
# 创建图形
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True))
# 为每个数据系列绘制雷达图
for i, d in enumerate(data):
values = d.tolist()
# 闭合图形
values += values[:1]
angles_closed = angles + [angles[0]]
ax.plot(angles_closed, values, 'o-', linewidth=1, alpha=0.8, label=data_labels[i])
ax.fill(angles_closed, values, alpha=0.25)
# 设置标签
ax.set_thetagrids(np.degrees(angles), radar_labels)
# 手动调整标签位置(可选)
for label, angle in zip(ax.get_xticklabels(), angles):
if angle in (0, np.pi):
label.set_horizontalalignment('center')
elif 0 < angle < np.pi:
label.set_horizontalalignment('left')
else:
label.set_horizontalalignment('right')
# 添加标题
plt.figtext(0.52, 0.95, '霍兰德人格分析', ha='center', size=20, fontproperties=font_prop)
# 显示图例
ax.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
# 显示网格
ax.grid(True)
# 保存图像
plt.savefig('holland_radar.jpg')
# 显示图像
plt.show()
6.Python 库之网络爬虫
Requtsts:最友好的网络爬虫功能库
提供了简单易用的类 HTTP 协议网络爬虫功能
支持连接池、SSL、Cookies、HTTP(S)代理等
Python 最主要的页面级网络爬虫功能库
import requests
r = requests.get('http://api.github.com/user',auth=('user','pass'))
r.status_code
r.headers['content-type']
r.encoding
r.text
Scrapy:优秀的网络爬虫框架
Scrapy | A Fast and Powerful Scraping and Web Crawling Framework
提供了构建网络爬虫系统的框架功能,功能半成品
支持批量或定时的网页爬取、提供数据处理流程等
Python 最主要且最专业的爬虫框架
pyspider:强大的 Web 页面爬取系统
提供了完整的页面爬取系统构建功能
支持数据库后端、消息队列、优先级、分布式框架等
7.Python 库之 Web 信息提取
Beautiful Soup:HTML 和 XML 的解析库
Beautiful Soup: We called him Tortoise because he taught us.
提供解析 HTML 和 XML 等 Web 信息的功能
又名 beautifulsoup4 或 bs4,可以加载多种解析引擎
常与网络爬虫库搭配使用,如 Scrapy、requests 等
Re:正则表达式解析和处理功能库
提供了定义和解析正则表达式的一批通用功能
可用于各类场景,包括定点的 Web 信息提取
Python 最主要的标准库之一,无需安装
比如我们定义一个字符串,正则表达式的形式,Re 提供 search、match、split 等一系列功能函数进行信息查找
Python-Goose:提取文章类型 Web 页面的功能库
GitHub - grangier/python-goose: Html Content / Article Extractor, web scrapping lib in Python
提供了对 Web 页面中文章信息/视频等元数据的提取功能
针对特定类型 Web 页面,应用覆盖面较广
Python 最主要的 Web 信息提取库
from goose import Goose
url = 'http://www.elmundo.es/elmundo/2012/10/28/espana/1351388909.html'
g = Goose({'use_meta_language':False,'target_language':'es'})
article = g.extract(url=url)
article.cleaned_text[:150]
8.Python 库之 Web 网站开发
Django:最流行的 Web 应用框架
提供了构建 Web 系统的基本应用框架
MTV 模式:模型(model)、模版(Template)、视图(Views)
Python 最重要的 Web 应用框架,略微复杂的应用框架
Pyramid:规模适中的 Web 应用框架
Welcome to Pyramid, a Python Web Framework
提供了简单方便构建 Web 系统的应用框架
不大不小,规模适中,适合快速构建并适度扩展类应用
Python 产品级 Web 应用框架,起步简单可扩展性好
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
def hello_world(request):
return Response('Hello World!')
if _name_=='_main_':
with Configurator() as config:
config.add_route('hello','/')
config.add_view(hello_world,route_name='hello')
app = config.make_wsgi_app()
server = make_server('0.0.0.0',6543,app)
server.server_forever()
Flask:Web 应用开发微框架
Welcome to Flask — Flask Documentation (3.0.x)
提供了最简单构建 Web 系统的应用框架
简单、规模小、快速
总结:Djange > Pyramid > Flask
9.Python 库之网络应用开发
WeROBot:微信公众号开发框架
提供了解析微信服务器消息及反馈消息的功能
建立了微信机器人的重要技术手段
aip:百度 AI 开放平台接口
提供了访问百度 AI 服务的 Python 功能接口
语言、人脸、OCR、NLP、知识图谱、图像搜索等领域
Python 百度 AI 应用的最主要的方式
MyQR:二维码生成第三方库
提供了生成二维码的系列功能
基本二维码、艺术二维码和动态二维码
10.Python 库之图形用户界面
图形用户界面(GUI)
PyQt5:Qt 开发框架的 Python 接口
提供了创建 Qt5 程序的 Python API 接口
Qt 是非常成熟的跨平台桌面应用开发系统 ,完备 GUI
推荐的 Python GUI 开发第三方库
wxPython:跨平台 GUI 开发框架
提供了专门于 Python 的跨平台 GUI 开发框架
理解数据类型与索引的关系,操作索引即操作数据
import wx
app = wx.App(False)
frame = wx.Frame(None,wx.ID_ANY,"Hello World")
frame.Show(True)
app.MainLoop()
PyGObject:使用 GTK+开发 GUI 的功能库
整合 GTK+、WebKitGTK+等库的功能
GTK+:跨平台的一种用户图形界面 GUI 框架
import gi
gi.require_version("Gtk","3.0")
from gi.repository import Gtk
window = Gtk.Windows(title="Hello World")
window.show()
window.connect("destroy",Gtk.main_quit)
Gtk.main()
11.Python 库之游戏开发
PyGame:简单的游戏开发功能库
提供了基于 SDL 的简单游戏开发功能及实现引擎
理解游戏对外部输入的响应机制及角色构建和交互机制
Python 游戏入门最主要的第三方库
Panda3D:开源、跨平台的3D渲染和游戏开发库
Panda3D | Open Source Framework for 3D Rendering & Games
一个 3D 游戏引擎,提供 Python 和 C++两种接口
支持很多先进特性:法线贴图、光泽贴图、卡通渲染等
由迪士尼和卡尼基梅隆大学共同开发
cocos2d:构建 2D 游戏和图形界面交互应用的框架
提供了基于 OpenGL 的游戏开发图形渲染功能
支持 GPU 加速,采用树形结构分层管理游戏对象类型
适用于 2D 专业级游戏开发
12.Python 库之虚拟现实
VR Zero:在树莓派上开发 VR 应用的 Python 库
提供大量与 VR 开发相关的功能
针对树莓派的 VR 开发库,支持设备小型化,配置简单化
非常适合初学者实践 VR 开发及应用
VR Zero:在树莓派上开发 VR 应用的 Python 库
GitHub - WayneKeenan/python-vrzero: VR on the Pi, in Python
raspberrypi(中文名为"树莓派"简写为rpi,(或者raspi/rp是为学习计算机编程教育而设计,只有信用卡大小的微型电脑,其系统基于linux.随着windows10iot的发布,我们也将可以用上运行windows的树莓派。
pyovr:Oculus Rift 的 Python 开发接口
GitHub - cmbruns/pyovr: Python bindings for Oculus Rift virtual reality SDK
针对 Oculus VR 设备的 Python 开发库
基于成熟的 VR 设备,提供全套文档,工业级应用设备
Python+虚拟现实领域探索的一种思路
Vizard:基于 Python 的通用 VR 开发引擎
专业的企业级虚拟现实开发引擎
提供详细的官方文档
支持多种的主流 VR 硬件设备,具有一定的通用性
13.Python 库之图形艺术
Quads:迭代的艺术
对图片进行四分迭代,形成像素风
可以生成动图或静图图像
简单易用,具有很高的展示度
ascii_art:ASCII 艺术库
将普通图片转为 ASCII 艺术风格
输出可能是纯文本或彩色文本
可采用图片格式输出
14.实例二十:玫瑰花绘制
import turtle as t
#定义一个曲线绘制函数
def DegreeCurve(n,r,d=1):
for i in range(n):
t.left(d)
t.circle(r,abs(d))
#初始位置设定
s = 0.2#size
t.setup(450*5*s,750*5*s)
t.pencolor("black")
t.fillcolor("red")
t.speed(100)
t.penup()
t.goto(0,900*s)
t.pendown()
#绘制花朵形状
t.begin_fill()#关于填充的函数
t.circle(200*s,30)
DegreeCurve(60,50*s)
t.circle(200*s,30)
DegreeCurve(4,100*s)
t.circle(200*s,50)
DegreeCurve(50,50*s)
t.circle(350*s,65)
DegreeCurve(40,70*s)
t.circle(150*s,50)
DegreeCurve(20,50*s,-1)
t.circle(400*s,60)
DegreeCurve(18,50*s)
t.fd(250*s)
t.right(150)
t.circle(-500*s,12)
t.left(140)
t.circle(550*s,110)
t.left(27)
t.circle(650*s,100)
t.left(130)
t.circle(-300*s,20)
t.right(123)
t.circle(220*s,57)
t.end_fill()
#绘制花枝形状
t.left(120)
t.fd(280*s)
t.left(115)
t.circle(300*s,33)
t.left(180)
t.circle(-300*s,33)
DegreeCurve(70,225*s,-1)
t.circle(350*s,104)
t.left(90)
t.circle(200*s,105)
t.circle(-500*s,63)
t.penup()
t.goto(170*s,-30*s)
t.pendown()
t.left(160)
DegreeCurve(20,2500*s)
DegreeCurve(220,250*s,-1)
#绘制一个绿色叶子
t.fillcolor('green')
t.penup()
t.goto(670*s,-180*s)
t.pendown()
t.right(140)
t.begin_fill()
t.circle(300*s,120)
t.left(60)
t.circle(300*s,120)
t.end_fill()
t.penup()
t.goto(180*s,-550*s)
t.pendown()
t.right(85)
t.circle(600*s,40)
#绘制另一个绿色叶子
t.penup()
t.goto(-150*s,-1000*s)
t.pendown()
t.begin_fill()
t.rt(120)
t.circle(300*s,115)
t.left(75)
t.circle(300*s,100)
t.end_fill()
t.penup()
t.goto(430*s,-1070*s)
t.pendown()
t.right(30)
t.circle(-600*s,35)
t.done()
第十二周:在 CS50 里发现的好玩的库
1.cowsay 库
import cowsay
cowsay.cow("This is cow")
___________
| This is cow |
===========
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
2.qrcode 库
from qrcode import *
img = make("https://www.bilibili.com/video/BV1YztreiEHR/?share_source=copy_web&vd_source=c4fffa513d6db04895d3e253e3d9cd1a")
img.save("这是用qrcode生成的","PNG")
第十三周:测试代码
1.测试函数
单元测试:用于核实函数的某方面没有问题
测试用例:一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求
Python 标准库中的模版 unittest 提供了代码测试工具
#要实现的函数
def get_formatted_name(first,last):
"""生成整洁的姓名"""
full_name = first + ' ' + last
return full_name.title()
#从name_function模版中导入get_formatted_name函数
from name_function import get_formatted_name
print("Enter 'q' at any time to quit.")
while True:
first = input("\nPlease give me a first name: ")
if first == 'q':
break
last = input("Please give me a last name: ")
if last == 'q':
break
formatted_name = get_formatted_name(first,last)
print("\tNeatly formatted name: " + formatted_name + '.')
import unittest
from name_function import get_formatted_name
class NamesTestVase(unittest.TestCase):#新类必须继承unittest.TestCase类
"""测试name_function.py"""
"""方法,当我们运行test_nmae_function.py时,所有以test_打头的方法都将自动运行"""
def test_first_last_name(self):
"""能够正确的处理像Janis Joplin这样的姓名吗?"""
formatted_name = get_formatted_name('janis','joplin')#调用get_formatted_name方法,并将结果存储到变量formatted_name中
self.assertEqual(formatted_name,'Janis Joplin')#unittest类中的断言方法,核实是否与期望值一致
"""将formatted_name与期望值Janis Joplin比较"""
unittest.main()
"""
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
"""
#要实现的函数
def get_formatted_name(first,middle,last):
"""生成整洁的姓名"""
full_name = first + ' ' + middle + ' ' + last
return full_name.title()
"""
E
======================================================================
ERROR: test_first_last_name (__main__.NamesTestVase.test_first_last_name)
能够正确的处理像Janis Joplin这样的姓名吗?
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/chuji/Desktop/个人/计算机/Sublime Text/Python/my_car.py", line 10, in test_first_last_name
formatted_name = get_formatted_name('janis','joplin')#调用get_formatted_name方法,并将结果存储到变量formatted_name中
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: get_formatted_name() missing 1 required positional argument: 'last'
----------------------------------------------------------------------
Ran 1 test in 0.004s
FAILED (errors=1)
"""
2.测试类
各种断言方法
方法 | 用途 |
assertEqual(a,b) | 核实 a==b |
assertNotEqual(a,b) | 核实 a!=b |
assertTrue(x) | 核实 x 为 True |
assertFalse(x) | 核实 x 为 False |
assertIn(item,list) | 核实 item 在 list 中 |
assertNotIn(item,list) | 核实 item 不在 list 中 |
class AnonymousSurvey():
"""收集匿名调查问卷的答案"""
def __init__(self,question):
"""存储一个问题,并为储存答案做准备"""
self.question = question
self.responses = []
def show_question(self):
"""显示调查问卷"""
print(self.question)
def store_response(self,new_response):
"""存储单份调查答卷"""
self.responses.append(new_response)
def show_results(self):
"""显示收集到的所有答卷"""
print("Survey results:")
for response in self.responses:
print('- ' + response)
from survey import AnonymousSurvey
#定义一个问题,并创建一个表示调查的AnonymousSurvey对象
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
#显示问题并存储答案
my_survey.show_question()
print("Enter 'q' at any time quit.\n")
while True:
response = input("Language: ")
if respense == 'q':
break
my_survey.store_response(response)
#显示调查结果
print("\nThank you to everyon who participated in the survey!")
my_survey.show_results()
#surver == 调查
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""针对AnonymousSurvey类的测试"""
def test_store_single_response(self):
"""测试单个答案会被妥善地储存"""
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
my_survey.store_response('English')#单个答案
self.assertIn('English',my_survey.responses)
def test_store_three_responses(self):
"""测试三个答案会被妥善的存储"""
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
responses = ['English','Spanish','Mandarin']
for response in responses:
my_survey.store_response(response)#存储单份答卷
for response in responses:
self.assertIn(response,my_survey.responses)
unittest.main()
3.方法 setUp()
如果你在 TestCase 类中包含了方法 setUP(),Python 将先执行它,再运行各个以 test_ 打头的方法
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""针对AnonymousSurvey类的测试"""
def setUp(self):
"""
创建一个调查对象和一组答案,供使用的测试方法使用
"""
question = "What language did you first learn to speak?"
"""前缀为self代表存储在属性中"""
self.my_survey = AnonymousSurvey(question)#创建调查对象
self.responses = ['English','Spanish','Mandarin']#创建答案列表
def test_store_single_response(self):
"""测试单个答案会被妥善的存储"""
self.my_survey.store_response(self.responses[0])
self.assertIn(self.responses[0],self.my_survey.responses)
def test_store_three_responses(self):
"""测试三个答案会被妥善地存储"""
for response in self.responses:
self.my_survey.store_response(response)
for response in self.responses:
self.assertIn(response,self.my_survey.responses)
unittest.main()
"""
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
"""