python
参考资料
https://www.bilibili.com/video/BV1hW41197sB?p=20&vd_source=a2b514506eac7ae95b386998824a4cc3
python的用途:
WBE的应用(网站)、爬虫程序、科学计算、自动化运维(服务器)[编写自动化的脚本]、大数据(数据清洗)[提取有用数据]、云计算、人工智能等
Python开发环境搭建
开发环境搭建就是安装Python的解释器/编译器
Python的解释器类型:
CPython(官方):用c语言编写的Python解释器
PyPy:用Python语言编写
IronPython
Jython
步骤:
1.下载安装包:(两个版本不兼容)
- 2.X
- 3.X
2.安装(傻瓜式安装)
如果无法运行,直接卸载,重新安装
或者自己配置环境变量
Python的交互界面
通过命令行进入的界面:
>>>
结构:
版本以及说明(版权说明)
>>> (命令提示符,在这之后可以直接输入Python指令!指令会被Python的解释器立即执行)
安装Python的同时,会自动安装一个Python的开发工具IDLE,通过IDLE会直接进入到交互模式,但是不同的是在IDLE中可以通过Tab键进行语句的提示/补全,并且可以将代码保存
交互模式只能一边输入,一边执行,所以它并适用于我们日常的开发!
尽可以用来做一些日常的简单的测试!
在IDLE中可以新建一个py文件,在这个新文件中编写代码。然后运行(F5),通过python指令来执行文件中的代码
几个概念
1.表达式:
表达式就是一个类似于数学公式的东西
比如:10 + 5、8 - 4等
不会对程序有实质性的影响,仅仅计算一些结果
只会在交互模式中自动输出
在py文件中不会自动输出,我们需要一个prit语句进行输出
2.语句
语句需要完成某种功能,比如打印信息、获取信息、为变量赋值。。。
比如:
print()
a = 10 (赋值语句)
语句的执行会对程序产生一定的影响
在交互模式中,不一定会输出语句的执行结果
3.程序(program)
程序就是由一条一条的语句和一条一条的表达式构成的
4.函数(function)
函数就是一种语句,函数专门来完成特定的功能
形如:xxx()
函数的分类:
内置函数
--由Python解释器自带的函数,可以在python中直接使用
自定义函数
--由程序员自主的创建的函数
当我们需要完成某个功能时,就可以去调用的内置函数,或自定义函数
内置函数:查找官方文档
函数的要素:
--参数:用逗号隔开,可以有多个/没有
--返回值:函数的返回结果,不是所有的函数都有返回值
Python的基本语法
1.Python中严格区分大小写
2.Python中每一行就是一条语句,每条语句以换行符结束
3.Python中每一条语句不要过长(规范中建议每一行不要超过80个字符)
4.语句可以分多行编写
比如:print("hellohellohellohellohello\
hellohellohellohellohello")
添加以一个 “ / ” 反斜杠符号即可进行编写
5.Python是缩进严格的语法,空格和Tab
6.Python中使用 ‘ # ’ 进行注释
比如: # 这是一个简单的注释,请你不要慌张
注释会被解释器忽略,通过注释来对程序进行解释说明,要求简单明了,一般#号后需要跟一个空格
多行注释/单行注释
字面量和变量
字面量就是一个一个的值,比如:1,2,3,4,“Hello”
所表示的就是他字面的意思,在程序中可以直接使用
变量(Variable)可以保存字面量,并且变量中保存的字面量是不定的
变量本身没有任何意思,他会根据不同的字面量表示不同的意思
一般在开发中很少使用字面量,都是讲字面量保存到变量中,通过变量来引用字面量
变量和标识符
Python中使用变量不需要声明,直接使用为变量赋值即可
但是不能使用没有赋值的变量,如果使用,会报错
比如: a = 10
print(‘b’)
Python是一个动态类型的语言,可以为变量赋任意类型的值,也可以任意修改变量的值
标识符
所有可以自主命名的内容都是属于标识符
比如:变量名、函数名、类名
标识符规范:
1.可以含有字母、数字、下划线 ’ _ ’
但不能数字开头
2.不能是Python中的关键字和保留字
也不建议使用Python中的函数名作为标识符
3.命名规范:
在Python中注意遵循两种命名规范:
下划线命名法
所有字母小写,单词之间使用_分割
帕斯卡命名法(大驼峰命名法)
首字母大写,每个单词开头字母大写,其余字母小写
数据类型
数据类型指的就是变量的值的类型,也就是可以为变量赋那些值
整数、浮点数(小数)、复数
整数:
在Python中所有的整数都是int类型,大小没有限制,可以是一个无限大的整数
如果数的长度过大,可以使用下划线进行分割
比如: c = 123_456_789
print©
结果是:123456789
只要是数字,打印时,只会以10进制输出
二进制:0b、八进制:0o、十六进制:0x
也可以通过运算符来对数字进行运算
浮点数:
小数、在Python中所有小数都是float类型
对浮点数进行运算时,可能会得到一个不精确的结果
字符串
字符串
用来表示一段文本信息,字符串是程序中使用最多的数据类型
在Python中需要使用引号引起来
引号可以是单引号,也可以是双引号,但是注意不要混着用
相同的引号之间不能嵌套
例如:
s = '子曰:'学而时习之,不亦乐乎''
但是可以相间使用
s = '子曰:"学而时习之,不亦乐乎"'
单、双引号不能换行,不能跨行使用
长字符串
使用三重引号来表示一个长字符串
“”" / ‘’’
s = '''
锄禾日当午
汗滴禾下土
谁之盘中餐
粒粒皆辛苦
'''
转义字符
可以使用反斜杠作为转义字符
s = "子曰:\"学而时习之,不亦乐乎\""
通过转义字符,可以在字符串中使用一些特殊的内容
例子:
\’ 表示 ‘
\" 表示 “
\t 表示制表符
\n 表示换行符
\\ 表示反斜杠
\uxxxx 表示Unicode编码
s = '\u0070'
p
格式化字符串
拼串
字符串之间也可以进行加法运算
结果是自动将两个字符串拼接为一个
a = 'abc' + 'hhh'
print(a)
# a = abchhh
print("a = " +a) # 这种写法在Python中不常见
# 必须是字符串,字符串只能和字符串进行拼接
多参数
print() 是一个函数,可以传递多个参数
# 格式化的第一种方式
a = 123
print('a = ', a )
占位符
在创建字符串时,可以在字符串中指定占位符
%s 在字符串中表示任意字符
b = 'hello %s'%'孙悟空'
print(b)
注意几个占位符,就需要几个参数,并且是按照顺序的
b = 'hello %s 你好 %s'%('abc' , 'asd')
注意可以为占位符指定位数
# 最大3位,不够就会自动补充空格
b = 'hello %3s'%'a'
b = 'hello %3s'%'abcdefg'
b = 'hello %3.5'%'a' # 表示在3~5之间
b = 'hello %3.5'%'abcdsf'
%f 表示浮点数的占位符,会自动四舍五入
%d 表示整数的占位符,无小数位,直接舍去
例如:打印出 a = 123
print('a = %s'%a)
格式化字符串
格式化字符串,可以通个在字符串前面添加一个f,来创建一个格式化字符串
在格式化字符串中可以直接嵌入变量
注意在格式化字符串中使用的变量都是合法的(有定义的)
a = 123
b = haha
c = f'hello {a} {b}'
print(c)
print(f'a = {a}')
字符串复制
将字符串和数字相乘
* 在语言中,代表乘法
a = 'abc'
a = a * 2
print(a)
# a = abcabc
如果将字符串和数字相乘,则解释器会将字符串重复指定的次数并返回
布尔值和空值
布尔值(Bool)
布尔值主要用来做逻辑判断,布尔值实际上也属于整型int
True 表示真,False 表示假
True 相当于1,False相当于0
None (空值)
None专门用来表示不存在
类型检查
a = 123
b = '123'
type()
通过类型检查,只能检查值(变量)的类型
# type 会将检查的结果最为返回值
print(type(123))
print(type('123'))
a = 123
b = '123'
print(type(a))
print(type(b))
对象(object)
介绍
- Python是一门面向对象的语言
- 一切皆对象!!!
- 程序运行当中,所有的数据都是存储到内存当中然后再运行的!
- 对象就是内存中专门用来 存储指定数据的一块数据!
- 对象实际上就是一个容器,专门用来存储数据
- 像我们之前学习的数值、字符串、布尔值、None都是对象
结构
- 每个对象中都要保存三种数据
- id(标识)
id用来标识对象的唯一性,每一个对象都有唯一的id,对象的id就相当于人的身份证号
可以通过id()函数来查看对象的id
id是由解析器生成的,在 CPython 中,id就是对象的内存地址
对象一旦创建,id不可更改,不会改变
- type(类型)
类型用来表示当前对象所属的类型
比如:int 、str、float、bool 。。。
类型决定了对象有什么功能
通过type()函数来查看对象的类型
Python是一门强类型语言,对象一旦创建类型便不能更改
- value
具体的值
对于有些对象值是可以改变的
对象分成两大类
可变对象的值可以改变
不可变对象的值可以改变
在这之前学习的对象都是可以不可变对象
变量和对象
对象并没有直接存储到变量中,在Python中变量更像是给对象起了一个别名
变量里存储的是对象的id,即内存地址
此时a与b指向同一个地址
如果
a = 456
则 a对应的值发生改变,而b变量保存的值不发生改变
即只有变量中保存的对象,只有在为变量重新赋值时才会改变
变量和变量之间是相互独立的,修改一个变量不会对另一个变量产生影响
类型转换
所谓的类型转换,将一个类型的对象转换为其他对象
类型转换不是转换对象本身的类型,而是将一个对象的值转换为新对象(根据当前对象的值创建一个新对象)
类型转换四个函数:
int() float() str() bool()
int() 将其他对象转化为整型
a = True
print('a = ',a)
print('a的类型是:', type(a))
# int() 函数不会对原来的变量产生影响,他是将对象转换为指定的类型并将其作为返回值返回
a = int(a)
print('a = ',a)
print('a的类型是:', type(a))
int:
布尔值:True -> 1 , False -> 0
浮点数:直接取整,直接去掉小数点后的内容
字符串:合法的整数字符串转化为对应的数字
如果不是一个合法的整数字符串,则报错
对于其他对象,不可转化为整型,会直接抛出异常
float() 就是将对象转换为浮点数,其他与int基本一致
str()可以将对象转换为字符串
b = 345
print('hello' + str(b))
bool()可以将对象转换为布尔值
注意:所有的空性对象都转换为False
空性: 0、None、‘ ’ (空字符串)。。。
运算符(操作符)
- 可以对一个值或多个值进行运算或多种操作
- 比如 + 、- 、= 都属于运算符
- 运算符的分类:
1.算术运算符
2.赋值运算符
3.比较运算符(关系运算符)
4.逻辑运算符
5.条件运算符(三元运算符)
算数运算符
+(加) -(减) *(乘) /(除)
+ : 计算与字符串拼串
- : 计算,无法进行字符串运算
a = 10 -5
a = 5 - True
a = a -2
print("a = ",a)
*
: ** 幂运算
16 ** 0.5 求16的平方根
/
1.除数不能为0
2. // 整除,只会保留计算后的整数位,返回一个整型,向下取整
% 取余
返回值取余数,求两个数相除的余数
赋值运算符
= 可以将等号右侧的值,赋值给等骄傲左侧的变量
a = 10
# -= += *= **= /= //= %=
# 中间不要加空格
# 例如: - = ,这样是不对的
a -= 10
# 相当于a = a - 10
a += 10
#相当于 a = a + 10
对浮点数进行运算时,结果还是一个浮点数
关系运算符
用来比较两个值之间的关系,总会返回一个布尔值
都是比较的对象的值(value),而不是id
# 关系运算符有:
# > >= < <= == !=
Eg:
result = 10 >20 # False
print("result = ",result)
注意:
result = '2' > '1' # True
print("result = ",result)
result = '2' > '11' # True
print("result = ",result")
对于字符串进行的比较时,Python会比较字符串的Unicode编码
并且会逐位进行比较,只会在第一位没有比较出来的时候,才会比较下一位
利用该特性可以对字符串按照字母顺序进行排序,但是对于中文来说意义不大
可以调用int函数进行比较
print(int('2') > int('11'))
注:
is 比较两个对象是否同一个对象,比较的是对象的id
is not 比较的是两个对象是否不是同一个对象,比较的是对象的id
逻辑运算符
主要进行一些逻辑判断
not 逻辑非
not 可以对符号右侧的值进行非运算
a = True
a = not a
print("a = ",a)
对于布尔值,not会对其进行取反操作
a = 1
a = not a # False
print("a = ",a)
对于非布尔值运算,非运算会先将其转换为布尔值,然后再取反
还是只有空性的值会转换成False
and 逻辑与
对符号两侧进行与运算
result = True and True
result = True and False
print('result = ',result)
只有and两侧同时为True,才返回True
其他情况都是False
多个条件同时满足
与运算是找False
Python中的与运算是短路的与,如果第一个值为False,则不再看其他的值
True and print("你猜我会执行吗?")
False and print("你猜我会执行吗?")
or 逻辑或
or 可以对符号两侧的值进行或运算
result = True or True
result = True or False
result = False or True
result = False or False
只要有一个True,就会返回True
或运算是找True
Python中的或运算是短运算,只要找到第一个True,其他后面的语句就不会执行
False or print("你猜我会执行吗?")
True or print("你猜我会执行吗?")
注:
逻辑运算符可以连着使用
result = 1 < 2 < 3
# 1 < 2 and 2 < 3
print(result)
# 都是对中间的数进行运算
当我们对非布尔值进行 与/或 运算时,Python会将其当作布尔值运算,最终会返回原值
# 与运算是找False
result = 1 and 2 # 2
result = 1 and 0 # 0
result = 0 and 1 # 0
result = 0 and None # 0
print(result)
# 或运算是找True
result = 1 or 2
result = 1 or 0
result = 0 or 1
result = 0 or None
print(result)
条件运算符(三元运算符)
语法:
语句1 if 条件表达式 else 语句2
执行流程:
条件运算符在执行时,先对条件表达式进行求值判断
如果判断结果是True,则执行语句1,并返回执行结果
如果判断结果是False,则执行语句2,并返回执行结果
print('你好') if True else print('hello')
print('你好') if Fasle else print('hello')
a = 10
b = 20
print("a的值确实大!") if a > b else print("b的值确实大!")
# 返回执行结果
Max = a if a > b else b
print("Max = ",Max)
运算符的优先级
运算符的优先级可以根据优先级的表格(官方文档)来查询,越往下优先级越高,同行越右的优先级越高
先计算小括号里面的,如果不知道可以通过加小括号改变运算顺序
流程控制语句
Python代码在执行时,是按照自上向下顺序执行的。
通过流程控制语句可以改变程序的执行顺序,也可以让指定的条件反复执行多次
类型:
条件判断语句
循环语句
条件判断语句
if 语句
语法:
if 条件表达式 :
(缩进)语句
执行流程:
先对条件表达式进行求值判断,如果是True,则执行if后的语句;如果是False,则不执行
默认情况下,if语句只会空值紧随其后的语句。
如果希望if控制多个语句,则可以在if后跟随一个代码块
代码块:同一个代码块中的代码,要么都执行,要么都不执行。
如果要编写代码块,语句就不能紧随在:后面,而是要写在下一行,并且需要缩进(Tab,四个空格)。
代码块以缩进开始,到恢复到上一个缩进级别结束
if True:
print(123)
print(456)
if True:
print(123)
print(456)
if False:
print(123)
print(456)
可以使用逻辑运算符来连接多个条件
如果希望所有条件都蛮做,则需要使用and
如果希望只要有一个条件满足即可,则需要使用or
缩进有两种方式:一种是使用tab键,一种是使用空格(四个)
Python官方文档中推荐使用空格,但现在一般编辑器都将tab键转换为四个空格
Python代码中使用的缩进方式必须统一
input函数
# 该函数可以获取用户的输入
# input(),调用后,程序会立即暂停,等待用户# 输入,当用户输入完内容后,点击回车程序才会继续向下执行
# 其输入的内容会以返回值的形式返回
# input()的返回值都是字符串
# input()函数可以设置一个字符串作为参数,这个字符串将会作为提示文字显示
# input()函数也可以用于暂时阻止程序结束
a = input('请输入你的用户名:')
print(a)
if else
简单if语句只能有一个选择,有时我们希望有一个另外的选择
语法:
if 条件表达式:
代码块
else :
代码块
执行流程:
if-else语句在执行时,先对if后的条件表达式进行求值判断
如果为True,执行if后的语句
如果为False,执行else后的语句
if-elif-else
更多的选择
语法:
if 条件表达式 :
代码块
elif 条件表达式:
代码块
elif 条件表达式:
代码块
.
.
else :
代码块
执行流程:
if-elif-else语句在执行过程中,会自上向下对条件表达式进行求值判断,
如果表达式的结果为True,则执行当前代码块,直到语句结束,后面的判断都不会执行
如果表达式的结果为False,则继续向下判断,知道找到True为止
如果所有的表达式的结果都是False,则执行else之后的代码块
注:
if-elif-else语句只会有一个代码块执行
循环语句
可以使指定的代码块重复指定的次数
分为两种:while 循环和 for 循环
while 循环
语法:
while 条件表达式 :
代码块
执行流程:
while语句在执行时,会先对 whlie 后的条件表达式进行求值判断,
如果判断结果时True,则执行循环体,
循环体执行完毕,继续对条件表达式进行求值判断,以此类推,
知道判断为False,则循环终止
如果条件表达式恒为True,则被称为死循环,他会一直运行,需要更具需要运用
循环的三个要件:
初始化表达式,通过初始化表达式初始化一个变量
i = 0
条件表达式,用来设置循环执行的条件
while i < 10 :
print(i)
i +=1
例如:创建一个执行十次的循环
i = 0
while i < 10:
i += 1
print(i)
可以添加一个else,当条件表达式为False时,执行else
i = 0
while i < 10:
i += 1
print(i)
else:
print("exit...")
# 假设用户输入的都是合法的数
num = int(input("请输入一个任意大于一的整数:"))
# 判断num是否是质数:只能被1和他自身整除的质数
# 获取到所有的可能整除num的整数
i = 2
# 创建一个变量,用来记录num是否是质数,默认num是质数
flag = True
while i < num :
# 判断num能否被i整除
# 如果num能被i整除,说明num一定不是质数
if num % i == 0:
# 一旦进入判断,则证明num不是质数,则需要将flag修改为false
flag = False
i += 1
if flag:
print(num,'是质数')
else:
print(num,'不是质数')
for循环
通过 for 循环来遍历列表
语法:
for 变量 in 序列 :
代码块
stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧']
for s in stus :
print(1)
for 循环会执行多次,序列中有几次就执行几次
- 每执行一次就会将序列中的一个元素赋值给变量
- 所以可以通过变量来获取列表中的元素
stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧']
for s in stus :
print(s)
循环嵌套
循环里面还有循环
要求在控制台中打印如下图形
*****
*****
*****
*****
*****
# 创建一个循环来控制图像的高度
# 循环嵌套时,外层循环执行一次时,内层循环就要执行一圈
i = 0
while i < 5 :
# 创建一个内层循环来控制图形的宽度
j = 0
while j < 5 :
print("*",end='')
j += 1
print()
i += 1
打印如下图形:
**
***
****
*****
# 创建一个循环来控制图像的高度
# 循环嵌套时,外层循环执行一次时,内层循环就要执行一圈
i = 0
while i < 5 :
# 创建一个内层循环来控制图形的宽度
j = 0
while j < i + 1 :
print("*",end='')
j += 1
print()
i += 1
打印如下图像:
*****
****
***
**
# 创建一个循环来控制图像的高度
# 循环嵌套时,外层循环执行一次时,内层循环就要执行一圈
i = 5
while i > 0 :
# 创建一个内层循环来控制图形的宽度
j = i
while j > 0 :
print("*",end='')
j -= 1
print()
i -= 1
打印九九乘法表
# 打印九九乘法表
# i控制外层循环,代表高度,1~9
i = 1
while i < 10 :
# j控制内层循环,代表宽度,j = i
j = 1
while j < i + 1 :
print(f"{j}*{i}={i * j}",end=" ")
j += 1
print()
i += 1
求一百以内的所有质数
# 创建一个循环,求1~100以内所有的数
i = 2
while i <= 100 :
# 创建一个变量,记录i的状态,默认i时质数
flag = True
# 判断i是否时质数
# 获取所有可能成为i的因数的数
j = 2
while j < i :
# 判断i能否被j整除
if i % j == 0:
flag = False
j += 1
if flag:
print(i,end=" ")
i += 1
break 和 continue
都只对距离它最近的循环起作用
break
可以立即退出循环语句(包括else)
例子:
i = 0
while i < 5:
if i == 3:
break
print(i,end=" ")
i += 1
else:
print("循环结束")
continue
可以用来跳过当次循环(不包括else)
i = 0
while i < 5:
i += 1
if i == 2:
continue
print(i)
else:
print("循环结束")
pass
是用来在判断或循环中进行占位的
性能优化(质数训练的第一次优化)
1.计算时间–判断现在程序的性能
引入模块,对Python进行扩展
引入一个time模块,统计程序执行的
from time import *
from time import *
begin = time()
i = 2
while i <= 10000 : # 100太小了,所以比较小,换成10000
flag = True
j = 2
while j < i :
if i % j == 0:
flag = False
j += 1
if flag:
# print(i,end=" ")
pass
i += 1
end = time()
# 计算程序花费时间
print(f"程序花费了: {end - begin}秒")
# 程序花费了: 5.8623082637786865秒
第一次优化
from time import *
begin = time()
i = 2
while i <= 10000 : # 100太小了,所以比较小,换成10000
flag = True
j = 2
while j < i :
if i % j == 0:
flag = False # 如果已经判断出不是质数了,就没有必要再去检查后面
# 一旦进入判断,则证明一定不是质数,此时内层循环没有继续执行的必要
break
j += 1
if flag:
# print(i,end=" ")
pass
i += 1
end = time()
# 计算程序花费时间
print(f"程序花费了: {end - begin}秒")
# 程序花费了: 0.6997308731079102秒
第二次优化
from time import *
begin = time()
i = 2
while i <= 100000 : # 100太小了,所以比较小,换成10000
flag = True
j = 2
while j <= i ** 0.5 : # # 实际上因数都是一对一对的,因此只需要求前几个因数即可,还有由于4,9等特殊情况,改为 j <= i ** 0.5
if i % j == 0:
flag = False # 如果已经判断出不是质数了,就没有必要再去检查后面
# 一旦进入判断,则证明一定不是质数,此时内层循环没有继续执行的必要
break
j += 1
if flag:
# print(i,end=" ")
pass
i += 1
end = time()
# 计算程序花费时间
print(f"程序花费了: {end - begin}秒")
小游戏–唐僧大战白骨精
综合练习–唐僧大战白骨精
身份选择
①显示提示信息
欢迎光临 xxx 游戏!
请选择你的身份:
1.xxx
2.xxx
请选择:
②根据用户选择来分配身份(唐僧)
1.—
2.—
3.—
游戏进行
① 显示玩家的基本信息(攻击力和生命值)
② 显示玩家可以进行的基本操作
1.练级
- 提升玩家的攻击力和生命值
2.打boos
- 玩家攻击boss,玩家要攻击boss,boss对玩家进行反击
- 计算Boss是否被玩家消灭,玩家是否被Boss消灭
- 游戏结束
3.逃跑()
- 退出游戏,显示提示信息,游戏结束!
# 显示欢迎信息
print('-'*20,'欢迎光临《唐僧大战白骨精》','-'*20)
# 显示身份信息
print("请选择你的身份:")
print("\t1.唐僧")
print("\t2.白骨精")
# 游戏身份的选择
player_choose = input("请选择[1/2]: ")
# 打印一条分割线
print('-'*66)
# 根据选择显示不同的信息
if player_choose == '1' :
# 选择1
print("你已经选择了1, 你将以->唐僧<-的身份进行游戏")
elif player_choose == '2' :
# 选择2
print("你竟然选择了白骨精, 太不要脸了,你将以->唐僧<-的身份进行游戏")
else:
# 选择其他
print("你的输入有误,系统将自动分配身份,你将以->唐僧<-的身份进行游戏")
# 进入游戏
# 创建变量,来保存玩家的攻击力和生命值
player_life = 2 # 生命值
player_attack = 2 # 攻击力
# Boss的攻击力和生命值
Boss_life = 10
Boss_attack = 10
# 打印一条分割线
print('-'*66)
# 显示玩家的基本信息(攻击力和生命值)
print(f"唐僧,你的生命值是{player_life},攻击力是{player_attack}")
while True: # 用户想要结束的时候才结束
# 打印一条分割线
print('-'*66)
# 正式进入游戏,显示游戏选项
print("请选择你要进行的操作:")
print("\t1.练级")
print("\t2.打Boss")
print("\t3.逃跑")
game_choose = input("请选择你要进行的操作[1/2/3]:")
# 处理用户的选择
if game_choose == '1' :
# 增加玩家的生命值和攻击力
player_life += 2
player_attack += 2
# 打印一条分割线
print('-'*66)
# 显示玩家的基本信息(攻击力和生命值)
print(f"唐僧,你的生命值是{player_life},攻击力是{player_attack}")
elif game_choose == '2' :
# 玩家攻击Boss
# 减去Boss的生命值,减去的生命值应该等于玩家的攻击力
# 打印一条分割线
print('-'*66)
Boss_life -= player_attack
print("->唐僧<-攻击了->白骨精<-")
print(f"->白骨精<-受到了{player_attack}点伤害")
# 检查Boss是否死亡
if Boss_life <= 0 :
# Boss死亡,玩家胜利,游戏结束
print(f"->白骨精<-受到了{player_attack}点伤害,死了,->唐僧<-赢得了胜利")
# 游戏结束
break
# Boss攻击玩家
# 减去玩家的生命值
player_life -= Boss_attack
print("->白骨精<-攻击了->唐僧<-")
# 检查玩家是否死亡
if player_life <= 0 :
# 玩家死亡
print(f"你收到了{Boss_attack}点伤害,死亡,游戏结束")
# 游戏结束
break
elif game_choose == '3' :
# 逃跑,退出游戏
# 打印一条分割线
print('-'*66)
print("->唐僧<-一扭头,撒腿就跑!->白骨精<-一看,一巴掌拍死了->唐僧<-")
print("GAME OVER!!!")
break
else:
# 打印一条分割线
print('-'*66)
print("你的输入有误,请重新输入!")
序列
列表(List)
- 列表是Python中的一个对象
- 对象(object)就是内存中专门用来存储书数据的一块区域
- 之前学习的对象,像数值,他只能保存一个单一的数据
- 列表可以保存多个有序的数据
- 列表的使用:
1.列表的创建
2.列表的操作
列表的简介
列表的创建,通过[] 来创建列表
my_list = [] # 创建一个空列表
my_list = []
print(my_list,type(my_list))
# [] <class 'list'>
列表存储的数据,我们成为数据
一个列表中可以存储多个元素,亦可以在创建列表时,来指定列表中的元素
my_list = [10]
当向列表中添加多个元素时,使用逗号隔开
my_list = [10,20,30]
列表中可以保存任意的对象,但我们一般存储同一类型的元素
my_list = [10,'hello',True,None,[1,2,3],print]
print(my_list)
列表中的对象会按照插入的顺序存储到列表中,第一个插入的对象保存到第一个位置,第二个保存到第二个位置,是有序的
10 | 20 | 30 | 40 |
---|
获取列表中的元素[1]
我们可以通过索引(index)来获取列表中的元素
- 索引是元素在列表中的位置,列表中的每一个元素都有一个索引
- 索引是从0开始的整数,第一个位置的索引为0,第二个为1
10 | 20 | 30 | 40 |
---|---|---|---|
0 | 1 | 2 | 3 |
语法: my_list[index]
my_list = [10,20,30,40]
print(my_list[0])
# 10
my_list = [10,20,30,40]
print(my_list[4])
# 如果使用的索引超过最大的范围,会抛出异常:IndexError: list index out of range
获取列表的长度[2]
就是获取列表中元素的个数
# 通过len()函数
# 获取到的长度的值,是列表的最大索引 + 1
my_list = [10,20,30,40]
print(len(my_list))
# 4
列表的切片[3]
切片指从现有列表中,获取一个子列表
一般创建列表时,变量的名字会使用复数
stus = ['孙悟空','猪八戒','沙和尚']
在列表中列表的索引可以是负数
负数会从后向前获取元素,-1表示倒数第一个,-2表示倒数第三个
超出序列最大长度,依旧会报错
stus = ['孙悟空','猪八戒','沙和尚']
print(stus[-1])
# 沙和尚
切片
语法:列表[起始:结束]
- 序列号
- 会包括起始位置的元素,但不包括结束位置的元素
- 做切片操作时,会返回一个新的列表,不会对原来的列表产生影响
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus[1:4])
print(stus)
# ['猪八戒', '沙和尚', '唐僧']
# ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
- 起始和结束位置的索引可以不写
- 如果省略结束位置,则会从起始位置截取到结尾
- 如果省略起始位置,则会从开始截取到结束位置
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus[:3])
print(stus[2:])
ptint(stus[:])
# ['孙悟空', '猪八戒', '沙和尚']
# ['沙和尚', '唐僧', '蜘蛛精', '白骨精']
# ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
第三个参数,步长
语法:列表[起始:结束:步长]
- 表示每次获取元素的间隔,默认值是1
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus[0:5:2])
# ['孙悟空', '沙和尚', '蜘蛛精']
print(stus[::3])
# ['孙悟空', '唐僧']
- 步长不能为0,可以是负数
- 如果是负数,就会从列表后面向前面去元素
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus[::-1])
# ['白骨精', '蜘蛛精', '唐僧', '沙和尚', '猪八戒', '孙悟空']
列表的通用操作[4]
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
- + 和 乘
my_list = [1,2,3] + [4,5,6]
my_list = [1,2,3] * 3
-
in 和 not in
in用来检查指定元素是否存在于列表中
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精'] print('牛魔王' in stus) # False
not in 用来检查指定元素是否不存在于列表中
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精'] print('牛魔王' not in stus) # True
-
# len() 获取列表中的元素位置 # max() 获取列表中的最大值 # min() 获取列表中的最小值
arr = [10,2,5,9,11] print(f"arr_max = {max(arr)},arr_mix = {min(arr)}") # arr_max = 11,arr_mix = 2
-
两个方法(method),方法和函数基本上是一样的,只不过方法必须通过-> 对象.方法() 的形式调用
# s.index() 和 s.count() stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精'] # s.index() 获取指定元素在列表中的位置 print(stus.index("孙悟空")) # 0
- 如果查找不存在的元素,会抛出异常
- 获取指定元素在列表中第一次出现时的索引
- index()的第二个参数,表示查找的起始位置
- index()的第三个参数,表示查找的结束位置
- 还是不包括结束位置
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精','孙悟空','孙悟空'] print(stus.index("孙悟空",3,7))
# s.index() 和 s.count() stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精','孙悟空','孙悟空'] # s.count() 获取指定元素在列表中出现的次数 print(stus.count("孙悟空")) # 3
序列
- 序列是Python中最基本的一种数据结构
- 数据结构就是指计算中数据存储的方式
- 序列用于保存一种有序的数据,所有的数据在序列当中都有一个唯一的位置(索引)
- 序列中的元素会按照添加的顺序来分配索引
- 序列的分类:
- 可变序列(序列中的元素可以改变)
列表(list)
- 不可变序列(序列中的元素不可以改变)
字符串(str)、元组(tuple)
- 上面的所有操作,都是序列的通用操作,即[1]~[4]
修改列表
一下操作只限于可变序列
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
修改列表中的元素-通过索引和切片
- 直接通过所以来修改元素
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
stus[0] = 'sunwukong'
print(stus)
- 通过del来删除元素
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus)
stus[0] = 'sunwukong'
del stus[2]
print(stus)
# ['孙悟空', '猪八戒', '沙和尚', '唐僧', '蜘蛛精', '白骨精']
# ['sunwukong', '猪八戒', '唐僧', '蜘蛛精', '白骨精']
- 通过切片来修改列表
- 在给切片进行赋值时,只能使用序列
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus)
stus[0] = 'sunwukong'
del stus[2]
print(stus)
stus[0:2] = 123
print(stus)
# TypeError: can only assign an iterable
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus)
stus[0] = 'sunwukong'
del stus[2]
print(stus)
stus[0:2] = ['牛魔王','红孩儿']
print(stus)
# ['孙悟空', '猪八戒', '沙和尚', '唐僧', '蜘蛛精', '白骨精']
# ['sunwukong', '猪八戒', '唐僧', '蜘蛛精', '白骨精']
# ['牛魔王', '红孩儿', '唐僧', '蜘蛛精', '白骨精']
- 注意不是只能传递相同的数目,可以任意
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus)
stus[0] = 'sunwukong'
del stus[2]
print(stus)
stus[0:2] = ['牛魔王','红孩儿','二郎神']
print(stus)
# ['牛魔王', '红孩儿', '二郎神', '唐僧', '蜘蛛精', '白骨精']
- 在某个位置插入元素
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus)
stus[0:0] = ['牛魔王']
print(stus)
- 如果有步长时,需要提供相同的元素个数
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus)
stus[::2] = ['牛魔王','红孩儿','二郎神']
print(stus)
- 通过切片来删除元素
stus = ['孙悟空','猪八戒','沙和尚','唐僧','蜘蛛精','白骨精']
print(stus)
del stus[0:2]
print(stus)
del stus[::2]
print(stus)
stus[1:3] = []
print(stus)
# ['孙悟空', '猪八戒', '沙和尚', '唐僧', '蜘蛛精', '白骨精']
# ['沙和尚', '唐僧', '蜘蛛精', '白骨精']
# ['唐僧', '白骨精']
# ['唐僧']
- list()函数可以将其他的序列转换为list
s = 'hello'
s = list(s)
print(s)
# ['h', 'e', 'l', 'l', 'o']
列表的方法
stus = ['孙悟空','猪八戒','沙和尚']
s.append(x)
将元素x添加到列表的最后
stus = ['孙悟空','猪八戒','沙和尚']
stus.append('唐僧')
print(stus)
s.insert(i,x)
像列表的指定位置添加元素
stus = ['孙悟空','猪八戒','沙和尚']
stus.insert(2,'唐僧')
print(stus)
# ['孙悟空', '猪八戒', '唐僧', '沙和尚']
s.extend(t)
- t就是一个序列
使用新的序列来扩展当前序列
- 相当于 +
stus = ['孙悟空','猪八戒','沙和尚']
stus.extend(['唐僧','白骨精'])
print(stus)
s.clear
清空序列
stus = ['孙悟空','猪八戒','沙和尚']
stus.clear()
print(stus)
# []
s.pop()
根据索引删除并返回指定元素
stus = ['孙悟空','猪八戒','沙和尚']
result = stus.pop(2)
print('result = ',result)
print(stus)
- 如果不写索引,默认删除最后一个元素
s.remove()
删除指定值的元素,如果相同值的元素有多个,只会删除第一个
stus = ['孙悟空','猪八戒','沙和尚']
stus.remove("猪八戒")
print(stus)
s.reverse()
用来反转列表
stus = ['孙悟空','猪八戒','沙和尚']
stus.reverse()
print(stus)
s.sort()
用来对列表中的元素进行排序
my_list = [10,1,20,5,8,-1]
print("修改前",my_list)
my_list.sort() # 默认是升序进行排序
print("修改后1",my_list)
my_list.sort(reverse = True) # 开启反转,降序排列
print("修改后2",my_list)
# 修改前 [10, 1, 20, 5, 8, -1]
# 修改后1 [-1, 1, 5, 8, 10, 20]
# 修改后2 [20, 10, 8, 5, 1, -1]
遍历列表
stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧']
创建一个循环来打印列表
# 创建一个列表
stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧']
# 通过while循环来遍历列表
i = 0
while i < len(stus) :
print(stus[i])
i += 1
通过 for 循环来遍历列表
语法:
for 变量 in 序列 :
代码块
stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧']
for s in stus :
print(1)
for 循环会执行多次,序列中有几次就执行几次
- 每执行一次就会将序列中的一个元素赋值给变量
- 所以可以通过变量来获取列表中的元素
stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧']
for s in stus :
print(s)
EMS(Employee Manager Sysyem 员工管理系统)练习
通过命令行版本的员工管理系统
- 功能
- 查询:显示当前系统内的所有员工
- 添加:将员工添加到当前系统中
- 删除:将员工将系统中删除
- 退出:退出系统
- 员工信息保存到列表中,系统中应该有一个列表,专门用来保存所有员工信息
# 显示欢迎信息
print('-'*20 ,'欢迎使用员工管理系统','-'*20)
# 创建一个列表,用来保存员工信息,员工信息是以字符串的形式统一保存到列表中
emps = ['孙悟空\t18\t男\t花果山','猪八戒\t20\t男\t花果山']
# 创建一个死循环
while True:
# 显示用户的选项
print("请选择要做的操作:")
print("\t1.查询员工")
print("\t2.添加员工")
print("\t3.删除员工")
print("\t4.退出系统")
user_choose = input("请选择1/2/3/4: ")
# 打印分割线
print('-'*62)
# 根据用户的选择进行相关的操作
if user_choose == '1' :
# 查询员工
# 打印表头
print("\t序号\t姓名\t年龄\t性别\t住址")
# 创建一个变量,来表示员工的序号
n = 1
# 显示员工信息
for emp in emps:
print(f"\t{n}\t{emp}")
n += 1
elif user_choose == '2' :
# 添加员工
# 设置一个预设字符串,用来暂时保存要添加的员工信息
emp = ''
# 用户输入员工信息
emp_name = input("请输入要添加的员工的姓名:")
emp_age = input("请输入要添加的员工的年龄:")
emp_gender = input("请输入要添加的员工的性别:")
emp_address = input("请输入要添加的员工的地址:")
# 将员工信息添加到列表中
emp = f'{emp_name}\t{emp_age}\t{emp_gender}\t{emp_address}'
# 预先展示添加员工的信息,确认是否要添加
print('-'*62)
print("姓名\t年龄\t性别\t住址")
print(emp)
print('-'*62)
while True:
user_confirm = input('是否确认该操作[Y/N]:')
# 判断
if user_confirm == 'y' or user_confirm == 'Y' :
# 确认添加
emps.append(emp)
# 显示提示信息
print("添加成功!")
break
elif user_confirm == 'n' or user_confirm == 'N':
# 取消操作
print("添加已取消")
break
else:
print("输入错误!请重新输入!!")
continue
elif user_choose == '3' :
# 删除员工,根据员工的序号来删除员工
# 获取渝澳删除的员工的序号
del_index = int(input("请输入要删除的员工的序号:"))
# 判断序号是否有序
if del_index <= len(emps) and del_index > 0 :
# 输入合法,需要根据序号来获取索引
del_i = del_index -1
# 显示提示
print('-'*62)
print("\t序号\t姓名\t年龄\t性别\t住址")
print(f'\t{del_index}\t{emps[del_i]}')
print('-'*62)
user_confirm = input('是否确认该操作[Y/N]:')
# 判断
if user_confirm == 'y' or user_confirm == 'Y' :
# 删除元素
emps.pop(del_i)
# 显示提示
print("员工已删除!")
elif user_confirm == 'n' or user_confirm == 'N':
# 取消操作
print("添加已取消")
else:
print("输入错误!请重新输入!!")
elif user_choose == '4':
# 退出系统
break
else:
print("输入错误,请重新输入")
# 打印分割线
print('-'*62)
range函数
range() 是一个幻术,可以用来生成一个自然数序列
r = range(0,5)
print(list(r))
# [0, 1, 2, 3, 4]
该函数需要三个此参数
- 起始位置(可以省略,默认是0)
- 结束位置
- 步长(可以省略,默认是1)
r = range(0,10,3)
print(list(r))
# [0, 3, 6, 9]
r = range(10,0,-1)
print(list(r))
# [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
range() ,可以创建一个指定次数的for循环
for i in range(10):
print(i,end=" ")
# 0 1 2 3 4 5 6 7 8 9
for 循环除了创建方式以外,其余都与while相同,包括else,break,continue都可以在for循环中使用
遍历字符串
for s in 'hello':
print(s,end="")
# hello
元组(tuple)
元组是一个不可变序列,操作方式基本上和列表一致
操作元组时,将元组当作一个不可操作的列表就行!
一般当我们希望数据不改变时,就是用元组,其余情况就使用列表
创建元组
使用()来创建元组
my_tuple = ()
print(my_tuple,type(my_tuple))
# () <class 'tuple'>
my_tuple = (1,2,3,4,5)
print(my_tuple)
print(my_tuple[3])
- 不能对元组中的元素重新赋值
…
当元组不是空元组时,括号可以省略
my_tuple = 1,2,3,4
print(my_tuple,type(my_tuple))
- 如果元组不是空元组,它里面至少有一个逗号
my_tuple = 10,
print(my_tuple,type(my_tuple))
my_tuple = ()
print(my_tuple,type(my_tuple))
元组的解包(解构)赋值
my_tuple = 1,2,3,4
print(my_tuple,type(my_tuple))
a ,b ,c ,d = my_tuple
print("a = ",a)
print("b = ",b)
print("c = ",c)
print("d = ",d)
# (1, 2, 3, 4) <class 'tuple'>
# a = 1
# b = 2
# c = 3
# d = 4
- 交换两个变量的值,这时我们就可以利用元组的解包
a = 100
b = 300
print(a,b)s
# 100 300
a , b = b , a
print(a,b)
# 300 100
- 注意解包时,变量的数目要与元组中元素数目相同
- 解决方法: *c – 可以获取元组中所有剩余的元素,保存到一个列表中
my_tuple = 10,20,30,40
a , b , *c = my_tuple
# *可以添加在任意元素,但只能有一个*
print("a = ",a)
print("b = ",b)
print("c = ",c)
# a = 10
# b = 20
# c = [30, 40]
- *可以添加在任意元素,但只能有一个*
my_tuple = 10,20,30,40
*a , b , c = my_tuple
# *可以添加在任意元素,但只能有一个*
print("a = ",a)
print("b = ",b)
print("c = ",c)
# a = [10, 20]
# b = 30
# c = 40
注意:
- 解包可以使用在任意序列中
my_tuple = [10,20,30,40]
*a , b , c = my_tuple
# *可以添加在任意元素,但只能有一个*
print("a = ",a)
print("b = ",b)
print("c = ",c)
# a = [10, 20]
# b = 30
# c = 40
可变对象
- 每个对象都保存了三个数据:
- id
- type
- value
- 可变的是值value
- 列表
# 修改对象
a = [1,2,3]
a[0] = 10 # 这种操作就是在通过变量去修改对象的值,则这种操作不会改变变量所指向的对象
# 修改变量
a = [4,5,6] # 这中操作是在给变量重新赋值,这种操作会修改变量所指向的对象
a = [1,2,3]
print("修改前:",a,"--id=",id(a))
# 修改前: [1, 2, 3] --id= 2008685154240
# 通过索引来改变列表
a[0] = 10
print("修改后1:",a,"--id=",id(a))
# 修改后1: [10, 2, 3] --id= 2008685154240
# 为变量重新赋值
a = [4,5,6]
print("修改后2:",a,"--id=",id(a))
# 修改后2: [4, 5, 6] --id= 2008684732160
改对象
- 我们去修改对象时,如果有其他的变量也指向该对象,那么其他变量发生同样的改变
- 因为他们指向的是同一个对象
a = [1,2,3]
b = a
b[0] = 10
print(a,id(a))
print(b,id(b))
改变量
- 修改变量时,不会对其他产生影响
a = [1,2,3]
b = a
b = [4,5,6]
print(a,id(a))
print(b,id(b))
注:
- == != 比较的是对象的值是否相等
- is not is 比较的是对象的id是否相同(比较他们是否同一个对象)
a = [1,2,3]
b = [1,2,3]
print(a == b) # True
print(a is b) # False
字典(dict)
字典属于一个新的数据结构,称为映射(mapping)
字典的作用和列表类似,都是用来存储对象的容器
列表存储数据的性能很好,但是查询数据的性能很差
在字典中每一个元素都有一个唯一的名字,通过这个唯一的名字可以进行快速的查找到指定的元素
在查询元素时,字典的效率是非常快的
在字典中可以保存多个对象,每个对象都会有一个唯一的名字
- 这个唯一的名字,我们称为键(Key),通过键可以快速查找其对应的值
- 这个对象,我们称其为值(value)
- 所以字典,我们称其为键值对结构
- 每个字典中都可以有多个键值对,而每个键值对我们称其为–项
字典的创建
1.{}
# 通过 {} 来创建字典
d = {}
print(d,type(d))
# {} <class 'dict'>
语法:
{key:value,key:value,key:value}
字典的值可以是任意对象
字典的键可以是任意的不可变对象(int,str,bool,tuple…),一般都是用字符串
d = {'name':'孙悟空','age':18,'gander':'男'}
print(d,type(d))
# {'name': '孙悟空', 'age': 18, 'gander': '男'} <class 'dict'>
- 注意:字典的键是不能重复的,如果出现重复,后面的会替换前面的
d = {'name':'孙悟空','age':18,'gander':'男','name':'sunwukong'}
print(d,type(d))
# {'name': 'sunwukong', 'age': 18, 'gander': '男'} <class 'dict'>
- 可以多行,为了更加清楚
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
'name':'sunwukong'
}
print(d,type(d))
2.dict()
d = dict(name='孙悟空',age=18,gander='男')
print(d,type(d))
# {'name': '孙悟空', 'age': 18, 'gander': '男'} <class 'dict'>
# 注意通过dict(),创建的字典,key都是字符串
- 双值子序列
双值序列,序列中只有两个值,[1,2],(‘a’,3),‘ab’
子序列:如果序列中的元素也是序列,那么我们就称这个元素为子序列
d = dict([('name','孙悟饭'),('age',18)])
print(d,type(d))
# {'name': '孙悟饭', 'age': 18} <class 'dict'>
相关操作
len() – 获取字典中键值对的个数
in 检查字典中是否包含指定的键
not in 检查字典中是否不包含指定的键
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
print(d,type(d))
print(len(d))
print('hello' not in d)
# {'name': '孙悟空', 'age': 18, 'gander': '男'} <class 'dict'>
# 3
# True
可以根据键(key)来获取值
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
print(d['name'],d['age'],d['gander'])
# 孙悟空 18 男
- 如果出现了字典中不存在的键,会报错
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
print(d['hello'])
# --> KeyError: 'hello'
get(key[,default]) 该方法用来根据键来获取字典中的值 – 方法
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
print(d.get('name'))
- 如果想要获取的键在字典中不存在,默认是返回None
- 可以设定一个返回值,来作为第二个参数,这样获取不到值时会返回你设定的返回值
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
print(d.get('hello','大圣'))
修改字典
d[key] = value
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
d['name'] = 'sunwukong' # 如果存在就覆盖
d['address'] = '花果山' # 如果不存在就添加
print(d)
# {'name': 'sunwukong', 'age': 18, 'gander': '男', 'address': '花果山'}
setdefault(key[,default]) – 方法
可以用来向字典中添加Key-value
- 如果key不存在,则返回key的值,不会对字典做任何操作
- 如果key不存在,则像字典中插入这个key,并设置value
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
d.setdefault('name','猪八戒') # 孙悟空
d.setdefault('hello','猪八戒') # 猪八戒
updata([other]) – 方法
将其他字典中的key-value添加到当前字典中
- 如果有重复的key,则后面的会替换当前的
d = {'1':'a','2':'b'}
b = {'3':'c','4':'d'}
d.update(b)
print(d)
# {'1': 'a', '2': 'b', '3': 'c', '4': 'd'}
d = {'1':'a','2':'b'}
b = {'1':'c','4':'d'}
d.update(b)
print(d)
# {'1': 'c', '2': 'b', '4': 'd'}
删除
del[key]
popitem() – 方法
- 随机删除字典中的一个键值对,一般都会删除最后一个键值对
d = {'1': 'a', '2': 'b', '3': 'c', '4': 'd'}
d.popitem()
print(d)
返回的是一个元组,元组中有两个元素,第一个元素时删除的key,第二个是删除的value
d = {'1': 'a', '2': 'b', '3': 'c', '4': 'd'}
result = d.popitem()
print(result)
pop(key[,default]) – 方法
- 根据key删除字典中的键值对
- 会将被删除的value返回
- 如果删除了不存在的key时,会抛出异常
- 如果指定了默认值,再删除不存在的key时,不会报错,而是直接返回默认值
- 如果删除空字典,会抛出异常
d = {'1': 'a', '2': 'b', '3': 'c', '4': 'd'}
result = d.pop('z','None')
print(result)
clear() – 方法
用来清空字典
d = {'1': 'a', '2': 'b', '3': 'c', '4': 'd'}
d.clear()
print(d) # {}
copy() – 方法
该方法用于对字典进行浅复制–复制以后的对象与原对象是独立的
- 修改一个是不会对另一个产生影响
- 浅复制:只会复制值,如果值也是一个可变对象,这个可变对象不会被复制
d = {'a':{'name':'孙悟空','age':18},'b':'2','c':'3'}
d2 = d.copy()
d2['a']['name'] = '猪八戒'
print(d)
print(d2)
# {'a': {'name': '猪八戒', 'age': 18}, 'b': '2', 'c': '3'}
# {'a': {'name': '猪八戒', 'age': 18}, 'b': '2', 'c': '3'}
遍历字典
–keys()
- 该方法会返回字典的所有的key
- 该方法会返回一个序列,序列中保存有字典中所有的键
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
print(d.keys())
# dict_keys(['name', 'age', 'gander'])
for i in d.keys():
print(i)
# name
# age
# gander
–values()
- 该方法会返回一个序列,序列中保存有所有字典的值
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
for i in d.values():
print(i)
# 孙悟空
# 18
# 男
–items()
- 该方法会返回一个序列,序列中包含双值子序列
- 双值分别是key和value
d = {
'name':'孙悟空',
'age':18,
'gander':'男',
}
for k,v in d.items():
print(k,':',v)
# name : 孙悟空
# age : 18
# gander : 男
集合(set)
集合和列表相似
不同点:
1. 集合中只能存储不可变对象
2. 集合中存储的对象是无序的(不是按照元素的插入顺序保存的)
3. 集合中不能出现相同的元素
集合的创建
1.{}
s = {10,3,5,1,2,1,1,1}
print(s,type(s))
# {1, 2, 3, 5, 10} <class 'set'>
- 注意无法直接创建
s = {}
- 这样创建的是一个字典,但可以通过set(),来进行创建
2.set()
set() – 还可以将序列和字典转化为集合
s = set()
s = set([1,2,3,4,5,1,6,21,2])
print(s)
s = set('hello')
print(s)
s = set({'a':1,'b':2})
print(s)
# {'a', 'b'}
# 注意字典转换的集合只会包含字典中的键
集合的操作
in 和 not in
len() – 获取集合中元素的数量,重复的元素不会重复计数
添加元素
add() --方法
s = {'a','b',1,2,3}
print(s)
s.add(10)
print(s)
update() – 方法
s = {'a','b',1,2,3}
s2 = set('hello')
s.update(s2)
print(s)
# {1, 2, 3, 'o', 'h', 'e', 'a', 'l', 'b'}
s = {'a','b',1,2,3}
s.update((10,20,30))
print(s)
s.update({10:'ab',20:'cd',30:'ef'})
print(s)
删除元素
pop() – 方法
随机删除一个元素
s = {'a','b',1,2,3}
s.pop()
print(s)
result = s.pop()
print('result = ',result)
remove() – 方法
删除集合中指定元素
s = {'a','b',1,2,3}
s.remove(1)
print(s)
# {2, 3, 'a', 'b'}
clear() – 方法
清空集合
s = {'a','b',1,2,3}
s.clear()
print(s)
# set()
复制
copy() – 方法
浅复制
…
集合的运算
在对集合进行运算时,不会对原来的集合产生结果,而是返回一个运算结果-新集合
s = {1,2,3,4,5}
s2 = {3,4,5,6,7}
print(s)
print(s2)
# & 交集运算
print(s & s2)
result = s & s2
print("result = ",result)
# | 并集运算
result = s | s2
print("result = ",result)
# - 差集运算
result = s - s2
print("result = ",result)
# ^ 亦或集 不相交的部分
result = s ^ s2
print("result = ",result)
# <= 检查一个集合是否是另一个集合的子集
# 如果一个集合的元素全部都在另一个集合中出现,那么这个集合就是另一个集合的子集
# a是b的子集,b是a的超集
a = {1,2,3}
b = {1,2,3,4,5}
result = a <= b
print("result = ",result) # True
result = {1,2,3} <= {1,2,3}
print("result = ",result) # True
# < 一个集合是否是另一个集合的真子集
# 如果超集b中含有子集a中的所有元素,并且b中还有a中没有的元素,则b就是a的真超集,a是b的真子集
result = a < b
print("result = ",result)
# result = True
result = {1,2,3} < {1,2,3}
print("result = ",result)
# result = False
# >= 检查一个集合是否是另一个集合的超集
# > 检查一个集合是否是另一个的真超集
函数(function)
1 简介
- 函数也是以一个对象
- 那么对象是干嘛得呢?
-对象是内存中专门用来存储数据的一块区域
-函数也是一个对象,python中万物皆对象,那么函数对象是用于存储一些可以执行得代码
-应用函数得意义在哪里?
-重复化调用,模块化编程
- 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用
- 定义函数一般都是要实现某种功能的,不是想我下面写的那些无意义的打印
- 函数名
- 必须要符合表示符的规范
- 可以包括字母数字下划线,但不能以数字开头
# 比如有如下三行代码,这三行代码是一个完整的功能
print("Hello")
print("你好")
print("再见~bye")
# 现在以我们学到的技术,在其他部分使用这三行代码时,只能进行复制
# 现在为了更加便捷,就有了函数
2 创建函数
def 函数名([形参1,形参2…形参n]) :
代码块
# 定义一个函数
def fn():
print("这是我的第一个函数!")
print(fn) # fn是函数对象
# 编程规范
from typing import List
# 在形参列表中声明类型,增强可读性
def function(lst:List[int],n:int,m:float):
"""
此函数的功能
:param lst:
:param n:
:param m:
:return :
"""
函数体
- 函数中的代码不会执行,只有调用函数时,才会执行
3 调用函数
语法:函数对象()
def fn():
print("这是我的第一个函数!")
# 调用函数
fn() # fn() 是调用函数
注意
fn是函数对象,fn()调用函数,print函数对象,print()调用函数
例如在QButton连接信号时候填入的是函数对象而非调用函数
button1.clicked.connect(function)
4 函数参数
4.1 形参和实参
- 在定义函数时,可以在函数名后的()内,定义数量不等的形参,
多个形参之间使用逗号隔开
- 形参(形式上的参数)
-定义形参,相当于在函数内部声明了变量,但没有赋值
-函数定义时,定义形参,在函数内部声明变量
- **实参(**实际上的参数),
- 如果函数定义时,指定了形参,那么在调用函数时,就必须传递实参
-函数调用时,传入实参
- 实参的数值就是形参的
# 定义函数时,指定形参
def sum(a, b):
print("a = ",a)
print("b = ",b)
print("a + b = ", a+b)
# 调用函数时,来传递实参
sum(10,20)
4.2 参数传递的方式
- 每一个函数的参数都是独立的,只在函数内部起作用
- 定义形参后,可以指定默认值
- 如果用户没有传递指定了默认值的参数,则默认值生效
- 如果用户传递了,那么默认值不会生效
- 实参的传递方式
- 位置参数
- 位置参数就是将对应位置的实参复制给对应位置的形参
- 第一个实参赋值给第一个形参,第二个实参赋值给第二个形参
- 关键字参数
- 可以不按照形参定义的顺序去传递,而直接根据参数名去传递
例如
print("hello",end='')
"hello"
为位置参数,end=''
为关键字参数
- 混合使用位置参数和关键字参数时,必须将位置参数写到前面
def fn(a = 5, b = 2 ,c = 1):
print("a = ",a)
print("b = ",b)
print("c = ",c)
# fn() # 位置
# fn(1,2,3)
# fn(1,2)
# fn(b=1,c=10,a=3) # 关键字参数
# fn(1,b=2,3) # 混合使用
-实参的类型
- 实参在调用的时候,python解析器不会检查实参的类型,即实参以传递任意类型的对象(包括函数),没有类型的限制
def fn2(a):
print("a = ",a)
fn2(123)
fn2(True)
fn2("hello")
fn2([1,2,3])
fn2(fn)
- 但是由于不会检查实参的类型,所以也会产生一些错误
def fn3(a,b):
print(a+b)
fn3(12,"123")
#由于不会检查变量的类型所以会报错
# 如何处理?异常检查
# 增强可读性写法
def fn3(a:int,b:int):
"""
计算两数之和
:param a: int
:param b:int
:return :NONE
"""
print(a+b)
- 所以调用时,要明确自己要传递的参数的类型
-定义函数的良好习惯,编程规范
定义的一些类,方法,函数要进行声明
def function():
"""
计算一个给定的数据集里面距离最近的两个点的坐标和距离
:param lstx: 表示每个点的横坐标
:param lsty: 表示每个点的纵坐标
:param n:表示点对的个数
:return:minPoint,minDistance: 返回距离最小的点的坐标和距离
"""
typing模块
[from typing import Dict, Tuple, List, Optional_from typing import list-CSDN博客](https://blog.csdn.net/weixin_46713695/article/details/125032851?ops_request_misc=%7B%22request%5Fid%22%3A%22171222374816800225524183%22%2C%22scm%22%3A%2220140713.130102334…%22%7D&request_id=171222374816800225524183&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-125032851-null-null.142v100pc_search_result_base3&utm_term=from typing import list%2C tuple&spm=1018.2226.3001.4187)
函数的形参也可以向c语言一样声明,变量类型,增强可读性
typing 是python3.5中开始新增的专用于类型注解(type hints)的模块,为python程序提供静态类型检查,具体的讲解参考资料
Question:
- rom typing imort List 中的List和python自带的变量list有何区别,为什么要用typing模块进行标注def function(lst:List)->None 为什么不能直接用list进行标注例如def function(lst:list)->None
Answer:
-
Python中,
List
是typing
模块中的一个泛型类型,用于表示一个列表,而list
是Python自带的内置类型,用于表示一个列表。它们的区别在于List
是用于类型标注的,而list
是实际的数据类型。当你使用
typing
模块中的List
时,你在进行类型标注,这有助于在静态类型检查器(如Mypy)中进行类型检查。这样做可以帮助你在编写代码时发现潜在的类型错误,提高代码的可读性和可维护性。因此,当你使用
def function(lst:List)->None
时,你在告诉其他开发者和静态类型检查器,function
函数接受一个列表作为参数,并且不返回任何内容。相反,如果你直接使用
def function(lst:list)->None
,这只是一种约定俗成的命名,它没有提供具体的类型信息,因此在静态类型检查器中可能无法进行准确的类型检查。总之,使用
typing
模块中的List
进行标注可以提供更丰富的类型信息,有助于代码的可维护性和可读性。
总结示例
from typing import Dict, Tuple, List, Optional
def cloest_Point(lstx:List[int],lsty:List[int],n:int) -> return Tuple[Tuple[int, int], float]
"""
计算一个给定的数据集里面距离最近的两个点的坐标和距离
:param lstx: 表示每个点的横坐标
:param lsty: 表示每个点的纵坐标
:param n:表示点对的个数
:return:minPoint,minDistance: 返回距离最小的两个点的索引和距离((i,j),distance)
"""
-所以要清楚是改变量还是该对象
- python实参到形参是值传递
对形参进行重新赋值,不会影响外部,即改变量不影响
def fn4(a):
a = 20
print(f"a={a}")
b = 10
fn4(b)
print(f"b={b}")
- 但是如果形参指向的是一个对象,当我们通过形参去修改对象时,会影响到所有指向该对象的变量
def fn(a):
a[0] = 30
print(a,id(a))
c = [1,2,3]
fn(c)
print(c)
- 如果我们不希望发生这种情况,那我们就可以传递一个实参的副本
def fn(a):
a[0] = 30
print(a)
c = [1,2,3]
fn(c.copy()) # copy方法
fn(c[:]) # 切片
print(c)
4.3 不定长参数(参数的装包)
- 在定义函数时,可以在形参前面添加一个 ,这样这个形参将会获得所有的实参,将所有的实参保存到一个元组中
- 他会将所有的实参保存到一个元组中
- a会接受所有的位置实参,并且会将这些实参同意保存到一个元组中(装包)
- 注意带号的参数只能有一个
def fn(*a):
print('a = ',a)
print(type(a))
fn(1,2,3,4)
# 例题:求任意数之和
def fn(*nums):
print('nums = ',nums)
# 定义一个变量,来保存结果
result = 0
# 遍历元组,并将元组中的数进行累加
for n in nums:
result += n
print('result = ',result )
fn(1,2,3,4)
- 可以和其他参数配合使用
def fn2(a,b,*c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn2(1,2,3,4,5,6)
- 可以写到前面/中间,但是注意可变参数带*参数其后的所有参数,必须以关键字的形式传递
# 不定长参数后的参数,必须以关键字参数传递
def fn2(a,*b,c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn2(1,2,3,4,5,c = 6)
def fn2(*a,b,c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn2(1,2,3,4,b = 5,c = 6)
- 如果在最前面加一个*号,则要求我们所有的参数必须以关键字参数的形式传递
def fn2(*,a,b,c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn2(a = 4,b = 5,c = 6)
- 参数只能接受位置参数,而不能接受关键字参数
- 这时候我们又有一个**参数
- **参数,会将这些参数同一保存到一个字典中
- 字典的key就是参数的名字,字典的value就是参数的值
- **形参只能有一个,并且必须写在所有参数的最后
若是放在前面用位置参数传递会报错,用关键字参数传递会影响后面的参数传递,所以**接受关键字的不定长参数只能放在最后
def fn3(b,c,**a):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn3(b = 1,d = 2,c = 3,e = 10)
# a = {'d': 2, 'e': 10}
# b = 1
# c = 3
总结
4.4 参数解包
对序列型(list,tuple,set)的参数进行解包用 *
对字典进解包 用**
def fn4(a,b,c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
# 创建一个元组/列表
t = (10,20,30)
# 解包
# 传递实参时,也可以在序列类型的参数前添加*,这样他会自动将序列中的元素依次作为参数传递
# 这里要求序列中元素的个数,必须和形参的个数一致
fn4(*t)
def fn4(a,b,c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
# fn4(*t)
# 创建一个字典
d = {'a':100,'b':200,'c':300}
# 通过**,对字典进行解包
fn4(**d)
5 返回值
就是函数执行以后返回的结果
1、可以通过 return 来指定函数的返回值
2、可以直接使用函数的返回值也可以通过一个变量来接受函数的返回值
return 后面跟什么值,函数就会返回什么值
3、- return 后面可以跟任意对象
def fn():
# return 100
# return 'hello'
# return [1,2,3]
return {'k':'v'}
r = fn()
print(r)
- 也可以是一个函数
def fn():
def fn2() :
print("hello")
return fn2
r = fn()
r()
4、如果仅仅写一个return 或者不写return,则相当于return None
def fn():
a = 10
return
r = fn()
print(r)
5、在函数中,return后的代码都不会执行,一个函数只会执行一个return
def fn() :
print('hello')
return
print('123')
fn()
实例:
def fn4() :
for i in range(5):
if i == 3 :
break # 用于退出当前循环
print(i)
print("循环执行完毕!")
fn4()
# 0
# 1
# 2
# 循环执行完毕!
def fn4() :
for i in range(5):
if i == 3 :
continue #用于跳过当次循环对下一次不影响
print(i)
print("循环执行完毕!")
fn4()
# 0
# 1
# 2
# 4
# 循环执行完毕!
def fn4() :
for i in range(5):
if i == 3 :
return # 在一个函数中return一旦执行,后面语句则不会再执行
print(i)
print("循环执行完毕!")
fn4()
# 0
# 1
# 2
6、function和function()的区别
def function(a;int,b:int)->int:
return a + b
print(function)
print(funtion(5,6))
#
# 11
function为函数对象,相当于机器
function()是调用函数,返回的是return的值,相当于我再用这个机器,给我的是这个机器生成的产品
6 文档字符串(doc str)
在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明
-
1、如何编写
-
def fn(a:int,b:int,c:int)->int: """ 返回三个数之和 :param a:int,数a,None :param b:int,数b,None :param c:int,数c,None return a + b + c """ return a + b + c
-
-
2、如何查看
- help(函数对象)用于查询python中的函数的用法
- 注意是函数对象,而非调用函数
- 可以是python内置的help(print)
- 可以是自己定义的help(function)
- 可以是类中定义的方法help(class1.functoin1)
-
3、为什么要编写?
- 一个项目好久不看了,或者说给别人看,想调用某个函数,但又不想读代码,只想看看这个函数有什么功能,传入什么参数,返回什么?
- 即快速查看某个函数的功能,参数,返回值
-
4、如何利用?
- 看别人特别是大佬的代码,例如yolov8想了解某个函数的功能使,可以把鼠标放在该函数上,或者help,或者直接看源码
当编写了文档字符串时,就可以通过help()函数来查看函数的说明
1.在第一行通过添加注释,help()函数就会显示
def fn(a,b,c):
'''
这是一个文档字符串的实例
函数的作用
函数的参数:
a, 作用,类型,默认值
...
'''
return 10
help(fn)
它的输出是:
Help on function fn in module __main__:
fn(a, b, c)
这是一个文档字符串的实例
函数的作用
函数的参数:
a, 作用,类型,默认值
...
2.通过冒号,注意这只是一个说明,并没有强制要求
例:
def fn(a:int,b:bool,c:str='hello') -> int:
'''
这是一个文档字符串的实例
函数的作用
函数的参数:
a, 作用,类型,默认值
...
'''
return 10
help(fn)
输出:
Help on function fn in module __main__:
fn(a: int, b: bool, c: str = 'hello') -> int
这是一个文档字符串的实例
函数的作用
函数的参数:
a, 作用,类型,默认值
...
7 作用域
作用域指的是变量生效的区域
b = 20
def fn():
a = 10
print('函数内部:','a = ',a)
print('函数内部:','b = ',b)
print('函数外部:','b = ',b)
fn()
在Python中一共有两种作用域
全局作用域
- 全局作用域在程序执行时创建,在程序执行结束时销毁
- 所有函数以外的区域都是全局作用域
- 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问
函数作用域
- 函数作用域在函数调用时创建,在调用结束时销毁
- 函数每调用一次就会产生一个新的函数作用域
- 在函数作用域中定义的变量,都是局部变量,他只能在函数内部被调用
当我们使用一个变量时,会优先在当前作用域中寻找该变量,如果有,则使用
如果没有则继续去上一级作用域中寻找
如果依然没有,则继续去上一级作用域中寻找,以此类推
b = 20
def fn():
b = 10 # 在函数中使用的变量,默认都是为局部变量赋值
print('函数内部:','b = ',b)
print('函数外部:','b = ',b)
fn()
# 函数外部: b = 20
# 函数内部: b = 10
如果需要去修改全局变量,即在函数内部修改全局变量,则需要使用global关键字,来声明变量
b = 20
def fn():
global b
b = 10
print('函数内部:','b = ',b)
fn()
print('函数外部:','b = ',b)
# 函数内部: b = 10
# 函数外部: b = 10
8 命名空间(namespace)
- 变量就存储在命名空间,每一个变量都需要存储到指定的命名空间当中
- 每一个作用域都会有一个它对应的命名空间
- 全局命名空间,用来保存全局变量;函数命名空间用来保存函数的变量
- 命名空间实际上就是一个字典,是一个专门用来存储变量的字典
- 函数:locals(),用来获取当前作用域的命名空间
- 如果在全局作用域中调用locals,则获取全局命名空间
- 如果在函数作用域中调用locals,则获取函数命名空间
b = 20
def fn():
b = 10
print('函数内部:','b = ',b)
fn()
scope = locals()
print(scope)
scope['c'] = 10000 # 可以通过scope来操作全局的命名空间,但是不建议这么做
print(c)
def fn4() :
a = 10
scope = locals() # 在函数内部调用locals,会获取函数的作用域
scope['b'] = 20 # # 可以通过scope来操作函数的命名空间,但是不建议这么做
print(scope)
fn4()
# {'a': 10, 'b': 20}
a = 10
def fn4() :
# 可以通过globals函数来获取全局命名空间
global_scope = globals()
global_scope['a'] = 30 # 可以进行修改
print(global_scope)
print(a)
fn4()
9 递归
递归简单来说就是自己去调用自己
无穷递归,如果这个函数被调用,程序的内存会溢出,效果类似于死循环
def fn():
fn()
fn()
递归是一种解决问题的方式,他和循环很像
- 他的整体思想是,将一个大问题分解为一个个小问题,知道问题无法分解时,再去解决问题
- 递归式函数的两个条件
- 1.基线条件,
- 问题可以被分解为的最小问题,当满足基线条件时,递归就不再执行了
- 2.递归条件
- 将问题继续分解的条件
- 递归和循环类似,基本是可以相互代替的
- 循环编写起来比较容易,阅读起来稍难
- 递归编写起来难,但方便阅读
实例:求解10的阶乘
def factorial(n):
'''
该函数用来求任意数的阶乘
参数 :
n 要求阶乘的数字
'''
if n == 1 :
# 1的阶乘是1,直接返回1
return 1
# 递归条件
return n * factorial(n-1)
factorial(10)
求解任意数的幂运算
def power(n,i):
'''
该函数用来求任意数的幂运算
参数:
n 要进行幂运算的数字
i 做幂运算的次数
'''
if i == 1 :
return n
return n * power(n,i-1)
power(2,3)
创建一个函数用来检查一个任意的字符串是否是一个回文字符串,如果是返回True,否则返回False
# abcba
# 先检查第一个字符和最后一个字符是否一致,如果不一致则不是回文字符串
# 如果一致,则看剩余的部分是否是回文字符串
# 检查 abcba 是不是回文
# 检查 bcb 是不是回文
# 检查 c 是不是回文
def hui_wen(s):
'''
该函数用来检查指定的字符串是否是回文字符串,如果是返回True,否则返回False
参数 :
s:就是要检查的字符串
'''
# 基线条件
if len(s) < 2 :
# 字符串的长度小于2,则字符串一定是回文
return True
elif s[0] != s[-1] :
# 第一个字符和最后一个字符不相等,不是回文字符串
return False
# 递归条件
return hui_wen(s[1:-1])
hui_wen('asdfghjklkjhgfdsa')
10 高阶函数
在Python中,函数都是一等对象
- 一等对象一般都会具有如下特点:
①对象实在运行时创建的
②能赋值给变量或作为数据结构中的元素
③能作为参数传递
④能作为返回值返回
- 高阶函数
接受函数作为参数或者将函数作为返回值的函数就是高阶函数
filter(function,iterable) --过滤器
- 可以从序列中过滤出符合条件的元素,保存到一个新的序列中
- 参数:
1.函数,根据该函数来过滤序列(可迭代结构)
2.需要过滤的序列(可迭代的结构)
- 返回值:过滤后的序列(可迭代的结构)
l = [1,2,3,4,5,6,7,8,9]
def fn(i):
if i % 3 == 0:
return True
return False
r = filter(fn,l)
print(r) # <filter object at 0x000001C69D623AC0 >
print(list(r)) # [3, 6, 9]
在filter()调用fn()后,fn(),就已经没有用了,但是这样就在全局定义了一个fn(),我们不希望这样,那就有了匿名函数
匿名函数
lambda 函数表达式
专门用来创建一些简单的函数,他也是函数创建的一种方式
语法: lambda 参数列表 : 返回值
只能写一些简单的表达式,不能写循环等负责的表达式
print(lambda a,b : a+b)
# 函数调用,但是我们一般不这么用
print((lambda a,b : a+b)(10,20)) # 但是我们一般不这么用
# 可以将匿名函数赋值给一个变量,但是我们一般也不这么用
fn = lambda a,b : a+b
print(fn(10,20))
# 因为这个函数一般只用一次,所以我们一般这么用
l = [1,2,3,4,5,6,7,8,9]
r = filter(lambda i : i % 3 == 0,l)
print(list(r))
map函数
map()函数可以对可迭代对象中的所用对象做指定的操作,然后将其添加到一个新的对象中返回
map参数:
1. 函数,或想要进行的操作
1. 进行操作的对象(可迭代)
l = [1,2,3,4,5,6,7,8,9]
r = map(lambda i : i + 1,l)
print(r)
print(list(r))
r = list(map(lambda i : i % 3,l))
print(r)
sort()方法
该方法用来对列表中的元素进行排序
- 默认就是用 < (小于号) 进行比较
l = ['bb','aaaa','c','dddddddd','ffff']
l.sort()
print(l)
# ['aaaa', 'bb', 'c', 'dddddddd', 'ffff']
- 在sort()中,可以接受一个关键字参数, Key
- key 需要一个函数作为参数,当设置了函数作为参数,每次都会以列表中的一个元素作为参数,来调用函数
- 并且会使用函数的返回值来比较元素的大小
- 是在比较的时候进行函数调用,并不会改变原来的值
l = [2,5,'1',3,'6',4]
l.sort(key = str)
print(l)
l.sort(key = int)
print(l)
sorted()函数
sorted函数,基本与sort方法相同,但他会返回一个排序好的新序列,原来的序列是不变的
l = [2,5,'1',3,'6',4]
print("排序前:",l)
print(sorted(l,key = int))
print("排序后:",l)
闭包
将函数作为返回值返回,也是一种高阶函数
简单实例:
def fn():
# 在函数内部再定义一个函数
a = 100
def inner():
print("我是inner",a)
# 将内部函数inner作为返回值返回
return inner
# r是一个函数,时调用fn()后返回的函数
# 这个函数是在fn()内部定义,并不是全局函数
# 所以这个函数总是能够访问到fn(),内部的变量
r = fn()
print(r)
r()
- 这个时候就形成了一个闭包,a只能在函数内部被使用
- 通过闭包我们可以创建一些只用当前函数能够访问的变量
- 可以将一些私有的数据藏到闭包中
闭包的形成:
- 函数嵌套
- 将内部函数作为返回值去返回
- 内部函数必须要使用外部函数的变量
# 求多个数的平均值
# 如果我想要能够去向里面加值
def make_averager():
# nums是一个全局变量,可能会被其他人使用,这样就不会被其他人在外部不小心改变
nums = []
# 创建一个函数用来计算平均值
def averager(n):
# 将n添加到列表中
nums.append(n)
# 求平均值
return sum(nums) / len(nums)
return averager
averager = make_averager()
print(averager(10))
print(averager(50))
print(averager(20))
装饰器
# 装饰器
# 创建几个函数
def add(a , b):
print("计算开始...")
r = a + b
print("计算结束...")
return r
def mul(a , b):
print("计算开始...")
r = a * b
print("计算结束...")
return r
# 希望函数能够在计算前,打印开始计算,计算结束,打印计算完毕
# r = add(123,456)
# print(r)
# 我们可以直接通过修改函数中的代码,来完成这个需求,但是会产生一下一些问题
# ①如果要修改的函数过多,修改起来会比较麻烦
# ②并且不方便后期的维护,非常的不方便
# ③并且这样做会违反我们的开闭原则(OCP)
# 程序的设计,要求开发对程序的扩展,要关闭对程序的修改
# (怎么在不修改原函数的情况下,来对函数进行扩展?)
def fn():
print('我是fn函数...')
# 只需要根据现有的函数,来创建一个新的函数
def fn2():
print("函数开始执行...")
fn()
print("函数执行结束...")
fn2()
# 错误实例:(add()需要两个参数)
def new_add():
print("函数开始执行...")
add()
print("函数执行结束...")
new_add()
# 可以传入两个参数
# 但是这样new_add并没有返回结果
def new_add(a , b):
print("函数开始执行...")
add(a , b)
print("函数执行结束...")
r = new_add()
print(r)
# 解决:
def new_add(a , b):
print("函数开始执行...")
r = add(a , b)
print("函数执行结束...")
return r
r = new_add(1,2)
print(r)
# 但是这样还是有一个问题,现在我是在对add进行扩展,加入是我对其他函数进行扩展呢?
但是这样还是有一个问题,现在我是在对add进行扩展,加入是我对其他函数进行扩展呢?
# 不要每次都去手动创建新函数
# 为了解决这个问题,我们可以创建一个函数,让这个函数可以自动为我们生成函数
# 功能是,函数能够在计算前,打印开始计算,计算结束,打印计算完毕
def fn():
print('我是fn函数...')
def begin_end(old):
'''
用来对其他函数进行扩展,是其他函数可以在执行前打印开始执行,执行后打印执行结束
参数:
old 要扩展的函数对象
'''
# 创建一个新函数
def new_function():
print("函数开始执行...")
# 调用被扩展的函数
old()
print("函数执行结束...")
# 返回这个新函数
return new_function
f = begin_end(fn)
f()
但是我们这样如果需要传入参数的时候,就会报错,因为我们没有设置形参
当然我们可以为它设置形参,但是要是我们又要传入没有参数的函数,就又会报错
为了解决这种问题,我们可以进行这样的设置
def fn():
print('我是fn函数...')
def add(a,b):
return a + b
def mul(a,b):
return a * b
def begin_end(old):
'''
用来对其他函数进行扩展,是其他函数可以在执行前打印开始执行,执行后打印执行结束
参数:
old 要扩展的函数对象
'''
# 创建一个新函数
def new_function(*args,**kwargs):
print("函数开始执行...")
# 调用被扩展的函数
result = old(*args,**kwargs)
print("函数执行结束...")
return result
# 返回这个新函数
return new_function
f = begin_end(fn)
f2 = begin_end(add)
f3 = begin_end(mul)
r = f()
print(r)
r2 = f2(123,456)
print(r2)
r3 = f3(123,456)
print(r3)
当然我们还有一种最常用的更加简便的方法
def begin_end(old):
'''
用来对其他函数进行扩展,是其他函数可以在执行前打印开始执行,执行后打印执行结束
参数:
old 要扩展的函数对象
'''
# 创建一个新函数
def new_function(*args,**kwargs):
print("函数开始执行...")
# 调用被扩展的函数
result = old(*args,**kwargs)
print("函数执行结束...")
return result
# 返回这个新函数
return new_function
# 在函数的上一行添加一个 @装饰器,来使用指定的装饰器
@begin_end
def say_hello():
print('大家好')
# 这时候这个say_hello就不是原来的函数了
say_hello()
并且我们可以为一个函数添加多个装饰器
- 是由内到外进行执行的
- 下面的例子:先fn,后begin_end
def begin_end(old):
'''
用来对其他函数进行扩展,是其他函数可以在执行前打印开始执行,执行后打印执行结束
参数:
old 要扩展的函数对象
'''
# 创建一个新函数
def new_function(*args,**kwargs):
print("函数开始执行...")
# 调用被扩展的函数
result = old(*args,**kwargs)
print("函数执行结束...")
return result
# 返回这个新函数
return new_function
# 在函数的上一行添加一个 @装饰器,来使用指定的装饰器
def fn(old):
'''
用来对其他函数进行扩展,是其他函数可以在执行前打印开始执行,执行后打印执行结束
参数:
old 要扩展的函数对象
'''
# 创建一个新函数
def new_function(*args,**kwargs):
print("fn装饰器~函数开始执行...")
# 调用被扩展的函数
result = old(*args,**kwargs)
print("fn装饰器~函数执行结束...")
return result
# 返回这个新函数
return new_function
@begin_end
@fn
def say_hello():
print('大家好')
# 这时候这个say_hello就不是原来的函数了
say_hello()
面向对象(object)
什么是对象?
- 对象是内存中专门用来存储数据的一块区域
- 对象中可以用来存放各种数据(数字、布尔值、代码)
- 对象有由三部分组成:
- 对象的标识(id)、对象的类型(type)、对象的值(value)
面向对象(OOP)
- Python是一门面向对象的编程语言
- 所谓的面向对象的语言,简单理解就是语言中的所有操作都是通过对象来进行的
- 面向过程的编程语言,
- 将程序的逻辑分解为一个一个的步骤。通过对每个步骤的抽象,来完成程序
- 这种编程方式,符合我们人类的思维,编写起来相对比较简单
- 但这种编程方式编写的代码,往往只适用于一个功能
- 如果要在实现别的功能,即使功能相差极小,也往往要重新编写代码,所以他的可用性低,并且难以维护
- 面向对象的编程语言
- 关注的是对象,而不是关注过程
- 我们需要将过程写到对象里面,面向对象中包含着面向过程
- 通过调用对象,来实现功能
- 面向对象的编程思想,将所有的功能统一保存到对应的对象中,要使用某个功能,直接找到对应的对象即可
- 这种方式编写的代码,比较容易阅读,并且易于维护
- 这种方式编写,不太符合常规的思维,编写起来要稍微麻烦一些
简单归纳
1.找对象
2.搞对象,实现功能
类(class)
- 我们目前所学习的对象,都是Python内置的对象
- 但是内置对象,并不能满足所有的需求,所以我们在开发中经常需要自定义一些对象
- 类,简单理解就是相当于一个图纸,在程序中,我们需要根据类来创建对象
- 类也是一个对象,类就是用来创建一个对象的对象!
- 就是创建了一个type类型的对象
- 我们也称对象是类的实例( instance )
- 如果多个对象是通过一个类创建的,我们称这些对象是一类对象
- 像 int() , float() , bool() , list() , dict() … 这些都是类
- a = int( 10 ) # 就是在创 建一个int的实例
类的创建
我们自己创建的类的命名,与标识符相同,但需要大写字母开头,并且是大驼峰命名法来对类进行命名
语法:
使用 class关键字来定义类,语法和函数相似
class 类名([父类]):
代码块
class MyClass():
pass
print(MyClass,type(MyClass))
# <class '__main__.MyClass'> <class 'type'>
class MyClass():
pass
# 使用类来创建一个对象,就像调用一个函数一样
mc = MyClass() # mc就是通过MyClass来创建的一个对象,mc是MyClass的实例
print(mc,type(mc))
# <__main__.MyClass object at 0x000001C69E2625D0> <class '__main__.MyClass'>
使用类创建对象的流程
简化版:
1. 创建一个变量mc
1. 在内存中创建一个新对象
1. 将我们的对象的id,赋值给变量
向类中添加属性
我们可以向对象中添加变量,对象中的变量称为属性
语法: 对象.属性名 = 属性值
class MyClass():
pass
# 现在我们通过MyClass这个类创建的对象,都是一个空对象,就相当于一个空盒子
# 我们可以向对象中添加变量,对象中的变量称为属性
# 语法: 对象.属性名 = 属性值
mc = MyClass()
mc.name = '孙悟空'
print(mc.name)
类的定义
我们上面的代码,对于一个空对象,当然是想放什么就放什么,但是这样就不太对吧,我们这个图纸似乎就没有什么用了
那我们应该怎么去做呢?
- 类和对象都是对现实生活中事务或程序中的内容的抽象
- 实际上所有的事物都有两部分构成:
- 1.数据(属性)
- 2.行为(方法)
- 在类的代码块中,可以定义变量和函数
- 在类中我们所定义的变量,将会成为该类所有实例的公共属性。都可以通过 对象.属性名 的形式访问
- 类中定义的函数成为方法,这些方法可以通过该类的所有实例来访问。都可以通过 对象.方法名() 的形式调用
- 注意方法调用时,第一个参数由解析器自动传递,所以定义方法时,必须要定义至少一个形参
# 尝试定义一个表示人的类
class Person:
# 在类中我们可以定义变量和函数
# 在类中我们所定义的变量,将会成为所有实例的公共属性
name = 'swk' # 公共属性,所有实例都可以访问
# 类中定义的函数成为方法
# 这些方法可以通过该类的所有实例来访问
def say_hello(a):
print('hello')
# 创建Person的一个实例
p1 = Person()
p2 = Person()
print(p1)
print(p1.name,p2.name)
# 方法调用:对象.方法名()
# 如果是函数调用,则调用时传递几个参数,就会有几个实参
# 如果是方法调用,默认传递一个参数,所以方法中至少要定义一个形参
p1.say_hello()
属性和方法
属性和方法的查找流程
当我们调用一个对象的属性时,解析器会想在当前对象中寻找是否含有该属性,
如果有,则直接返回当前的对象的属性值
如果没有,则去返回当前对象的类对象中寻找,如果有则返回类对象的属性值,
如果没有则报错
类对象和实例对象中都可以保存属性和方法
- 如果这个属性(方法)是所有的实例共享的,则应该将其保存到类对象中
- 如果这个属性(方法)是某个实例独有的,则应该保存到实例对象中
- 一般属性保存到实例对象中,方法保存到类对象中
# 尝试定义一个表示人的类
class Person:
# 在类中我们可以定义变量和函数
# 在类中我们所定义的变量,将会成为所有实例的公共属性
name = 'swk' # 公共属性,所有实例都可以访问
# 类中定义的函数成为方法
# 这些方法可以通过该类的所有实例来访问
def say_hello(a):
print('hello')
# 创建Person的一个实例
p1 = Person()
p2 = Person()
p1.name = "zbj"
p2.name = 'shs'
print(p1)
print(p1.name,p2.name)
# 删除p2.name shs
del p2.name
print(p1.name,p2.name)
调用,自动传递的第一个参数
方法每次被调用是,解析器都会自动传递第一个实参
第一个参数就是调用方法的对象本身
一般我们会将这个参数命名为self
# 尝试定义一个表示人的类
class Person:
# 在类中我们可以定义变量和函数
# 在类中我们所定义的变量,将会成为所有实例的公共属性
name = 'swk' # 公共属性,所有实例都可以访问
# 类中定义的函数成为方法
# 这些方法可以通过该类的所有实例来访问
def say_hello(self):
# 方法每次被调用是,解析器都会自动床底第一个实参
# 第一个参数就是调用方法的对象本身
# 一般我们会将这个参数命名为self
print(self)
# 在方法中,不能直接使用类中的属性
print('hello, %s'% self.name)
# 创建Person的一个实例
p1 = Person()
p2 = Person()
p1.name = "zbj"
p2.name = 'shs'
p1.say_hello()
print(p1)
# <__main__.Person object at 0x00000284E87BC950>
# hello, zbj
# <__main__.Person object at 0x00000284E87BC950>
类的特殊方法init
p1 = Person() 的运行流程
1.创建一个变量
2.在内存中创建一个新对象
3.__init__(self)方法执行
4.将对象的id付给变量
class Person():
# 在类中可以定义一些特殊方法(魔术方法)
# 特殊方法都是以__开头,以__结尾的方法
# 特殊方法不需要我们自己调用
# 学习特殊方法:
# 1.特殊方法什么时候调用
# 2.特殊方法有什么作用
# 创建对象的流程
# p1 = Person() 的运行流程
# 1.创建一个变量
# 2.在内存中创建一个新对象
# 3.__init__(self)方法执行
# 4.将对象的id付给变量
# init会在对象创建以后立刻执行
# init可以用来相信创建的变量中初始化属性
# 调用类创建对象时,类后面的所有参数都会依次传递到init中
def __init__(self,name) :
# 通过self向新建的对象中初始化属性
# 就是在实例对象中创建了name属性
self.name = name
def say_hello(self):
print(f'大家好,我是->{self.name}<-')
p1 = Person('孙悟空')
print(p1.name)
p1.say_hello()
类的结构
# 类的结构
class 类名([父类]) :
公共的属性
# 对象的初始化方式
def __init__(self,...):
...
# 其他的方法
def method_1(self,...):
...
...
简单的练习
class Dog():
'''
表示狗的类
属性:name、age、gender、height
方法:jiao()、yao()、run()
'''
def __init__(self,name,age,gender,height):
self.name = name
self.age = age
self.gender = gender
self.height = height
def jiao(self):
print('汪汪汪~~~')
def yao(self):
print('我咬你~')
def run(self):
print('%s 快乐的奔跑着~~'% self.name)
d = Dog('旺财',8,'male',30)
d.jiao()
d.run()
d.yao()
# print(d.name,d.age,d.gender,d.height)
封装※
封装是面向对象的三大特性之一
封装指隐藏对象中一些不希望被外部所访问到的属性和方法
如何去隐藏一个对象中的属性
问题
目前我们可以直接通过 对象.属性值 的方式来修改属性的值,这种方式导致对象中的属性可以随意修改
这样就非常的不安全,值可以任意修改,不论对错
现在我们需要一种方式来增强数据的安全性
1.属性不能随意修改
2.属性不能修改为任意的值
例:
class Rectangle:
'''
表示矩形的类
'''
def __init__(self,width,height):
self.hidden_height = height
self.hidden_width = width
def get_width(self):
return self.hidden_width
def get_height(self):
return self.hidden_height
def set_width(self,width):
self.hidden_width = width
def set_width(self,height):
self.hidden_width = height
def get_area(self):
return self.hidden_height * self.hidden_width
解决方法
- 将对象的属性名,修改为一个外部不知道的名字
- 如果想要修改呢?
- 提供一个getter和setter方法
- getter 获取对象的指定属性(get_属性名)
- setter 用来设置对象的指定属性(set_属性名)
使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性
-
增加了属性名,是调用者无法随意的修改对象中的属性
-
增加了getter和setter方法,很好的控制了属性是否是只读的
如果希望属性是只读的,则可以直接去掉setter方法
如果希望属性不能被外部访问,则可以直接去掉getter方法
-
使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
-
使用getter方法获取属性,使用setter方法设置属性
-
可以在读取属性和修改属性的同时做一些其他的处理
setter和getter的装饰器
class Person:
def __init__(self,name,age):
self._name = name
self._age = age
# property 装饰器,用来将一个get方法,转换为对象的属性
# 添加 property装饰器后,我们就可以像调用属性一样使用get方法
# 使用property装饰的方法,必须和属性名是一样的
@property
def name(self):
print('get方法执行了~~~')
return self._name
# set方法的装饰器 : @属性名.setter
@name.setter
def name(self,name):
print('setter方法调用了')
self._name = name
@property
def age(self):
return self._age
@age.setter
def age(self,age):
self._age = age
p = Person('zbj',20)
p.name = 'swk'
p.age = 18
print(p.name)
print(p.age)
隐藏类中的属性
class Person:
# 可以为对象的属性使用双下划线开头,__xxx
# 双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问
# 实际上是将名字修改为了,_类名__属性名
def __init__(self,name):
self.__name = name
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
p = Person('孙悟空')
# print(p.__name) # __开头的属性是隐藏属性,无法通过对象访问
# p.__name = '猪八戒'
# print(p._Person__name)
# p.Person__name = '猪八戒'
# 使用__开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用
# 一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
# 一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性
class Person:
def __init__(self,name):
self._name = name
def get_name(self):
return self.hidden_name
def set_name(self,name):
self.hidden_name = name
p = Person('swk')
print(p._name)
继承※
定义一个类 Dog (狗)
这个类中需要三个方法:run(),sleep(),bark()
有一个类,能够实现我们的大部分功能,但是不能实现全部功能
如何能够让类来实现我们全部的功能
1.直接修改这个类,在这个类中添加我们需要的功能
- 修改起来会比较麻烦,并且会违反OP原则
2.直接创建一个新的类
- 但是这样也太麻烦了吧,每次都要改,这种方式也不好
3.直接从Animal类中来继承他的属性和方法
-
继承是面向对象的三大特性之一
-
通过继承我们可以使一个类获得其他类中的属性和方法
-
在定义类中,可以在类名后的括号中指定当前类的父类(超类、基类、super)
-
子类 可以直接是可以直接使用父类中所有的属性和方法
通过继承可以直接让子类获得父类的方法或属性,避免编写重复性的代码,并且也符合OCP原则
所以我们经常需要通过继承来对一个类进行扩展
在创建类时,如果省略了父类,则默认父类为object
object时所有类的父亲,所有的类都继承自object
所有的对象都是object的实例
class Animal:
def run(self):
print('动物会跑~~')
def sleep(self):
print('动物睡觉~~~')
# 定义一个类 Dog (狗)
# 这个类中需要三个方法:run(),sleep(),bark()
# 有一个类,能够实现我们的大部分功能,但是不能实现全部功能
# 如何能够让类来实现我们全部的功能
# 1.直接修改这个类,在这个类中添加我们需要的功能
# - 修改起来会比较麻烦,并且会违反OP原则
# 2.直接创建一个新的类
# - 但是这样也太麻烦了吧,每次都要改,这种方式也不好
# 3.直接从Animal类中来继承他的属性和方法
# - 继承是面向对象的三大特性之一
# - 通过继承我们可以是一个类获得其他类中的属性和方法
# - 在定义类中,可以在类名后的括号中指定当前类的父类(超类、基类、super)
# - 子类 可以直接是可以直接使用父类中所有的属性和方法
# 通过继承可以直接让子类获得父类的方法或属性,避免编写重复性的代码,并且也符合OCP原则
# 所以我们经常需要通过继承来对一个类进行扩展
class Dog(Animal):
def brak(self):
print('汪汪汪~~~~')
class HaShiQi(Dog):
def fansha(self):
print('我是一只傻傻的哈士奇')
d = Dog()
h = HaShiQi()
h.run()
h.fansha()
# d.run()
# d.sleep()
# d.brak()
# 在创建类时,如果省略了父类,则默认父类为object
# object时所有类的父亲,所有的类都继承自object
重写
# 当我们调用一个对象的方法时,会优先去当前对象中寻找是否具有该方法,如果有则直接调用
# 如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类的方法,
# 如果没有,则去父类的父类中去寻找,以此类推,知道找到object,如果依然没有找到,则报错
# 方法的重写※
class Animal:
def run(self):
print('动物会跑~~')
def sleep(self):
print('动物睡觉~~~')
class Dog(Animal):
def run(self):
print('goupao~~')
def brak(self):
print('汪汪汪~~~~')
# 创建以一个Dog类的实例
# 如果在子类中有和父类同名的方法,则通过子类实例去调用方法时
# 会调用子类的方法而不是父类的方法,这个特点我们叫做方法的重写(覆盖,override)
d = Dog()
d.run()
super()
class Animal:
def __init__(self,name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
def run(self):
print('动物会跑~~')
def sleep(self):
print('动物睡觉~~~')
# 类中的所有方法,都会被子类继承,包括特殊方法
class Dog(Animal):
def __init__(self,name,age):
# 希望可以通过直接调用父类的__init__来初始化父类中定义的属性
# 1. Animal.__init__(self,name)
# Animal 是写死的,不好,如果有一天父类变了,就不合适了
# 2. super() 可以动态的获取当前类的父类,并且无需传递self
super().__init__(name)
self._age = age
@property
def age(self):
return self._age
@age.setter
def age(self,age):
self._age = age
def run(self):
print('goupao~~')
def brak(self):
print('汪汪汪~~~~')
d = Dog('旺财',18)
print(d.name)
d.name = 'xiaohei'
print(d.name)
多重继承
如果没有特殊方法,应该尽量避免使用多重继承,因为多重继承会让我们的代码归于复杂
如果多个父类中有同名的方法,则会在第一个父类中寻找,然后找第二个,然后找第三个…(前面的会覆盖后面的)
class A(object):
def test(self):
print('aaa')
class B(object):
def test2(self):
print('bbb')
# __bases__ 可以用来获取当前类的所有父类
print(B.__bases__)
# (<class '__main__.B'>,)
# (<class 'object'>,)
# Python中支持多重继承,一个类中可以有多个父类
# 可以在类名的括号内添加多个父类
# 并且可以获取到所有父类中的所有方法
# 如果多个父类中有同名的方法,则会在第一个父类中寻找,然后找第二个,然后找第三个...
# 前面的会覆盖后面的
class C(A , B):
pass
print(C.__bases__)
# (<class '__main__.A'>, <class '__main__.B'>)
c = C()
c.test() # aaa
c.test2() # bbb
多态※
面向对象的三大特征之一
从字面上理解,是多种形态
狗(狼狗,藏獒,哈士奇…)
鸭子类型 如果一个东西,走路像鸭子,叫声像鸭子,那么他就是鸭子
class A():
def __init__(self,name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class B():
def __init__(self,name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
# 定义一个函数
# 对于say_hello函数,只要对象中含有name属性,他就可以作为参数传递
# 这个函数并不会考虑对象的类型,只要有name属性即可
def say_hello(obj):
print('你好 %s'% obj.name)
a = A('swk')
say_hello(a)
b = B('zbj')
say_hello(b)
类和实例
# 定义一个类
class A(object):
# 类属性,直接在类中定义的属性是类属性
# 类属性可以通过类或类的实例访问
# 但是类属性只能通过类对象来修改,无法通过实例对象修改
count = 0
def __init__(self):
# 实例属性只能通过实例对象来访问和修改,类对象无法和修改
self.name = 'swk'
# 实例方法
# 在类中定义,以self为第一个参数的方法都是实例方法
# 实例方法在调用时,Python会将调用对象self传入
# 实例方法可以通过实例和类去调用
# 当通过类调用时,不会自动传递self
def test(self):
print('test方法~~~',self)
# 类方法
# 在类内部使用 @classmethod 来修饰的方法属于类方法
# 类方法的第一个参数时cls,也会被自动传递,cls局势当前的类对象
# 类方法也可以通过类去调用,也可以通过实例去调用,没有区别
@classmethod
def test_2(cls):
print('这是test_2方法,他是一个类方法~~~',cls)
print(cls.count)
# 静态方法
# 在类中使用 @statucmethod 来修饰的方法,属于静态方法
# 不需要指定任何默认参数,静态方法可以通过类和实例去调用
# 静态方法,基本上是一个和当前类无关的方法,他只是一个保存安东当前类中的函数
@staticmethod
def test_3():
print('test_3~~执行了')
a = A()
# a.count = 100
# print(a.count)
# print(A.count)
# a.test()
# A.test(a)
# A.test_2()
a.test_3()
垃圾回收
# 程序运行过程中会产生垃圾
# 程序运行过程中产生的垃圾会影响到程序运行的运行性能,所以这些垃圾必须被即使清理
# 没用的东西就是垃圾
# 在程序中没有被引用的对象就是垃圾,这种垃圾对象过多时就会影响到程序的运行性能
# 所以我们就要进行垃圾回收,就是将垃圾对象将从内存中删除
# 在Python中有自动垃圾回收的机制,他会自动将没有被引用的对象删除
# 所以我们不用手动进行删除
class A:
def __init__(self,name):
self.name = name
# 会在对象被删除前调用
def __del__(self):
print("%s被删除了"%self)
a = A('a')
print(a.name)
a = None # 将a设置为None,此时没有任何变量对A()对象进行引用,他就是变成了垃圾
input('回车键退出...')
特殊方法
# 特殊方法
# 特殊方法都是__开头,__结尾
# 特殊方法,一般不需要我们手动调用,在特殊的时候会自动运行
class Person(object):
'''人类'''
def __init__(self,name,age):
self.name = name
self.age = age
# __str__() 特殊方法会在尝试将对象转换为字符串的时候调用
# 可以用来指定对象转换成字符串的结果
def __str__(self):
return 'Hello [name=%s , age=%d]'%(self.name,self.age)
# __repr__()这个特殊方法会在对当前对象使用repr函数时调用
# 它的作用时指定对象在 "交互模式" 中直接输出的效果
def __repr__(self):
return 'Hello'
# 支持比较的特殊函数
# __lt__(self,other) 小于
# __le__(self,other) 小于等于
# __eq__(self,other) 等于
# __ne__(self,other) 不等于
# __gt__(self,other) 大于
# __ge__(self,other) 大于等于
# self 表示当前对象,other表示和当前对象比较的对象
def __gt__(self,other):
return self.age > other.age
# __len__(),获取对象的长度
# __bool__(self) 将对象转化为bool值
# 可以通过bool来指定对象转换为bool的情况
def __bool__(self):
return self.age > 17
# 运算方法,加减乘除等相对应的特殊方法
# object.__add__(self, other)
# object.__sub__(self, other)
# object.__mul__(self, other)
# object.__matmul__(self, other)
# object.__truediv__(self, other)
# object.__floordiv__(self, other)
# object.__mod__(self, other)
# object.__divmod__(self, other)
# object.__pow__(self, other[, modulo])¶
# object.__lshift__(self, other)
# object.__rshift__(self, other)
# object.__and__(self, other)
# object.__xor__(self, other)
# object.__or__(self, other)
# 创建两个Person的实例
p1 = Person('swk',18)
p2 = Person('zbj',28)
# 当我们打印一个对象时,实际上打印的时对象中的特殊方法 __str__() 的返回值
print(p2)
print(repr(p1))
print(p1 > p2)
print(bool(p1))
函数
isinstance()
class MyClass():
pass
# isinstance()是一个函数,用来检查一个对象是否是一个类的实例
result = isinstance(mc,MyClass)
print(result)
result = isinstance(mc,int)
print(result)
模块化(module)
模块化,将一个完整的程序分解为一个一个小的模块
通过将模块组合,来搭建出一个完整的程序
采用模块化,将程序分别编写到多个文件中
一个py文件就是一个模块,创建模块就是创建一个python文件
注意:模块名要符合标识符的规范
模块化的优点:
① 方便开发
② 方便维护
③ 模块可以复用 ! 将其他项目的模块代码,用到其他项目中,在做其他修改
模块化的应用
创建
# PythonLearn_module_01.py
print("~~这是一个模块化的演示~~~") # 实际上没有任何意义
# PythonLearn_module.py
# 在一个模块中引入外部模块
# ① import 模块名(模块名就是python文件的名字,注意不要加py后缀)
# ② import 模块名 as 模块别名
# - 可以引入同一个模块多次,但是模块的实例只会创建一个
# - import 可以在程序中的任意位置调用,但是一般情况下,import语句都会同意写道程序的开头
# - 模块中内部都会有__name__属性,通过这个属性可以获取到模块的名字
# - __name__属性值为 __main__ 的模块是主模块,一个程序中只有一个主模块
# import PythonLearn_module_01
# print(PythonLearn_module_01 )
import PythonLearn_module_01 as _01
print(_01.__name__)
print(__name__)
应用
# PythonLearn_module_01.py
# print("~~这是一个模块化的演示~~~")
# 可以在模块中定义变量
# 在模块中定义的变量,可以直接引用
a = 10
b = 20
# 添加了下划线的属性不能被访问
_c = 30
def test():
print("123")
def test2():
print('234')
class Person():
def __init__(self,name):
self.name = name
# 编写测试代码,这部分代码,
# 只有当前文件作为主模块的时候才需要执行
# 而当模块被其他模块引入时,不需要执行,此时我们就必须要检查当前模块是否是之模块
if __name__ == '__main__':
test()
test2()
p = Person('孙悟空')
print(p.name)
注意模块的引用方式
# PythonLearn_module.py
# 在一个模块中引入外部模块
# ① import 模块名(模块名就是python文件的名字,注意不要加py后缀)
# ② import 模块名 as 模块别名
# - 可以引入同一个模块多次,但是模块的实例只会创建一个
# - import 可以在程序中的任意位置调用,但是一般情况下,import语句都会同意写道程序的开头
# - 模块中内部都会有__name__属性,通过这个属性可以获取到模块的名字
# - __name__属性值为 __main__ 的模块是主模块,一个程序中只有一个主模块
# import PythonLearn_module_01
# print(PythonLearn_module_01 )
# import PythonLearn_module_01 as _01
# print(_01.__name__)
# print(__name__)
import PythonLearn_module_01 as _01
# 模块名.变量名,就可以调用模块中的变量
print(_01.a,_01.b)
# 模块名.函数名,就可以调用模块中的函数
_01.test()
# 同样,模块名.类名(...),就可以调用模块中的类,来生成实例
p1 = _01.Person('swk')
print(p1)
print(p1.name)
# 也可以只引用模块中的部分内容
# 语法 from 模块名 import 变量,变量
from PythonLearn_module_01 import Person
p2 = Person('zbj')
print(p2)
print(p2.name)
# from 模块名 import * 表示引用模块中所有内容,一般不会使用
# 可能不同模块会出现相互覆盖的情况
# 也可以为引入的变量使用别名
# 语法:from 模块名 import 变量 as 别名
from PythonLearn_module_01 import Person as P
p3 = P('swj')
print(p3)
print(p3.name)
# import PythonLearn_module_01
# print(PythonLearn_module_01._c)
包(Package)
包也是一个模块
当模块中的代码过多时,或者一个模块需要都被分解为多个模块时,这是需要使用到包
普通的模块就是一个py文件,而包是一个文件夹
包中必须要有一个__init__.py 文件,这个文件可以包含包中的主要内容
__pycache__ 是模块的缓存文件
py代码在执行前,需要被解析器先转化成机器码,然后再交由计算机执行
为了提高程序运行的性能,python会在编译后将代码保存到一个缓存文件中,这样下次执行就不需重新编译,而是直接加载缓存中编译好的代码
# __init__.py
a = 10
b = 20
def test():
print("test~~")
# PythonLearn_Package_01.py
print("PythonLearn_PAckage")
main :
# PythonLearn_Package_00.py
import Package
print(Package.a)
Package.test()
from Package import PythonLearn_Package_01
Python标准库
开箱即用
为了实现这个思想,Python为我们提供了模块的标准库
在这个标准库中,用很多强大的模块我们可以直接使用
标准库会随着Python的安装,一起安装到我们的电脑中
以后再想使用一个功能的时候,可以先去标准库中找找
sys 模块, 它里面提供了一些变量和函数,是我们可以获取到Python解析器的信息
#sys 模块, 它里面提供了一些变量和函数,是我们可以获取到Python解析器的信息
import sys
# pprint 模块,为我们提供了一个方法pprint(),该方法可以用来对打印的对象镜像简单的格式化
import pprint
# sys.argv
# 获取执行该代码时,命令行中所包含的参数
# 该属性是一个列表,列表中保存了当前命令的所有参数
print(sys.argv)
# sys.modules
# 获取当前程序中引入的所有模块
# modules是一个字典,key是模块的名字,value是模块对象
print(sys.modules)
pprint.pprint(sys.modules)
# sys.path
# 一个列表,列表中保存的是模块的搜索路径
pprint.pprint(sys.path)
# sys.platform
# 表示当前Python运行的平台
print(sys.platform)
# sys.exit()
# 函数用来退出程序
sys.exit('程序出现异常~结束!')
os 模块,让我们可以对操作系统进行访问
简单写一下,以后用到再说
import os
import pprint
# os.environ
# 获取系统的环境变量
print(os.environ)
pprint.pprint(os.environ['path'])
# os.system()
# 可以用来执行操作系统的命令
os.system('dir')
异常
异常处理和异常传播
# 异常
# 程序在运行的过程当中,不可避免的会出现一些错误,比如:
# 使用了没有赋值过的变量
# 使用了不存在的索引
# 除0
# ...
# 这些错误在程序中,被称为异常
# 程序运行过程中,一旦出现异常将会导致程序立即终止,异常以后的代码全都不会执行!
## 处理异常
# 程序运行时出现异常,目的并不是让我们的程序直接终止!
# Python希望我们能够编写代码时,对这个异常进行处理
#
# try 语句
# try :
# 代码块(可能出现错误的语句)
# except 异常类型 as 异常名:
# 代码块(出现错误以后的处理方式)
# except 异常类型 as 异常名:
# 代码块(出现错误以后的处理方式)
# except 异常类型 as 异常名:
# 代码块(出现错误以后的处理方式)
# ...
# finally:
# 代码块(必须执行的代码, 无论是否出现异常)
# else:
# 代码块(没有出现错误后的执行语句)
print('Hello')
try:
print(10 / 0)
except:
print('~ERROR~~')
else:
print('~BingGo~')
print('nihao')
# 可以将可能出错的语句放置到try语句中,这样如果代码没有错误,则会正常执行
# 如果出现错误,则会执行except子句中的代码,这样我们就可以通过代码来处理异常
# 避免因为一个异常,而导致整个程序终止
# 异常传播(抛出异常)
# 当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播,
# 如果没有进行处理,则异常会继续像调用处传播
# 如果函数调用处处理了异常,则不再传播,如果没有处理则继续向调用处传播
# 直到全局作用域,如果还是没有处理,则停止程序
# 当程序运行过程中出现异常后,所有的异常信息会被保存到一个专门的异常对象中,
# 而异常传播时,实际上就是异常对象抛给了调用处
#
# 如果except后不跟任何的内容,则此时它会捕获到任何所有的异常
# 如果在except后跟着一个异常的类型,那么此时它就只会捕获该类型的异常
print('~')
try:
l + 'Hello'
print(10 / 0)
# except NameError:
# print('出现NameError 异常')
# except ZeroDivisionError:
# print('出现ZeroDivisionError')
except Exception as e:
print('未知异常',e ,type(e))
finally :
print('必须执行的代码')
print('~')
# Exception 是所有异常的父类,所以可以捕获所有的异常
抛出异常
# 抛出异常
# raise 可以抛出异常
def add(a,b):
if a < 0 or b < 0 :
# raise用于向外部抛出异常,后面可以跟一个异常类,或异常类的实例
# 抛出异常的目的,告诉调用者这里调用时,出现问题,希望你自己处理一下
raise Exception('两个参数中不能出现负数!')
r = a + b
return r
print(add(-123,456))
def add(a,b):
if a < 0 or b < 0 :
# raise用于向外部抛出异常,后面可以跟一个异常类,或异常类的实例
# 抛出异常的目的,告诉调用者这里调用时,出现问题,希望你自己处理一下
# raise Exception('两个参数中不能出现负数!')
# 也可以通过if-else语句来代替异常的处理,但是我们一般不这样
# 一方面不能接受所有的异常,另一方面可能出现不可预料的错误/后果
return None
r = a + b
return r
print(add(-123,456))
自定义异常
# 自定义异常,只需要创建一个类继承Exception
class MyError(Exception):
pass
def add(a,b):
if a < 0 or b < 0 :
raise MyError('两个参数中不能出现负数!')
r = a + b
return r
print(add(-123,456))
文件
文件(File)
通过python程序来对计算机中的各种文件进行增删改查的操作
I/O (Input / Output)
操作文件的步骤
① 打开文件
② 对文件进行各种操作(读、写),然后保存
③ 关闭文件
打开文件
# open(file, mode='r', buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
# 使用open函数来打开一个文件
# 参数:
# file 要打开的文件的名字(路径)
# 返回值:
# 返回一个对象,代表了当前打开的文件
# 如果目标文件和当前文件在同一级目录下,则直接使用文件名即可
# file_name = "PreTice.txt"
# 如果没有,则需要使用相对路径或绝对路径
# - 在windows系统中使用路径时,可以使用 / 来代替 \
# - 或者可以使用 \\ 来代替 \
# - 或者使用原始字符串,例: r"D:\VsCode\VsCode_python\PythonLearning\PreTice.txt"
# file_name = "D:\\VsCode\\VsCode_python\\PythonLearning\\PreTice_01.txt"
# 相对路径
# 表示路径,可以使用..来返回一级目录
# file_name = '../Ems/Pretice_02.txt'
# 绝对路径
# file_name = "D:\\VsCode\\VsCode_python\\PythonLearning\\PreTice_01.txt"
# file_obj = open(file_name)
# print(file_obj)
关闭文件
file_name = 'Pretice_01.txt'
file_obj = open(file_name)
# 当我们获取了文件对象以后,所有的对文件的操作都应该通过对象来进行
# 读取文件中的内容
# read()方法,用来读取文件的内容,他会将内容全都保存为一个字符串返回
content = file_obj.read()
print(repr(content))
# 关闭文件
# 调用close()方法来关闭文件
file_obj.close()
# with ... as 语句
with open(file_name) as file_obj :
# 代码块,可以直接使用file_obj来做文件操作
# 此时这个文件只能在with中使用,一旦with结束则文件会自动close()
print(file_obj.read())
## 异常捕获
# file_name = 'hello'
# try:
# with open(file_name) as file_obj :
# print(file_obj.read())
# except FileNotFoundError:
# print(f"{file_name} 文件不存在")
操作文件
读取
read()
file_name = 'Pretice_03.txt'
try:
# 调用open()来打开一个文件,可以将文件分成两种类型
# 1.纯文本文件(使用utf-8等编码编写的文件)
# 2.二进制文件(图片、MP3、ppt等这些文件)
# open()打开文件时,默认是以文本文件来打开的,但是open的默认编码是None
# 所以处理文本文件时,必须要指定文件的编码
with open(file_name,encoding='utf-8') as file_obj :
# 通过read()来读取文件中的内容
# 如果直接调用read(),它会将文本文件的所有内容全部都读取出来
# 如果要读取的文件较大时,会一次性将文件的内容加载到内存中,容易导致内存泄漏
# 对于较大的问价不要直接调用read()
# help(file_obj.read)
# read会接受一个参数size,可以指定要读取的字符数量
# 默认值为-1,即全部读取
content01 = file_obj.read(2)
# 会从上次读取到的位置开始去读取
content02 = file_obj.read(2)
content03 = file_obj.read(2)
# 如果剩余字符数量小于size,则会读取剩余全部内容
# 如果已经读取完了,则会返回空号
content04 = file_obj.read(2)
print(content01,content02,content03)
# 读取大文件的方式
file_name = 'Pretice_03.txt'
try:
with open(file_name,encoding='utf-8') as file_obj :
# 定义一个变量,来指定每次读取的大小
chunk = 2
# 读,创建循环
while True:
# 读取chunk大小的内容
content = file_obj.read(chunk)
# 检查是否读取到了内容
if not content:
# 内容读取完毕
break
# 输出内容
print(content,end=' ')
except FileNotFoundError:
print(f"{file_name} 文件不存在")
readline()和readlines()
file_name = 'Pretice_03.txt'
with open(file_name,encoding='utf-8') as file_obj:
# readline()
# 该方法可以用来读取一行内容
# print(file_obj.readline(),end='')
# print(file_obj.readline())
# print(file_obj.readline())
# readlines()
# 该方法用于一行一行读取文件内容,他会一次性的将读取的文件内容封装到一个列表中返回
# r = file_obj.readlines()
# print(r)
# for 循环亦可以按行读取数据
for t in file_obj:
print(t)
写入
## 文件写入
# file_name = 'Pretice_04.txt'
# open 打开文件时,必须要指定打开文件时,所需要的操作(读、写、追加)
# 如果不指定操作类型,则默认是 读取文件 , 而读取文件时是不能向文件中写入的
# r 表示只读
# w 表示可写 , 使用 w 来写入文件时,如果文件不存在会创建存在;如果文件存在,则会截断文件
# 截断文件指删除原来中的所有内容
# with open(file_name,'w',encoding='utf-8') as file_obj:
# # write() 用来向文件中写入内容
# # 如果操作的是一个文本文件的化,则write()需要传入一个字符串
# # 该方法可以分多次向文件中写入内容,必须是字符串(可以str作转换)
# # write(),写入没有换行,你需要自己写换行符
# # 写入完成以后,该方法会返回写入字符的个数
# file_obj.write('Holle 。。。')
# file_obj.write('Holle swk\n')
# file_obj.write('Holle zbj\n\n')
# r = file_obj.write('Holle 。。。')
# print(r)
# file_name = 'Pretice_04.txt'
# # a 表示追加内容,如果文件不存在会创建文件,如果文件存在,会向文件中追加内容
# with open(file_name,'a',encoding='utf-8') as file_obj:
# file_obj.write('Holle 。。。')
# file_obj.write('Holle swk\n')
# file_obj.write('Holle zbj\n')
# r = file_obj.write('Holle 。。。')
# print(r)
# file_name = 'Pretice_04.txt'
# # + 为操作符增加功能
# # r+ 可读还可写,但不会创建文件
# # w+ 可写还可读
# # a+ 追加和可读
# with open(file_name,'r+',encoding='utf-8') as file_obj:
# file_obj.write('Holle 。。。')
# file_obj.write('Holle swk\n')
# file_obj.write('Holle zbj\n')
# r = file_obj.write('Holle 。。。')
# print(r)
# x 用来新建文件,如果文件不存在则新建,如果存在,则报错
# file_name = 'Pretice_04.txt'
# with open(file_name,'x',encoding='utf-8') as file_obj:
# file_obj.write('Holle 。。。')
# file_obj.write('Holle swk\n')
# file_obj.write('Holle zbj\n')
# r = file_obj.write('Holle x。。。')
# print(r)
二进制文件
## 二进制文件
# 所有文本文件之外的文件,都是二进制文件
file_name = 'Pretice_voice.mp3'
# t 读取文本文件(默认值)
# b 读取二进制文件
with open(file_name,'rb') as file_obj:
# 读取文本文件时,size是以字符为单位
# 读取二进制文件时,size是以字节为单位
# print(file_obj.read(20))
# 将读取到的内容写出来
# 创建一个新的文件
new_name = 'Pretice_newVoice.mp3'
with open(new_name,'ab') as new_obj:
# 定义每次读取的大小
chunk = 1024 * 100
while True:
# 从已有的对象中读取数据
content = file_obj.read(chunk)
if not content :
break
# 将读取到的数据读取到新文件中
new_obj.write(content)
读取文件的位置
# ## 读取文件的位置
# file_name = 'Pretice_05.txt'
# with open(file_name,'rb') as file_obj:
# # 对于英文,一个字符就是一个字节
# # 中文,一个字符是三个字节
# # print(file_obj.read(100))
# # seek() 可以修改当前读取到的位置
# file_obj.seek(100,0)
# # 两个参数
# # 1. 是要切换到的位置
# # 2. 计算位置方式
# # 可选值:
# # 0 从头计算,默认值
# # 1 从当前位置计算
# # 2 从最后位置开始计算
# file_obj.seek(10,1)
# file_obj.seek(-10,2)
# # tell() 方法用来查看当前读取到的位置
# print('当前读取到的位置-->',file_obj.tell())
# print(file_obj.read(10))
# file_name = 'Pretice_06.txt'
# with open(file_name,'rt',encoding='utf-8') as file_obj:
# # 也可以用于文本文件,一定要与字节数对应,不可以1/3个字节
# # 中文,一个字符是三个字节
# file_obj.seek(3)
# # 两个参数
# # 1. 是要切换到的位置
# # 2. 计算位置方式
# # 可选值:
# # 0 从头计算,默认值
# # 1 从当前位置计算
# # 2 从最后位置开始计算
# # file_obj.seek(10,1)
# # file_obj.seek(-10,2)
# # tell() 方法用来查看当前读取到的位置
# print('当前读取到的位置-->',file_obj.tell())
# print(file_obj.read(5))
其他操作
## 其他操作
# import os
# from pprint import pprint
# listdir 获取指定路径的目录结构
# 默认路径为 . 获取当前目录结构
# 该方法会返回一个列表,每个文件(夹)的名字,都是列表中的一个元素
# r = os.listdir('..')
# pprint(r)
# os.getcwd() 获取当前所在的目录
# r = os.getcwd()
# pprint(r)
# os.chdir() 切换目录
# os.chdir('C:/')
# r = os.getcwd()
# pprint(r)
# os.mkdir() 创建一个目录,在当前目录下
# os.mkdir("preticT")
# os.rmdir() 删除目录
# os.rmdir("preticT")
# 删除文件
# open('Pre.txt','w')
# os.remove('pRe.txt')
# os.rename('旧名字','新名字')
# 可以对一个文件进行重命名,亦可以移动一个文件
# os.rename("pRe.txt","D:/pRe.txt")
read()
file_name = 'Pretice_03.txt'
try:
# 调用open()来打开一个文件,可以将文件分成两种类型
# 1.纯文本文件(使用utf-8等编码编写的文件)
# 2.二进制文件(图片、MP3、ppt等这些文件)
# open()打开文件时,默认是以文本文件来打开的,但是open的默认编码是None
# 所以处理文本文件时,必须要指定文件的编码
with open(file_name,encoding='utf-8') as file_obj :
# 通过read()来读取文件中的内容
# 如果直接调用read(),它会将文本文件的所有内容全部都读取出来
# 如果要读取的文件较大时,会一次性将文件的内容加载到内存中,容易导致内存泄漏
# 对于较大的问价不要直接调用read()
# help(file_obj.read)
# read会接受一个参数size,可以指定要读取的字符数量
# 默认值为-1,即全部读取
content01 = file_obj.read(2)
# 会从上次读取到的位置开始去读取
content02 = file_obj.read(2)
content03 = file_obj.read(2)
# 如果剩余字符数量小于size,则会读取剩余全部内容
# 如果已经读取完了,则会返回空号
content04 = file_obj.read(2)
print(content01,content02,content03)
# 读取大文件的方式
file_name = 'Pretice_03.txt'
try:
with open(file_name,encoding='utf-8') as file_obj :
# 定义一个变量,来指定每次读取的大小
chunk = 2
# 读,创建循环
while True:
# 读取chunk大小的内容
content = file_obj.read(chunk)
# 检查是否读取到了内容
if not content:
# 内容读取完毕
break
# 输出内容
print(content,end=' ')
except FileNotFoundError:
print(f"{file_name} 文件不存在")
readline()和readlines()
file_name = 'Pretice_03.txt'
with open(file_name,encoding='utf-8') as file_obj:
# readline()
# 该方法可以用来读取一行内容
# print(file_obj.readline(),end='')
# print(file_obj.readline())
# print(file_obj.readline())
# readlines()
# 该方法用于一行一行读取文件内容,他会一次性的将读取的文件内容封装到一个列表中返回
# r = file_obj.readlines()
# print(r)
# for 循环亦可以按行读取数据
for t in file_obj:
print(t)
写入
## 文件写入
# file_name = 'Pretice_04.txt'
# open 打开文件时,必须要指定打开文件时,所需要的操作(读、写、追加)
# 如果不指定操作类型,则默认是 读取文件 , 而读取文件时是不能向文件中写入的
# r 表示只读
# w 表示可写 , 使用 w 来写入文件时,如果文件不存在会创建存在;如果文件存在,则会截断文件
# 截断文件指删除原来中的所有内容
# with open(file_name,'w',encoding='utf-8') as file_obj:
# # write() 用来向文件中写入内容
# # 如果操作的是一个文本文件的化,则write()需要传入一个字符串
# # 该方法可以分多次向文件中写入内容,必须是字符串(可以str作转换)
# # write(),写入没有换行,你需要自己写换行符
# # 写入完成以后,该方法会返回写入字符的个数
# file_obj.write('Holle 。。。')
# file_obj.write('Holle swk\n')
# file_obj.write('Holle zbj\n\n')
# r = file_obj.write('Holle 。。。')
# print(r)
# file_name = 'Pretice_04.txt'
# # a 表示追加内容,如果文件不存在会创建文件,如果文件存在,会向文件中追加内容
# with open(file_name,'a',encoding='utf-8') as file_obj:
# file_obj.write('Holle 。。。')
# file_obj.write('Holle swk\n')
# file_obj.write('Holle zbj\n')
# r = file_obj.write('Holle 。。。')
# print(r)
# file_name = 'Pretice_04.txt'
# # + 为操作符增加功能
# # r+ 可读还可写,但不会创建文件
# # w+ 可写还可读
# # a+ 追加和可读
# with open(file_name,'r+',encoding='utf-8') as file_obj:
# file_obj.write('Holle 。。。')
# file_obj.write('Holle swk\n')
# file_obj.write('Holle zbj\n')
# r = file_obj.write('Holle 。。。')
# print(r)
# x 用来新建文件,如果文件不存在则新建,如果存在,则报错
# file_name = 'Pretice_04.txt'
# with open(file_name,'x',encoding='utf-8') as file_obj:
# file_obj.write('Holle 。。。')
# file_obj.write('Holle swk\n')
# file_obj.write('Holle zbj\n')
# r = file_obj.write('Holle x。。。')
# print(r)
二进制文件
## 二进制文件
# 所有文本文件之外的文件,都是二进制文件
file_name = 'Pretice_voice.mp3'
# t 读取文本文件(默认值)
# b 读取二进制文件
with open(file_name,'rb') as file_obj:
# 读取文本文件时,size是以字符为单位
# 读取二进制文件时,size是以字节为单位
# print(file_obj.read(20))
# 将读取到的内容写出来
# 创建一个新的文件
new_name = 'Pretice_newVoice.mp3'
with open(new_name,'ab') as new_obj:
# 定义每次读取的大小
chunk = 1024 * 100
while True:
# 从已有的对象中读取数据
content = file_obj.read(chunk)
if not content :
break
# 将读取到的数据读取到新文件中
new_obj.write(content)
读取文件的位置
# ## 读取文件的位置
# file_name = 'Pretice_05.txt'
# with open(file_name,'rb') as file_obj:
# # 对于英文,一个字符就是一个字节
# # 中文,一个字符是三个字节
# # print(file_obj.read(100))
# # seek() 可以修改当前读取到的位置
# file_obj.seek(100,0)
# # 两个参数
# # 1. 是要切换到的位置
# # 2. 计算位置方式
# # 可选值:
# # 0 从头计算,默认值
# # 1 从当前位置计算
# # 2 从最后位置开始计算
# file_obj.seek(10,1)
# file_obj.seek(-10,2)
# # tell() 方法用来查看当前读取到的位置
# print('当前读取到的位置-->',file_obj.tell())
# print(file_obj.read(10))
# file_name = 'Pretice_06.txt'
# with open(file_name,'rt',encoding='utf-8') as file_obj:
# # 也可以用于文本文件,一定要与字节数对应,不可以1/3个字节
# # 中文,一个字符是三个字节
# file_obj.seek(3)
# # 两个参数
# # 1. 是要切换到的位置
# # 2. 计算位置方式
# # 可选值:
# # 0 从头计算,默认值
# # 1 从当前位置计算
# # 2 从最后位置开始计算
# # file_obj.seek(10,1)
# # file_obj.seek(-10,2)
# # tell() 方法用来查看当前读取到的位置
# print('当前读取到的位置-->',file_obj.tell())
# print(file_obj.read(5))
其他操作
## 其他操作
# import os
# from pprint import pprint
# listdir 获取指定路径的目录结构
# 默认路径为 . 获取当前目录结构
# 该方法会返回一个列表,每个文件(夹)的名字,都是列表中的一个元素
# r = os.listdir('..')
# pprint(r)
# os.getcwd() 获取当前所在的目录
# r = os.getcwd()
# pprint(r)
# os.chdir() 切换目录
# os.chdir('C:/')
# r = os.getcwd()
# pprint(r)
# os.mkdir() 创建一个目录,在当前目录下
# os.mkdir("preticT")
# os.rmdir() 删除目录
# os.rmdir("preticT")
# 删除文件
# open('Pre.txt','w')
# os.remove('pRe.txt')
# os.rename('旧名字','新名字')
# 可以对一个文件进行重命名,亦可以移动一个文件
# os.rename("pRe.txt","D:/pRe.txt")