全部是一个一个字手敲的,有理论有实例代码,整理出来希望可以给大家帮助
目录
1.变量以及数据类型
注释:快捷键 Ctrl+/
1、单行注释 #
2、多行注释 ''' '''
格式化快捷键:Ctrl+Alt+L
删除一行:Ctrl+Y
变量:‘容器’
格式:变量名=值
1.1 怎么起名?
驼峰式命名:开头第一个单词全部小写——小驼峰(更推荐下划线)
大驼峰:python面向对象:类名 每个单词的首字母大写
变量名的命名规范:
1)字母、数字、下划线
2)不能数字开头
3)不能使用关键字
4)严格区分大小写
1.2 有哪些数据类型?
int、float、
string(单引号、双引号、三引号-保留格式)
boolean(True、False)
通过type(变量名)输出变量类型
money = 28.9
print(type(money))
1.3 输入、输出语句
输入:input()——输入的值一律为string类型
输出:print()
(1)%c 整数转成对应的 ASCII 字元;
(2)%d 整数转成十进位;digit
(3)%f 倍精确度数字转成浮点数;float
(4)%s 整数转成字符串;string
(5)%o 整数转成八进位;
(6)%x 整数转成小写十六进位;
(7)%X 整数转成大写十六进位。
name = '蔡徐坤'
age = 26
print('我喜欢听' + str(age) + '岁的' + name + '唱歌')
print('我喜欢听%d岁的%s唱歌' % (age, name))
money = 999.99
print('%d岁的%s一首歌挣了%.1f块钱' % (age, name, money))
print('%s岁的%s一首歌挣了%s块钱' % (age, name, money))
输出结果:
我喜欢听26岁的蔡徐坤唱歌
我喜欢听26岁的蔡徐坤唱歌
26岁的蔡徐坤一首歌挣了1000.0块钱
26岁的蔡徐坤一首歌挣了999.99块钱
format
1、参数字段名
print('我爱吃{}'.format('香蕉'))
大括号个数多于位置参数的个数则会报错
2、数字字段名
数字必须是大于等于0的整数
带数字的替换字段可以重复使用
大括号内的数字不能越界
print('我爱吃{0},我也爱喝{1}'.format('香蕉','可乐'))
3、变量字段名
使用变量名形式的简单字段名传递关键字参数
print('我大哥是{name},今年{age}岁'.format(name='阿飞',age=20))
1.4 类型转换
name = input("输入你的名字:")
print(name)
money = input('请输入缴费金额:')
print(money)
print(type(money))
输出结果:
请输入缴费金额:1234
1234
<class 'str'>
money = input('请输入缴费金额:')
print(money)
print(type(money))
print(int(money)+1000)
print(money+str(1000))
输出结果:
请输入缴费金额:1234
1234
<class 'str'>
2234
12341000
将例子 中的money变为int类型:int(money),就可以做数值运算;
但是,如果money是小数,就不能转为int类型,需要转换为float类型;
将1000变为字符串类型,就可以做字符串的拼接
flag = True
print(int(flag))
print(float(flag))
print(str(flag))
输出结果:
1
1.0
True
布尔类型的转换:当变量是0、空字符串‘ ’、“ ”、None、()、{ }、【 】的时候,转化为布尔类型就是False,其余情况有值都是True
2.运算符
2.1 算数运算符
+ 加法
- 减法
* 乘法
/ 除法
% 取余
// 整除
m**n m的n次方
print(2 - 1)
print(2 * 3)
print(2 ** 3) # 2的3次方
print(3 / 2) # 除法
print(3 // 2) # 整除
print(3 % 2) # 取模,取余
输出结果:
1
6
8
1.5
1
1
键盘输入一个三位数的整数,打印个位数,十位数,百位数
# 键盘输入一个3位数的整数,打印个位数,十位数,百位数
number = int(input('请输入一个三位数:'))
print('个位数:', number % 10)
print('十位数:', number // 10 % 10)
print('百位数:', number // 100)
输出结果:
请输入一个三位数:345
个位数: 5
十位数: 4
百位数: 3
2.2 赋值运算符
= 、+=、-=、*=、/=、//=、**=、%=
a = 8
b = 4
c = 3
a += 1 # a=a+1
print(a) # a=9
b += a # b=b+a
print(a, b) # a=4,b=13
b -= 2 # b=b-2
print(b) # b=11
b //= c # b=b//c
print(b) # b=3
2.3 关系运算符
结果:True False
> < >= <= == != is
字符串用ASCII码,从第一位依次按照位数比较
a = 10
b = 23
print(a > b) # 结果返回False
print(a < b) # 结果返回True
print(a == b) # 结果返回False
print(a != b) # 结果返回True
x = 'abf'
y = 'abc'
print(x == y) # 结果返回False
print(x > y) # 结果返回True
输入考试成绩,判断成绩是否在100~80之间?
score = float(input('请输入分数:'))
print(80<=score<=100)
2.4 逻辑运算符
and or not
and: 与 并且,and的两边有一边为假结果就是假,只有两边都是真结果才是真
or : 或 或者,只要有一边为真,结果就为真
not: 非,把真变成假,把假变成真
a = 1
b = 3
c = 0
print(a and b) # 结果为3,即b的值 and两边都是非0数字,结果是最后的数字值
print(c and a) # 结果为0
print(b or c) # 结果为3,b的值,因为先判断b为真后就不在判断后面了(短路)
print(c or b) # 结果为3,b的值,因为后判断b为真
flag = True
print(not flag) # False
print(not a > b) # True
2.5 进制转换
n = 149
result = bin(n) # binary二进制
print(result)
result = oct(n) # 转换为8进制
print(result)
result = hex(n) # 转换为16进制
print(result)
前缀:0b二进制、0o八进制、0x十六进制、默认十进制
1.n=0x558,十进制输出?
2.已知n=0x558,转换为二进制?转成八进制?
n = 0x558
result = bin(n) # binary二进制
print(result)
result = oct(n) # 转换为8进制
print(result)
result = hex(n) # 转换为16进制
print(result)
2.6 位运算符
基于二进制的运算
与运算符(&):按位与运算符将两个数字进行按位与操作,只有当两个相应的二进制位都为1时,结果才为1。否则,结果为0。在Python中,按位与运算符使用符号"&"表示。
a = 60 # 60的二进制表示为 0011 1100
b = 13 # 13的二进制表示为 0000 1101
result = a & b # 12的二进制表示为 0000 1100
print(result) # 输出:12
或运算符(|):按位或运算符将两个数字进行按位或操作,只要两个相应的二进制位中有一个为1,结果就为1。在Python中,按位或运算符使用符号 "|" 表示。
a = 60 # 60的二进制表示为 0011 1100
b = 13 # 13的二进制表示为 0000 1101
result = a | b # 61的二进制表示为 0011 1101
print(result) # 输出:61
异或运算符(^):按位异或运算符将两个数字进行按位异或操作,当两个相应的二进制位有一个为1且另一个为0时,结果为1。在Python中,按位异或运算符使用符号 "^" 表示。
a = 60 # 60的二进制表示为 0011 1100
b = 13 # 13的二进制表示为 0000 1101
result = a ^ b # 49的二进制表示为 0011 0001
print(result) # 输出:49
非运算符(~):按位非运算符将数字进行按位非操作,即将每个二进制位取反。在Python中,按位非运算符使用符号 "~" 表示。
a = 60 # 60的二进制表示为 0011 1100
result = ~a # -61的二进制表示为 1100 0011
print(result) # 输出:-61
位移运算符:位移运算符是一种对二进制位进行移动的运算符,包括左移和右移。左移运算符将数字的二进制位向左移动指定的位数,右移运算符将数字的二进制位向右移动指定的位数。在Python中,左移运算符使用符号“<<”表示,右移运算符使用符号“>>”表示。
a = 60 # 60的二进制表示为 0011 1100
result = a << 2 # 240的二进制表示为 1111 0000
print(result) # 输出:240
result = a >> 2 # 15的二进制表示为 0000 1111
print(result) # 输出:15
2.7 运算符优先级
顺序是由高到低依次是:算术运算符、移位运算符、位运算符优先级、关系运算符、逻辑运算符、赋值运算符
1、算术运算符(+ - * / % // **)中的优先级顺序和数学运算里一样,先乘除后加减。
2、位运算符(&、|、^、~、<<、>>)优先级低于算术运算符,其中移位运算符优先级又高于按位运算符。
3、关系运算符(> < >= <= == != is)优先级低于位运算符和算术运算符。
4、逻辑运算符(and or not)优先级又低于关系运算符,其中的优先级从高到低是not、and、or。
5、赋值运算符(=)优先级最低。
7、可以通过小括号来改变运算的优先级顺序。
3. 流程控制语句
3.1 if条件语句
猜数游戏
import random
ran = random.randint(1, 10)
print(ran)
guess = int(input('请输入你猜的数:'))
if ran == guess:
print('恭喜你!猜对了')
else:
print('很遗憾,你猜错了')
print('答案是:%d' % ran)
输入销售金额,判断符合那种奖励范围
1-5:1000元
5-10:奖励笔记本
10-20:奖励iPhone
鼓励奖
money = int(input('请输入你的销售金额:'))
if 1 <= money < 5:
print('1000元')
elif 5 <= money < 10:
print('奖励笔记本')
elif 10 <= money < 20:
print('奖励iPhone')
else:
print('鼓励奖')
3.2 while循环结构
打印1~10之间的所有数字
# 初始值
n = 1
# 结束条件
while n <= 10:
print('n = %d' % n)
# 变量要有变化
n += 1
印1~50之间能被3整除的数字
初始值
n = 1
# 结束条件
while n <= 50:
# 变量要有变化
if n % 3 == 0:
print(n)
n += 1
n = 3
n = 3
while n < 50:
print(n)
n += 3
打印1~10之间数字的累加之和
n = 1
sum = 0
while n <= 10:
sum = sum + n
n = n + 1
print(sum)
多次猜数游戏
import random
ran = random.randint(1, 10)
while True:
guess = int(input('请输出猜的数:'))
if guess < ran:
print('您猜的数小了')
elif guess > ran:
print('您猜的数大了')
elif guess == ran:
print('恭喜你猜对了')
break
import random
ran = random.randint(1, 10)
n = 0
while True:
guess = int(input('请输出猜的数:'))
n = n + 1
if guess < ran:
print('您猜的数小了')
elif guess > ran:
print('您猜的数大了')
elif guess == ran:
if n == 1:
print('恭喜你一次就猜对了,猜数大师')
elif 1 < n <= 5:
print('猜对了,猜数能手')
elif 5 < n:
print('猜对了,运气不太好,猜数菜鸟')
print('您一共猜了%d次,游戏结束' % n)
break
3.3 for循环
格式1:
for i in range(n):
循环体中的内容
range(n):默认从0开始取值到n-1结束
range(start,stop):[start,stop) 包前不包后
range(start,stop,step):从start(包含)开始取值到stop(不包含)结束,其中步长由step指定,默认step是1
打印数字1~10
for i in range(1,11):
print(i)
求1~50的累加和
sum = 0
for i in range(51):
sum += i
print(sum)
输入用户名和密码,如果三次没有登录成功,提示账号被锁定
for i in range(1, 4):
# 提示输入用户名和密码
username = input('请输入用户名:')
password = input('请输入密码:')
# 判断输入的用户名和密码是否正确 admin 1234
if username == 'admin' and password == '1234':
print('登录成功')
break
else:
m = 3-i
print('登录失败,您还有%d次机会'%m)
i += 1
if m == 0:
print('你已经登录失败三次,账号被锁定')
格式2:
for i in range(n):
循环体
else:
如果上面的for循环0~n-1没有出现中断(break),就执行else
格式3:
while ....else
for .... else
注意else的特点:循环体完全执行完才会执行,中间break就不执行else
for i in range(1, 4):
# 提示输入用户名和密码
username = input('请输入用户名:')
password = input('请输入密码:')
# 判断输入的用户名和密码是否正确 admin 1234
if username == 'admin' and password == '1234':
print('登录成功')
break
print('登录失败')
else:
print('你已经登录失败三次,账号被锁定')
for与while的区别:
for :肯定是有固定循环次数
while :1、有固定的循环次数 2、不确定次数的循环
掷骰子:两个骰子1-6 1、玩游戏要有金币,没有金币不能玩游戏 2、玩游戏赠金币一枚,充值获取金币 3、充值金额需要是整数,充值得双倍金币数 4、玩游戏消耗5个金币 5、猜大小:猜对(两个点数相加超出6点以上,认为是大,否则是小) 鼓励金币2枚 猜错没有奖励 6、游戏结束:主动退出或者没有金币 7、只要退出则打印金币数以及共玩了几局
import random
import time
money = 0
coin = 0
i = 0
print('*'*30)
print('欢迎来到白马会所赌场(掷骰子)')
if coin < 5:
print('您的剩余金币数为%d,很可惜不能再玩了'%coin)
select = input('是否充值,请填写是或否:')
if select == '是':
money+=int(input('请输入充值的金额数(必须是整数)可以获得双倍金币:'))
coin += money*2
else:
print('游戏结束,欢迎下次再来')
while coin >= 5:
play = input('要来一局游戏吗,填是或否:')
if play == '是':
i += 1
coin -= 4
print('***掷骰子中***')
time.sleep(3)
a = random.randint(1,6)
b = random.randint(1,6)
guess = input('掷骰子完毕,请猜大或小:')
if a+b>6 and guess == '大' or a+b<6 and guess == '小':
print('恭喜你猜对了,奖励金币2枚')
coin += 2
else:
print('很遗憾猜错了')
if coin < 5:
print('您的剩余金币数为%d,很可惜不能再玩了' % coin)
select = input('是否充值,请填写是或否:')
if select == '是':
money += int(input('请输入充值的金额数(必须是整数)可以获得双倍金币:'))
coin += money * 2
else:
print('游戏结束,欢迎下次再来')
break
else:
print('你还剩余%d金币数,一共玩%d局'%(coin,i))
break
else:
print('你还剩余%d金币数,一共玩%d局'%(coin,i))
3.4 跳出语句
break:直接结束循环
continue: 跳过本次循环,后面的语句不执行,继续下一次循环
打印三角形
*
**
***
****
*****
n = 1
while n <= 5:
m = 0
while m < n:
print('*', end='')
m += 1
n += 1
print()
4.字符串列表元组字典集合
4.1 字符串基础
4.1.1字符串的输入输出
详情见1.3输入、输出语句
4.1.2字符串的下标和切片
字符串的索引机制:
1、0~len(s)-1
2、-len(s)~-1
3、两套规则可以互相交叉用
s1 = 'abcdef'
print(s1[4]) #取出来e
print(s1[-1]) #取出来f
切片:字符串、列表
格式:字符串变量[start:end]
s1 = 'abcdef'
print(s1[1:4]) # 打印bcd
print(s1[0:4]) # 打印abcd
print(s1[:4]) # 打印abcd
print(s1[3:]) # 打印def
print(s1[-4:-2]) # 打印cd
step:
1、步长
2、获取元素的方向,正数表示从左往右,负数表示从右往左
注意:取元素的时候先看方向,在确定起始值
s1 = 'abcdef'
print(s1[:-1:2]) # 打印ace
print(s1[1::2]) # 打印bdf
print(s1[::4]) # 打印ae
print(s1[::-1]) # 打印fedcba
print(s1[::-2]) # 打印fdb
4.1.3字符串的常见操作
获取长度:len
查找内容:find,index,rfind,rindex
find:从左往后查找,rfind(从右往左找)只要遇到一个符合要求的则返回位置。如果没有找到任何符合要求的,则返回-1
index:与find类似,不同的是,如果没有找到任何符合要求的,则报错
判断:startswith,endswith,isalpha,isdigit,isalnum,isspace
返回值都是布尔类型:True False
startswith:判断是否以XXX为开头的
endswith:判断是否以XXX为后缀的
isalpha:判断是否是纯字母
isdigit:判断是否为纯数字
isalnum:判断是否为字母加数字
isspace:判断是否为空格
isupper: 判断是否全部是大写字母
islower:判断是否去全部是小写字母
计算出现次数:count
替换内容:replace
替换内容:replace(old,new,count) 默认全部替换,也可以通过count指定次数
切割字符串:split,rsplit,splitlines,partition,rpartition
splitlines:按照行分割
split(‘分隔符’,maxsplit) 返回的结果是一个列表,maxsplit最多的分割次数
同理:rsplit
修改大小写:capitalize,title,upper,lower
空格处理:ljust,rjust,center,lstrip,rstrip,strip
ljust,rjust,center,添加空格控制字符串的对齐方式
lstrip,rstrip,strip 删除字符串左侧或者右侧的空格
strip:去除左右两侧的空格
lstrip:去除左侧的空格部分
rstrip:去除右侧的空格部分
字符串拼接:join
注意:在python中,字符串是不可变的!所有的字符串相关方法,都不会改变原有的字符串,都是返回一个结果,在这个新的返回值里,保留了执行后的结果
练习:生成4为包含大小写字母及数字的验证码
filename = ''
s = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890'
for i in range(4):
index = random.randint(0, len(s) - 1)
filename += s[index]
print(filename)
练习:模拟文件上传,键盘输入上传文件的名称(abc.jpg),判断文件名(abc)是否大于6位以上,扩展名是否:jpg,gif,png格式。如果 不是则提示上传失败,如果名字不满足条件,而扩展名满足条件则随机生成一个6位大小写字母和数字组成的文件名,打印成功上传XXX.jpg
import random
file = input('输入图片文件全称:')
# 判断扩展名
if file.endswith('jpg') or file.endswith('gif') or file.endswith('png'):
#判断文件的名字
i = file.rfind('.')
name = file[:i]#切片
if len(name)<6:
#重新构建名字,产生字母与数字的组合名称
filename = ''
s = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890'
for i in range(4):
index = random.randint(0, len(s) - 1)
filename += s[index]
file = filename + file[i:]#完整的文件名
print('成功上传%s文件'%file)
else:
print('文件格式错误,上传失败!')
练习:
用户名或者手机号码登录+密码:15811119999 200325
用户名:全部小写,首字母不能是数字,长度必须6位以上: admin123
手机号码:纯数字 长度11
密码必须是6位数字
以上符合条件则进入下层验证:
判断用户名+密码 是否是正确,则成功,否则登录失败
flag = True
while flag:
name = input('用户名/手机号码:')
# 判断
if (name.islower() and name[0].isalpha() and len(name)>=6) or (name.isdigit() and len(name) == 11):
# 继续输入密码,密码输入错误允许多次输入
while True:
password = input('密码:')
# 判断是否是6位数字
if len(password) == 6 and password.isdigit():
#验证name+密码的正确性
if(name == 'admin123' or name == '15811119999') and password == '200325':
print('用户登录成功!')
flag = False
break
else:
print('用户名或者密码有误!')
break
else:
print('密码必须是6位数字')
else:
print('用户名或者手机号格式错误!')
+
数字:n=1+3 ------>4
字符串:s=‘aa’+‘bb’ --------->aabb
列表: list0 = [1,2,3]+['a','b'] -------->[1,2,3,'a','b']
4.4 列表基础
如何定义一个列表 :
1、空列表:[ ]
2、有内容的列表:['A','B','C'], [1,2,3,4], [[ ],[ ], [ ]]
4.4.1 列表的增删改查
修改:
insert(位置,元素):元素占了位置,其他元素只能向后移动
index(元素):根据元素找该元素的位置下标,返回值是下标位置
删除:
del(index):根据下标删除列表中元素,下标在写的时候要注意不要超出范围
pop(index):根据下标删除列表中元素,下标在写的时候要注意不要超出范围
pop():从后往前依次删除
del语句与pop方法的区别:
- 返回值:pop方法会返回被删除的元素的值,可以将其赋值给一个变量进行进一步处理。而del语句不返回被删除的元素的值,它仅用于删除指定索引处的元素。
- 使用场景:当你需要删除某个元素并将其值用于其他操作时,pop方法更为合适。如果你只关心从列表中移除元素,而不关心其值,那么del语句是更好的选择。
remove(element):根据元素名称删除,如果删除的元素列表中不存在则报错
如果列表中存在多个同名元素element,只删除遇到的第一个元素,后面的元素不会被删除
关键字in:元素 in 列表 表示元素是否在列表中? 返回值:bool
clear():清空列表元素
del和clear的区别
- dict.clear(),清空字典数据,但删除后字典仍存在,变成空字典{}。
- del dict, dict被彻底删除,继续使用dict会返回未定义错误
添加:
append:将元素追加到列表的尾部,每次只能追加一个元素,也可以追加一个可迭代对象(列表、元组、字符串、字典等
extend:extend()函数也是将元素添加到列表尾部,添加元素与append函数略微区别的是必须为可迭代对象(列表、元组、字典、字符串等)。extend函数与'+='运算符等效
insert(位置,元素):元素占了位置,其他元素只能向后移动
查找:
元素 in 列表:返回bool类型
元素 not in 列表:返回bool类型
列表.index(元素):返回元素的下标位置,如果没有此元素则报错
列表.count(元素):返回整数,返回值是0则表示不存在此元素,存在则返回该元素个数
排序和翻转:
列表.sort():默认升序的,可以通过reverse参数控制升序还是降序
列表.sort(reverse=True):True 降序,False 升序(默认)
列表.reverse():没有排序,单纯的翻转
4.4.2 列表的循环遍历
1、使用while循环
nameList = ['xiaoWang', 'xiaoZhang', 'xiaoHua']
length = len(nameList) # 获取列表长度 length==3
i = 0
while i < length:
print(nameList[i])
i += 1
2、使用for循环
while循环是一种基本的遍历列表数据的方式,但是最常用也是最简单的方式是使用for循环
nameList = ['xiaoWang', 'xiaoZhang', 'xiaoHua']
for name in nameList:
print(name)
交换两个元素:
a = 1
b = 2
a, b = b, a
print(a, b)
经典排序算法:冒泡排序
nums = [5, 1, 7, 6, 8, 2, 4, 3]
for i in range(len(nums) - 1):
flag = 0
for j in range(len(nums) - 1 - i):
if nums[j] > nums[j + 1]:
nums[j], nums[j + 1] = nums[j + 1], nums[j]
flag = 1
if flag == 0:
break
print(nums)
4.5 元组基础
元组和列表相比,是非常相似的。只是列表里的元素可以修改调整,而元组中的元素是创建元组的时候就设定好的,之后不能再修改调整。
元组的特点:
●不可变性:一旦创建了一个元组,你就不能更改、添加或删除其中的任何元素。
●使用圆括号:元组使用圆括号 () 来定义,而列表使用方括号 []
●可哈希性:由于元组是不可变的,它们可以用作字典的键,而列表则不能。
●多值赋值:当你将一个元组赋值给多个变量时,这些变量将分别存储元组中的每个值。这与列表不同,列表会尝试将整个列表赋值给多个变量,这会导致类型错误。(这可以让我们想到函数的多个返回值,实际上是返回了一个元组(tuple))
定义元组:
元组名 = ()
注意:如果元组中只有一个元素,必须添加逗号(‘aaa’,)(1,)(2.8,)
t1 = ()
print(type(t1))
t2 = ('aa')
print(type(t2))
t3 = ('aa',)
print(type(t3))
<class 'tuple'>
<class 'str'>
<class 'tuple'>
下标+切片(同字符串类似)
count():查询元素出现多少次
index():使用index()方法查询元素首次出现的索引
t = ('a', 'f', 'b', 'a', 'e')
n = t.count('a') # 查询元素'a'出现多少次
print(n)
print('--------------------------------')
index = t.index('a') # 使用index()方法查询元素'a'首次出现的索引
print(index)
关键字:
in , not in
for ... in
while
转换:
list(tuple)----->元组转成列表
tuple(list)------>列表转元组
4.6 字典基础
特点:键值对
结构:{键1:值,键2:值,键3:值}
字典:{ }
元素:键值对 注意:键是唯一的,值是允许重复的
下标 或者 切片 -------->没有
4.6.1 字典的增删改查
操作:
1、添加元素:
字典名[key] = value
注意:key是唯一的,所以在添加的时候如果出现同名的key,后面的key对应的value则替换原来的
字典名.setdefault(key,value) 只能做添加键值对元素使用,不能修改已经有的键值对
2、修改value值
字典名[key]= value
关键看“键”:键 可以添加、删除,但是键不能修改,只能修改键后面的值
如果字典中不存在键,则是添加
如果字典中存在键,则是修改
3、字典删除
pop(key):根据key实现删除,删除的是键值对。返回key对应的value
popitem():返回值:(key,value),从后往前删除
clear():清空
del 字典名[key]:根据key实现删除,删除的是键值对。
del 字典名:删除整个字典结构
4、字典遍历和查询
list.index() list.count() in
获取:
dict.get(key) : 根据key获取value的值
dict[key] :根据key获取value的值
区别:
get(key) :里面的key如果不存在则返回None,同时get(key,默认值)可以设置默认值
dict[key] :里面的key如果不存在则报error错误
如果使用for..in直接遍历字典,取出的是字典的key
for i in book:
print(i)
获取字典中所有的value值:字典.value() 就是将所有的值存放到了一个列表
for v in book:
print(v)
获取字典所有的key:字典.keys() 获取到的是把所有的键放到了一个列表中
获取键值对: 字典.items() ----->[(key,value),(),(),...]
for k,v in book.items():
print(k,v)
print(k)
print(v)
实现两个字典的合并:字典1.update(字典2) 在字典1的后面加上字典2
字典.fromkeys() 函数:用于创建一个新字典,以序列 seq 中元素做字典的键,value 为字典所有键对应的初始值。
dict.fromkeys(seq[, value])
seq = ('Google', 'Runoob', 'Taobao')
# 不指定默认的键值,默认为 None
thisdict = dict.fromkeys(seq)
print ("新字典为 : %s" % str(thisdict))
# 指定默认的键值
thisdict = dict.fromkeys(seq, 10)
print ("新字典为 : %s" % str(thisdict))
新字典为 : {'Google': None, 'Taobao': None, 'Runoob': None}
新字典为 : {'Google': 10, 'Taobao': 10, 'Runoob': 10}
练习:
添加三本书,不能添加同名的书
books=[ ]
书:{ }
键:书名、作者、价格
books = []
while True:
if len(books) == 3:
break
name = input('请输入书的名字:')
for book in books:
if name == book.get('书名'):
print('书名重复')
break
else:
author = input('请输入作者:')
price = float(input('请输入价格:'))
books.append({'书名': name, '作者': author, '价格': price})
print(books)
books = []
flags = True
while flags:
book = input('请输入添加的书名,作者,价格(以空格分割):').split(' ') # ['','','']
for i in books: # i是一个字典
if i['书名'] == book[0]:
print('{}已存在,已跳过此选项'.format(book[0]))
break
else:
books.append({'书名': book[0], '作品': book[1], '价格': book[2]})
if len(books) == 3:
flag = False
print(books)
4.7 集合
set()
特点:{ } {元素,元素,元素,...} ----->集合
{ } {key:value,key:value,key:value,...} ----->字典
定义集合
set1 = {'zhangsan'}
print(type(set1)) # <class 'set'>
list1 = [1, 2, 3, 4, 5, 3, 2, 5, 7, 8, 6, 7]
set2 = set(list1)
print(set2) # {1, 2, 3, 4, 5, 6, 7, 8}
set3 = set() #空集合
print(type(set3)) # <class 'set'>
添加元素
集合.add(元素)
集合.update(元素)
append extend ------>list
add update ------>set
list:有序,允许重复
set:无序,不允许重复
练习:产生5组(不允许重复),字母和数字组成的4位验证码,最终打印此5组验证码
import random
code_list = set()
s = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890'
while True:
code = ''
for i in range(4):
r = random.choice(s)
code += r
code_list.add(code)
if len(code_list) == 5:
break
print(code_list)
import random
code_list = set()
s = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890'
while True:
code = ''
for i in range(4):
# r = random.choice(s)
# code += r
index = random.randint(0, len(s))
code += s[index]
code_list.add(code)
if len(code_list) == 5:
break
print(code_list)
删除
集合名.remove(元素) 如果元素不是集合内的元素,会返回keyerror错误
集合名.discard(元素) 如果元素不是集合内的元素,不会有任何动作
del 集合名 将整个集合结构全部删除
集合名.clear() 将集合内的元素全部清空
集合名.pop() 随机删除集合中的元素
交集、并集、差集
交集:intersection |
并集:union &
差集:difference -
set1 = {1, 2, 3, 4, 5}
set2 = {3, 4, 5, 6, 7, 8}
result1 = set1.intersection(set2)
result2 = set1.union(set2)
result3 = set1.difference(set2)
print(result1)
print(set1 | set2)
print(result2)
print(set1 & set2)
print(result3)
print(set1 - set2)
{3, 4, 5}
{1, 2, 3, 4, 5, 6, 7, 8}
{1, 2, 3, 4, 5, 6, 7, 8}
{3, 4, 5}
{1, 2}
{1, 2}
总结:
list:允许重复。有序,有下标 [ ]
tuple:允许重复,里面的元素不能增加删除修改,只能查看 ( )
dict: 键值对存在 键:唯一 值:允许重复 { }
set : 不允许重复,无序 { }
练习:图书管理系统,至少有5本书
1、借书
2、还书
3、查询
4、查看所有
5、退出
library = [{'书名':'西游记','作者':'吴承恩','库存':'3'},
{'书名':'三国演义','作者':'罗贯中','库存':'3'},
{'书名':'红楼梦','作者':'曹雪芹','库存':'3'},
{'书名':'水浒传','作者':'施耐庵','库存':'3'},
{'书名':'安徒生童话','作者':'安徒生','库存':'3'}]
print('欢迎来到懒羊羊的图书管理系统')
while True:
select = int(input('-----------------------------\n借书请按1\n还书请按2\n查询请按3\n查看所有请按4\n退出请按5\n请选择:'))
if select == 1:
bookName = input('请输入书名:')
for book in library:
if bookName == book.get('书名'):
if int(book.get('库存')) > 0:
print('借书成功')
book['库存']= int(book['库存'])-1
else:
print('该书库存不够,无法借出')
break
else:
print('此书不存在')
if select == 2:
bookName = input('请输入您将要归还的书的名字:')
author = input('请输入您将要归还书籍的作者:')
for book in library:
if bookName == book.get('书名') and author == book.get('作者'):
print('还书成功')
book['库存'] = int(book['库存']) + 1
break
else:
print('无法归还,请仔细检查书名和作者是否输入错误')
if select == 3:
find = int(input('根据书名查询请按1\n根据作者查询请按2\n'))
if find == 1:
bookName = input('请输入书名:')
flag = 0
for book in library:
if bookName == book.get('书名'):
print(book)
flag = 1
if flag == 0:
print('未查询到该书的信息')
if find == 2:
author = input('请输入作者名:')
flag = 0
for book in library:
if author == book.get('作者'):
print(book)
flag = 1
if flag == 0:
print('未查询到该书的信息')
if select == 4:
print(library)
if select == 5:
break
4.8 公共方法
内置方法:
print()
input()
type()
id()
len()
bin() 转二进制
oct() 转八进制
chr() 将整数转换为ASCII码
ord() 给ASCII码值转换为整数
max() min() 最大值、最小值
sum() 求和
abs() 绝对值
sorted(元组,reverse=True) 将元组的元素进行顺序排序,返回一个列表
del 变量名
in 元素是否在...内
not in 元素是否不再...内
is 比较地址是否相同
运算符 | Python表达式 | 结果 | 描述 | 支持的数据类型 |
+ | [1,2]+[3,4] | [1,2,3,4] | 合并 | 字符串、列表、元组 |
* | [1,2]*3 | [1,2,1,2,1,2] | 复制 | 字符串、列表、元组 |
in | 3 in (1,2,3) | True | 元素是否存在 | 字符串、列表、元组、字典 |
not in | 4 not in (1,2,3) | True | 元素是否不存在 | 字符串、列表、元组、字典 |
- & | 只能在集合中使用
5.函数的使用
5.1 函数定义
格式:
def 函数名([参数,...]):
代码
import random
def generate_code():
# 生成验证码
s = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890'
code = ''
for i in range(4):
r = random.choice(s)
code += r
print(code)
generate_code()
练习:定义一个login函数:输入用户名(admin)和密码(1234),验证是否正确
def login():
username = input('请输入用户名:')
password = input('请输入密码:')
if username == 'admin' and password == '1234':
print('登录成功')
else:
print('登录不成功')
login()
5.2 参数
1、无参数
def 函数名():
pass
2、有参数:参数就是在调用函数的时候向函数中传值作用
def 函数名(参数1,参数2,参数3,...):
pass
import random
def generate_code(n):
# 生成验证码
s = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890'
code = ''
for i in range(n):
r = random.choice(s)
code += r
print(code)
# 调用函数
generate_code(4)
练习:login函数带参数n,表示允许输入错误的次数
def login(n):
for i in range(n):
username = input('请输入用户名:')
password = input('请输入密码:')
if username == 'admin' and password == '1234':
print('登录成功')
break
else:
print('登录不成功')
else:
print('已超过{}次,账户锁定'.format(n))
login(3)
练习:求1~n的累加和
def sum(n):
s = 0
for i in range(1,n+1):
s += i
print(s)
sum(10)
带多个参数的函数:
def 函数名(参数1,参数2):
函数体
练习:求两个数的和
def sum(a, b):
print(a + b)
sum(1, 3)
默认值参数:在定义函数的时候,有一个或者多个参数已经赋值
def 函数名(参数1,参数2,参数3=值,参数4=值,参数5=值):
pass
调用特点:
函数名(值1,值2) --------------------->默认参数如果不需要更改值则不需要传,需要更改值则传
注意:1、在定义函数的时候,普通参数要位于默认值参数的前面
2、默认参数的顺序是固定的,可以使用关键字参数赋值,明确指明某参数的值
def borrow_book(bookname, number=1):
print('进入借书系统...')
print('要借阅的书名是:{},借阅的数量是:{}'.format(bookname, number))
borrow_book('西游记')
borrow_book('水浒传', 3)
进入借书系统...
要借阅的书名是:西游记,借阅的数量是:1
进入借书系统...
要借阅的书名是:水浒传,借阅的数量是:3
练习:在list1中获取大于50的元素
list1 = [23, 45, 77, 88, 59, 10]
def get_list(*args):
new_list = []
for i in list1:
if i > 50:
new_list.append(i)
print(new_list)
get_list(list1)
练习:删掉比50小的元素
list1 = [23, 45, 77, 88, 59, 10]
def remove_from_list(*args):
i = 0
while i <len(list1):
if list1[i] < 50:
list1.remove(list1[i])
else:
i += 1
print(list1)
remove_from_list(list1)
5.3 函数装包与拆包
1、函数装包:
def 函数(*args): ----------> 此时会出现装包操作
pass
参数:1,2,3,4 ----------> (1,2,3,4) 将一个个参数,变成一整个元组
# 求和
def get_sum(*args):
print(args) # args是一个元组 (1, 2, 3, 4, 5, 6, 7, 8)
s = 0
for i in args:
s += i
print('和:',s)
get_sum(1,2,3,4,5,6,7,8)
2、函数拆包:
a1, b1 = (11, 22)
print(a1, b1) # 11 22
a2, b2 = [11, 22] # 11 22
print(a2, b2)
a3, b3 = {"m": 11, "n": 22}
print(a3, b3) # m n 取出来的是key,而不是键值对
传的参数为list、tuple、set -----------> 拆成一个一个参数
调用的时候:
函数(*list) 函数(*tuple) 函数(*set)
# 求和
def get_sum(*args):
print(args) # args是一个元组 (23, 45, 12, 44, 78, 39, 29)
s = 0
for i in args:
s += i
print('和:',s)
list1 = [23,45,12,44,78,39,29]
get_sum(*list1) #传进去的是23,45,12,44,78,39,29
可变参数:**kwargs
关键字参数
在函数调用的时候必须传递关键字参数,才可以将其转化为 key:value 装到字典中
def show_book(**kwargs):
print(kwargs) #kwargs是一个字典
show_book() #{}
show_book(bookname='西游记', author='吴承恩', number=5) #{'bookname': '西游记', 'author': '吴承恩', 'number': 5}
def show_book(**kwargs):
print(kwargs) #kwargs是一个字典
for k,v in kwargs.items():
print(k,v)
show_book() #{}
show_book(bookname='西游记', author='吴承恩', number=5) #{'bookname': '西游记', 'author': '吴承恩', 'number': 5}
{}
{'bookname': '西游记', 'author': '吴承恩', 'number': 5}
bookname 西游记
author 吴承恩
number 5
def show_book(**kwargs):
print(kwargs) #kwargs是一个字典
for k,v in kwargs.items():
print(k,v)
book = {'bookName': '西游记', 'author': '吴承恩', 'number': 5}
show_book(**book) #--------> bookName='西游记', author='吴承恩', number=5
def 函数名(*args,**kwargs):
print(args) # ( )
print(kwargs) # { }
5.4 函数的返回值 return
参数: 外界向函数里面传值
返回值:里面的内容向外界传值
格式:
def 函数名(参数,...):
pass
return XXX
当函数调用时通过return向外返回值
注意:
1、只要函数有返回值,则需要用变量接收
2、一个函数中可以有多个return语句,但是只要有一个return语句被执行到,那么这个函数就会结束了,因此后面的return没有什么用处
3、return后面可以是元组,列表,字典等,只要是能够存储多个数据的类型,就可以一次性返回多个数据
# 求和
def get_sum(*args):
s = 0
for i in args:
s += i
return s
total =get_sum(1,2,3,4,5,6,7,8)
print(total)
return 后面的值可以是一个值,也可以是多个值
如果是多个值 类似:return a,b,c 会将多个值封装到一个元组中,将元组作为整体返回
结果(a,b,c)
def get_maxandmin(numbers):
for i in range(0, len(numbers) - 1):
for j in range(0, len(numbers) - 1 - i):
if numbers[j] > numbers[j + 1]:
numbers[j], numbers[j + 1] = numbers[j + 1], numbers[j]
min = numbers[0]
max = numbers[len(numbers) - 1]
return min, max
list1 = [34, 11, 78, 92, 54, 67, 43, 12, 43, 26]
result = get_maxandmin(list1)
print(result) #(11, 92)
a, b = get_maxandmin(list1)
print(a, b) #11 92
5.5 全局变量与局部变量
声明在函数外面的变量为全局变量
声明在函数内部的变量为局部变量;局部变量的作用范围仅限函数内部,所以不同函数可以定义相同名字的局部变量。局部变量的作用就是为了临时保存数据需要再函数中定义变量来进行存储,当函数调用时局部变量被创建,当函数调用完成后这个变量就不能够使用了
全局变量与局部变量名字相同时的问题:优先寻找函数内部的变量,当做局部变量使用,而不是修改全局变量的值
如何进行全局变量的修改?
函数内部可以直接使用全局变量,但是不能直接修改全局变量;如果想修改全局变量,则必须使用关键字:global 变量名
只有不可变的类型才需要添加global
可变的类型不需要加global
可变与不可变:
不可变类型:int str float bool tuple 当改变变量的值时,地址也发生改变
可变类型:list dict set 里面的内容发生改变,但是地址没有发生改变
练习:
验证是否登录:islogin
自定义一个判断用户是否登录功能islogin,参数:username,password
函数体:判断用户输入的用户名和密码是否正确,如果正确则返回True,否则返回False
借书:borrow_book
参数是:书名
函数体:判断是否登录,如果登录则可以借书
如果没有登录则提示:还未登录不能借书
islogin = False
def login(u, p):
global islogin
if u == 'admin' and p == '1234':
islogin = True
print('登录成功')
else:
print('登录失败')
def borrow_book(name):
print('{}借书成功'.format(name))
username = input('请输入用户名:')
password = input('请输入密码:')
login(username, password)
print(islogin)
if islogin:
bookname = input('请输入要借阅的书籍名称:')
borrow_book(bookname)
else:
print('还未登录不能借书')
练习:
停车计费系统:
进入停车场记录进入时间,如果要出去则记录出去的时间,停车时间是:出去time-进入time
停车场的数据结构是:
[{'车牌':[进入时间,0}],{'车牌':[进入时间,出去时间]},...]
15分钟 1元
1小时 4元
停车场变量park--------->全局变量
import random
park = []
def enter():
print('欢迎进入停车场:')
number = input('请输入您的车牌号码:')
# 构建结构{'车牌':[0,5]}
car = {number: [0]}
park.append(car)
print('欢迎{}进入停车场'.format(number))
def go_out():
number = input('请输入您的车牌号码:')
# 判断汽车是否进入停车场
for car in park:
# car ------> {}
if number in car:
# 记录结束时间
time = random.randint(0, 24) # 模拟停车结束时间
time_record = car.get(number) # []
time_record.append(time)
# 计算停车费用
money = (time_record[1] - time_record[0]) * 4
print('{}停车{}小时,总费用为{}元'.format(number, time, money))
break
else:
print('此车未进入停车场!')
while True:
choice = int(input('进入停车场请按1\n离开停车场请按2\n退出系统请按3\n请输入:'))
if choice == 1:
# 进入停车场
enter()
elif choice == 2:
go_out()
elif choice == 3:
break
else:
print('输入错误!请重新输入!')
5.6 函数注释
函数的注释:
def 函数名(参数1,...):
基本注释------->双引号 “注释内容”
高级注释 ------>三引号
‘’‘’
函数的说明
参数的说明:
:param 参数名1 :XXXXXX
:param 参数名2 :XXXXXX
返回值的说明:
:return :XXXXXX
‘’‘’
5.7 引用和函数参数引用
值,是靠引用来传递的
我们可以用id()来判断两个变量是否为同一个值的引用。可以将id值理解为那块内存的地址标示
引用:
1、不是在函数中使用,可以通过sys.getrefcount(变量名) 查看变量的被引用个数(该方法也算引用变量一次)
def 变量 表示删除了一个引用
2、函数的引用:
必须要分清楚传递的值是可变类型还是不可变类型
如果是可变类型,函数里面发生改变,函数外面就能看到改变后的内容
如果是不可变类型,函数里面发生改变,不会影响外部的变量
5.8 闭包
函数的嵌套:
变量以及函数的寻找顺序:内层函数------>外层函数------->全局变量-------->系统 builtins
def inner():
print('我是内部函数')
b = 200
# b += a # 内部函数可以使用外部函数的变量
nonlocal a
a += b # 内部函数不能直接修改外部函数的变量,如果想修改需要 nonlocal 变量名
print(a)
print(b)
# 调用inner()
inner()
# result = locals() #locals() 表示查看函数中的局部变量,以字典的形式返回
# print(result) #{'a': 100, 'inner': <function outer.<locals>.inner at 0x0000020C0FFB6B80>}
outer()
闭包:闭包是由函数及其相关的引用环境组合而成的实体,同时满足以下三个条件
1、嵌套函数
2、内部函数引用了外部函数的变量
3、返回值是内部函数
def outer(n):
a = 10
def inner():
b = a + n
print('内部函数:', b)
return inner # 把内部函数扔出去
r = outer(5)
print(r) # <function outer.<locals>.inner at 0x00000226481F6B80> inner()的地址
r() #--------->调用内层函数inner()
5.9 装饰器
函数名仅仅是个变量,只不过指向了定义的函数而已,所以才能通过 函数名() 调用,
如果 函数名=XXX被修改了,那么当在执行 函数名()时,调用的就不是之前的那个函数了。
装饰器:遵循开放封闭原则,在不改变原函数的情况下,扩展了函数的功能
装饰器定义:
def aaa(func):
def xxx(参数,...):
....
func()
....
return yyy
return xxx
装饰:
@装饰器名 aaa ----------------> 原函数 = 装饰器(原函数) 原函数作为参数传给装饰器
def 原函数():
pass
装饰器的功能:
1、引入日志
2、函数执行时间统计
3、执行函数前预备处理
4、执行函数后清理功能
5、权限校验等场景
6、缓存
# 定义装饰器
def decorater(func):
def wrapper():
func()
print('刷漆')
print('铺地板')
print('买家具')
print('精装修房子')
return wrapper
@decorater
def house():
print('毛坯房...')
house()
带参数的装饰器:
如果原函数有参数则装饰器内部函数也要有参数
# 定义装饰器
def decorater(func):
def wrapper(*args, **kwargs): # args = (address,area) 装包
func(*args, **kwargs) # func(*(address,area)) 拆包
print('刷漆')
print('铺地板')
print('买家具')
print('精装修房子')
print('-------房屋装修完毕-------')
return wrapper
@decorater
def house(address):
print('房子的地址在{}是一个毛坯房'.format(address))
@decorater
def company(address, area):
print('公司的地址在{},有{}平方米'.format(address, area))
@decorater
def hotel(name, address, area=40):
print('{}位置在{},单间面积为{}平方米'.format(name, address, area))
house('北京')
company('杭州', '10000')
hotel('全季酒店', '上海')
'''
房子的地址在北京是一个毛坯房
刷漆
铺地板
买家具
精装修房子
-------房屋装修完毕-------
公司的地址在杭州,有10000平方米
刷漆
铺地板
买家具
精装修房子
-------房屋装修完毕-------
全季酒店位置在上海,单间面积为40平方米
刷漆
铺地板
买家具
精装修房子
-------房屋装修完毕-------
'''
装饰器修饰有返回值的函数:
原函数有返回值,装饰器的内部也要有返回值
# 定义装饰器
def decorater(func):
def wrapper(*args, **kwargs):
r = func(*args, **kwargs) # 50000
print('预计装修费用是:{}元'.format(r))
print('刷漆')
print('铺地板')
print('买家具')
print('精装修房子')
print('-------房屋装修完毕-------')
return 60000
return wrapper
@decorater
def house():
print('房子是一个毛坯房')
return 50000
r = house() # house就是wrapper
print(r)
'''
房子是一个毛坯房
预计装修费用是:50000元
刷漆
铺地板
买家具
精装修房子
-------房屋装修完毕-------
60000
'''
5.10 递归函数
如果一个函数在内部不调用其他的函数,而是自己本身的话,这个函数就是递归函数
遵循:
1、必须要有出口
2、每次递归要向出口靠近
练习:用递归函数实现1~10数字的打印
def test(i):
if i == 10:
print('10')
else:
print(i)
i += 1
test(i)
test(1)
练习:用递归函数实现1~10数字的累加和
def num_sum(i):
if i == 1:
return 1
else:
return num_sum(i - 1) + i
s = num_sum(10)
print(s)
def num_sum(i):
if i == 10:
return 10
else:
return num_sum(i + 1) + i
s = num_sum(1)
print(s)
5.11 匿名函数
匿名函数定义格式:lambda 参数列表:返回值表达式
def test1(a):
return a + 1
m1 = test1(1)
print(m1)
test2 = lambda a: a + 1
m2 = test2(1)
print(m2)
test3 = lambda x, y: x * y
m3 = test3(2, 3)
print(m3)
匿名函数的使用场合:匿名函数作为参数使用
def func(a, f):
print(a) # 2
r = f(a) # 6
print(r)
func(2, lambda x: x * 3)
5.12 高阶函数
在python中,函数其实也是一种数据类型
函数对应的数据类型是function,可以把它当做是一种复杂的数据类型
既然同样都是一种数据类型,我们就可以把它当做数字或字符串来处理
既然变量可以指向函数,函数的参数能接接收变量,那么一个函数就可以接收另一个函数作为参数,同样,我们还可以把一个函数当做另一个函数的返回值。这种函数的使用方式称之为高阶函数
高阶函数:一个函数的参数是另一个函数
系统高阶函数:max min sorted filter map reduce
m = max(5, 9)
print(m) # 9
m = max([2, 4, 67, 8, 9])
print(m) # 67
list1 = [('tom', 19), ('tony', 20), ('lily', 18), ('rose', 22)]
m = max(list1, key=lambda x: x[1])
print(m) # ('rose', 22) 最大年龄的人
s1 = sorted(list1, key=lambda x: x[1])
print(s1) # [('lily', 18), ('tom', 19), ('tony', 20), ('rose', 22)] 按照年龄排序
s2 = sorted(list1, key=lambda x: x[1], reverse=True)
print(s2) # [('rose', 22), ('tony', 20), ('tom', 19), ('lily', 18)]
filter 的匿名函数要求返回值必须是bool类型,只有bool类型结果为True的才是符合过滤条件的
list1 = [('tom', 19), ('tony', 20), ('lily', 18), ('rose', 22)]
r = filter(lambda x:x[1]>18,list1)
print(list(r)) # 将r强转成列表 [('tom', 19), ('tony', 20), ('rose', 22)]
map 通过匿名函数指明提取的内容,并对内容进行加工
list1 = [('tom', 19), ('tony', 20), ('lily', 18), ('rose', 22)]
r = map(lambda x: x[1] > 18, list1)
print(list(r)) # [True, True, False, True]
r = map(lambda x: x[1], list1)
print(list(r)) # [19, 20, 18, 22]
r = map(lambda x: x[0].title(), list1)
print(list(r)) # ['Tom', 'Tony', 'Lily', 'Rose']
r = map(lambda x: x[0].upper(), list1)
print(list(r)) # ['TOM', 'TONY', 'LILY', 'ROSE']
reduce 用于对可迭代对象中的元素进行累积操作
from functools import reduce
list1 = [1, 2, 3, 4, 5]
r = reduce(lambda x, y: x + y, list1)
print(r) # 1+2+3+4+5
6.文件操作
6.1 读取文件 open
mode:
r :read 读 纯文本文件
w: write 写 纯文本文件
rb:read binary 二进制 读二进制文件
wb:write binary 写二进制文件
rt:read txt 读 纯文本文件
wt: write txt 写 纯文本文件
open(path/filename,'rt') --------> 返回值:stream(管道)
container = stream.read() --------> 读取管道中内容
注意:
如果传递的path/filename有误,则会报错FileNotFoundError
如果是读取图片则不能使用默认的读取方式,mode = ‘rb’ 读二进制文件
read() 读取所有内容
stream = open(r'C:\Users\lxy\Desktop\临时\aa.txt','r') #读取文件,返回值为stream流
container = stream.read() # 读取文件里面的所有内容
print(container)
readline() 每次读取一行内容
stream = open(r'C:\Users\lxy\Desktop\临时\aa.txt','r') #读取文件,返回值为stream流
line = stream.readline() # 读取文件里面的一行
print(line)
readlines() 读取所有行保存到列表中
stream = open(r'C:\Users\lxy\Desktop\临时\aa.txt','r') #读取文件,返回值为stream流
lines = stream.readlines()
print(lines)
readable() 判断是否可读的
stream = open(r'C:\Users\lxy\Desktop\临时\aa.txt','r') #读取文件,返回值为stream流
result = stream.readable() #判断这个文件是不是可读的 True or False
print(result)
6.2 文件的追加和写操作
open(path/filename,'w') ---------->如果指定的文件不存在,则自动创建
mode 是‘w’表示就是写操作,每次都会将原来的内容清空
方法:
write(内容) 每次都会将原来的内容清空,然后写当前的内容
writelines(Iterable) 没有换行的效果,自己加\n
如果 mode = ‘a’ 每次不会将原来的内容清空,然后追加写当前的内容
open(r'C:\Users\lxy\Desktop\临时\aa.txt','a')
stream = open(r'C:\Users\lxy\Desktop\临时\aa.txt','w') #读取文件,返回值为stream流
s = '''
*
**
***
'''
stream.write(s)
stream.close() # 释放资源
stream = open(r'C:\Users\lxy\Desktop\临时\aa.txt','w') #读取文件,返回值为stream流
s = '''
*
**
***
'''
stream.write(s)
stream.write('-------------')
stream.writelines(['!\n','@\n','#\n','$\n','%\n','^\n'])
stream.close() # 释放资源
6.3 文件复制和os模块
源文件:C:\p1\aa.jpg
目标文件:C:\p2\aa.jpg
with 结合open使用,可以帮助我们自动释放资源
with open(r'C:\p1\aa.jpg', 'rb') as stream1:
container = stream1.read() # 读取文件内容
with open(r'C:\p2\aa.jpg', 'wb') as stream2:
stream2.write(container)
print('文件复制完成!')
os模块
相对路径:是从盘符开始的路径
绝对路径:是从当前路径开始的路径
os.path
os.chdir( ) 切换目录
返回上层目录 ../
增
os.mkdir(path) 创建文件夹,不能创建已经存在的文件夹
os.makedirs(path) 递归式创建文件夹
删
os.remove(path) 删除文件
os.rmdir(path) 删除文件夹,只能删除空文件夹
改
os.rename ("原文件夹/文件名称","新文件夹/文件名称") 重命名文件或文件夹
查
os.path.abspath(_file_) 获取当前文件的绝对路径
os.path.abspath( )
os.path.dirname(_file_) 获取当前文件所在的文件夹路径(绝对路径)与 os.getcwd( ) 类似
os.path.dirname( ) 与 os.getcwd( ) os.curdir( ) 作用类似
os.listdir(path) 查看指定目录下面所有的文件或者文件夹的名称,返回一个列表
os.path.getsize(path) 返回的是文件大小,单位为字节个数
拆分与拼接
os.path.join(path,'xxx') 返回的是一个拼接后的新的路径 path\xxx
os.path.split(path) 返回的是元组,将文件路径分成两个部分,一个是文件夹路径,一个是文件名
os.path.splitext(path) 返回的是元组,将文件路径分成两个部分,一个是路径文件名,一个是扩展名如.py .txt .jpg
判断
os.path.exists(文件path) 判断文件是否存在,若存在返回True,若不存在返回False
os.path.isfile(path) 判断是否是文件,若是返回True,若不是返回False
os.path.isdir(path) 判断是否是文件夹,若是返回True,若不是返回False
练习:把一个路径的文件夹下的所有文化复制到另一个路径下
import os
src_path = r'c:\p1'
target_path = r'c:\p2'
def copy(src, target):
# 将原路径下的所有文件放到一个列表
filelist = os.listdir(src_path)
for file in filelist:
# 获取文件的路径
path1 = os.path.join(src_path, file)
# 判断是否是文件还是文件夹
if os.path.isdir(path1):
# 获取未来新增的文件夹的路径
target_path1 = os.path.join(target_path, file)
# 新增文件夹
os.mkdir(target_path1)
# 递归调用copy
copy(path1, target_path1)
else:
# 不是文件夹直接复制
with open(path1, 'rb') as rstream:
container = rstream.read()
path2 = os.path.join(target_path, file)
with open(path2, 'wb') as wstream:
wstream.write(container)
else:
print('复制成功!')
copy(src_path, target_path)
6.4 异常机制
格式:
try:
函数主体
except:
如果有异常执行的代码
finally: ------------------->finally 可有可没有
无论是否存在异常都会被执行的代码
情况1:
try:
函数主体
except 异常类型1:
print(xxxxxx)
except 异常类型2:
print(xxxxxx)
except Exception:
print(xxxxxx)
如果是多个except,异常类型的顺序需要注意,最大的Exception要放到最后
情况2:
try:
函数主体
except 异常类型1:
print(xxxxxx)
except 异常类型2:
print(xxxxxx)
except Exception as err:
print(err) ------------------> err的内容就是错误原因
def func():
try:
n1 = int(input('请输入第一个数字:'))
n2 = int(input('请输入第二个数字:'))
per = input('请输入运算符号(+ - * /):')
result = 0
if per == '+':
result = n1 + n2
elif per == '-':
result = n1 - n2
elif per == '*':
result = n1 * n2
elif per == '/':
result = n1 / n2
else:
print('符号输入错误!')
print('运算结果是:', result)
except ValueError:
print('必须输入数字!!!')
except ZeroDivisionError:
print('除数不能为0!!!')
except Exception as err:
print(err)
func()
情况3:
try:
函数主体
except 异常类型1:
print(xxxxxx)
else:
xxxx -----------------> 没有异常才会执行的代码块
def func():
try:
n1 = int(input('请输入数字:'))
print(n1)
except ValueError:
print('必须输入数字!!!')
else:
print('数字成功输入')
func()
情况4:
try:
函数主体
except:
如果有异常执行的代码
finally: ------------------->finally 可有可没有
无论是否存在异常都会被执行的代码
def func():
stream = None
try:
stream = open(r'c:\p1')
container = stream.read()
print(container)
except Exception as err:
print(err)
finally:
print('---------finally-----------')
if stream:
stream.close()
func()
6.5 抛出异常
手动抛出异常 raise
格式:
raise 异常类型('提示信息= ')
# 注册 用户名必须6位
def register():
username = input('输入用户名:')
if len(username) < 6:
raise Exception('用户名长度必须6位以上')
else:
print('输入的用户名是:', username)
register()
'''
输入用户名:12
Traceback (most recent call last):
File "D:\project\python_code\pythonstudy\test.py", line 10, in <module>
register()
File "D:\project\python_code\pythonstudy\test.py", line 5, in register
raise Exception('用户名长度必须6位以上')
Exception: 用户名长度必须6位以上
'''
7.列表推导式与生成器
7.1 列表推导式
最终得到的是一个列表
格式1: [i for i in 可迭代的]
list = []
for i in range(1, 21):
list.append(i)
print(list)
结果: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
list1 = [i for i in range(1,21)]
print(list1)
结果: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
list2 = [i+2 for i in range(1,21)]
print(list2)
结果: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
0~100之间所有的偶数 存放到列表中
list1 = [i for i in range(0, 101, 2)]
print(list1)
格式2: [i for i in 可迭代的 if 条件]
list1 = [i for i in range(0, 101) if i % 2 == 0]
print(list1)
取出列表中的单词
list1 = ['43', '56', 'high', '90', 'lucy', 'hello']
list2 = [word for word in list1 if word.isalpha()]
print(list2)
格式3: [结果1 if 条件 else 结果2 for 变量 in可迭代的]
如果是h开头的则将首字母大写,不是h开头的全部大写
list1 = ['43', '56', 'high', '90', 'lucy', 'hello']
list2 = [word.title() if word.startswith('h') else word.upper() for word in list1 ]
print(list2)
7.2 集合推导式与字典推导式
集合推导式
{ } 类似列表推导式,在列表推导式的基础上添加了一个去除重复项
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 5, 7, 3, 6, 8, 1]
set1 = {x - 1 for x in list1 if x > 5}
print(set1) # {8, 5, 6, 7}
字典推导式
dict1 = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D'}
newdict1 = {value: key for key, value in dict1.items()}
print(newdict1) # {'A': 'a', 'B': 'b', 'C': 'c', 'D': 'd'}
7.3 生成器
什么是生成器:通过列表推导式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的,而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间。如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。
在python中,这种一边循环一边计算的机制,称为生成器:generator
定义生成器的方式一:通过列表推导式方式
g = (x * 3 for x in range(10))
print(type(g)) # <class 'generator'>
print(g) # <generator object <genexpr> at 0x00000252BFDACBA0>
# 每调用一次则会产生一个元素
# 方式1:通过调用__next__()方式得到元素
print(g.__next__())
print(g.__next__())
print(g.__next__())
# 方式2:next(生成器对象)--------> 系统内置函数
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g)) # StopIteration 生成器本来就可以产生10个,生成了10个后再调用next(g)会抛出异常
g = (x * 3 for x in range(10))
while True:
try:
print(next(g))
except:
print('没有更多的元素了')
break
定义生成器的方式二:函数+yield
借助函数完成,只要函数中出现了yield关键字,说明函数就不是函数了,变成生成器了
步骤:
1、定义一个函数,函数中使用yield关键字
2、调用函数,接收调用的结果
3、得到的结果就是生成器
4、借助与next(),__next()__()得到元素
def func():
n = 0
while True:
n += 1
yield n # --------> return n + 暂停
g = func()
print(g)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
'''
<generator object func at 0x0000023DBFCBCBA0>
1
2
3
4
5
'''
# 斐波那契数列
def fib(length):
a, b = 0, 1
n = 0
while n < length:
yield b
a, b = b, a + b
n += 1
return '没有更多元素!!!' # return就是在得到StopIteration后的提示信息
g = fib(8)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
'''
1
1
2
3
5
8
13
21
Traceback (most recent call last):
File "D:\project\python_code\pythonstudy\test.py", line 22, in <module>
print(next(g))
StopIteration: 没有更多元素!!!
'''
产生元素方法:
1、next(generator) --------> 每次调用都会产生一个新的元素,如果新的元素产生完毕,再次调用的话就会产生异常
2、生成器自己的方法:
g.__next__(): 获取下一个元素
g.send(value): 向每次生成器调用中传值 注意: 第一次调用send(None)
def gen():
i = 0
while i < 5:
temp = yield i # 相当于return加上暂停的意思,先拿到i的值,再暂停等待send值传过去
print('temp:', temp)
i += 1
return '没有更多的数据'
g = gen()
# print(next(g))
# print(next(g))
# print(next(g))
g.send(None)
n1 = g.send('呵呵') # yield与send的值互相传
print('n1', n1)
n2 = g.send('哈哈')
print('n2', n2)
'''
temp: 呵呵
n1 1
temp: 哈哈
n2 2
'''
生成器之应用多任务: 协程
def task1(n):
for i in range(n):
print('正在搬第{}块砖'.format(i))
yield None
def task2(n):
for i in range(n):
print('正在听第{}首歌'.format(i))
yield None
g1 = task1(5)
g2 = task2(5)
while True:
try:
g1.__next__()
g2.__next__()
except:
break
'''
正在搬第0块砖
正在听第0首歌
正在搬第1块砖
正在听第1首歌
正在搬第2块砖
正在听第2首歌
正在搬第3块砖
正在听第3首歌
正在搬第4块砖
正在听第4首歌
'''
7.4 迭代器和可迭代对象
可迭代对象:1、生成器
2、元组、列表、集合、字典、字符串
如何判断一个对象是否是可迭代?
from collections.abc import Iterable
list1 = [1, 3, 5, 7, 4, 5]
f = isinstance(list1, Iterable)
print(f) # True
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束
迭代器只能往前不会后退
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
可迭代的是不是肯定就是迭代器? No!
生成器是可迭代的,也是迭代器
list是可迭代的,但不是迭代器
from collections.abc import Iterable
list1 = [1, 3, 5, 7, 4, 5]
list1 = iter(list1) # 通过iter()函数将可迭代的变成了一个迭代器
f = isinstance(list1, Iterable)
print(f) # True
print(next(list1)) # 1
print(next(list1)) # 3
迭代器与生成器是包含于被包含的关系
8.面向对象
面向过程:
1、把完成挪移需求的所有步骤从头到尾逐步实现
2、根据开发需求,将某些功能独立的代码封装成一个又一个函数
3、最后完成的代码,就是顺序的调用不同的函数
特点:
1、注重步骤与过程,不注重职责分工
2、如果需求复杂,代码会变得很复杂
3、开发复杂项目,没有固定的套路,开发难度很大
面向对象:
相比较于函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法
1、在完成某一个需求前,首先确定职责-------->要做的事情(方法)
2、根据职责确定不同的对象,在对象内部封装不同的方法(多个)
3、最后完成的代码,就是顺序地让不同的对象调用不同的方法
特点:
1、注重对象和职责,不同的对象承担不同的职责
2、更加适合应对复杂的需求变化,是专门应对复杂项目的开发,提供的固定套路
3、需要在面向过程基础上,在学习一些面向对象的语法
8.1 类和对象的概念
类:
类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,不能直接使用
特征被称为属性
行为被称为方法
类就相当于制造飞机的图纸,是一个模板,是负责创建对象的
对象:
对象是由类创建出来的一个具体存在,可以直接使用
由哪一个类创建出来的对象,就拥有在哪一个类中定义的属性和方法
在程序开发中,应该先有类,再有对象
所有的类名要求首字母大写,多个单词使用驼峰式命名
类与对象的关系:
类是模板,对象是根据类这个模板创建出来的,应该先有类,再有对象
类只有一个,而对象可以有很多个,不同对象的属性可能会各不相同
类中定义了什么属性和方法,对象中就有什么属性和方法,不可能多,也不可能少
8.2 类的设计
8.2.1 类的设计
设计一个类满足三要素:
1、类名:这类事物的名字,满足大驼峰命名法(首字母大写,每个单词的首字母大写,单词与铲单词之间没有下划线)
2、属性:这类事物具有什么样的特征
3、方法:这类事物具有什么样的行为
提示:需求中没有涉及的属性或者方法在设计类时,不需要考虑
class 类名[(父类)]:
属性:特征
方法:动作
练习1:
需求:小明今年18岁,身高1.75,每天早上跑完步,会去吃东西
小美今年17岁,身高1.65,小美不跑步,小美喜欢吃东西
类名:Person
属性:name、age、height
方法:run()、eat()
练习2:
需求:一只黄颜色的狗狗叫大黄,看见陌生人汪汪叫,看见家人摇尾巴
类名:Dog
属性:name、color
方法:shout()、shake()
8.2.2 类属性
8.2.2.1 术语--实例
1、使用面向对象开发,第一步是设计类
2、使用类名()创建对象,创建对象的动作有两步
1)在内存中为对象分配空间
2)调用初始化方法__init__方法为对象初始化
3、对象创建后,内存中就有了一个对象的实实在在的存在---实例
因此,通常也会把:
1、创建出来的对象叫做类的实力
2、创建对象的动作叫做实例化
3、对象的属性叫做实例属性
4、对象调用的方法叫做实例方法
程序执行时:
1、对象各自拥有自己的实例属性
2、调用对象方法,可以通过self.属性/方法
结论:
1、每个对象都有自己独立的内存空间,保存各自不同的属性
2、多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用传递到方法内部
8.2.2.2 类是一个特殊的对象
python中一切皆对象:
classAAA:定义的类属于类对象
obj1 = AAA() 属于实例对象
8.2.2.3 类属性的定义及使用
class Tool(object):
count = 0
def __init__(self):
Tool.count += 1
tool1 = Tool()
print(Tool.count)
8.2.2.4 类属性的获取机制
8.2.3 类方法和静态方法
8.2.3.1 类方法
class Tool(object):
count = 0
@classmethod
def show_tool_count(cls):
print('工具对象的数量{}'.format(cls.count))
def __init__(self):
Tool.count += 1
tool1 = Tool()
print(Tool.count)
# 调用类方法
Tool.show_tool_count()
8.2.3.2 静态方法
class Dog(object):
@staticmethod
def run():
# 不访问实例属性以及类属性
print('小狗要跑...')
# 通过类名. 调用静态方法---不需要创建对象
Dog.run()
8.3 面向对象基础语法
8.3.1 dir内置函数
怎么判断xxx是不是对象?
使用内置函数 dir 传入标识符/数据(xxx),可以查看对象内的所有属性及方法
8.3.2 定义简单的类(只包含方法)
定义只包含方法的类:
class 类名:
def 方法1(self,参数列表):
pass
def 方法2(self,参数列表):
pass
注意:
1、类名满足大驼峰命名法(首字母大写,每个单词的首字母大写,单词与铲单词之间没有下划线)
2、方法的定义与函数几乎一样
3、方法的第一个参数必须是self
创建对象:
对象变量 = 类名()
练习:
需求:小猫爱吃鱼,小猫要喝水
# 定义类
class Cat:
def eat(self):
print('小猫爱吃鱼')
def drink(self):
print('小猫要喝水')
# 创建猫对象
tom = Cat()
print('tom=====》', tom) # <__main__.Cat object at 0x000002A6DA6F9430>
tom.eat() # 小猫爱吃鱼
tom.drink() # 小猫要喝水
在python中使用类创建对象之后,tom变量中仍然记录的是对象在内存中的地址,tom变量引用了新建猫的对象
在计算机中,通常使用 十六进制表示内存地址
使用同一个类创建出来的对象不是同一个对象
# 定义类
class Cat:
def eat(self):
print('小猫爱吃鱼')
def drink(self):
print('小猫要喝水')
# 创建猫对象
tom = Cat()
tom.eat() # 小猫爱吃鱼
tom.drink() # 小猫要喝水
print('tom:', tom) # <__main__.Cat object at 0x000001F5EBA39430>
# 再创建一个猫对象
lazy_cat = Cat()
lazy_cat1 = lazy_cat
lazy_cat.eat()
lazy_cat.drink()
print('lazy_cat:', lazy_cat) # <__main__.Cat object at 0x000001F5EBA98070>
print('lazy_cat1:', lazy_cat1) # <__main__.Cat object at 0x000001F5EBA98070>
8.3.3 方法中的self参数
给对象增加属性:
虽然在python中给对象设置属性非常的容易,只需要在类的外部代码中直接通过 . 设置一个属性即可,但是不推荐使用,推荐使用初始化方法
因为对象属性的封装应该封装在类的内部
不推荐!!!!
# 定义类
class Cat:
def eat(self):
print('{}爱吃鱼'.format(self.name))
def drink(self):
print('{}要喝水'.format(self.name))
# 创建猫对象
tom = Cat()
tom.name = 'tom'
tom.eat() # tom爱吃鱼
tom.drink() # tom要喝水
由哪一个对象调用的方法,方法内的self就表示当前调用方法的对象自己
调用方法时,程序员不需要传递self参数
在方法内部,可以通过self. 访问对象的属性,也可以通过self. 调用其他的对象方法
class Student:
# 类属性
name = 'xiaoxiao'
age = 2
xiaoxiao = Student() # 使用类创建对象
print(xiaoxiao.name) # xiaoxiao
print(xiaoxiao.age) # 2
xiaoxiao.age = 18 # 对象属性
print(xiaoxiao.age) # 18
对象属性,先找自己空间的,然后再去模型中找,如果自己空间中存在age属性,则不会去模型中查找。
class Phone:
brand = 'xiaomi'
price = 4999
type = 14
# Phone类里面的方法:call
def call(self):
print('self:', self)
print('正在打电话。。。')
phone1 = Phone()
print('phone1:', phone1) # phone1: <__main__.Phone object at 0x0000021858039430>
phone1.call() # self: <__main__.Phone object at 0x0000021858039430> 正在打电话。。。
class Phone:
brand = 'xiaomi'
price = 4999
type = 14
# Phone类里面的方法:call
def call(self):
print('self:', self)
print('正在访问通讯录')
for person in self.address_book:
print(person.items())
print('正在打电话。。。')
print('留言:', self.note)
phone1 = Phone()
phone1.note = 'phone1的note'
phone1.address_book = [{'123456789': 'aa'}, {'987654321': 'bb'}]
print('phone1:', phone1) # phone1: <__main__.Phone object at 0x0000021858039430>
phone1.call() # self: <__main__.Phone object at 0x0000021858039430> 正在打电话。。。
print('----------------------------------------------------------')
phone2 = Phone()
phone2.note = 'phone2的note'
phone2.address_book = [{'123456789': 'aa'}, {'987654321': 'bb'}]
print('phone2:', phone2) # phone2: <__main__.Phone object at 0x000001B0C4958C70>
phone2.call() # self: <__main__.Phone object at 0x000001B0C4958C70> 正在打电话。。。
'''
phone1: <__main__.Phone object at 0x00000220B6C69430>
self: <__main__.Phone object at 0x00000220B6C69430>
正在访问通讯录
dict_items([('123456789', 'aa')])
dict_items([('987654321', 'bb')])
正在打电话。。。
留言: phone1的note
----------------------------------------------------------
phone2: <__main__.Phone object at 0x00000220B6CC8C70>
self: <__main__.Phone object at 0x00000220B6CC8C70>
正在访问通讯录
dict_items([('123456789', 'aa')])
dict_items([('987654321', 'bb')])
正在打电话。。。
留言: phone2的note
'''
8.3.4 初始化方法
当使用类名()创建对象时,会自动执行以下操作:
1、为对象在内存中分配空间---创建对象
2、为对象的属性设置初始值---初始化方法 __init__(是对象的内置方法)
__init__方法时专门用来定义一个类具有哪些属性的方法
class Phone:
# 魔术方法之一
def __init__(self):
print('---------init----------')
def call(self): # self是不断发生变化的
print('call')
print('价格:', self.price) # 不能保证每个self中都存在price
p = Phone()
p.price = 1000
p.call() # p.call() p是对象
'''
---------init----------
call
价格: 1000
'''
1、找有没有一块空间是Phone
2、利用Phone类,向内存申请一块和Phone一样的空间
3、去Phone中找有没有 __init__,如果没有则执行将开辟的内存给对象p
4、如果有__init__,则会进入init方法执行里面的动作,将内存地址赋值给对象p
在初始化方法内部定义属性:
class Phone:
# 魔术方法之一
def __init__(self):
print('---------init----------')
self.brand = 'xiaomi' # 动态的给self空间中添加了两个属性:brand和price
self.price = 4999
def call(self): # self是不断发生变化的
print('call')
print('价格:', self.price)
print('品牌:', self.brand)
p1 = Phone()
p2 = Phone()
p1.price = 1000
p1.call() # p.call() p是对象
p2.call()
'''
---------init----------
---------init----------
call
价格: 1000
品牌: xiaomi
call
价格: 4999
品牌: xiaomi
'''
'''
---------init----------
call
价格: 1000
'''
使用参数设置属性初始值:
class Person:
name = '张三'
def eat(self):
print('{}正在吃红烧肉!。。。'.format(self.name))
p1 = Person()
p1.eat()
p2 = Person()
p2.name = '李四'
p2.eat()
class Person:
name = '张三' # 类属性
def __init__(self, gender, age):
self.gender = gender
self.age = age
def eat(self,food):
print('{}的性别是{}今年{}岁了,爱吃{}'.format(self.name, self.gender, self.age,food))
Person.name = 'liuliu' # 改变类属性
p1 = Person('男', '18') # 参数传给__init__(self, gender, age)中的gender, age
p1.eat('红烧肉')
p2 = Person('女', '17')
p2.name = '李四' # 改变对象属性
p2.eat('手枪腿')
8.3.5 内置方法和属性
8.3.5.1 __del__方法
当使用 类名() 创建对象时,为 对象 分配完空间后,自动 调用__init__方法
当一个 对象被从内存中销毁之前,会自动 调用 __del__方法
__del__:如果希望在对象被销毁之前,再做一些事情,可以考虑一下__del__方法
对象的生命周期:一个对象从调用类名()创建,生命周期开始,一个对象的__del__方法一旦被调用,生命周期结束。在对象的生命周期内,可以访问对象属性,或让对象调用方法
# 定义类
class Cat:
def __init__(self, name):
self.name = name
print('{}对象诞生了'.format(self.name))
def __del__(self):
print('{}对象结束了'.format(self.name))
# 创建猫对象
tom = Cat('tom')
print('-' * 20)
'''
tom对象诞生了
--------------------
tom对象结束了
'''
8.3.5.1 __str__方法
在python中,使用print输出对象变量,默认情况下,会输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址(十六进制表示)
如果,希望使用print输出对象变量的值,能够打印自定义的内容,就可以利用__str__方法
注意:__str__方法必须返回一个字符串
# 定义类
class Cat:
def __init__(self, name):
self.name = name
print('{}对象诞生了'.format(self.name))
def __del__(self):
print('{}对象结束了'.format(self.name))
def __str__(self):
# 必须返回一个字符串
return '我是小猫{}'.format(self.name)
# 创建猫对象
tom = Cat('tom')
print(tom) # 我是小猫tom
8.4 面向对象封装
案例1
练习1:小明爱跑步
需求:1、小明体重75.0公斤
2、小明每次跑步会减肥0.5公斤
3、小明每次吃东西体重会增加1公斤
提示:在对象的方法内部,是可以直接访问对象的属性的
class Person:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __str__(self):
return '{}的体重为{}公斤'.format(self.name, self.weight)
def run(self):
self.weight -= 0.5
def eat(self):
self.weight += 1
xiaoming = Person('小明', 75)
xiaoming.run()
xiaoming.eat()
print(xiaoming)
练习2:小明小美爱跑步
需求:1、小明体重75.0公斤
2、小美体重50.0公斤
3、每次跑步会减肥0.5gongjin
4、每次吃东西体重会增加1公斤
提示:同一个类创建多个对象之间,属性互不干扰
class Person:
def __init__(self, name, weight):
self.name = name
self.weight = weight
def __str__(self):
return '{}的体重为{}公斤'.format(self.name, self.weight)
def run(self):
self.weight -= 0.5
def eat(self):
self.weight += 1
# 小明对象
xiaoming = Person('小明', 75)
xiaoming.run()
xiaoming.eat()
print(xiaoming)
# 小美对象
xiaomei = Person('小美', 50)
xiaomei.run()
xiaomei.eat()
print(xiaomei)
练习3:摆放家具
需求:
1、房子有户型、总面积和家具名称列表(新房子没有任何的家具)
2、家具有名字和占地面积,其中
床占地4平方米
衣柜占地2平方米
餐桌占地1.5平方米
3、将以上三件家具添加到房子中
4、打印房子时,要求输出:户型、总面积、剩余面积、家具名称列表
剩余面积:在创建房子对象时,定义一个剩余面积属性,初始值与总面积相等,当向房间添加家具时,让剩余面积 -=家具面积
# 1、房子有户型、总面积和家具名称列表(新房子没有任何的家具)
# 2、家具有名字和占地面积,其中床占地4平方米、衣柜占地2平方米、餐桌占地1.5平方米
# 3、将以上三件家具添加到房子中
# 4、打印房子时,要求输出:户型、总面积、剩余面积、家具名称列表
# 剩余面积:在创建房子对象时,定义一个剩余面积属性,初始值与总面积相等,当向房间添加家具时,让剩余面积 -=家具面积
class HouseItem:
def __init__(self, name, area):
self.name = name
self.area = area
def __str__(self):
return '{}占地{}平方米'.format(self.name, self.area)
class House:
def __init__(self, house_type, area, ):
self.house_type = house_type
self.area = area
# 剩余面积
self.free_area = area
# 家具名称列表
self.item_list = []
def __str__(self):
return ('户型:{}\n总面积:{}\n剩余面积:{}\n家具:{}'.format
(self.house_type, self.area, self.free_area, self.item_list))
def add_item(self, item):
print('要添加{}'.format(item))
# 1.判断家具的面积
if item.area > self.free_area:
print('{}的面积太大了,无法添加'.format(item.name))
return
# 2.将家具的名称添加到列表中
self.item_list.append(item.name)
# 3.计算剩余面积
self.free_area -= item.area
# 创建家具
bed = HouseItem('床', 4)
chest = HouseItem('衣柜', 2)
table = HouseItem('餐桌', 1.5)
print(bed, chest, table)
# 创建房子对象
my_home = House('两室一厅', 60)
my_home.add_item(bed)
my_home.add_item(chest)
my_home.add_item(table)
print(my_home)
案例2
一个对象的属性可以是另外一个类创建的对象
练习1:士兵突击
需求:
1、士兵许三多有一把AK47
2、士兵可以开火
3、枪能够发射子弹
4、枪装填子弹增加子弹数量
每一个新兵都没有枪
fire方法需求:
1、判断是否有枪,没有枪没法冲锋
2、喊一声口号
3、装填子弹
4、射击
class Gun:
def __init__(self, model, bullet_count):
self.model = model
self.bullet_count = bullet_count
def add_bullet(self, count):
self.bullet_count += count
def shoot(self, shoot_number):
# 1.判断子弹数量
if self.bullet_count < 1:
print('{}没有子弹了'.format(self.model))
return
# 2.发射子弹
self.bullet_count -= shoot_number
if self.bullet_count < 0:
print('{}没有子弹了'.format(self.model))
return
# 3.提示发射信息
print('{}突突突...子弹剩余{}'.format(self.model, self.bullet_count))
def __str__(self):
return self.model
class Soldier:
def __init__(self, name):
# 姓名
self.name = name
# 枪-新兵没有枪
self.gun = None
def fire(self, shoot_number, add_number):
# 1、判断士兵是否有枪
if self.gun is None:
print('{}没有枪'.format(self.name))
return
# 2、高喊口号
print('{}冲啊!!!'.format(self.name))
# 3、装填子弹
self.gun.add_bullet(add_number)
# 4、发射子弹
self.gun.shoot(shoot_number)
# 1、创建枪对象
ak47 = Gun('AK47', 0)
# 2、创建许三多
xusanduo = Soldier('许三多')
xusanduo.gun = ak47
xusanduo.fire(5, 7)
'''
许三多冲啊!!!
AK47突突突...子弹剩余2
'''
8.4.1 身份运算符
身份运算符用于比较两个对象的内存地址是否一致------>是否是对同一个对象的引用
在python中针对None比较时,建议使用is判断
运算符 | 描述 | 实例 |
---|---|---|
is | is是判断两个标识符是不是引用同一个对象 | x is y,类似id(x)==id(y) |
is not | is not 是判断两个标识符是不是引用不同的对象 | x is not y,类似 id(x)!=id(b) |
is 与 == 的区别
is 用于判断两个变量引用对象是否为同一个
== 用于判断引用变量的值是否相等
8.5 私有属性和私有方法
8.5.1 对象的私有属性和私有方法
在实际的开发中,对象的某些属性或方法可能只希望在对象的内部被使用,而不希望在外部被访问到,私有属性就是对象不希望公开的属性,私有化方法就是对象不希望公开的方法
定义方式:
在定义属性或者方法时,在属性名或者方法名前增加两个下划线__,定义的就是私有属性或方法
class Women:
def __init__(self, name):
self.name = name
self.__age = 18
def __secret(self):
# 在对象的方法内部,是可以访问对象的私有属性的
print('{}的年龄是{}'.format(self.name, self.__age))
xiaofang = Women('小芳')
# 私有属性在外界是不能被直接访问
# print(xiaofang.__age) #报错了 AttributeError: 'Women' object has no attribute '__age'
# 私有方法同样不允许在外界直接访问
# xiaofang.__secret()
在python中,并没有真正意义上的私有
在给属性、方法命名的时候,实际对名称做了一些特殊处理,使得外界无法访问
处理方式:在名称前面加上_类名----> _类名__名称
8.5.2 父类的私有属性和私有方法
子类对象不能再自己的方法内部,直接访问父类的私有属性或私有方法
子类对象可以通过父类的公有方法间接访问到私有属性或私有方法
class A:
def __init__(self):
self.num1 = 100
self.__num2 = 200
def __test(self):
print('__test私有方法 num1:{} __num2:{}'.format(self.num1, self.__num2))
def test(self):
print('test共有方法 num1:{} __num2:{}'.format(self.num1, self.__num2))
class B(A):
def demo(self):
# #1、在子类的对象方法中不能访问父类的私有属性
# print('访问父类的私有属性__num2{}'.format(self.__num2))
# #2、在子类的对象方法中不能调用父类的私有方法
# self.__test()
# 3、访问父类的共有属性
print('访问父类的私有属性num1{}'.format(self.num1))
# 4、调用父类的共有方法
self.test()
# 创建一个子类对象
b = B()
# 在外界不能直接访问对象的私有属性或调用私有方法
# print(b.__num2)
# b.__test()
b.demo()
# 在外界直接访问父类的公有属性或调用公有方法
print(b.num1)
b.test()
8.6 方法综合练习
class Game(object):
# 类属性:历史最高分
top_score = 0
# 初始化方法
def __init__(self, player_name):
self.player_name = player_name
# 静态方法
@staticmethod
def show_help():
print('帮助信息-------------')
# 类方法
@classmethod
def show_top_score(cls):
print('历史记录{}'.format(cls.top_score))
# 实例方法
def start_game(self):
print('{}开始游戏了'.format(self.player_name))
# 1、查看游戏的帮助信息
Game.show_help()
# 2、查看历史最高分 调用类方法不需要传参
Game.show_top_score()
# 3、创建游戏对象
game = Game('小明')
game.start_game()
8.7 面向对象继承
继承实现代码的重用,相同的代码不需要重复的编写
8.7.1 单继承
继承的概念:子类拥有父类的所有方法和属性
继承的语法:
class 类名(父类名):
pass
子类:继承父类,可以直接享受父类中已经封装好的方法,不需要再次开发,子类中应该根据职责,封装子类特有的属性和方法
class Animal:
def eat(self):
print('eat')
def drink(self):
print('drink')
def run(self):
print('run')
def sleep(self):
print('sleep')
# 子类拥有父类的所有方法和属性
class Dog(Animal):
def bark(self):
print('bark')
# 创建一个对象
wangcai = Dog()
wangcai.eat()
wangcai.drink()
wangcai.run()
wangcai.sleep()
wangcai.bark()
专业术语介绍:
Dog类是Animal类的子类,Animal类是Dog类的父类,Dog类从Animal类继承
Dog类是Animal类的派生类,Animal类是Dog类的基类,Dog类从Animal类派生
继承的传递性:
C类从B类继承,B类又从A类继承,那么C类拥有B类和A类的所有属性和方法
子类拥有父类以及父类的父类的所有方法和属性
class Animal:
def eat(self):
print('eat')
def drink(self):
print('drink')
def run(self):
print('run')
def sleep(self):
print('sleep')
# 子类拥有父类的所有方法和属性
class Dog(Animal):
def bark(self):
print('bark')
class xiaotianquan(Dog):
def fly(self):
print('fly')
# 创建一个对象
wangcai = xiaotianquan()
wangcai.eat()
wangcai.drink()
wangcai.run()
wangcai.sleep()
wangcai.bark()
wangcai.fly()
8.7.2 方法的重写
当父类的方法实现不能满足子类需求时,可以对方法进行重写(override)
重写父类方法有两种情况:
8.7.2.1 覆盖父类的方法
在开发中,父类的方法实现和子类的方法实现完全不同,就可以采用覆盖的方式,在子类中重新编写父类的方法实现
具体的实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现
重写之后,在运行时,只会调用子类中重写的方法,而不再会调用父类封装的方法
class Dog(Animal):
def bark(self):
print('bark')
class XiaoTianQuan(Dog):
def fly(self):
print('fly')
def bark(self):
print('叫的跟神狗一样')
8.7.2.2 对父类方法进行扩展
如果在开发中,子类的方法实现中包含父类的方法实现,即父类原本封装的方法实现是子类方法的一部分,就可以使用扩展的方式
1、在子类中重写父类的方法
2、在需要的位置使用super().父类方法来调用父类方法的执行
3、代码其他的位置针对子类的需求,编写子类特有的代码实现
# 子类拥有父类的所有方法和属性
class Dog(Animal):
def bark(self):
print('bark')
class XiaoTianQuan(Dog):
def fly(self):
print('fly')
def bark(self):
# 1、针对子类特有的需求,编写代码
print('神狗叫') # 神狗叫
# 2、使用super().父类方法来调用父类方法
super().bark() # bark
# 3、增加其他子类的代码
print('二郎神等等我') # 二郎神等等我
调用父类方法的另外一种方式:
在python2.x时,使用 父类名.方法(self)
不推荐使用,因为一旦父类发生变化,方法调用位置的类名同样需要修改
提示:
1、在开发时, 父类名.方法(self) 与 super().父类 两种方式不要混用
2、如果使用 当前子类名.方法(self) ,会形成递归调用,出现死循环
8.7.3 多继承
8.7.3.1 多继承的概念和语法
概念:子类可以拥有多个父类,并且具有所有父类的属性和方法
语法:
class 子类名(父类名1,父类名2,...):
pass
class A:
def test(self):
print('A类test方法')
class B:
def demo(self):
print('B类demo方法')
class C(A, B):
'''多继承可以让子类对象,同时具有多个父类的属性和方法'''
pass
# 创建子类对象
c = C()
c.test() # A类test方法
c.demo() # B类demo方法
8.7.3.2 多继承的使用注意事项
如果不同的父类中存在同名的方法,子类对象在调用方法时,会按照方法搜索顺序来继承的父类中的方法
python中的MRO(方法搜索顺序)__mro__方法,主要用于在多继承时判断方法、属性的调用路径,按照__mro__方法得到的继承顺序来查找方法
class A:
def test(self):
print('A类test方法')
def demo(self):
print('A类demo方法')
class B:
def test(self):
print('B类test方法')
def demo(self):
print('B类demo方法')
class C(A, B):
'''多继承可以让子类对象,同时具有多个父类的属性和方法'''
pass
# 创建子类对象
c = C()
c.test() # A类test方法
c.demo() # A类demo方法
# 确定C类对象调用方法的顺序
print(C.__mro__) # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
提示:开发时,应该尽量避免这种容易产生混淆的情况!如果父类之间存在同名的属性或者方法,应该尽量避免使用多继承
8.7.3.3 新式类和经典类
object 是python为所有对象提供的基类,提供一些内置的属性和方法,可以使用dir函数查看
新式类:以object为基类的类,推荐使用
经典类:不以object为基类的类,不推荐使用
python3.x中定义类时,如果没有指定父类,会默认使用object作为该类的基类(python3.x中定义的类都是新式类)
python2.x中定义类时,如果没有指定父类,不会使用object作为该类的基类
新式类和经典类在多继承时,会影响到方法的搜索顺序
为了保证编写的代码能够同时在python3.x、python2.x中运行,今后在定义类时,如果没有父类,建议统一继承自object
8.8 面向对象多态
多态:不同的子类对象调用相同的父类方法,产生不同的执行结果,增加代码的灵活度,以继承和重写父类方法为前提,是调用方法的技巧,不会影响到类的内部设计
class Dog(object):
def __init__(self, name):
self.name = name
def game(self):
print('{}简单的玩耍'.format(self.name))
class XiaoTianQuan(Dog):
def game(self):
print('{}在天上玩耍'.format(self.name))
class Person(object):
def __init__(self, name):
self.name = name
def game_with_dog(self, dog):
print("{}与{}玩耍".format(self.name, dog.name))
# 让狗玩耍
dog.game()
# 1、创建一个狗对象
# wangcai = Dog('旺财')
wangcai = XiaoTianQuan('哮天犬旺财')
# 2、创建一个小明对象
xiaoming = Person('小明')
# 3、让小明调用和狗玩的方法
xiaoming.game_with_dog(wangcai)
8.9 设计模式与单例设计模式
8.9.1 单例设计模式
8.9.2 __new__方法
重写new方法
class MusicPlayer(object):
def __new__(cls, *args, **kwargs):
# 创建对象使,__new__方法会被自动调用
print('new创建对象,分配空间')
# 为对象分配空间
instance = super().__new__(cls)
return instance
# 返回对象的引用
def __init__(self):
print('播放器初始化')
# 创建播放器对象
player = MusicPlayer()
print(player)
8.9.3 python中的单例
8.9.3.1 类创建的对象在系统中是唯一的一个实例
class MusicPlayer(object):
# 记录第一个被创建对象的引用
instance = None
def __new__(cls, *args, **kwargs):
# 判断类属性是否是空对象
if cls.instance is None:
# 调用父类的方法,为第一个对象分配空间
cls.instance = super().__new__(cls)
# 返回类属性保存的对象引用
return cls.instance
# 创建播放器对象
player1 = MusicPlayer()
print(player1) # <__main__.MusicPlayer object at 0x000001AD8A2EAE50>
player2 = MusicPlayer()
print(player2) # <__main__.MusicPlayer object at 0x000001AD8A2EAE50>
8.9.3.2 初始化动作只执行一次
class MusicPlayer(object):
# 记录第一个被创建对象的引用
instance = None
# 记录是否执行过初始化动作
init_flag = False
def __new__(cls, *args, **kwargs):
# 判断类属性是否是空对象
if cls.instance is None:
# 调用父类的方法,为第一个对象分配空间
cls.instance = super().__new__(cls)
# 返回类属性保存的对象引用
return cls.instance
def __init__(self):
# 判断是否执行过初始化动作
if MusicPlayer.init_flag:
return
# 如果没有执行过,执行初始化动作
print('初始化播放器')
# 修改类属性的标记
MusicPlayer.init_flag = True
# 创建播放器对象
player1 = MusicPlayer()
print(player1) # <__main__.MusicPlayer object at 0x000001AD8A2EAE50>
player2 = MusicPlayer()
print(player2) # <__main__.MusicPlayer object at 0x000001AD8A2EAE50>
'''
初始化播放器
<__main__.MusicPlayer object at 0x0000026C9868BE50>
<__main__.MusicPlayer object at 0x0000026C9868BE50>
'''
9. 模块的导入与包的导入
9.1 模块
9.1.1 模块的概念
9.1.2 模块的两种导入方式
1、import导入
2、from...import导入
3、from...import*
9.1.3 模块的搜索顺序
9.1.4 __name__属性
原则:每一个独立的python文件就是一个模块,在导入文件时,文件中所有没有任何缩进的代码都会被执行一遍
__name__属性 可以做到,测试模块的代码只在测试情况下被运行,而在被导入时不会被执行
1、__name__是Python的一个内置属性,记录着一个字符串
2、如果是被其他文件导入的,__name__是模块名
3、如果是当前执行的程序__name__是__main__
代码示例:
9.2 包
9.2.1 包的导入
概念
具体操作:
![](https://i-blog.csdnimg.cn/direct/7edc1f6c2f4a44afb9e0c12184a711c1.png)
10. 正则表达式
10.1 正则表达式
正则表达式在线验证工具:regex101: build, test, and debug regex
看白月黑羽的视频及文档:白月黑羽