目录
注意:标红处与C/JAVA做区分!!!
常量和表达式
print(2 / 3)
print(1 + 2 / 3)
- 在python中,1 + 2 / 3 = 1.66665,而不是1
编程中,一般没有“四舍五入”这样的规则,IEEE754标准这套规则下,在内存中表示浮点数的时候可能会存在微小的误差,如上面第二行代码
2 / 3 称为表达式,表达式结果称为表达式的返回值,2、3这样的数字称为字面值常量,+、-、*、/称为运算符/操作符
变量
avg = (1 + 2 + 3) / 3
total = (1 - avg) ** 2 + (2 - avg) ** 2 + (3 - avg) ** 2
result = total / 2
print(result)
- 在python中,**2表示平方
变量命名规则:
硬性规则:
1.变量必须由数字、字母、下划线构成,数字不能开头
2.不能和python的“关键字”重复(即在语法中有特殊含义的单词)
3.区分大小写
软性规则:
1.尽量使用描述性的单词,通过名字来表现出变量的作用
2.当有多个单词的时候,命名有规范:
驼峰命名~除了第一个单词的首字母之外,后续每个单词的首字母都大写
蛇形命名~单词之间,使用下划线_来进行分隔
变量类型
整型int
a = 10
print(type(a))
变量类型是由初始化的值的类型决定的,不需要在定义变量的时候显式声明
在python中,int能够表示的数据范围是“无穷”的,可以根据要表示的数据的大小自动扩容
因此,python中不存在long,byte,short这样的类型
浮点数float
b = 0.5
print(type(b))
python中的float就是双精度浮点数,等同于C++/JAVA里面的double
python的一个设计哲学:解决一个问题,只提供一种方案
字符串
引号使用单引号或双引号都可以
c = 'hello'
d = "hello"
print(type(c))
print(type(d))
e = 'My name is "sy"'
print(e)
f = '''My 'name'is "sy"'''
print(f)
也可以使用三引号'''
求字符串长度
d = "hello"
print(len(d))
字符串的拼接
a1 = 'hello'
a2 = 'world'
print(a1 + a2)
不能把字符串和数字混合相加
在python中报错,有两种情况:
1.语法错误,在程序运行之前,python解释器能把错误识别出来
2.运行错误,在程序运行之前识别不了,必须执行到对应的代码才能发现问题
布尔
取值只有两种,True和False(首字母大写),用于逻辑判定
c1 = True
print(type(c1))
变量类型的意义
- 不同类型占用空间不同(int默认4个字节,动态扩容;float固定8个字节;bool一个字节;str变长的)
- 不同类型对应的能够进行的操作也是不同的(str不能-,只能+)
动态类型特性
动态类型:程序运行过程中,变量的类型可能会发生变化;比较灵活,提高语言的表达能力,然而,在编程中,“灵活”这个词往往是“贬义”,更容易出错!相比之下,静态类型的语言还是好一些,尤其是在大型的程序中,多人协作开发
C++/JAVA中是静态类型
a = True
print(type(a))
a = 10
print(type(a))
a的类型随着程序的运行,发生改变
一个编程语言是否是动态类型,只是取决于运行时类型是否发生改变,不取决于变量定义的时候是否声明类型!
python作为一个动态类型的语言,在定义变量的时候,可以写类型,算是锦上添花!
a: int = 10
print(type(a))
注释的使用
批量注释代码:
选中要注释的代码,ctrl+/
# a = True
# print(type(a))
# a: int = 10
- # 行注释
一般写在代码的上方,少数情况写在代码右侧,很少写在代码下方
# 以下代码用来求几个数字的方差
avg = (1 + 2 + 3) / 3
total = (1 - avg) ** 2 + (2 - avg) ** 2 + (3 - avg) ** 2
result = total / 2
print(result)
- 文档字符串
使用三引号引起来的称为“文档字符串”,也可以视为一种注释
可以包含多行内容
一般放在文件/函数/类的开头
"""或者'''均可(等价)
'''
print(type(a))
这是文档字符串
'''
输出
a = 10
# 希望打印出"a=10"这样的内容,数字和字符串混在一起
print(f"a={a}")
print(f"a={a + 10}")
这个语法,叫做“格式化字符串”
f-string此处的f表示"format"
此时可以使用{}
输入
num = input('请输入一个整数:')
print(type(num))
print(f'您输入的数字是{num}')
input返回的值是一个字符串(str)
如果只是单纯拿到用户的输入,然后打印,此时就按照str打印即可
如果需要根据用户输入的内容进行算术计算,此时就需要先把读到的str->int
可以使用int()进行转换
a = input('请输入第一个数字:')
b = input('请输入第一个数字:')
print(f'a+b={a + b}')
直接拼接!而不是算术运算
算术运算(需要进行类型转换):
a = input('请输入第一个数字:')
b = input('请输入第一个数字:')
a = int(a)
b = int(b)
print(f'a+b={a + b}')
把整数转成字符串:str()
算术运算符
除法遇到的问题
除0异常
print(10 / 0)
print('hello')
在python中,0和0.0都不能做除数,运行时出现错误,“抛出异常”——程序直接终止,后面的代码也将不会被执行
有些编程语言中,/0会抛出异常,/0.0(浮点数0)会得到无穷大
而python中都认为是除0异常
截断问题
整数/整数,如果除不尽,得到小数,不会出现截断的情况
**进行乘方运算
既能支持整数次方,也支持小数次方(开方运算)
print(2 ** 0.5)
//地板除法(取整除法)
针对计算的结果进行“向下取整”
print(7 // 3)
print(-7 // 3)
关系运算符
关系运算符对应的表达式,值是布尔类型,表达式符合要求为真,不符合为假
关系运算不光可以针对数字进行比较,还能够比较字符串
比较规则:字典序!依次比较每个字母在英文词典上的顺序
字符串在词典上越靠前就越小,越靠后就越大
a = 'abc'
b = 'abd'
print(a > b)
print(a < b)
针对中文字符串比较大小是没有意义的
C和JAVA中字符串之间不能直接使用==或者!=来比较
C strcmp,如果直接使用==本质上在比较两个字符串首元素地址
JAVA equals方法,如果直接使用==本质上在比较这两个字符串是否是同一个对象
以上都是小众行为
像python直接使用==和!=来比较字符串内容相同是大部分编程语言遵守的语言
针对浮点数来说,使用==比较相等存在一定的风险
因为浮点数在内存中的存储和表示可能存在误差,这样的误差在进行算术运算的时候就可能被放大导致==的判定出现误判!
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
正确比较浮点数是否相等:作差,看差值是否小于预期的误差范围
a = 0.1 + 0.2
b = 0.3
print(-0.000001 < (a - b) < 0.000001)
python中支持这种连续小于的写法,判定a-b既是<0.000001又是>-0.000001
逻辑运算符
and,or,not
a<b<c等价于a<b and b<c
逻辑运算符中的重要细节:短路求值
对于and来说,如果左侧为False,那么整体的值一定是False,右侧表达式不必求值
or同理
a = 1
b = 2
print(a > b and 10 / 0 == 1)
右侧不再求值,右侧一旦求值,代码是会报错的
a = 1
b = 2
print(a < b and 10 / 0 == 1)
赋值运算符
链式赋值:
a = b = 20
先把20赋值给b,再把b赋值给a,一般不建议使用
多元赋值
a, b = 1, 2
能够帮助我们解决一些问题,比如交换两个变量
# 使用多元赋值,直接一步到位完成交换
a, b = b, a
python中不支持++、--这样的操作
++a、--a之所以没有报错,是python解释器把++、--当成了正号,但是后置++、--会报错!
练习题总结
- python中的字符串之间能够相加,字符串不能与整数相加,整数和浮点数能够相加,整数和布尔值能够相加(没有意义,Ture表示1,False表示0)
- python中只有字符串类型,没有字符类型,'a'表示长度为1的字符串;正是因为python中没有字符类型,所以"和'都能表示字符串,C++/JAVA有单独的字符类型,所以单引号表示字符,双引号表示字符串
- python中只有float,int,整数表示范围无上限
- int a = 10是典型的错误,如果要表示类型,需要这样做:a:int = 10
- a = 10;在python中,一个语句写完了之后可以加上分号,也可以不加,通常情况下不加,但是如果把多个语句写到同一行了,这时务必加上分号!这种写法并不推荐,影响代码可读性
条件语句
python中的条件语句写法,和很多编程语言不太一样
- if后面的条件表达式,没有()使用,使用:作为结尾
- if/else命中条件后要执行的“语句块”,使用缩进(通常是4个空格或者1个tab)来表示,而不是{}
- 对于多条件分支,不是写作else if,而是elif(合体了)
- python中没有switch,if语句已经可以代替了
choice = input('输入1表示愿意认真学习,输入2表示躺平摆烂:')
# 注意这里要比较的是字符串1,而不是整数1!
if choice == '1':
print('能找到好工作')
elif choice == '2':
print('毕业即失业')
else:
print('输入错误')
缩进和代码块
代码块指的是一组放在一起执行的代码
在python中使用缩进表示代码块,不同级别的缩进,程序的执行效果是不同的
a = input('请输入一个数字:')
if a == '1':
print('aa')
print('bb')
a = input('请输入一个数字:')
if a == '1':
print('aa')
print('bb')
bb和条件无关了,条件是否成立都会打印bb,不属于条件语句
a = input('请输入一个数字:')
if a == '1':
print('aa')
print('bb')
语法上出现问题
a = input('请输入一个数字:')
if a == '1':
print('aa')
print('bb')
python中缩进非常重要,但也不能乱写!
在C++/JAVA中,对于代码缩进是没有强制要求的,缩进具体怎么写都不影响代码的编译运行结果,如果缩进没有好好统一风格,也会影响可读性!
代码解析:两个条件都满足,才会打印a;第一个条件满足,就会打印b,因为打印b的语句只有一级缩进,相当于是if a == '1'条件内部的代码块;两个条件都不满足,也能打印c,因为打印c的语句没有缩进,相当于与两个if都无关
当有多级条件嵌套时,当前的语句属于哪个代码块,完全取决于缩进的级别
由于嵌套层次太多,最后两个语句对应哪一级代码块,不容易观察出来,更容易出错
条件语句练习
a = input('请输入一个整数:')
a = int(a) # 类型转换:字符串——>整型
# 等价于:a = int(input('请输入一个整数:'))
if a % 2 == 0:
print('偶数')
else:
print('奇数')
在python中负数余2得到正数0或1,所以以下代码也可以实现:
而在C++/JAVA中不可以:-19%2==-1
a = input('请输入一个整数:')
a = int(a) # 类型转换:字符串——>整型
# a = int(input('请输入一个整数:'))
if a % 2 == 1:
print('奇数')
else:
print('偶数')
空语句
# 输入一个数字,如果数字为1,打印hello
a = input('请输入一个数字:')
if a != '1':
# 啥都不做
else:
print('hello')
没有空语句,报错,需要加上pass(即空语句):
# 输入一个数字,如果数字为1,打印hello
a = input('请输入一个数字:')
if a != '1':
pass
# 啥都不做
else:
print('hello')
for循环
基本语法格式:
for 循环变量 in 可迭代对象:
循环体
注意:
- python中的for和其他语言不同,没有“初始化语句”,“循环条件判定语句”,“循环变量更新语句”,而是更加直接
- 所谓的“可迭代对象”指的是“内部包含多个元素,能一个一个把元素取出来的特殊变量”
代码示例:
for i in range(1, 11):
print(i)
range是一个内建函数,range(beg,end)=>[beg,end)前闭后开区间
range还提供了第三个参数,表示“步长”,默认的步长为1
打印2~10(偶数):
for i in range(2, 12, 2):
print(i)
打印10~1:
for i in range(10, 0, -1):
print(i)
python中没有do while,goto
人生重开模拟器小游戏
import random
import sys
import time
# 人生重开模拟器
print('+-----------------------+')
print('| 花有重开日,人无再少年 |')
print('| |')
print('| 欢迎来到 |')
print('| 人生重开模拟器 |')
print('+-----------------------+')
# 设置初始属性
# 颜值,体质,智力,家境,总和不能超过20,每一项取值都是1~10
while True:
print('请设置初始属性(可用点数为20)')
face = int(input('请输入颜值(1~10):'))
strong = int(input('请输入体质(1~10):'))
iq = int(input('请输入智力(1~10):'))
home = int(input('请输入家境(1~10):'))
# 通过条件语句,对于用户输入的属性做出校验检查
if face < 1 or face > 10:
print('输入错误,请重新输入:')
continue
if strong < 1 or strong > 10:
print('输入错误,请重新输入:')
continue
if iq < 1 or iq > 10:
print('输入错误,请重新输入:')
continue
if home < 1 or home > 10:
print('输入错误,请重新输入:')
continue
if face + strong + iq + home > 20:
print('总的属性超过了20')
continue
print('初始属性输入完毕!')
print(f'颜值:{face},体质:{strong},智力:{iq},家境:{home}')
break
# 生成角色的性别
# 使用random.randint(beg,end),就能生成[beg,end]随机整数
point = random.randint(1, 6) # 在python中,引入其他模块需要先使用import导入
if point % 2 == 0:
gender = 'boy'
print('你是个男孩')
else:
gender = 'girl'
print('你是个女孩')
# 设定角色的出生年份
point = random.randint(1, 3)
if home == 10:
# 第一档
print('你出生在北京,你的父母是高官政要')
home += 1
iq += 1
face += 1
elif 7 <= home <= 9:
# 第二档
if point == 1: # 出生在1月
print('你出生在大城市,父母是公务员')
elif point == 2:
print('你出生在大城市,父母是企业高管')
else:
print('你出生在大城市,父母是大学教授')
iq += 2
elif 4 <= home <= 6:
# 第三档
if point == 1:
print('你出生在三线城市,父母是医生')
strong += 2
elif point == 2:
print('你出生在镇上,你的父母是老师')
iq += 1
else:
print('你出生在镇上,你的父母是个体户')
else:
# 第四档
if point == 1:
print('你出生在农村,你的父母是农民')
strong += 1
face -= 2
elif point == 2:
print('你出生在穷乡僻壤,你的父母是无业游民')
home -= 1
else:
print('你出生在镇上,你的父母感情不和')
home -= 2
print(f'颜值:{face},体质:{strong},智力:{iq},家境:{home}')
for age in range(1, 11):
info = f'你今年{age}岁'
point = random.randint(1, 3)
if gender == 'girl' and home <= 3 and point == 1:
info += '你的家人重男轻女思想非常严重,你被遗弃了'
print(info)
print('游戏结束')
sys.exit(0) # sys是system单词的缩写,也是内部的一个模块
elif strong < 6 and point < 3:
info += '你生了一场病'
if home >= 5:
info += '在父母的悉心照顾下,你康复了'
strong += 1
home -= 1
else:
info += '你的父母没时间管你,你的身体状况更糟糕了'
strong -= 1
elif face <= 4 and age >= 7:
info += '你长得太丑了,别的的小朋友不喜欢你'
if iq > 5:
info += '你决定用学习填充自己!'
else:
if gender == 'boy':
info += '你和别的的小朋友经常打架'
strong += 1
iq -= 1
else:
info += '你经常被别的小朋友欺负'
strong -= 1
elif iq < 5:
info += '你看起来傻傻的'
if home >= 8 and age >= 6:
info += '你的父母把你送到更好的学校学习'
iq += 1
elif 4 <= home <= 7:
if gender == 'boy':
info += '你的父母鼓励你多运动,争取成为运动员'
else:
info += '你的父母鼓励你多打扮自己'
face += 1
else:
info += '你的父母经常吵架'
if point == 1:
strong -= 1
elif point == 2:
iq -= 1
else:
pass
else:
info += '你健康成长'
if point == 1:
info += '你看起来更结实了'
strong += 1
elif point == 2:
info += '你看起来更好看了'
face += 1
else:
pass
print(info)
print(f'颜值:{face},体质:{strong},智力:{iq},家境:{home}')
print('-----------------------------------------------------')
time.sleep(1) # time是程序提供的模块
函数
- python中,函数必须先定义,再调用
- 形参只要求个数,不要求类型(动态类型)
- 一个函数可以返回多个值,C++/JAVA只能返回一个值
- 如果返回多个值,只需要其中一部分,可以使用_来进行占位!比如:
def getPoint():
x = 10
y = 20
return x, y
a, _ = getPoint() # 只要x的值
x = 10
def test():
global x # 全局
x = 20
test()
print(f'x={x}')# x = 20
没有global,就会把x=20当作是在函数内部创建了一个局部变量,而实际上是要修改全局变量
函数形参的默认值
def add(x, y, debug=False):
if debug:
print(f'x={x},y={y}')
return x + y
result1 = add(10, 20, True)
print(result1)
result2 = add(10, 20)
print(result2)
带有默认值的形参,可以在调用函数的时候,不必传参;让函数的设计更灵活
要求带有默认值的形参,得在形参列表的后面,不能在前面/中间
def test(x, y):
print(f'x={x}')
print(f'y={y}')
test(y=20, x=10)
test(x=10, y=20) # 明确知道参数传给谁,另外可以无视实参、形参位置
test(10, 20)
位置参数和关键字参数能混着用,要求位置参数在前,关键字参数在后
关键字参数一般搭配默认参数使用
列表和元组
变量就是内存空间,用来表示/存储数据
如果表示的数据少,直接定义几个变量即可;有时表示的数据较多,需要用到列表和元组(类似于其他编程语言中的“数组”),这种机制可以用一个变量来表示多个数据
- 列表是一种让程序员在代码中批量表示/保存数据的方式
- 元组和列表相比,非常相似,只是列表中放哪些元素可以修改调整,元组中放的元素是创建元组的时候就设定好的,不能修改调整
列表的创建和下标访问
# 创建列表
# 1.直接使用字面值来创建
# []表示一个空的列表
a = []
print(type(a))
# 2.使用list()来创建
b = list()
print(type(b))
# 3.可以在创建列表的时候,在[]中指定列表的初始值
# 元素之间使用逗号来分割
a = [1, 2, 3, 4]
print(a) # [1, 2, 3, 4]
# 4.可以在同一个列表里放不同类型的变量
a = [1, 'hello', True, [4, 5, 6]]
print(a)
# 5.使用下标来访问列表元素
a = [1, 2, 3, 4]
print(a[2]) # 3
# 6.使用下标来修改列表元素
a = [1, 2, 3, 4]
a[2] = 100
print(a) # [1, 2, 100, 4]
# 7.python中的下标,可以写成负数
# 例如写成-1,其实等价于len(a)-1
# -1就是倒数第一个元素
a = [1, 2, 3, 4]
print(a[len(a) - 1]) # 4
print(a[-1]) # 4
len可以传字符串,列表,元组,字典,自定义的类...——>动态类型
列表的切片操作
通过下标操作一次取出一个元素
通过切片,一次取出一组连续的元素,相当于得到一个子列表
# 1.切片操作的基本使用
a = [1, 2, 3, 4]
print(a[1:3]) # [2, 3]
# 两个数字表示了一段区间,1表示区间开始下标,3表示区间结束下标(前闭后开)[1,3)
# 2.使用切片的时候,省略边界
a = [1, 2, 3, 4]
# 省略后边界,意思是从开始位置,一直取到整个列表结果
print(a[1:]) # [2, 3, 4]
# 省略前边界,意思是从列表的0号元素开始取,一直到结束的后边界
print(a[:2]) # [1, 2]
# 此处切片中的下标也可以写成负数
print(a[:-1]) # [1, 2, 3]
# 把开始边界和结束边界都省略,得到列表本身
print(a[:]) # [1, 2, 3, 4]
切片是一个比较高效的操作,进行切片的时候只是取出了原有列表中的一个部分,并不涉及到数据的拷贝;
假设有一个很大的列表,进行切片,切片的范围也很大,即使如此,切片操作仍然非常高效
切片操作,还可以指定“步长”.range
# 1.切片操作的基本使用
a = [1, 2, 3, 4]
print(a[1:3]) # [2, 3]
# 两个数字表示了一段区间,1表示区间开始下标,3表示区间结束下标(前闭后开)[1,3)
# 2.使用切片的时候,省略边界
a = [1, 2, 3, 4]
# 省略后边界,意思是从开始位置,一直取到整个列表结果
print(a[1:]) # [2, 3, 4]
# 省略前边界,意思是从列表的0号元素开始取,一直到结束的后边界
print(a[:2]) # [1, 2]
# 此处切片中的下标也可以写成负数
print(a[:-1]) # [1, 2, 3]
# 把开始边界和结束边界都省略,得到列表本身
print(a[:]) # [1, 2, 3, 4]
# 3.带有步长的切片操作
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
print(a[::1]) # 1指的是步长,每隔一个元素取一个元素
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
print(a[::2]) # [1, 3, 5, 7, 9]
print(a[1:-1:2]) # [2,4,6,8]
# 4.步长可以是负数,当步长为负数的时候,意为从后往前来取值
print(a[::-1]) # [0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
# 5.当切片中的范围超出有效下标之后,不会出现异常!而是尽可能把符合要求的元素给获取到
a = [1, 2, 3, 4]
print(a[1:100]) # [2, 3, 4]
列表的遍历操作
遍历:把列表/数组/元组中的元素依次取出并进行某种操作
遍历=>搭配循环
# 1.使用for来遍历列表
a = [1, 2, 3, 4]
for elem in a:
print(elem)
# 2.使用for循环遍历,通过下标的方式,并且此方法可以修改里面的值
a = [1, 2, 3, 4]
for i in range(0, len(a)): # 左闭右开
print(a[i])
# 3.使用while循环,通过下标遍历
a = [1, 2, 3, 4]
i = 0
while i < len(a):
print(a[i])
i += 1
列表的插入操作
# 1.使用append往列表末尾新增一个元素
a = [1, 2, 3, 4]
a.append(5)
a.append('hello')
# 此处的append是搭配列表对象a来一起使用的,而不是作为一个独立的函数
# type,print,input,自定义函数...都是独立的函数
# 这种要搭配对象(变量)来使用的函数,也叫做“方法”(method)
print(a) # [1, 2, 3, 4, 5, 'hello']
b = [5, 6, 7, 8]
b.append('world')
print(b) # [5, 6, 7, 8, 'world']
# 2.还可以使用insert方法,往列表任意位置来新增函数
a = [1, 2, 3, 4]
a.insert(1, 'hello') # 下标为1插入
print(a) # [1, 'hello', 2, 3, 4]
a.insert(100, 'world') # 当超过下标范围,将插在末尾
print(a) # [1, 'hello', 2, 3, 4, 'world']
使用append和insert方法
列表的查找和删除
# 1.使用in来判定某个元素是否在列表中存在
a = [1, 2, 3, 4]
print(1 in a) # True
print(10 in a) # False
print(1 not in a) # False
# 2.使用index方法来判定当前元素在列表中的位置,得到一个下标
a = [1, 2, 3, 4]
print(a.index(2)) # 1 2的下标是1
# print(a.index(10)) # 报错——10 is not in list
# 1.使用pop删除列表中的最末尾的元素
a = [1, 2, 3, 4]
a.pop()
print(a) # [1,2,3]
# 2. 使用pop还能删除任意位置的元素,pop的参数可以传一个下标过去
a = [1, 2, 3, 4]
a.pop(1) # 将下标为1的元素删去,也就是2
print(a) # [1, 3, 4]
# 3.使用remove方法,可以按照值来进行删除
a = ['a', 'b', 'c', 'd']
a.remove('c') # 将'c'删除
print(a) # ['a', 'b', 'd']
列表的拼接
# 1.使用+针对两个列表进行拼接
a = [1, 2, 3]
b = [4, 5, 6]
print(a + b) # [1, 2, 3, 4, 5, 6]
# 使用+来拼接内容,原列表不变
# 2.使用extend来进行拼接
# 将后一个列表内容拼接到前一个列表里面,前一个列表改变,后一个列表不变
a = [1, 2, 3]
b = [4, 5, 6]
c = a.extend(b)
print(a) # [1, 2, 3, 4, 5, 6]
print(b) # [4, 5, 6]
print(c) # None——表示什么都没有,相当于C里面的NULL,或者JAVA里面的null
# extend方法没有返回值
# 倾向于使用extend来完成拼接
# 3.使用+=来进行拼接
a = [1, 2]
b = [3, 4]
a += b
print(a) # [1, 2, 3, 4]
print(b) # [3, 4]
元组的操作
# 1.创建元组
a = ()
print(type(a)) # <class 'tuple'>
b = tuple()
print(type(b)) # <class 'tuple'>
# 2.创建元组的时候,指定初始值
a = [1, 2]
print(a)
# 3.元组中的元素也可以是任意类型的
a = (1, 2, 'hello', True, [])
print(a) # [1, 2, 'hello', True, []]
# 4.通过下标来访问元组中的元素,下标从0开始,到len-1结束
a = (1, 2, 3)
print(a[1]) # 2
print(a[-1]) # 3
# print(a[100]) # 报错——tuple index out of range
# 5.通过切片来获取元组中的一个部分
a = (1, 2, 3)
print(a[1:3]) # (2, 3)
# 6.也同样可以使用for循环等方式来进行遍历元素
a = (1, 2, 3)
for elem in a:
print(elem)
# 7.可以使用in来判断元素是否存在,使用index查找元素的下标
# 8.可以使用+来拼接两个元组
# 9.元组内容不能修改
# 10.当进行多元赋值的时候,其本质上是按照元组的方式来进行工作
def getPoint():
x = 10
y = 20
return x + y
# x, y = getPoint()
print(type(getPoint()))
字典的创建
字典是一种存储键值对的结构
键值对:把键(key)和值(value)进行一个一对一的映射,然后可以根据键快速找到值
在python的字典中,可以同时包含多个键值对,同时这些键不能重复
# 1.创建字典
a = {}
print(type(a)) # <class 'dict'>
b = dict()
print(type(b)) # <class 'dict'>
# 2.创建字典的同时设置初始值
a = {'id': 1, 'name': 'zhangsan'}
# 两组键值对
# 'id':1 key就是'id',value就是1
# 'name':'zhangsan' key就是'name',value就是'zhangsan'
# 一个字典中的key类型不一定都一样,value的类型也不必都一样
# 字典对于key是啥类型有约束,对于value是啥类型没约束
# 如果字典中的内容过多,将无法知道有多少键值对,因此,采用以下方法(写成多行形式):
a = {
'id': 1,
'name': 'zhangsan' # 最后一个键值对的逗号可写可不写
}
print(a) # {'id': 1, 'name': 'zhangsan'}
字典查找key
a = {
'id': 1,
'name': 'zhangsan' # 最后一个键值对的逗号可写可不写
}
print(a) # {'id': 1, 'name': 'zhangsan'}
print('id' in a) # True
print('classId' in a) # False
# in只是来判定某个key是否存在,和value无关!
print('zhangsan' in a) # False
# not in来判定key在字典中不存在
print('id' not in a) # False
print('classId' not in a) # True
# 2.使用[]来根据key获取到value
a = {
'id': 1,
'name': 'zhangsan',
100: 'list'
}
print(a['id']) # 1
对于字典来说,使用in或者[ ]来获取value,都是非常高效的操作!
对于列表来说,使用in比较低效(把整个列表遍历),而使用[ ]是比较高效的!
字典的新增修改删除
字典的各种操作,都是针对key来进行的!
# 1.在字典中使用[]来新增元素
a = {
'id': 1,
'name': 'zhangsan'
}
a['score'] = 90
print(a)
# 2.在字典中,根据key修改value,也是使用[]来操作
a['score'] = 100
print(a)
# 3.使用pop方法,根据key来删除键值对
a.pop('name')
print(a)
理解字典操作的效率
遍历:能够把一个可迭代对象里面包含的元素依次取出,并进行一些操作,整个操作不重不漏
字典被设计出来的初衷,不是为了实现遍历,而是为了增删改查
字典是哈希表,进行增删改查,效率都是非常高的!而字典的遍历效率就差一些!
哈希表这个结构很巧妙,能够以“常数级”时间复杂度来完成增删改查,最重要的数据结构!
工作中最常用到的数据结构就是哈希表(没有之一);也是面试中非常高频的问题!
常数级:无论字典中有多少元素,新增、修改、查找、删除都是固定时间,不会因为元素多而操作慢
字典的遍历
keys 获取到字典中所有的key
values 获取到字典中的所有value
items 获取到字典中所有的键值对
a = {
'id': 1,
'name': 'zhangsan',
'score': 90
}
print(a.keys()) # dict_keys(['id', 'name', 'score'])
返回的结果,看起来像列表,又不完全是,自定义的类型
a = {
'id': 1,
'name': 'zhangsan',
'score': 90
}
print(a.values()) # dict_values([1, 'zhangsan', 90])
a = {
'id': 1,
'name': 'zhangsan',
'score': 90
}
print(a.items()) # dict_items([('id', 1), ('name', 'zhangsan'), ('score', 90)])
首先是一个列表一样的结构,里面每个元素又是一个元组,元组里面包含了键和值
a = {
'id': 1,
'name': 'zhangsan',
'score': 90
}
for key, value in a.items():
print(key, value) # 一样完成字典的遍历
可哈希的类型
不是所有的类型都可以作为字典的key
字典本质上是一个哈希表,哈希表的key要求是“可哈希的”,也就是可以计算出一个哈希值
可以使用hash函数计算某个对象的哈希值
但凡能够计算出哈希值的类型,都可以作为字典的key
# 使用hash函数能够计算出一个变量的哈希值
print(hash(0))
print(hash(2))
print(hash(3.14)) # 小数
print(hash('hello')) # 字符串
print(hash(True)) # 布尔值
print(hash((1, 2, 3))) # 元组
# 有的类型不能计算哈希值,比如:
# print(hash([1,2,3]))# 列表 TypeError: unhashable type: 'list'
# print(hash({})) # 字典 TypeError: unhashable type: 'dict'
不可变的对象,一般就是可哈希的;可变的对象,一般就是不可哈希的
列表、字典是可变的
字典、列表、元组是python中非常常用的内置类型,相比于int,str,float...它们内部可以再包含其他元素,可以称得上“容器”或“集合类”
文件
变量是把数据保存到内存中,如果程序重启/主机重启,内存中的数据就会丢失,要想数据持久化存储,就可以把数据存储到硬盘中,也就是在文件中保存
内存、外存区别:
- 内存的空间更小,硬盘空间更大
- 内存访问更快,硬盘访问更慢
- 内存成本更贵,外存成本更便宜
- 内存的数据易失,硬盘的数据持久化存储
硬盘上的数据就是以文件的形式来组织
文件路径
"D:\pycharm\PyCharm Community Edition 2023.3.3\bin\pycharm64.exe"这样的一段字符串,就是pycharm的路径(文件的路径)——是唯一的
目录名之间,使用\来分割,使用/也可以
打开文件
open打开一个文件
# 使用open打开一个文件
f = open('d:/Python环境/test.txt', 'r') # 文件对象
# r表示read,按照读方式打开
# w表示write,按照写方式打开
# a表示append,也是写方式打开,把内容写到原有文件内容的末尾
print(f)
print(type(f))
open的返回值是一个文件对象,此处的文件对象是内存上的一个变量,后续读写操作,都是拿着这个文件对象来进行操作,此处的文件对象就像一个“遥控器”一样
计算机中,也把这样的远程操控的“遥控器”称为“句柄”(handler)
关闭文件
close关闭文件;文件使用完之后,一定要关闭,打开文件其实是在申请一定的系统资源,不再使用文件的时候,资源就应该及时释放,否则造成文件资源泄露,进一步导致其他部分的代码无法顺利打开文件——要有借有还
因为一个系统的资源是有限的,所以程序能打开的文件的个数也是有上限的
# 打开文件个数的上限
flist = []
count = 0
while True:
f = open('d:/Python环境/test.txt', 'r')
flist.append(f)
count += 1
print(f'开开文件的个数:{count}')
结果:
打开文件的个数:8189
在系统中,可以通过一些设置项,来配置能打开文件的最大数目的,但无论配置多少,都不是无穷无尽,需要记得及时关闭,释放资源
8189 + 3 => 8192(2的13次方!)
每个程序在启动的时候,都会默认打开三个文件:
- 标准输入——键盘
- 标准输出——显示器
- 标准错误——显示器
# 打开文件个数的上限
flist = []
count = 0
while True:
f = open('d:/Python环境/test.txt', 'r')
flist.append(f)
f.close()
count += 1
print(f'开开文件的个数:{count}') # 可以显示文件数上限
文件资源泄露,是一个重要的问题,不会第一时间暴露出来,而是在角落里冷不丁偷袭一下
python有一个重要机制,垃圾回收机制(GC),自动地把不适用的变量进行释放
虽然python给了我们后手,让我们在一定程度上避免了上述问题,但是也不能完全依赖自动释放机制!因为自动释放不一定及时,尽量手动释放保证万无一失
写文件
# 使用write来实现写文件的操作
f = open('d:/Python环境/test.txt', 'w')
f.write('hello')
f.close()
# 写文件的时候,需要使用w的方式打开,如果是r方式打开,则会抛出异常
写方式打开,有两种情况,直接写方式打开,追加写方式打开
如果是使用w方式打开,会清空文件原有的内容
f = open('d:/Python环境/test.txt', 'w')
f.close()
如果使用a方式打开,则将在原有内容之上,拼接内容
f = open('d:/Python环境/test.txt', 'a')
f.write('2')
f.close()
如果文件对象已被关闭,那么意味着系统中和该文件相关的内存资源已被释放,强行去写会报错
读文件
# 使用read读取文件内容,指定读几个字符
f = open('d:/python环境/test.txt', 'r', encoding='utf8') # 关键字参数——为了防止报错
# 位置参数和关键字参数可以混着用
result = f.read(2) # 读前两个字符
print(result)
f.close()
更常见的需求,是按行来读取:
最简单的方法,使用for循环:
f = open('d:/Python环境/test,txt', 'r', encoding='utf8')
for line in f:
print(f'line={line}')
f.close()
之所以多了空行,是因为本来读到的文件内容(这一行内容,末尾就有\n,此处使用print来打印,又会自动加一个换行符)
可以给print多设定个参数,修改print自动添加换行的行为
f = open('d:/Python环境/test,txt', 'r', encoding='utf8')
for line in f:
print(f'line={line}', end='') # end参数表示每次打印之后要在末尾加个...
f.close()
还可以使用readlines方法直接把整个文件所有内容都读出来,按照行组织到一个列表里
一次读完,速度更快!
f = open('d:/Python环境/test,txt', 'r', encoding='utf8')
lines = f.readlines()
print(lines)
f.close()
上下文管理器
打开文件之后,容易忘记关闭,python提供了上下文管理器,帮助程序员自动关闭文件
使用with语句打开文件,当with内部的代码块执行完毕后,就会自动调用关闭方法
有些情况非常容易遗漏close
万一中间的代码里,有条件判定,函数返回,抛出异常
def func():
f = open('d:/Python环境/test.txt', 'r', encoding='utf8')
# 中间写其他的操作文件的逻辑
# 万一中间的代码里,有条件判定,函数返回,抛出异常
f.close() # 先写
使用上下文管理器可以解决这个问题
def func():
with open('d:/Python环境/test.txt', 'r', encoding='utf8') as f:
#进行文件这里的处理逻辑
if cond:
return
上下文管理器起到的作用,当with对应的代码块执行结束,会自动执行f的close
C++中的智能指针,Java中的try with Resources一样的作用
使用库
库就是别人已经写好的代码,可以直接拿来用
一个编程语言能不能流行起来,一方面取决于语法是否简单方便容易学习,一方面取决于生态是否完备(所谓的“生态”指的是语言是否有足够丰富的库,来应对各种各样的场景)
实际开发中,也并非所有的代码都自己手写,而是要充分利用现成的库,简化开发过程
按照库的来源,可以大致分为两大类:
- 标准库:python自带的库,只要安装了python就可以直接使用Python 标准库 — Python 3.12.2 文档
- 第三方库:其他人实现的库,要想使用,需额外安装(数量更庞大,更丰富)
代码案例
日期计算器
datetime函数
# 构造datetime变量
# import datetime
# date1 = datetime.datetime(2023, 9, 10)
# date2 = datetime.datetime(2024, 3, 3)
# print(date2 - date1) # 175 days, 0:00:00 入学175天
# 或进行以下代码:
# from datetime import datetime
#
# date1 = datetime(year=2023, month=9, day=10) # 不需要再进行.datetime
# date2 = datetime(year=2024, month=3, day=3)
# print(date2 - date1) # 175 days, 0:00:00
# 或进行以下方法:
import datetime as dt
date1 = dt.datetime(2023, 9, 10)
date2 = dt.datetime(2024, 3, 3)
print(date2 - date1) # 175 days, 0:00:00
单词逆序
字符串是python的内置类型,字符串的很多方法不需要导入额外的模块
怎样区分单词?根据空格来分割
在python中的思路:
- 针对上述字符串,使用空格进行切分,字符串split方法可以指定分隔符,把字符串分成多个部分,放到一个list里面
- 针对刚才的切分结果列表,进行逆序
- 把逆序后的列表组合起来~join
def reverseWords(s: str):
tokens = s.split(' ') # 使用空格来区分
tokens.reverse()
return ' '.join(tokens)
print(reverseWords('I am a student')) # student a am I
旋转字符串
把最左侧的字符依次放到最右侧
def rotateString(s, goal):
if len(s) != len(goal):
return False
return goal in (s + s)
print(rotateString('abcd', 'dcba')) # False
print(rotateString('abcd', 'bcda')) # True
print(rotateString('abcd', 'cdab')) # True
print(rotateString('abcd', 'dabc')) # True
统计字符串前缀
遍历words,取出每个字符串,判定当前这个字符串是否是s的前缀即可(s是否是以这个字符串开头的)
startswith方法判断前缀
def countPrefixes(words: list, s: str):
count = 0
for word in words:
s.startswith(word)
if s.startswith(word):
# s是以word开头
count += 1
return count
print(countPrefixes(['a', 'b', 'ab', 'abc'], 'abc')) # 3
print(countPrefixes(['a', 'a'], 'aa')) # 2
文件搜索工具
everything
递归查找:遇到子目录,就进到目录里面进行查找
os.walk使用循环递归遍历目录,不用手写递归代码
dirpath(遍历到当前位置对应的路径是什么), dirnames(当前目录下有哪些目录,这是一个列表,可以包含多个目录), filenames(当前目录下有哪些文件,这是一个列表,可以包含多个文件名)
for dirpath, dirnames, filenames in os.walk(inputPath): os.walk每次调用都能自动针对子目录进行递归操作,只需要使用上述循环就可以把所有的路径都获取出来
# 输入要查找的路径,输入要搜索的文件名(一部分)
# 自动在指定路径中进行查找
import os
inputPath = input('请输入要搜索的路径:')
pattern = input('请输入要搜索的关键词:')
for dirpath, dirnames, filenames in os.walk(inputPath):
print('------------------------------')
print(f'dirpath={dirpath}')
print('dirnames:')
for name in dirnames:
print(name)
print('filenames:')
for name in filenames:
print(name)
# 输入要查找的路径,输入要搜索的文件名(一部分)
# 自动在指定路径中进行查找
import os
inputPath = input('请输入要搜索的路径:')
pattern = input('请输入要搜索的关键词:')
for dirpath, _, filenames in os.walk(inputPath):
for f in filenames:
if pattern in f:
print(f'{dirpath}/{f}')
pip的使用
pip是python内置的包管理器
所谓包管理器就类似于我们平时用的手机app应用商店一样
第三方库很多,是不同的人,不同的组织实现的为了方便大家整理,python官方提供一个网站PyPI · The Python Package Index来收集第三方库
安装python的时候已自动将pip安装好,直接使用
使用以下命令,即可安装第三方库:
pip install [库名]
注意:这个命令需要从网络上下载,使用的时候保证网络畅通
安装成功后,即可使用import导入相关模块,即可进行使用
生成二维码
二维码本质上就是一段字符串,生活中使用的二维码,更多的是一个URL(网址)
- 通过搜索引擎,确定使用哪个库
- 查看qrcode文档
import qrcode
img = qrcode.make('未来的程序员,你好')
img.save('qrcode.png') # no news in good news——没有报错,执行成功
我的代码仓库二维码:
操作excel
读取excel可以使用xlrd模块xlrd — xlrd 2.0.1 documentation
修改excel可以使用xlwt模块xlwt documentation — xlwt 1.3.0 documentation
操作excel
- 安装xlrd
pip install xlrd==1.2.0(此处注意要指定版本号安装,如果不指定版本号,则安装最新版,最新版里删除了对xlsx格式文件的支持)
- 编写代码
# 操作excel
import xlrd
# 1.先打开文件
xlsx = xlrd.open_workbook('d:/python环境/test.xlsx')
# 2.获取到指定标签页
table = xlsx.sheet_by_index(0) # 或者标签页的名字(重命名)
# 3.获取到表格中有多少行
nrows = table.nrows
print(f'nrows={nrows}') # nrows=8——excel中有8行
# 4.进行循环统计操作
for i in range(1, nrows): # 表头不算
print('-------------------------')
print(table.cell_value(i, 1)) # 班级
print(table.cell_value(i, 0)) # 姓名
print(table.cell_value(i, 2)) # 分数
统计班级平均分:
# 操作excel
import xlrd
# 1.先打开文件
xlsx = xlrd.open_workbook('d:/python环境/test.xlsx')
# 2.获取到指定标签页
table = xlsx.sheet_by_index(0) # 或者标签页的名字(重命名)
# 3.获取到表格中有多少行
nrows = table.nrows
print(f'nrows={nrows}') # nrows=8——excel中有8行
# 4.进行循环统计操作
total = 0
count = 0
for i in range(1, nrows): # 表头不算
print('-------------------------')
classId = table.cell_value(i, 1) # 班级
if classId == 100: # 100班
total += table.cell_value(i, 2) # 分数总和
count += 1 # 统计人数
print(f'平均分:{total / count}')