参考资料:https://www.bilibili.com/video/BV1wD4y1o7AS
前置知识
print函数
print 函数的输出内容:数字、字符串、含有运算符的表达式
print 函数输出的地方:显示器、文件
print 函数输出的形式:换行与不换行
注释
单行注释:# 注释内容
多行注释:’’’ 注释内容 ‘’’
使用jupetr需要在后面加代码才能识别为多行注释
编码格式声明注释:
#coding:gbk —> 文件以gbk模式存储
#coding:utf-8 —> 文件以utf-8存储
python3 默认格式为utf-8
# 数字
print(1.2)
# 字符串
print('nihao')
# 含有运算符的表达式
# 3和1 为运算数, +-*/=等等为运算符。运算数+运算符的式子称为表达式
print(3+1)
1.2
nihao
4
# 输出到文件当中
# open('文件路径',‘选择那种方式打开文件’)
# a+ 表示在该路径下,有文件就以读写的方式打开文件并在文件后面继续追加内容,没文件就创建文件
fp=open('/Users/xieshaolin/workpalce/python/nihao.txt','a+')
print("nihao",file=fp)
fp.close()
# 用“,”进行分隔在一行进行输出
print('ni')
print('hao')
print('ni','hao')
# print函数默认end=\n(换行符),end=','表示以','结尾 end=‘ ’ 表示以空格结尾
print('bu',end=' ')
print('hao',end=' ')
ni
hao
ni hao
bu hao
转义字符
\n —> 换行符 \t —> 制表符
\—> 反斜杠 '—> 单引号
不重要,遇到查一下就好
二进制与字符编码 (不重要)
python 中的保留字与标识符(不重要,用多了就知道了)
保留字:如break,continue等(用多了就知道了)
标识符:严格区分大小写,不能以数字开头,字母数字和下划线
变量与数据类型
变量的定义与使用
变量由三个部分组成
如 name = ‘玛丽亚’
标识:上面的name,表示对象所存储的内存地址,id(obj)可以获取
类型:表示对象的数据类型,上面‘’表示该对象为字符串类型,type(obj)可以获取
值:表示对象所存储的具体数据,print(obj)可以获取
上面的 = 为赋值运算
name = ‘玛丽亚’ 含义: 把一个字符串类型,值为玛丽亚的一个数据,赋值给name(内存地址)所代表的内存村空间
多次赋值后,变量名会指向一个新的空间
name = '玛丽亚'
print('值=',name,';name的内存地址=',id(name),';name的类型=',type(name))
name = '玛丽亚'
print('值=',name,';name的内存地址=',id(name),';name的类型=',type(name))
name = '玛丽亚'
print('值=',name,';name的内存地址=',id(name),';name的类型=',type(name))
# 以上三次赋值,内存地址都变了,表示3次赋值指向了不同的内存空间
值= 玛丽亚 ;name的内存地址= 4348995024 ;name的类型= <class 'str'>
值= 玛丽亚 ;name的内存地址= 4367296144 ;name的类型= <class 'str'>
值= 玛丽亚 ;name的内存地址= 4367295280 ;name的类型= <class 'str'>
数据类型
常用的数据类型
- 整数类型 –> int –> 100
- 服点数类型 –> float –> 3.1415926
- 布尔类型 –> bool –> true/false
- 字符串类型–> str –> ‘人生苦短‘
# 整数类型的进制问题
print('默认十进制=',16)
print('0b开头表示二进制=',0b10000)
print('0o开头表示八进制',0o20)
print('0x开头表示十六进制',0x1)
# print默认输出的是十进制,所以print内部做出了转换,把其他进制都转换成了十进制
默认十进制= 16
0b开头表示二进制= 16
0o开头表示八进制 16
0x开头表示十六进制 1
# 浮点数存储不精确
print('1.1+2.2=%s'%(1.1+2.2))
# 浮点数之间的计算需要使用:decimal
from decimal import Decimal
print('1.1+2.2=',(Decimal('1.1')+Decimal('2.2')))
# 并不是所有的浮点数相加都不准确,这和二进制的底层相关
print('1.1+1.2=%s'%(1.1+1.2))
1.1+2.2=3.3000000000000003
1.1+2.2= 3.3
1.1+1.2=2.3
# 布尔值和整数可以相互转换
# True = 1 False = 0 注意首字母大写
print(True+1,False+1)
2 1
# 字符串又被称为不可变大夫序列
str1='使用单引号表示'
str2="使用双引号表示"
str3="""使用三引号,
可以换行"""
str4='''使用三引号,
可以换行'''
print(str1,type(str1))
print(str2,type(str2))
print(str3,type(str3))
print(str4,type(str4))
使用单引号表示 <class 'str'>
使用双引号表示 <class 'str'>
使用三引号,
可以换行 <class 'str'>
使用三引号,
可以换行 <class 'str'>
数据类型转换
str –> int ===> int( )
int –> str ===> str( )
str –> float ===> float( )
float –> str ===> str( )
int –> float ===> float( )
float –> int ===> int( )
print('------------------int float bool --> str----------------------')
a = 9
b = 9.8
c = True
d = False
print(a,type(a),'===>',str(a),type(str(a)))
print(b,type(b),'===>',str(b),type(str(b)))
print(c,type(c),'===>',str(c),type(str(c)))
print(d,type(d),'===>',str(d),type(str(d)))
print('------------------str float bool --> int----------------------')
a1='9'
a2='9.8'
a3='nihao'
b1=10.7
c1=True
c2=False
# 只能把整数的字符窜转换为整数,小数或者文字的字符串都会报错
print(a1,type(a1),'===>',int(a1),type(int(a1)))
#print(a2,type(a2),'===>',int(a2),type(int(a2)))
#print(a3,type(a3),'===>',str(a3),type(str(a3)))
# 直接截取整数部分
print(b1,type(b1),'===>',int(b1),type(int(b1)))
# True=1 False=0
print(c1,type(c1),'===>',int(c1),type(int(c1)))
print(c2,type(c2),'===>',int(c2),type(int(c2)))
print('------------------str int bool --> float----------------------')
x='9'
y='9.8'
z='nihao'
u=9
v=True
w=False
#整数和小数可以转,字符不能
print(x,type(x),'===>',float(x),type(float(x)))
print(y,type(y),'===>',float(y),type(float(y)))
#print(z,type(z),'===>',int(z),type(int(z)))
print(u,type(u),'===>',float(u),type(float(u)))
print(v,type(v),'===>',float(v),type(float(v)))
print(w,type(w),'===>',float(w),type(float(w)))
------------------int float bool --> str----------------------
9 <class 'int'> ===> 9 <class 'str'>
9.8 <class 'float'> ===> 9.8 <class 'str'>
True <class 'bool'> ===> True <class 'str'>
False <class 'bool'> ===> False <class 'str'>
------------------str float bool --> int----------------------
9 <class 'str'> ===> 9 <class 'int'>
10.7 <class 'float'> ===> 10 <class 'int'>
True <class 'bool'> ===> 1 <class 'int'>
False <class 'bool'> ===> 0 <class 'int'>
------------------str int bool --> float----------------------
9 <class 'str'> ===> 9.0 <class 'float'>
9.8 <class 'str'> ===> 9.8 <class 'float'>
9 <class 'int'> ===> 9.0 <class 'float'>
True <class 'bool'> ===> 1.0 <class 'float'>
False <class 'bool'> ===> 0.0 <class 'float'>
运算符
input 函数
present=input(str)
str –> 打印在控制台的语句
present –> str类型,是我们输入的语句
python中的运算符
- 算术运算符
- ‘+’ 加法运算符
- ‘-’ 减法运算符
- ‘*’ 乘法运算符
- ‘/’ 除法运算符
- ‘//’ 整除运算符
- ‘%’ 取余运算
- ‘**’ 幂运算符
- 赋值运算符
- =赋值运算符,从右执行到左
- 链式赋值: a=b=c=20;a、b、c三个指向同一个地址值
- 参数赋值: +=、-=、*=、/=、//=、%=
- a+=2相当于 a=a+2,其他类似
- 解包赋值: a,b,c=20,30,40 ===> a=20,b=30,c=40,顺序和个数要一致
- 解包赋值常用于变量交换
- 没有解包赋值交换a和b: temp=a;a=b;b=temp
- 有解包赋值一行搞定: a,b=b,a
- 解包赋值常用于变量交换
- 比较运算符
- 比较运算符返回的是bool(False/True)
- 比较对象的value:>,<,>=,<=,!=,==
- 比较对象的id(地址值):is,is not
- 与java不同,java==比较的是地址值
- 布尔运算符
- and 且
- or 或
- not 非
- in 在…里面
- not in 不在…里面
- 位运算符(难但用的少)
- 位与&: 对应数位都是1(true),结果才是1(true),否则位0(false)
- 位或|: 对应数位都是0(false),结果才是0(false),否则位1(true)
- 左移位运算符<<: 高位溢出舍弃,低位补0
- 右移位运算符>>: 低位溢出舍弃,高位补0
运算符的优先级(加括号就行)
present=input('你几岁?')
print(present,type(present))
你几岁?1
1 <class 'str'>
print('5/3=',5/3)
print('5//3=',5//3)
print('5%3=',5%3)
print('2的3次方=',2**3)
print('3的2次方=',3**2)
print('---------------------算术运算符:正负号问题----------------------------')
# 取整//:一正一负向下取整
print('-5//-3=',-5//-3)
print('-5//3=',-5//3)
print('5//-3=',5//-3)
# 取余% : 余数=被除数-除数*商, 其中 商遵循 一正一负上下整
print('-5%-3=',-5%-3) # -5-(-3*1)= -2 ---> -3 + -2 = -5
print('-5%3=',-5%3) # -5-(3*-2)= 1 ---> 3*(-2) + 1 = -5
print('5%-3=',5%-3) # 5-(-3*-2)= -1 ---> -3*(-2) - 1 = 5
5/3= 1.6666666666666667
5//3= 1
5%3= 2
2的3次方= 8
3的2次方= 9
---------------------算术运算符:正负号问题----------------------------
-5//-3= 1
-5//3= -2
5//-3= -2
-5%-3= -2
-5%3= 1
5%-3= -1
# a 与 b 的地址值相同是因为常量在内存空间的地址是固定的,即内存中有专门的一个区域来存储常量
a=10
b=10
print('a==b为',a==b)
print('a is b为',a is b)
print('a的ID为',id(a))
print('b的ID为',id(b))
list1=[10,11]
list2=[10,11]
print('list1==list2为',list1==list2)
print('list1 is list2为',list1 is list2)
print('list1的ID为',id(list1))
print('list2的ID为',id(list2))
a==b为 True
a is b为 True
a的ID为 4303518736
b的ID为 4303518736
list1==list2为 True
list1 is list2为 False
list1的ID为 4368027328
list2的ID为 4368027520
s = 'nihao'
print('n' in s)
print('b' not in s)
l = [10,20]
print(10 in l)
print(30 not in l)
True
True
True
True
程序的组织结构
顺序结构(略)
选择结构(if)
对象的布尔值
- 获取对象的布尔值:bool()
- 以下对象的布尔值都是False
- False
- 数值0
- None
- 空字符串
- 空列表
- 空数组
- 空字典
- 空集合
单分支结构:如果…就…
语法结构:
if 条件表达式:
条件执行体
双分支结构:如果…不满足…就…
语法结构:
if 条件表达式:
条件执行体1
else:
条件执行体2
多分支结构
语法结构:
if 条件表达式:
条件执行体1
elif:
条件执行体2
elif:
条件执行体N
[elif:]
条件执行体N+1
嵌套if(略)
条件表达式:if-else 的简写
语法结构:x if 判断条件 else y
运算规则:如果判断条件为ture,则执行x并返回x的结果;为false则执行y并返回y的结果
pass 语句
是什么:语句什么都不做,只是一个占位符,用在语法上需要语句的地方
何时用:在搭建语法结构,但还没想好怎么写代码的时候
用在哪:
- if语句的条件执行体
- for-in语句的循环体
- 定义函数时的函数体
类似java的todo
# 单分支结构
money=1000
m=int(input('请输入取款金额'))
if money>=m: # 和java不一样,java是(),这里是:
money-=m # 执行的语句要缩紧
print('取款成功,余额为:',money)
请输入取款金额500
取款成功,余额为: 500
# 双分支结构
num=int(input("请输入一个整数:"))
if num%2==0:
print("您输入的是一个偶数")
else:
print("您输入的是一个奇数")
请输入一个整数:23
您输入的是一个奇数
# 多分支结构
score = int(input("请输入一个成绩:"))
if(score>=90 and score<=100): # 加()也不影响
print("A")
elif score<90 and score>=80:
print("B")
elif score<80 and score>=70:
print("C")
elif score<70 and score>=60:
print("D")
elif score<60 and score>=0:
print("E")
else:
print("非法数据")
请输入一个成绩:-1
非法数据
# 条件表达式
a = int(input("请输入第一个数字:"))
b = int(input("请输入第二个数字:"))
print(a,'>=',b) if a>=b else print(a,'<',b)
请输入第一个数字:2
请输入第二个数字:3
2 < 3
# pass语句
a= int(input('请输入一个整数'))
if a>0:
pass # 有时候这部分的代码没有想好,但是如果没想好就放在这里,运行程序的时候会报错
else:
pass # 在java中if后面不写语句也是不会报错的
if a>10:{# 如果这里加{}后程序也不报错了
}
请输入一个整数1
循环结构(while/for-in)
rang( ) 函数
- 用于生成一个整数序列
- 创建range()对象的三种方式
- range(stop):创建一个【0,stop)之间的整数序列,步长为1
- range(star,stop):创建一个【start,stop)之间的整数序列,步长为1
- range(star,stop,step):创建一个【start,stop)之间的整数序列,步长为step
- 步长就是相邻的两个数之间的差距
- 返回值是一个迭代器对象,不是列表
- range类型的优点:不管range对象表示的整数序列有多长,所有range对象占用的内存空间都是相同的。
因为仅仅需求存储start,stop和step,只有当用到range对象时,才会去计算序列中的相关元素 - in语not in 判断整数序列是否存在(不存在)制定的整数
# range(stop)
r=range(10);# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(r) # range(0, 10)---> 迭代器对象
print(list(r))# 用于查看range对象中的整数序列 ---> list是列表的意思
range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# range(start,stop)
r=range(1,10);# [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(list(r))# 用于查看range对象中的整数序列 ---> list是列表的意思
[1, 2, 3, 4, 5, 6, 7, 8, 9]
# range(start,stop,step)
r=range(1,10,2);# [1, 3, 5, 7, 9]
print(list(r))# 用于查看range对象中的整数序列 ---> list是列表的意思
[1, 3, 5, 7, 9]
r=range(1,10,2)# [1, 3, 5, 7, 9]
print(1 in r)
print(2 in r)
True
False
while
while 条件表达式:
循环体
条件表达式为true,会一直执行循环体
a = 1
sum=0
while(a<=10):
sum+=a
a+=1
print('sum=',sum)
sum= 55
for-in
for 自定义的变量 in 可迭代的对象:
循环体
- 循环体内不需要访问自定义变量,可以将自定义变量替代为下划线
# 遍历字符串
for item in 'Python':
print(item,end=',')
P,y,t,h,o,n,
# 遍历range
sum=0
for i in range(1,11):
sum+=i
print('sum=',sum)
sum= 55
# 如果循环体中用不到自定义变量,可以 _ 代替
for _ in range(5):
print('人生苦短,我用python')
人生苦短,我用python
人生苦短,我用python
人生苦短,我用python
人生苦短,我用python
人生苦短,我用python
# 水仙花数:abc=a*a*a+b*b*b+c*c*c
for item in range(100,1000):
a=item//100
b=(item//10)%10
c=item%10
if(item-a**3-b**3-c**3==0):
print(item,end=',')
153,370,371,407,
流程控制语句:break与continue
- break:结束循环
- continue:结束当前循环
- 对于二重循环,break与continue用于控制本层循环
else
- if+else:条件表达式不成立,执行else语句
- while+else:没遇得到break,执行else语句
- for-in+else:没遇得到break,执行else语句
# 使用else
for item in range(3):
pwd=int(input("请输入密码:"))
if(pwd==8888):
print('密码正确')
break
else:
print("密码不正确")
else:
print("对不起,三次密码均错误!")
请输入密码:8888
密码正确
# 不使用else要先判断item才能达到上面的效果
for item in range(3):
pwd=int(input("请输入密码:"))
if(pwd==8888):
print('密码正确')
break
else:
print("密码不正确")
if(item==2):
print("对不起,三次密码均错误!")
请输入密码:3
密码不正确
请输入密码:3
密码不正确
请输入密码:3
密码不正确
对不起,三次密码均错误!
嵌套循环
# 99乘法表
for a in range(1,10):
for b in range(1,a+1):
print(b,'x',a,'=',b*a,end='\t')
print()
1 x 1 = 1
1 x 2 = 2 2 x 2 = 4
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6 = 36
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7 = 42 7 x 7 = 49
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8 = 48 7 x 8 = 56 8 x 8 = 64
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9 = 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81
列表(数组)
列表相当于其他语言的数组
列表的创建:
- [ ]
- 内置函数 list()
list1 = ['hello','o',98,98.3]
print(list1)
list2 = list(['hello',98])
print(list2)
['hello', 'o', 98, 98.3]
['hello', 98]
列表的特点
- 列表元素按顺序有序排列
- 索引映射唯一一个数据
- 正数表示正序,重0开始;负数表示倒叙,重-1开始
- 列表可以存储重复数据,也就是列表不去重
- 任意数据类型混存
- 根据需要动态分配和回收内存,也就是不需要担心元素太多,列表会存不下,会根据数据的多少,动态分配内存
list1=[1,'2',3.0,'four',1]
print(list1[2],list1[-2])
3.0 four
列表元素的查询操作
- index():获取列表指定元素的索引
- 如果列表中存在N个相同元素,值返回相同元素中的第一个元素的索引
- 如果查询的元素在列表中国呢不存在,则会抛出ValueError
- 还可以在指定的start和stop之间进行查找
- 获取列表中的单个元素
- 正向索引0到N-1
- 逆向索引-N到-1
- 指定索引不存在,抛出indexError
- 获取类别中的多个元素
- 语法格式:列表名[start:stop:step]
- 切片的结果:原列表片段的拷贝,一个新的类别对象
- 切片的范围:start-stop,不包含stop
- step步长:
- 默认为1,简写[start,stop]
- step为正数:从start开始往后计算切片
- step为负数:从start开始往前计算切片
- 判断指定元素在列表中是否存在:
- 元素 in 列表名
- 元素 not in 列表名
- 列表元素遍历
for 迭代变量 in 列表名:
操作
l = ['a',2,'c',4,'a',2]
# index
print(l.index(2,1,5))# 不包含5
s=[10,20,30,40,50,60,70,80]
'''
10,20,30,40,50,60,70,80
0 1 2 3 4 5 6 7 正
-8 -7 -6 -5 -4 -3 -2 -1 负
'''
s2=s[0:7]
print(s2)# 不包含最后一个
print(id(s),id(s2))# 不同的对象
print(s[::-1])# 逆排序
'''
取数的步骤:
1-根据正负号判断取数的方向
2-根据start判断从里面开始数
s[1: : 1]的含义:从20(start=1)开始取数,因为step为正数,所以从右边取,又因为stop没写,所以sotp=最后一个元素=80(向右数)
s[1: :-1]的含义:从20开始取,因为step为付数,所以从左边取,又因为stop没写,所以sotp=最后一个元素=10(向左数)
s[7:0:-1]的含义:从80开始取,因为step为付数,所以从左边取,又因为stop=10(不包含10)
s[1:7:-1]的含义:从20开始取,因为step为付数,所以从左边取,又因为stop=60(不包含60),从左边数,数到10,就为止了,数不到60,矛盾
'''
print('s[1: : 1]=',s[1::1])# [20, 30, 40, 50, 60, 70, 80] # 包含最后一个
print('s[1: :-1]=',s[1::-1])# [20, 10]
print('s[7:0:-1]=',s[7:0:-1])# [80, 70, 60, 50, 40, 30, 20, 10]
print('s[1:7:-1]=',s[1:7:-1])# []
1
[10, 20, 30, 40, 50, 60, 70]
4425176896 4530576512
[80, 70, 60, 50, 40, 30, 20, 10]
s[1: : 1]= [20, 30, 40, 50, 60, 70, 80]
s[1: :-1]= [20, 10]
s[7:0:-1]= [80, 70, 60, 50, 40, 30, 20]
s[1:7:-1]= []
列表元素的增加操作
- append():在列表的末尾添加一个元素,不会创建新对象
- extend():在列表的末尾至少添加一个元素
- insert():在列表的任意位置添加一个元素
- 切片: 在列表的任意位置至少添加一个元素
# append
l=[1,2,3]
print(l,id(l))
l.append(4)
print(l,id(l))
# extend
l2=['a','b']
l.append(l2)
print(l,id(l))
l.extend(l2)
print(l,id(l))
# insert
l.insert(1,'c')
print(l,id(l))
[1, 2, 3] 4530576512
[1, 2, 3, 4] 4530576512
[1, 2, 3, 4, ['a', 'b']] 4530576512
[1, 2, 3, 4, ['a', 'b'], 'a', 'b'] 4530576512
[1, 'c', 2, 3, 4, ['a', 'b'], 'a', 'b'] 4530576512
[1, 'a', 'b'] 4530576512
# 切片
l=[1,2,3]
print(l,id(l))
l2=['a','b']
'''
l[1:]=l2
相当于把l从index=1(包含)到位置处切掉:[1]
接着再拼接+['a','b']
'''
l[1:]=l2
print(l,id(l))
'''
l[1:1] 没有切蛋在index=1的位置处+[8,9]
'''
l[1:1]=[8,9]
print(l,id(l))
[1, 2, 3] 4424952768
[1, 'a', 'b'] 4424952768
[1, 8, 9, 'a', 'b'] 4424952768
列表元素的删除操作
- remove():
- 一次删除一个元素
- 重复元素只删除第一个
- 元素不存在抛出ValueError
- pop():
- 删除一个指定索引位置上的元素
- 指定索引不存在抛出IndexError
- 不指定索引,删除列表中最后一个元素
- 切片:一次至少删除一个元素,产生一个新的列表对象
- clear():清空列表
- del:删除列表
# remove
l=[1,1,2,3,4,5,5]
l.remove(1)
print(l)
# pop
l.pop()
print(l)
l.pop(2)
print(l)
[1, 2, 3, 4, 5, 5]
[1, 2, 3, 4, 5]
[1, 2, 4, 5]
# 切片:产生新的对象--元素的查找
l=[1,2,3,4,5]
l2=l[0:3]
print(l,id(l))
print(l2,id(l2))
# 切片:不产生新的对象--元素的切片增加
l[3:]=[]
print(l,id(l))
[1, 2, 3, 4, 5] 4530576256
[1, 2, 3] 4530510464
[1, 2, 3] 4530576256
# clear
l=[1,2,3,4,5]
l.clear()
print(l)
del l
# print(l) # 已经没有这个对象,再打印就报错了
[]
列表元素的修改操作
- 为指定索引的元素赋予新的值,变化的是地址值
- 为指定的切片赋予新的值
l = [1,2,3,4]
l[0]=10
print(l)
l[1:3]=[20,30] # 把1-3(不包括3)的位置的元素替换成[20,30]
print(l)
[10, 2, 3, 4]
[10, 20, 30, 4]
列表元素的排序操作
- sort( )
默认元素按照从小到大进行升序排列;指定reverse=true,进行降序排列 - sorted( )
为内置函数。默认升序;指定reverse=true,进行降序排列
与sort的区别:sorted会生成一个新的对象,原列表不发生任何改变
l=[3,4,2,1,6,5]
print(l,id(l))
l.sort()
print(l,id(l))
l.sort(reverse=True)
print(l,id(l))
[3, 4, 2, 1, 6, 5] 4539524736
[1, 2, 3, 4, 5, 6] 4539524736
[6, 5, 4, 3, 2, 1] 4539524736
l=[3,4,2,1,6,5]
print(l,id(l))
l2=sorted(l)
print(l2,id(l2))
l3=sorted(l,reverse=True)
print(l3,id(l3))
[3, 4, 2, 1, 6, 5] 4541143808
[1, 2, 3, 4, 5, 6] 4539489408
[6, 5, 4, 3, 2, 1] 4538265728
列表生成式
语法格式:
list=[f(i) for i in 可迭代对象 ]
i:属于自定义变量,来自于可迭代对象里面的元素
f(i): 列表元素表达式,生成list的每一个元素,不能是赋值操作
list:生成的新的列表
l1=[i for i in range(5)]
print(l1)
a=2
l2=[a*i for i in range(5)]
print(l2)
ls=[-1,-2,-3,-4,-5,-6]
#l2=[ls[i]=i for i in range(5)]# 不能是赋值操作
l2=[ls[i] for i in range(5)]
print(l2)
l3=[2 for i in range(5)]# 可以和i无关
print(l3)
l3=[-1*i for i in ls]# 不一定要是range
print(l3)
[0, 1, 2, 3, 4]
[0, 2, 4, 6, 8]
[-1, -2, -3, -4, -5]
[2, 2, 2, 2, 2]
[1, 2, 3, 4, 5, 6]
字典
什么是字典
- python内置的数据结构之一,与列表一样是一个可变序列
- 以键值对的方式存储数据,字典是一个无序的序列
- 与java中的map类似
字典的创建
- 使用花括号{ }
- 使用dist()
a={"张三":100,"wang":20}
print(a,type(a))
s=dict(name='jack',age=20)
print(s,type(s))
{'张三': 100, 'wang': 20} <class 'dict'>
{'name': 'jack', 'age': 20} <class 'dict'>
字典元素的获取
- [ ]: 如果没有对应的key会报错——keyError
- get()方法:没有key的时候不会报错,会返回None,也可以设置默认值
a={'a':1,'b':2}
print(a['a'])
#print(a['c'])#KeyError: 'c'
print(a.get('a'))
print(a.get('c'))
print(a.get('c',0))# 0 - 设置的默认值
1
1
None
0
字典元素的增删改
- key的判断
- in:存在为true
- not in: 不存在为true
- 删除 del 字典[key]
- 清空 clear
- 新增与修改 字典[key]=值
a={'a':1,'b':2,'c':3}
print('a'in a,'a' not in a)
del a['a']
print(a)
a.clear()
print(a)
a['d']=4
print(a)
a['d']=5
print(a)
True False
{'b': 2, 'c': 3}
{}
{'d': 4}
{'d': 5}
获取字典视图
- keys():获取字典的所有key
- values():获取字典的所有value
- items(): 获取字典的所有键值对
a={'a':1,'b':2,'c':3}
keys=a.keys()
print(type(keys),keys)
print(list(keys))# 可以通过list函数把dict_keys类型转换成列表
<class 'dict_keys'> dict_keys(['a', 'b', 'c'])
['a', 'b', 'c']
a={'a':1,'b':2,'c':3}
values=a.values()
print(type(values),values)
print(list(values))# 可以通过list函数把dict_values类型转换成列表
<class 'dict_values'> dict_values([1, 2, 3])
[1, 2, 3]
a={'a':1,'b':2,'c':3}
items=a.items()
print(type(items),items)
print(list(items))# 可以通过list函数把dict_values类型转换成列表 其中( ) 称为元组
<class 'dict_items'> dict_items([('a', 1), ('b', 2), ('c', 3)])
[('a', 1), ('b', 2), ('c', 3)]
字典元素的遍历
a={'a':1,'b':2,'c':3}
for item in a: # 获取的是字典元素的key
print(item,a[item],a.get(item))
a 1 1
b 2 2
c 3 3
字典元素的特点
- key不允许重复,value可以重复
- 字典只能够的元素是无序的
- 字典中的key必须是不可变对象
- 字典也可以根据需要动态地伸缩,不需要考虑存不了的情况
- 字典会浪费较大的内存,是一种用空间换时间的数据结构
字典生成式
- 内置函数zip():可以将迭代的对象打包成一个元组,然后返回由这些元组组成的列表
- 字典生成式:{ key:value for key, value in zip(迭代对象1,迭代对象2}
- key对应迭代对象1的元素;value对应迭代对象2的元素
items=['fruits','books','others']
price=[96,78,85]
lst1= zip(items,price)
lst2= zip(price,items)
print(lst1,type(lst1))# 返回的是一个迭代器对象,只能遍历一次
print(lst2,type(lst2))
print(list(lst1))
print(list(lst2))
print(list(lst1))# list 内部是有遍历的,上面用了一次,这次在用就为{}
<zip object at 0x10eb28dc0> <class 'zip'>
<zip object at 0x10e72ae40> <class 'zip'>
[('fruits', 96), ('books', 78), ('others', 85)]
[(96, 'fruits'), (78, 'books'), (85, 'others')]
[]
items=['fruits','books','others']
price=[96,78,85]
lst= zip(items,price)
dct={key:value+10 for key,value in lst}
print(dct)
{'fruits': 106, 'books': 88, 'others': 95}
元组
什么是元组
- python内置的数据结构之一,是一个不可变序列
- 不可变序列与可变序列
- 不可变序列:没有增删改操作,如字符串和元组
- 可变序列:对元素可以执行增删改操作,对象地址值不发生更改,如列表和字典
元组的创建
- 使用小括号 ()
- 使用内置函数tuple
- 小括号也可以省略
- 但如果元组中只有一个元素,小括号和逗号都不能省略
- 空元组:()和tuple()
t = (10,"tt")
print(t,type(t))
d = tuple((10,"tt"))
print(d,type(d))
t2 = "t2",12,32.3
print(t2,type(t2))
#t3 = tuple("t3",20) # 这个不行
#print(t3,type(t3))
t4 = ("t4")
print(t4,type(t4))# 被认为是字符串
t5 = ("t5",)
print(t5,type(t5))
t6=()
print(t6,type(t6))
t7=tuple()
print(t7,type(t7))
(10, 'tt') <class 'tuple'>
(10, 'tt') <class 'tuple'>
('t2', 12, 32.3) <class 'tuple'>
t4 <class 'str'>
('t5',) <class 'tuple'>
() <class 'tuple'>
() <class 'tuple'>
为什么要将元组设计成不可变序列
- 一旦创建不可变序列,数据就不可修改,避免因修改数据而造成错误
- 在多任务多的环境下,同时操作对象时就不需要加锁
元组中存储的是对象的引用
所以在元组中,不变的是对象的引用。但是我们可以改变改引用多指向的值。
t = (1,[2,3],4)
print(t,type(t[1]),id(t[1]))
#t(0) = 5# 会报错
t[1].append(5)
print(t,type(t[1]),id(t[1]))
t[1][0]=6
print(t,type(t[1]),id(t[1]))
(1, [2, 3], 4) <class 'list'> 4541580672
(1, [2, 3, 5], 4) <class 'list'> 4541580672
(1, [6, 3, 5], 4) <class 'list'> 4541580672
元组的遍历
t = (1,[2,3],4)
for item in t:
print(item,end="-->")
1-->[2, 3]-->4-->
集合
什么是集合
- 是python的内置数据结构
- 可变序列
- 集合是没有value的字典
- 特点:去重于无序
集合的创建方式
- {}
- set()
- 把序列range转为集合
- 把列表转为集合
- 把元组转为集合
- 把字符串序列转为集合
- 把集合转成新的集合
- 空集合:只能使用set(),使用{}得到的是一个字典
s = {1,1,2,3,4,5,5}# 不允许重复
print(s)
s2=set(range(6))
print(s2,type(s2))
l=[1,2,2,3,3]
s3=set(l)
print("l=",l)
print("s3=",s3)# 去重
t=(56,45,9,100)
print(t)
print(set(t))# 集合是无序的
print(set("python"))# 集合是无序的
print(set(set("python")))
{1, 2, 3, 4, 5}
{0, 1, 2, 3, 4, 5} <class 'set'>
l= [1, 2, 2, 3, 3]
s3= {1, 2, 3}
(56, 45, 9, 100)
{56, 9, 100, 45}
{'t', 'n', 'h', 'p', 'o', 'y'}
{'t', 'n', 'h', 'p', 'o', 'y'}
s={}
print(s,type(s))
s2 = set()
print(s2,type(s2))
{} <class 'dict'>
set() <class 'set'>
集合的相关操作
判断操作:in或not in
新增操作
- add:一次添加一个元素
- update:至少添加一个元素
修改操作
- remove:一次删一个指定元素,如果指定元素不存在,抛keyerro
- discard:一次删一个指定元素,如果指定元素不存在,不抛异常
- pop:一次删除任意一个元素,无参
- clear:清空集合
s = {"1",1,3,4}
print(s)
s.add("t")
print(s)
s.update({5,6})# 集合
s.update([7,8])# 列表
s.update((9,10))# 元组
print(s)
s.remove(1)
s.discard(1)
print(s)
s.pop()
print(s)
s.clear()
print(s)
{'1', 3, 4, 1}
{'1', 1, 3, 4, 't'}
{'1', 1, 3, 4, 5, 6, 7, 8, 9, 10, 't'}
{'1', 3, 4, 5, 6, 7, 8, 9, 10, 't'}
{3, 4, 5, 6, 7, 8, 9, 10, 't'}
set()
集合间的关系
- 两个集合是否相等:==/!=(判断元素是否相等)
- 一个集合是否是另一个集合的子集:issubset
- A.issubset(B):A是B的子集么?A包含于B么?
- 一个集合是否是另外一个集合的超集:issuperset
- A.issuperset(B):A是B的超集么?A包含B么?
- 两个集合是否有交集:isdisjoint- 是否没有交集
s1={1,2,3}
s2={1,2,3,4}
s3={4,5,6}
print(s1==s2)
print(s1!=s2)
print(s1.issubset(s2))
print(s2.issuperset(s1))
print(s2.isdisjoint(s1))# false - 有交集
print(s2.isdisjoint(s3))# false - 有交集
False
True
True
True
False
False
集合的数据操作
- 交集操作:intersection和&
- 并集操作:union和|
- 差集操作:difference和-
- 对称差集操作:symmetry_difference和^
s1 = {1,2,3}
s2 = {2,3,4}
si1=s1.intersection(s2)
si2=s1&s2
print("交集:",si1,si2)
su1=s1.union(s2)
su2=s1|s2
print("并集",su1,su2)
sd1=s1.difference(s2)
sd2=s1-s2
print("s1-s2的差集:",sd1,sd2)
ssd1=s1.symmetric_difference(s2)
ssd2=s1^s2
print("s1和s2的对称差集:",ssd1,ssd2)
交集: {2, 3} {2, 3}
并集 {1, 2, 3, 4} {1, 2, 3, 4}
s1-s2的差集: {1} {1}
s1和s2的对称差集: {1, 4} {1, 4}
集合生成式
# 列表生成式
ls=[i*i for i in range(10)]
print(ls)
# 集合生成式
st={i*i for i in range(10)}
print(st)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
{0, 1, 64, 4, 36, 9, 16, 49, 81, 25}
列表、字典、元组、结合总结
数据结构 | 是否可变 | 是否重复 | 是否有序 | 定义符号 |
---|---|---|---|---|
列表list | 可变 | 可重复 | 有序 | [ ] |
字典dist | 可变 | key不可重复 value可重复 |
无序 | {key:value} |
元组tuple | 不可变 | 可重复 | 有序 | ( ) |
集合set | 可变 | 不可重复 | 无序 | { } |
字符串
字符串的驻留机制
- 字符串是python的基本数据类型,是一个不可变的字符序列
- 什么叫字符串驻留机制
仅保存一份相同且不可变字符串的方法,不同的值被存放在字符串的驻留池中,python的驻留机制对相同的字符串只保留一份拷贝,后续创建相同的字符串时,不会开辟新的内存空间,而是把该字符串的地址赋给新创建的变量 - 驻留机制的几种情况
- 字符串的长度为1或0时
- 字符串符合标识符的规则:数字、字母、下划线
- 字符串只在编译时驻留,而非运行时
- [-5,256]之间的整数数字
- sys中的intern方法强制2个字符串指向同一个对象
- PyCharm对字符串进行了优化处理
- 字符串驻留机制的优缺点
- 当需要值相同的字符串时,可以之间从字符串池中拿来使用,避免频繁的创建和销毁,提升效率和节约内存,因此拼接字符串和修改字符串时会比较影响性能。
- 在需要进行字符串拼接时建议使用str类型的join方法,而非+,首先字符串为不可变序列,每一个新的字符串都会生成一个新的对象。
a+b+c:a+b生成一个对象,接着+c又生成一个对象
而””.join(a,b,c)会计算出所有字符的长度,然后在拷贝,只new一次对象,效率比+要高
a = 'abc'
b = "abc"
c = '''abc'''
print(id(a))
print(id(b))
print(id(c))
4384582768
4384582768
4384582768
# 字符串的长度为1或0时
a=''
b=''
print(a is b)
c='w'
d='w'
print(c is d)
True
True
# 字符串符合标识符的规则
a='1_a'
b='1_a'
print(a is b)
c='1_a%'
d='1_a%'
print(c is d)
True
False
# 字符串只在编译时驻留,而非运行时
a = 'abc'
b = 'a'+'bc'
c = 'a'
d =c.join('bc')
print(a,id(a))
print(b,id(b))
print(c,id(c))# id不同
print(d,id(d))# id不同
abc 4384582768
abc 4384582768
a 4384821936
bac 4538639984
import sys
a = 'abc%'
b = 'abc%'
print(a is b)
c = sys.intern(a)# 把a的地址给c
print(a is c)
False
True
字符串的常用操作
查询操作
- index:找到字串中第一次出现的位置,从前面开始找,找不到valueError,返回int
- rindex:找到字串中最后一次出现的位置,从后面开始找,找不到valueError,返回int
- find:找到字串中第一次出现的位置,从前面开始找,找不到不报错,返回int,找不到返回-1
- rfind:找到字串中最后一次出现的位置,从后面开始找,找不到不报错,返回int,找不到返回-1
'''
p y t h o n , p y t h o n
0 1 2 3 4 5 6 7 8 9 10 11 12
'''
str='python,python'
a=str.index("on")
print(a,type(a))
b=str.rindex("on")
print(b,type(b))
#a=str.index("onn")#ValueError: substring not found
#a=str.rindex("onn")#ValueError: substring not found
c=str.find("on")
print(c,type(c))
d=str.find("onn")
print(d,type(d))
e=str.rfind("on")
print(e,type(e))
e=str.rfind("onn")
print(e,type(e))
4 <class 'int'>
11 <class 'int'>
4 <class 'int'>
-1 <class 'int'>
11 <class 'int'>
-1 <class 'int'>
字符串的大小写转换操作
- upper:把字符串中所有字符转成大写
- lower:把字符串中所有字符转成小写
- swapcase:大写转小写,小写转大写
- capitalize:第一个字符串大写,后面小写
- title:每个单词的首字母大写,其余的字符串为小写
str = 'heLLo,woRLD'
a=str.upper()
print(a,type(a))
b=str.lower()
print(b,type(b))
c=str.swapcase()
print(c,type(c))
d=str.capitalize()
print(d,type(d))
e=str.title()
print(e,type(e))
HELLO,WORLD <class 'str'>
hello,world <class 'str'>
HEllO,WOrld <class 'str'>
Hello,world <class 'str'>
Hello,World <class 'str'>
字符串内容对齐操作
- center:
- 居中对齐
- 第1个参数:指定宽度
- 第2个参数:指定填充,可选,默认为空格
- 如果设置宽度小于实际宽度,返回原字符串
- ljust:
- 左对齐
- 第1个参数:指定宽度
- 第2个参数:指定填充,可选,默认为空格
- 如果设置宽度小于实际宽度,返回原字符串
- rjust:
- 右对齐
- 第1个参数:指定宽度
- 第2个参数:指定填充,可选,默认为空格
- 如果设置宽度小于实际宽度,返回原字符串
- zfill:
- 右对齐
- 左边用0填充
- 只接受一个参数,用于指定字符串的宽度
- 如果设置宽度小于实际宽度,返回原字符串
str='hello'
a=str.center(10)
print(a,type(a))
a=str.center(10,'*')
print(a,type(a))
b=str.ljust(10,'*')
print(b,type(b))
c=str.rjust(10,'*')
print(c,type(c))
d=str.zfill(10)
print(d,type(d))
hello <class 'str'>
**hello*** <class 'str'>
hello***** <class 'str'>
*****hello <class 'str'>
00000hello <class 'str'>
字符串劈分操作
- split:
- 从字符串的左边开始劈分,默认的劈分字符是空字符串,返回的值都是一个列表
- 以通过参数sep指定劈分字符串的劈分符
- maxsplit指定字符串时的最大劈分次数,在经过最大劈分之后,剩余的字串会单独作为一部分
- rsplit:
- 从字符串的右边开始劈分,默认的劈分字符串是空哥字符串,返回的值都是一个列表
- 以通过参数sep指定劈分字符串的劈分符
- maxsplit指定字符串时的最大劈分次数,在经过最大劈分之后,剩余的字串会单独作为一部分
str='h-e-l-l-o'
ls=str.split("-")#默认sep
print(ls,type(ls))
ls=str.split(sep="-")
print(ls,type(ls))
ls=str.split("-",maxsplit=3)# 切3次
print(ls,type(ls))
['h', 'e', 'l', 'l', 'o'] <class 'list'>
['h', 'e', 'l', 'l', 'o'] <class 'list'>
['h', 'e', 'l', 'l-o'] <class 'list'>
判断字符串操作的方法
- isidentifier:判断是不是合法标识符
- 标识符有字母、数字、下划线组成。
- 所有标识符可以包括英文、数字以及下划线(_),但不能以数字开头。
- 以下划线开头的标识符是有特殊意义的。以单下划线开头(_foo)的代表不能直接访问的类属性,需通 过类提供的接口进行访问,不能用”from xxx import *”而导入;
- 以双下划线开头的(__foo)代表类的私有成员;以双下划线开头和结尾的(__foo__)代表python里 特殊方法专用的标识,如__init__()代表类的构造函数。
- isspace:判断字符串是否全部由空白字符组成:回车、换行、水平制表符,有就为False,没有就为True
- isalpha:判断字符串是否全部由字母字串
- isdecimal:判断指定字符串是否全部由十进制的数字组成
- isnumeric:判断指定的字符串是否全部由数字组成
- isalnum:判断指定字符串是否由字母和数字组成
print("1_x","1_x".isidentifier())
print("张三","张三".isidentifier())# 汉字也可以为标识符
print("a%","a%".isidentifier())
print("\t","\t".isspace())# True
print("a\t","a\t".isspace())# False,不是全部由空字符串组成
print("aSDb","aSDb".isalpha())
print("aSDb!","aSDb!".isalpha())
print("100","100".isdecimal())
print("001","001".isdecimal())# 001-也是true
print("00四","00四".isdecimal())# False
print("00四","00四".isnumeric())# True
print("ab12","ab12".isalnum())# True
print("ab12章","ab12章".isalnum())# True
print("ab12!","ab12!".isalnum())# False
1_x False
张三 True
a% False
True
a False
aSDb True
aSDb! False
100 True
001 True
00四 False
00四 True
ab12 True
ab12章 True
ab12! False
字符串的操作的其他方法
- replace:
- 第1个参数:被替换的字串
- 第2个参数:指定替换字串的字符串
- 第3个参数:最大替换次数
- 返回:替换后得到的字符串
- join:将列表或元组的字符串合并成一个字符串
str="helloll"
s=str.replace("l","z")
print(s)
s=str.replace("l","z",3)
print(s)
ls=['1','sd','cd']
s=''.join(ls)
print(s)
s='-'.join(ls)# 链接
print(s)
# 必须要全为字符串,否则会报错
#tp=("a",2,"c")#TypeError: sequence item 1: expected str instance, int found
tp=("a","2","c")
t='-'.join(tp)
print(t)
hezzozz
hezzozl
1sdcd
1-sd-cd
a-2-c
字符串的比较操作
- 运算符:>,>=,<,<=,==,!=
- 比较规则:一个一个字符串进行比较
- 比较原理:比较的oridnal value(原始值),即Unicode值,其中Unicode的前128位数ASCII码
- 调用内置函数ord可以得到指定字符的ordinal value
- 调用内置函数chr时指定ordinal value 可以得到其对应的字符
print("apple">"app")
print("apple"<="app")
print("apple"!="app")
# 获取原始值
print(ord("a"),ord('b'))
print(ord("章"),ord('张'))
# == 比较的是value;is比较的是id
a=b='app'
c='app'
print(a==c,a is c)# True True 都相等时因为字符串的驻留机制
True
False
True
97 98
31456 24352
True True
字符串的切片操作
- s[:5]:从头开始到5结束,不包含5
- s[6:]:从6开始到尾结束,包含6
- s[:5:-1]:负数的开头是最右边,从最右边开始,到index=5的地方结束,不包含5
- s[6::-1]:负数的结束是最左边,从index=6的地方开始(包含6)直到结束
- s[:-5:-1]:负数的开头是最右边,从最右边开始,到index=-5的地方结束,不包含5
- s[-6::-1]:负数的结束是最左边,从index=-6的地方开始(包含6)直到结束
# -9 -8 -7 -6 -5 -4 -3 -2 -1
#. 零 一 二 三 四 五 六 七 八
str='零一二三四五六七八'
a=str[:5]
b=str[6:]
print(a)
print(b)
print('------------------')
c=str[:5:-1]
d=str[6::-1]
print(c)
print(d)
print('------------------')
e=str[:-5:-1]
f=str[-6::-1]
print(e)
print(f)
零一二三四
六七八
------------------
八七六
六五四三二一零
------------------
八七六五
三二一零
格式化字符串
- %作占位符:
- %s:字符串
- %i或%d:整数
- %f:浮点数
- 参数值是依次对应的
- {}作占位符:
- {num}:num是第几个参数,从0开始
- {pramName}+f:pramName:变量参数名,f是固定格式
- 宽度和精确度
- %
- %10d:表示宽度是10
- %.3f:表示精度是小数点后3位
- %10.3f:表示宽度为10,精度是小数点后3位
- {}
- {0:.3}:表示一共是3位数,四舍五入
- {0:.3f}:表示保留小数点3,四舍五入
- {0:10.3f}:宽度为10,保留小数点3,四舍五入
- %
str1="我叫%s,今年%d岁,高考考了%f分"
# 这里的 % 是固定符号
print(str1%("张三",20,675.5))
str2="我叫{1},今年{0}岁,高考考了{2}分"
print(str2.format(20,'张三',675.5))
# f-固定格式
str3=f"我叫{name},今年{age}岁,高考考了{score}分"
name='张三'
age=20
score=675.5
print(str3.format(age,name,score))
我叫张三,今年20岁,高考考了675.500000分
我叫张三,今年20岁,高考考了675.5分
我叫张三,今年20岁,高考考了675.5分
print('----------')
print('%10d'%10)
print('%10s'%"ni")
print('%10.3f'%675.55555)#会四舍五入
print('%10.3d'%10)#不够补0
print('%10.3s'%"ni")#精度不起作用
----------
10
ni
675.556
010
ni
print('----------')
print('{0:.3}'.format(7.4566))
#ValueError: Precision not allowed in integer format specifier
#print('{0:.3}'.format(7585))整数不能用.3的格式
#print('{0:.3}'.format(56))
print('{0:.3}'.format(7451.4566))#7.45e+03=7450:整数位数>=3会用科学记数法
print('{:.3f}'.format(7.4566))#一个参数,0可以省略
print('{:10.3f}'.format(7.4566))
----------
7.46
7.45e+03
7.457
7.457
字符串的编码转换
- 为什么需要字符串的编码转换:计算机之间是通过byte字节传输
- 编码与解码:
- 编码:字符串转换为二进制数据(bytes)—— encode
- 解码:将bytes类型的数据转换为字符串类型 —— decode
s="天涯共此时"
# 用GBK编码
a=s.encode(encoding='GBK')
print(a,type(a))
b=a.decode(encoding='GBK')
print(b,type(b))
#使用不同的格式去解码会报错
#c=a.decode(encoding='UTF-8')#UnicodeDecodeError
b'\xcc\xec\xd1\xc4\xb9\xb2\xb4\xcb\xca\xb1' <class 'bytes'>
天涯共此时 <class 'str'>
函数
函数的创建:
def 函数名(参数):
函数体
「return xxx」
def sub(a,b):
c=a-b;
return c
res=sub(10,1)
print(res)
9
函数的参数传递
- 位置实参:根据参数的位置进行实参传递
- 关键字实参:根据形参名称进行实参传递
def sub(a,b):
c=a-b;
return c
res=sub(b=10,a=1)
print(res)
-9
函数调用的参数传递内存分析:传递的是地址值
def fun(arg1,arg2):
print('----------------------------------')
print('arg1=',arg1,'id(arg1)=',id(arg1));
print('arg2=',arg2,'id(arg2)=',id(arg2));
arg1=100;
arg2.append(100)
print('arg1=',arg1,'id(arg1)=',id(arg1));
print('arg2=',arg2,'id(arg2)=',id(arg2));
print('----------------------------------')
a=10
b=[10,20]
print('a=',a,'id(a)=',id(a));
print('b=',b,'id(b)=',id(b));
fun(a,b)
print('a=',a,'id(a)=',id(a));
print('b=',b,'id(b)=',id(b));
a= 10 id(a)= 4382432272
b= [10, 20] id(b)= 4546440192
----------------------------------
arg1= 10 id(arg1)= 4382432272
arg2= [10, 20] id(arg2)= 4546440192
arg1= 100 id(arg1)= 4382435152
arg2= [10, 20, 100] id(arg2)= 4546440192
----------------------------------
a= 10 id(a)= 4382432272
b= [10, 20, 100] id(b)= 4546440192
fun之前:
a的地址值:2272->10;
b的地址值:0192->[10, 20];
调用fun,传入的是地址值
arg1=a->2272
arg2=b->0192
arg1=100:
100在是一个新的内存空间,arg1这个变量等于是换了一个地址:5152
arg2.append(100):
这个操作操作的仍是0192这个内存空间的数据
调用之后:
a= 10:因为fuc这个函数没有对2272这个内存空间的数据进行任何操作,所以不变
b= [10, 20, 100]:因为arg2.append(100)对0192这个内存的数据进行了操作,所以变了
函数的返回值
- 如果函数没有返回值,retrun可以省略不写
- 可以直接使用return结束方法
- 返回一个参数时,返回的是该返回值类型
- 返回多个值时,结构为元组
# 原例子中这里写的是num,我一开始以为是填一个数,但往后看代码才发现应该填一个list
# 这反映了弱类型语言的劣势,如果参数名字不见名知意,我就不知道要传什么类型的参数
def fun(numList):
odd=[]#存奇数
even=[]#存偶数
for i in numList:
if i%2:#i%2==0 0和True可以相互转换,C的特点
even.append(i)
else:
odd.append(i)
return odd,even
num=[10,23,24,4,12,33,3]
res=fun(num)
print(res,type(res))
([10, 24, 4, 12], [23, 33, 3]) <class 'tuple'>
函数的参数定义
- 默认值参数:print的end的参数的默认值为:\t
- 个数可变的位置参数:
- 定义函数时,可能无法事先确定传递的位置参数的个数,这时可以使用可变的位置参数
- 使用*定义个数可变的位置参数
- 结果为一个元组
- 只能有一个可变位置参数
- 个数可变的关键字形参
- 定义函数时,无法事先确定传递的关键字实参的个数,这时可以使用可变的关键字形参
- 使用**丁个数可变的关键字形参
- 结果为一个字典
- 只能有一个可变关键字参数
- 实参与形参
- 在函数定义时,定义的是形参
- 在函数调用时,传入的是实参
- 函数调用时使用*:把序列中的每一个元素转换为位置实参
- 函数调用时使用**:把字典中的每一个键值对转换为关键字实参
- def fun(a,b,,c,d):表示之后的参数只能采用关键字传参
# 默认值设置
def fun(a,b=0):
print(a,b)
fun(10)
fun(11,12)
10 0
11 12
#个数可变的位置参数
#def fun(*args,*a):过不了编译
def fun(*args):
print(args,type(args))
fun(10)
fun(10,'ab',12)
print('---------------------')
# 可变位置参数+另一个形参时,需要使用关键字传参,否则会报错
# TypeError: fun() missing 1 required keyword-only argument: 'a'
def fun1(*args,a):
print(args,type(args),'a=',a)
fun1(10,a=0)
fun1(10,'ab',12,a=0)
(10,) <class 'tuple'>
(10, 'ab', 12) <class 'tuple'>
---------------------
(10,) <class 'tuple'> a= 0
(10, 'ab', 12) <class 'tuple'> a= 0
# 个数可变的关键字形参
#def fun(**args,**a):过不了编译
def fun(**args):
print(args,type(args))
# 必须使用关键字穿参,否则报错
# TypeError: fun() takes 0 positional arguments but 3 were given
# fun(10,20,30)
fun(a=10,b=20,c=30)
# 不能这么定义:def fun2(**args,a),否则会报语法错误
def fun2(a,**args):
print(args,type(args),'a=',a)
#fun2(d=10,b=20,c=30)必须传入a,否则会报错:
#TypeError: fun2() missing 1 required positional argument: 'a'
fun2(a=10,b=20,c=30)
{'a': 10, 'b': 20, 'c': 30} <class 'dict'>
{'b': 20, 'c': 30} <class 'dict'> a= 10
# 可变位置参数+可变关键字参数
#def fun(**args,*arg):没有这种形式
def fun(*args1,**args2):
print(args1,type(args1))
print(args2,type(args2))
print('------------------------')
fun()
fun(10,11)
fun(a=10,b=11)
# fun(10,a=20,30,b=40)SyntaxError: positional argument follows keyword argument
fun(10,20,a=30,b=40)
# 如果位置参数和关键字参数都要传,位置参数必须在前面
# fun(a=1,b=2,"s","b")SyntaxError: positional argument follows keyword argument
fun("s","b",a=1,b=2)
() <class 'tuple'>
{} <class 'dict'>
------------------------
(10, 11) <class 'tuple'>
{} <class 'dict'>
------------------------
() <class 'tuple'>
{'a': 10, 'b': 11} <class 'dict'>
------------------------
(10, 20) <class 'tuple'>
{'a': 30, 'b': 40} <class 'dict'>
------------------------
('s', 'b') <class 'tuple'>
{'a': 1, 'b': 2} <class 'dict'>
------------------------
# 多个位置实参
def fun(a,b,c):
print(a,b,c)
fun(1,2,3)
ls=[1,2,3]
fun(*ls)
print('---------')
def fun2(*arg):
print(arg)
fun2(ls)#([1, 2, 3],) 把ls作为一个参数
fun2(*ls)
'''
少了会报错:TypeError: fun() missing 1 required positional argument: 'c'
ls2=[1,2]
fun(*ls2)
'''
print('---------')
1 2 3
1 2 3
---------
([1, 2, 3],)
(1, 2, 3)
---------
# 多个关键字传参
def fun(a,b,c):
print(a,b,c)
print('---------')
fun(a=1,b=2,c=3)
dis={"a":1,'b':2,'c':3}
fun(**dis)
1 2 3
---------
1 2 3
---------
# 指定关键字传参
def fun(a,b,*,c,d):
print(a,b,c,d)
#fun(10,20,30,40)#TypeError: fun() takes 2 positional arguments but 4 were given
fun(10,20,c='a',d='c')
10 20 a c
变量的作用域
- 局部变量:函数内定义的
- 全局变量:
- 函数外定义的
- global修饰的
a=1;
def fun (param):
b=10
global d
d=20
c=param+a# 全局变量可以在函数内使用
return c
#TypeError: unsupported operand type(s) for +: 'int' and 'list'
'''b是局部变量,不能在函数外用'''
#res=fun(5)+b
res=fun(5)+d# d是全局变量,可以拿出来用
print(res)
26
递归函数
- 什么是递归:函数自己调自己
- 递归的组成部分:递归的调用与递归的终止条件
- 递归的调用过程:
- 每递归调用一次函数,都会在栈内存分配一个栈帧
- 每执行完一次函数,都会释放相应的空间
- 递归的优缺点:
- 缺点:占用内存多,效率低下
- 优点:思路和代码简单
# 阶乘
def fun(n):
if(n==1):
return 1
return fun(n-1)*n
print(fun(5))
120
# 斐波那契数列
# 1,1,2,3,5,8...
# a1=1;a2=1 f(n)=f(n-1)+f(n-2)
def fun(n):
if(n==1 or n==2):
return 1
return fun(n-1)+fun(n-2)
print(fun(6))
8
异常
异常的处理机制
- try-except
- try-except-except-…-except
- 捕获顺序:先子类后父类(由小到大)
- BaseException 数最大的异常
- try-except-else
- 没遇到异常就执行else
- try-except-else-finally
- finally:无论是否遇到异常都会执行
python常见的异常类型
- ZeroDivisionError:除(或取模)零
- IndexError:序列中没有此索引
- KeyError:映射中没有这个键
- NameError:未声明/初始化对象(没有属性)
- SyntaxError:语法错误
- ValueError:传入无效参数
traceback模块
使用traceback模块打印异常信息
# try-except
try:
n1=int(input("请输入第一个数:"))
n2=int(input("请输入第二个数:"))
res=n1/n2
print('结果为:{0:0.2}'.format(res))
except ZeroDivisionError:
print("除数不能为0")
print("程序结束")
请输入第一个数:1
请输入第二个数:0
除数不能为0
程序结束
# try-except-except-...-except
try:
n1=int(input("请输入第一个数:"))
n2=int(input("请输入第二个数:"))
res=n1/n2
print('结果为:{0:0.2}'.format(res))
except ZeroDivisionError:
print("除数不能为0")
except ValueError:
print("您输入的不是数字")
except BaseException as e:# BaseException
print(e)
print("程序结束")
请输入第一个数:-
您输入的不是数字
程序结束
# try-except-else
try:
n1=int(input("请输入第一个数:"))
n2=int(input("请输入第二个数:"))
res=n1/n2
except ZeroDivisionError:
print("除数不能为0")
except ValueError:
print("您输入的不是数字")
except BaseException as e:# BaseException
print(e)
else:
print('结果为:{0:0.2}'.format(res))
print("程序结束")
请输入第一个数:1
请输入第二个数:2
结果为:0.5
程序结束
# try-except-else-finally
try:
n1=int(input("请输入第一个数:"))
n2=int(input("请输入第二个数:"))
res=n1/n2
except ZeroDivisionError:
print("除数不能为0")
except ValueError:
print("您输入的不是数字")
except BaseException as e:# BaseException
print(e)
else:
print('结果为:{0:0.2}'.format(res))
finally:
print("程序结束")
请输入第一个数:-
您输入的不是数字
程序结束
import traceback
try:
print('-----1-------')
num=1/0
except: # 不写,发生异常就直接走这段代码
traceback.print_exc()
-----1-------
Traceback (most recent call last):
File "/var/folders/06/0p7d3_4x4xsgmjl7lb00hvg80000gn/T/ipykernel_3338/1999639933.py", line 4, in <module>
num=1/0
ZeroDivisionError: division by zero
对象
两大编程思想
- 面向过程
- 面向对象
类和对象的创建
数据类型与对象:
不同的数据类型属于不同的类。如100、99、520都是int类的不同实例,即对象
像int、list、dict等都是类,其具体的value就是一个个实例
类的创建
- 创建语法:
class Student:
属性/方法等 - 类的组成:
- 类属性
- 实例方法
- 静态方法:@staticmethod
- 类方法:@classmethod
- 初始化方法:_ init _
对象的创建
- 对象的创建又称类的实例化
- 语法:实例名=类名()
# 创建类
class Student:
pass
'''
当我们定义Student类的时候,也会在内存中开辟空间,Student是一个类对象
'''
print(id(Student))
print(type(Student))
print(Student)
140205459718400
<class 'type'>
<class '__main__.Student'>
'''-------------------------------------类的定义-----------------------------------------'''
class Student:
#类属性
native_place='深圳'# 类里面定义的变量称为类属性
#初始化方法:用于初始化对象,类似java的构造器
def __init__(self,name,age):
'''
self.name称为实例属性,进行了一个赋值操作,将局部变量的name的值赋给实体属性
这里也可以是self.a=name,但是这样就不见名知意了
'''
self.name=name
self.age=age
# 实例方法,定义在类之后的称为函数
def eat(self):#只是习惯用self,写a也可以
print('学生吃饭')
#静态方法
@staticmethod
def smethod():
print("----静态方法-----")
#类方法
@classmethod
def claMethod(cls):#同self
print('----类方法-------')
'''----------------------------------------对象的创建和使用-----------------------------'''
# 创建对象
print('----------实例对象------------')
jack=Student('jack',20)
print(jack)
print(id(jack))# 地址值:十进制-4547494336 十六进制-0x10f0d41c0
print(type(jack))
print('----------类对象------------')
print(Student)
print(id(Student))
print(type(Student))
print('----------访问实例属性------------')
print(jack.name)#对象名.实例属性名
print(jack.age)
print('----------调用实例方法------------')
jack.eat()# 对象名.方法名
Student.eat(jack)# 类名.方法名(类的实例)-->实际上就是方法定义处的self
----------实例对象------------
<__main__.Student object at 0x10ee4f730>
4544853808
<class '__main__.Student'>
----------类对象------------
<class '__main__.Student'>
140205437441424
<class 'type'>
----------访问实例属性------------
jack
20
----------调用实例方法------------
学生吃饭
学生吃饭
类对象和类属性
类属性-类方法-静态方法的使用
- 类属性的访问:实例对象公用一个类属性
- 实例对象名.类属性名
- 类名.实类属性名
- 类方法:类名.类方法名
- 静态方法:类名.静态方法
class Student:
#类属性
native_place='深圳'# 类里面定义的变量称为类属性
#初始化方法:用于初始化对象,类似java的构造器
def __init__(self,name,age):
'''
self.name称为实例属性,进行了一个赋值操作,将局部变量的name的值赋给实体属性
这里也可以是self.a=name,但是这样就不见名知意了
'''
self.name=name
self.age=age
# 实例方法,定义在类之后的称为函数
def eat(self):#只是习惯用self,写a也可以
print('学生吃饭')
#静态方法
@staticmethod
def smethod():
print("----静态方法-----")
#类方法
@classmethod
def claMethod(cls):#同self
print('----类方法-------')
'''-------------------------------类对象-类属性-静态方法-----------------------------'''
print('--------类属性的使用---------')
print(Student.native_place)
stu1=Student('张三',20)
stu2=Student('李四',23)
print(stu1.native_place)
print(stu2.native_place)
Student.native_place='广州'
print(stu1.native_place)
print(stu2.native_place)
'''
stu1和sut2共用native_place这个类属性
但是stu1.native_place='南昌'这个操作,相当于往stu1这个实例对象里面动态绑定了一个native_place的实例属性
于是stu1.native_place优先会访问实例对象的native_place属性
'''
stu1.native_place='南昌'
print(stu1.native_place)# 只改了stu1的值
print(stu2.native_place)
Student.native_place='北京'
print(stu1.native_place)# stu1回不去了
print(stu2.native_place)
print('--------类方法的使用---------')
Student.claMethod()#类方法有默认参数
print('--------静态方法的使用---------')
Student.smethod()#静态方法没有默认参数
--------类属性的使用---------
深圳
深圳
深圳
广州
广州
南昌
广州
南昌
北京
--------类方法的使用---------
----类方法-------
--------静态方法的使用---------
----静态方法-----
类属性的内存分析
动态绑定属性和方法
动态绑定属性和方法的内存分析图
# 绑定动态
stu1=Student('李四',30)
stu2=Student('张三',20)
#绑定属性
stu1.gender='女'
print(stu1.name,stu1.age,stu1.gender)
#stu2没有gender属性,访问了会报错
#AttributeError: 'Student' object has no attribute 'gender'
#print(stu2.name,stu2.age,stu2.gender)
def show():
print('-----show-----')
#绑定方法
stu1.show=show
stu1.show()
#stu2没有show方法,调用会报错
#AttributeError: 'Student' object has no attribute 'show'
#stu2.show()
李四 30 女
-----show-----
对象的三大特性之封装
- 设置私有属性:属性两边使用‘__‘
- 但私有属性还是可以访问的,python的封装完全是靠程序员的自觉
class Student:
def __init__(self,name,age):
self.name=name
self.__age=age#age不希望在类的外部被使用,所以加了两个_
def show(self):
print(self.name,self.__age)
stu=Student('jerry',20)
stu.show()
print(stu.name)
#直接访问__age会报错
#AttributeError: 'Student' object has no attribute '__age'
#print(stu.__age)
print('stu的属性和方法有:',dir(stu))
# stu里面有'name', 'show'还有一个'_Student__age',通过这个可以去访问
print(stu._Student__age)
jerry 20
jerry
stu的属性和方法有: ['_Student__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'show']
20
对象的三大特性之继承
- class 子类(要继承的父类):
- 如果一个类没有继承任何类,则默认继承object,即所有类都继承了object
- python支持多继承:class 子类(父类1,父类2)
- 定义子类时,必须在其构造函数中调用父类的构造函数
- 子类可以使用父类的属性和方法
方法重写
- 如果子类对继承自父类的某个属性或方法不满意,可以在其子类中对其(方法体)进行重新编写
- 子类重写后的方法中可以通过super().xxx()调用父类中的方法
class Person(object):#不写object也可以
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print(self.name,self.age)
def eat(self):
print('----eat-----')
class Student(Person):
def __init__(self,name,age,stu_no):
# 这个super()应该类似于java的super,返回的是父类的实例对象
super().__init__(name,age)
self.stu_no=stu_no
#重写父类方法
def info(self):
#再使用父类的info方法
super().info()
print(self.stu_no)
class Teacher(Person):
def __init__(self,name,age,teach_year):
# 这个super()应该类似于java的super,返回的是父类的实例对象
super().__init__(name,age)
self.teach_year=teach_year
#重写父类方法
def info(self):
#再使用父类的info方法
super().info()
print(self.teach_year)
#这样就是多继承
class A (Student,Teacher):
pass
stu=Student('张三',20,'1001')
tec=Teacher('李四',34,10)
stu.info()#调用重写的方法
tec.info()#调用重写的方法
stu.eat()#可以使用父类的方法
tec.eat()#可以使用父类的方法
张三 20
1001
李四 34
10
----eat-----
----eat-----
object类
- object类是所有类的父类,因此所有类都有object的属性和方法
- 内置函数dir()可以查看知道对象所有属性
- Object有一个__str__()方法,用于返回“对象的描述”(类似java的toString)
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return '我的名字是{0},今年{1}岁'.format(self.name,self.age)
stu=Student('jerry',20)
'''
没有重写object的__str__方法前:
print(stu)输出的是:<__main__.Student object at 0x10a88af40>
重写object的__str__方法后:
print(stu)输出的是:我的名字是jerry,今年20岁
'''
print(stu)
'''
print(stu)方法内部调用了stu的__str__()方法
'''
st=stu.__str__()
print(st,type(st))
我的名字是jerry,今年20岁
我的名字是jerry,今年20岁 <class 'str'>
对象的三大特性之多态
- 在java中的多态是这样的:父类的引用指向子类的对象
如:Person person = new Student(),如果我们调用person.eat(),实际上调用的是Student(子类)的方法 - 在Python中的多态是这样体现的:只要有同名方法就可以调用,而不需要关注对象
class Animal(object):
def eat(self):
print("Animal:eat")
class Dog(Animal):
def eat(self):
print("Dog:eat")
class Cat(Animal):
def eat(self):
print("Cat:eat")
class Person(object):
def eat(self):
print("Person:eat")
def fun(obj):
obj.eat()
fun(Cat())
fun(Dog())
'''
没有任何继承关系的也可以调用,只要方法名字相同就好
这个与其弱类型语言的特征有关
个人觉得好用,但是危险。你永远无法知道你队友的水平是怎样的
'''
fun(Person())
Cat:eat
Dog:eat
Person:eat
特殊方法和特殊属性
- 特殊属性:
__dict_ _
:获得类对象或者实例对象所绑定的所有属性和方法的字典__class__
:对象的类型- 其他:
__bases__
,__base__
,__mro__
- 特殊方法
__len__( )
:通过重写__len__( )
方法,让内置函数len()的参数可以是自定义的类型__add__( )
:通过重写__add__( )
方法,可以使自定义的对象具有‘+’功能__new__( )
:用于创建对象__init__( )
:对创建的对象进行实例化
class A:
pass
class B:
pass
class C(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
def eat():
print('C:eat')
class D(A):
pass
c=C('jack',20)
print(c.__dict__)#实例对象的属性字典
print(C.__dict__)#类对象的属性和方法的字典
print(c.__class__)#输出对象的类型
print(C.__class__)#输出对象的类型
print(C.__bases__)#输出父类类型的元组:C-AB,实例对象不能调用
print(C.__base__)#输出离得最近的父类类型,如果class C(B,A)就会输出B的类型 实例对象不能调用
print(C.__mro__)#类的层次结构 实例对象不能调用
print(A.__subclasses__())# 子类的列表
{'name': 'jack', 'age': 20}
{'__module__': '__main__', '__init__': <function C.__init__ at 0x10a908e50>, 'eat': <function C.eat at 0x10a806670>, '__doc__': None}
<class '__main__.C'>
<class 'type'>
(<class '__main__.A'>, <class '__main__.B'>)
<class '__main__.A'>
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
[<class '__main__.C'>, <class '__main__.D'>]
a=20
b=100
c=a+b
print(c)
'''
两个整数通过‘+’符号进行相加,底层调用的是__add__方法
'''
d=a.__add__(b)
print(d)
class Student:
def __init__(self,name):
self.name=name
'''
重写__add__方法后,Student类也可以通过‘+’调用add方法进行相加
'''
def __add__(self,other):
return self.name+other.name
def __len__(self):
return len(self.name)
stu1=Student('张三')
stu2=Student('李四')
print(stu1+stu2)
'''---------------------------------------------------------------------------------'''
lst=[1,2,3,4]
# len是内置函数,可以计算list的长度
print(len(lst))
'''
len()实际上调用的是__len__()方法
对于任意一个对象我们都可以重写__len__()方法来实现自定义的长度的计算
'''
print(lst.__len__())
print('stu1的长度=',len(stu1))
120
120
张三李四
4
4
stu1的长度= 2
'''
init-new顺序:先通过new方法创建对象(1568),再通过init方法对对象(1568)进行赋值
object对象(9520)--->类对象Person(3712)
--->new传入的cls(3712)-->调用父类的new方法得到的obj对象(1568)
--->init的self(1568)
--->最后的实例对象(1568)
p1=Person('张三',20):把Person(3712)传给了__new__的cls
obj=super().__new__(cls):把Person传给了object的__new__方法,创建对象obj(1568)
return obj:返回给__init__的self(1568)
self初始化完成之后又给了p1(1568)
'''
class Person(object):
def __init__(self,name,age):
print('__init__被调用了,self的id值为{0}'.format(id(self)))
self.name=name
self.age=age
def __new__(cls,*args,**kwargs):
print('__new__被调用执行了,cls的id值为{0}'.format(id(cls)))
obj=super().__new__(cls)
print('创建的对象的id为:{0}'.format(id(obj)))
return obj
print('object这个类对象的id为:{0}'.format(id(object)))
print('Person这个类对象的id为:{0}'.format(id(Person)))
p1=Person('张三',20)
print('p1这个Person类的实例对象的id:{0}'.format(id(p1)))
object这个类对象的id为:4411189520
Person这个类对象的id为:140462607923712
__new__被调用执行了,cls的id值为140462607923712
创建的对象的id为:4469041568
__init__被调用了,self的id值为4469041568
p1这个Person类的实例对象的id:4469041568
类的浅拷贝与深拷贝
- 变量的赋值操作:只是形成两个变量,实际上还是指向同一个对象
- 浅拷贝:
python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象 - 深拷贝:
使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同
class CPU:
pass
class Disk:
pass
class Computer:
def __init__(self,cpu,disk):
self.cpu=cpu
self.disk=disk
print('''-----------------赋值操作------------------------''')
cpu1=CPU()
cpu2=cpu1
print(cpu1)#0x10a941700 同一个内存地址
print(cpu2)#0x10a941700 同一个内存地址
print('''-----------------浅拷贝操作------------------------''')
import copy
disk=Disk()
computer=Computer(cpu1,disk)
'''
computer1和computer2是两个不同的对象,有不同的地址值
但里面的子对象是相同的有相同的地址值
'''
computer2=copy.copy(computer)
print(computer,computer.cpu,computer.disk)
print(computer2,computer2.cpu,computer2.disk)
print('''-----------------深拷贝操作------------------------''')
'''
深拷贝的子对象的地址都不相同,深拷贝会再产生内存空间来存储子对象
'''
computer3=copy.deepcopy(computer)
print(computer,computer.cpu,computer.disk)
print(computer3,computer3.cpu,computer3.disk)
-----------------赋值操作------------------------
<__main__.CPU object at 0x10a941700>
<__main__.CPU object at 0x10a941700>
-----------------浅拷贝操作------------------------
<__main__.Computer object at 0x10a888430> <__main__.CPU object at 0x10a941700> <__main__.Disk object at 0x10a941c70>
<__main__.Computer object at 0x10a941b20> <__main__.CPU object at 0x10a941700> <__main__.Disk object at 0x10a941c70>
-----------------深拷贝操作------------------------
<__main__.Computer object at 0x10a888430> <__main__.CPU object at 0x10a941700> <__main__.Disk object at 0x10a941c70>
<__main__.Computer object at 0x10a941dc0> <__main__.CPU object at 0x10a8b1910> <__main__.Disk object at 0x10a8b1640>
模块
什么叫模块
- 一个.py的文件就是一个模块
- 一个模块包含函数、类、语句
自定义模块
- 创建模块:新建一个.py文件,名称尽量不用与Python自带的标准模块名称相同
- 导入模块
- import 模块名称 as 别名
- from 模块名称 import 函数/变量/类
- 导入的模块也是一个对象,有内存地址,类型(module)等
- 再pycharm中导入自定义的模块报错:右键对应的包—>Mark Directory as—>Sources Root
以主程序的形式执行
if__name__
=='__main__'
:
代码B
意思是:在一个模块中我定义了代码A,同时又定义了代码B,如果另一个文件导入这个模块,A代码和B代码会同时执行。但是如果加上上诉代码,只有当改模块称为主程序的时候才会执行代码B,导入该模块的文件只会执行A代码。python中的包
- 包是一个分层次的目录结构,它将一组功能相近的模块组织在一个目录下
- 包的作用
- 代码规范
- 避免模块名称冲突
- 包的导入:
- import 包名.模块名 as 别名
- from 包名 import 模块名
- from 包名.模块名 import 函数/变量/类
- 目录与包
- 包在pycharm中是Python Package,会有一个init的py文件
- 目录是Directory,没有init文件
常用模块:
- sys:与Python解释器及其环境操作相关的标准库
- time:提高与时间相关的各种函数的标准库
- os:提供访问操作系统服务功能的标准库
- calendar:提供与日期相关的各种函数的标准库
- urllib:用于读取来自网上(服务器)的数据标准库
- json:用于石油Json序列化和反序列化对象
- re:用于在字符串中执行正则表达式匹配和替换
- math:提供标准算术运算函数的标准库
- decimal:用于进行精确控制运算精度、有效位数和四舍五入的十进制运算
- logging:提供了灵活的记录事件、错误、警告和调试信息等日子信息等功能
第三方模块的安装及使用
- 第三方模块的安装:pip install 模块名
- 第三方模块的使用:import 模块名
import math
print(id(math))
print(type(math))
print(math)
4415612624
<class 'module'>
<module 'math' from '/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/lib-dynload/math.cpython-38-darwin.so'>
文件
编码格式
- python的解释器使用的是Unicode(内存)
- .py文件在磁盘上使用UTF-8存储(外存)
- 常见编码格式:
文件的读写原理
- 文件的读写俗称IO操作
- 文件的读写流程
Python操作文件->打开或者新建文件->读写文件->关闭资源 - 操作原理:解释器运行.py文件,调用操作系统,操作硬盘上的文件
文件读写操作
- 文件类型:
- 文本文件:存储的是普通‘字符’文本,默认为unicode字符集,可以使用记事本程序打开
- 二进制文件:把数据内容用‘字节’进行存储,如图片,视频,音频和doc等文件
- 内置函数open创建或者打开文件:file=open(filename,[mode,encoding])
- file:被创建的文件对象
- open:创建文件对象的函数
- 要创建或打开的文件名称
- 打开模式,默认只读
- 默认文本文件中字符的编写格式文gbk
- 常用的文件打开模式
- r:只读模式,文件指针放在文件的开头
- w:只写模式,如果文件不存在则创建,如果文件存在则覆盖原有内容,文件指针在文件开头
- a:追加模式,如果文件不存在则创建,文件指针在文件开头,如果文件存在则在文件末尾追加内容,文件指针在文件末尾
- b:二进制模式,不能单独使用,要和其他模式一起使用,如:rb或者wb
- +:以读写方式打开文件,不能单独使用,需要与其他模式一起使用,a+
# 文件写入
file=open('a.txt','w')
file.write('Python')
file.close()
# 文件读取
file=open('a.txt','r')
s=file.readlines()# 读全部
print(s,type(s))
file.close()
file2=open('a.txt','r')
s2=file2.readline()# 读一行
print(s2,type(s2))
file2.close()
['Python\n', 'JavaPythonPythonPythonPython'] <class 'list'>
Python
<class 'str'>
# 追加模式
file=open('a.txt','a')
file.write('Python')
file.write('Python')
file.close()
# rb+wb 实现图片的复制
src_file=open('./PythonBase/1-类属性.png','rb')
target_file=open('1.png','wb')
target_file.write(src_file.read())
src_file.close()
target_file.close()
# + 以读写方式打开
'''
如果没有+,那么执行print(file.readlines())的时候会报错
UnsupportedOperation: not readable
'''
file=open('a.txt','a+')
'''
需注意的是你若刚用‘a+’打开一个文件,一般不能直接读取,
因为此时光标已经是文件末尾,除非你把光标移动到初始位置或任意非末尾的位置。
'''
print(file.readlines())
file.write('Python')
file.close()
[]
光标操作
- seek函数:需要使用文件对象进行调用,无返回值。
seek(offset,whence)- offset 控制光标移动的位移量(字节)
- whence 模式
- 0 基于文件开头移动多少字节
- 1 基于光标当前所在位置移动多少字节
- 2 基于文件末尾移动多少字节
- ps:1和2只能在二进制模式下使用 0无所谓
- tell函数:用来获取光标当前的位置(移动的字节数)
- 代码表示:文件名.tell( )
- 返回光标当前所在的字节数
file=open('a.txt','a+')
file.write('Python')
file.seek(0,0)# 把光标置于开头
print(file.readlines())
s=file.tell()
print(s,type(s))
file.close()
['Python\n', 'JavaPythonPython']
23 <class 'int'>
文件对象常用的方法
with语句:上下文管理器
- 语法:
with open(文件名,模式) as src_file:
操作src_file - 作用:不用手动关闭流
- 什么是上下文管理器:实现了
__enter__()
方法和__exit__()
方法 - open(文件名,模式):其为上下文表达式,结果为上下文管理器,
- 上下文管理器同时创建一个运行时上下文,自动调用
__enter__()
方法,并将返回值赋值给src_file - 离开运行时上下文,自动调用上下文管理器的特殊方法
__exit__()
# 上下文管理器
'''
MyContentMgr实现了特殊方法__enter__和__exit__,称该类对象遵循了上下文管理器协议
该类对象的实例对象称为上下文管理器
'''
class MyContentMgr(object):
def __enter__(self):
print('enter方法被调用执行了')
return self
def __exit__(self,exc_type,exc_val,exc_tb):
print('exit方法被执行了')
def show(self):
print('show方法被调用执行了')
def showError(self):
print('showError方法被调用执行了',1/0)
with MyContentMgr() as file: # 相当于file=MyContentMgr()
file.show()
print('走出with-----')
with MyContentMgr() as file: # 相当于file=MyContentMgr()
file.showError()
enter方法被调用执行了
show方法被调用执行了
exit方法被执行了
走出with-----
enter方法被调用执行了
exit方法被执行了
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In [93], line 20
18 print('走出with-----')
19 with MyContentMgr() as file: # 相当于file=MyContentMgr()
---> 20 file.showError()
Cell In [93], line 15, in MyContentMgr.showError(self)
14 def showError(self):
---> 15 print('showError方法被调用执行了',1/0)
ZeroDivisionError: division by zero
# rb+wb 实现图片的复制
with open('./PythonBase/1-类属性.png','rb') as src_file:
with open('2.png','wb') as target_file:
target_file.write(src_file.read())
目录操作
- os模块是Python内置的与操作系统功能和文件系统相关的模块,该模块中的语句的执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一样
- os模块与os.path模块用于对目录或文件进行操作
- os模块操作目录相关的函数
- getcwd( ):返回当前的工作目录
- listdir(path):返回指定路径下的文件和目录信息
- mkdir(path,[,mode]:创建目录
- makedirs(path1/path2…[,mode]):创建多级目录
- rmdir(path):删除目录
- removedirs(path1/path2…):删除多级目录
- chdir(path):将path设置为当前工作目录
- os.path模块操作目录相关的函数
- abspath(path):用于获取文件或目录的绝对路径
- exists(path):用于判断文件或目录是否存在,如果存在返回True,否则返回False
- join(path,name):将目录与目录或文件名拼接起来
- split(path):将文件路径和文件名分离
- splitext():分离文件名和拓展名
- basename(path):从一个目录中提取文件名
- dirname(path):从一个路径中提取文件路径,不包括文件名
- isdir(path):判断是否为路径
- os.walk(path):获取path下所有文件和目录
import os
# os.system('应用名.exe')可以打开系统自动的软件
# mac的电脑还不知道怎么打开
#os.system('Stickies.app')
# 调用可执行文件:os.startfile(文件路径)mac电脑还不知到怎么弄
#os.startfile('/Applications/WeChat.app/Contents/MacOS/WeChat')
s=os.getcwd()
print(s)
print(os.listdir(s))
os.mkdir('newdir2')
os.makedirs('a/b/c')
os.rmdir('newdir2')
os.removedirs('a/b/c')
os.chdir('/Users/xieshaolin/workpalce/python/quant/newdir')
print(os.getcwd())
os.chdir('/Users/xieshaolin/workpalce/python/quant')
print(os.getcwd())
/Users/xieshaolin/workpalce/python/quant
['.DS_Store', 'python基础语法.ipynb', 'newdir', 'PythonBase', 'a.txt', 'numpy.ipynb', '.ipynb_checkpoints', 'python基础语法.md', '2.png', '1.png']
/Users/xieshaolin/workpalce/python/quant/newdir
/Users/xieshaolin/workpalce/python/quant
import os.path as op
print(op.abspath('a.txt'))
print(op.abspath('./PythonBase/1-类属性.png'))#可以用相对路径
print(op.exists('a.txt'),op.exists('b.txt'))
print(op.join('/Users','a.txt'))#不会校验,只是单纯拼接
print(op.split('/a/b/c'))# 不会区分,只是把最后一层分出来
print(op.splitext('/a/b/c.txt'))#不校验
print(op.basename('/a/b/c'))#不校验,只是提取最后一个
print(op.dirname('/a/b/c'))#不校验,提取前面的
# 会校验是不是真的目录
print(op.isdir('/a/b/c'),op.isdir('/a/b/c.txt'),
op.isdir('/Users/xieshaolin/workpalce/python/quant/a.txt'),
op.isdir('/Users/xieshaolin/workpalce/python/quant'))# ../a.txt是文件不是目录
/Users/xieshaolin/workpalce/python/quant/a.txt
/Users/xieshaolin/workpalce/python/quant/PythonBase/1-类属性.png
True False
/Users/a.txt
('/a/b', 'c')
('/a/b/c', '.txt')
c
/a/b
False False False True
# 列出指定目录下的所有文件
import os
path=os.getcwd()
pathlist=os.listdir(path)
for item in pathlist:
print(os.path.abspath(item))
/Users/xieshaolin/workpalce/python/quant/.DS_Store
/Users/xieshaolin/workpalce/python/quant/python基础语法.ipynb
/Users/xieshaolin/workpalce/python/quant/newdir
/Users/xieshaolin/workpalce/python/quant/PythonBase
/Users/xieshaolin/workpalce/python/quant/a.txt
/Users/xieshaolin/workpalce/python/quant/numpy.ipynb
/Users/xieshaolin/workpalce/python/quant/.ipynb_checkpoints
/Users/xieshaolin/workpalce/python/quant/python基础语法.md
/Users/xieshaolin/workpalce/python/quant/2.png
/Users/xieshaolin/workpalce/python/quant/1.png
import os
path=os.getcwd()
listFile=os.walk(path)
print(listFile,type(listFile))
print('------------------------------------')
for item in listFile:
print(item,type(item))# item 是一个元组
print('------------------------------------')
<generator object walk at 0x10b3ec9e0> <class 'generator'>
------------------------------------
('/Users/xieshaolin/workpalce/python/quant', ['newdir', 'PythonBase', '.ipynb_checkpoints'], ['.DS_Store', 'python基础语法.ipynb', 'a.txt', 'numpy.ipynb', 'python基础语法.md', '2.png', '1.png']) <class 'tuple'>
------------------------------------
('/Users/xieshaolin/workpalce/python/quant/newdir', [], []) <class 'tuple'>
------------------------------------
('/Users/xieshaolin/workpalce/python/quant/PythonBase', [], ['.DS_Store', '3-编码格式.jpeg', '2-动态绑定.png', '1-类属性.png']) <class 'tuple'>
------------------------------------
('/Users/xieshaolin/workpalce/python/quant/.ipynb_checkpoints', [], ['numpy-checkpoint.ipynb', 'python基础语法-checkpoint.ipynb']) <class 'tuple'>
------------------------------------
# 元组还可以这么遍历
ls=[(1,2,3),(4,5,6),(7,8,9)]
for a,b,c in ls:
print(a,b,c)
1 2 3
4 5 6
7 8 9
import os
path=os.getcwd()
listFile=os.walk(path)
'''
第一个:dirpath-当前路径
第二个:dirname-当前路径下的文件夹
第三个:filename-当前路径下的文件名
'''
for dirpath,dirname,filename in listFile:
for item in filename:
#print(os.path.abspath(item))这样不行,得出的结果是当前路径+文件名
print(os.path.join(dirpath,item))
print('--------------------------------------------------')
/Users/xieshaolin/workpalce/python/quant/.DS_Store
/Users/xieshaolin/workpalce/python/quant/python基础语法.ipynb
/Users/xieshaolin/workpalce/python/quant/a.txt
/Users/xieshaolin/workpalce/python/quant/numpy.ipynb
/Users/xieshaolin/workpalce/python/quant/python基础语法.md
/Users/xieshaolin/workpalce/python/quant/2.png
/Users/xieshaolin/workpalce/python/quant/1.png
--------------------------------------------------
--------------------------------------------------
/Users/xieshaolin/workpalce/python/quant/PythonBase/.DS_Store
/Users/xieshaolin/workpalce/python/quant/PythonBase/3-编码格式.jpeg
/Users/xieshaolin/workpalce/python/quant/PythonBase/2-动态绑定.png
/Users/xieshaolin/workpalce/python/quant/PythonBase/1-类属性.png
--------------------------------------------------
/Users/xieshaolin/workpalce/python/quant/.ipynb_checkpoints/numpy-checkpoint.ipynb
/Users/xieshaolin/workpalce/python/quant/.ipynb_checkpoints/python基础语法-checkpoint.ipynb
--------------------------------------------------
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1909773034@qq.com