一 入门基础
1 编码
1.1计算机底层只能识别010101010101【二进制】
- 编码本质:将我们所用到的字母、符号、汉字等用01010二进制创建对于关系。
- ascii码:只包含字母、符号。
- gbk编码:亚洲国家文字
- unicode:万国码(世界发现的所有文字)
- 用4组8位(共32位)01 代表一个文字,如:
- 00000000 00001010 00111100 00000000 代表 “中”
- 比较冗长
- 用4组8位(共32位)01 代表一个文字,如:
- utf-8 、utf-16等:对unicode进行压缩
- 00000000 00001010 00111100 代表 “中”
1.2 在Python中,默认utf-8编码
1.3 打开文件并读取,一定要以相同的编码方式打开,不然会乱码。
在代码头部加入# -- coding:gbk -- 可改变文件编码
2 输出
场景:
- 用户输入账户\密码,系统返回 正确?错误?
- 在excel中获取数据,分析某个字符出现快乐没有,出现了多少次---->把结果打印出来
2.1 基本输出
print("账户错误!")
2.2 多个输出
print("账户错误!","账户正确,密码错误!","账户密码正确!")
print("账户错误!","账户正确,密码错误!","账户密码正确!",sep="-")
#sep="-" 以 - 代替, 输出
2.3 默认尾部都有换行
print("账户错误!","账户正确,密码错误!","账户密码正确!")
print("账户错误!","账户正确,密码错误!","账户密码正确!",sep="-")
#------------------end="" 去除换行
print("账户错误!","账户正确,密码错误!","账户密码正确!",end="")
print("账户错误!","账户正确,密码错误!","账户密码正确!",sep="-")
3 数据类型
3.1 整形(int)
生活中的数字,代码中无需用引号括起来即可使用
1 2 3 4 5 。。。。
print(34)
print(22)
运算符
print(1+2) #3
3.2 字符串(str)
生活中的文本信息 “中国陕西”、 “优美的文章”、“asdffgga”
在代码中需要引号括起来,python中双引号,单引号都可以(甚至可以使用三引号"“” “”",‘’’ ‘’',三引号可以表示多行的字符串内容,单引号和双引号不可以),没有区分,但是段字符串的闭合需要同一种类型的引号,且闭合的字符串中不能有有与之同类型的引号,但是可以存在不同的引号
print(“aaddcc”)
print("aaddcc’) 错误
print(“aa"dd"cc”)错误
print("aa’'dd"cc)
3.2.1 str操作
- 拼接
print(“aaddcc”+“陕西”) #aaddcc陕西
- 转换
-整形转字符串
str(100) —>“100”
–字符串转整型
int(“100”) —>100
int(“陕西”) —>错误
-
切片
aa = "abcdefgh" print(aa[0:3]) #abc 【前包后不包】 print(aa[:3]) #abc print(aa[-5:]) #defgh print(aa[-1:-5])#空 print(aa[-5:-1]) #defg print(aa[-5:1])#空 print(aa[0:-1:2])#aceg 带步长的切片,每隔2个切一次,如果不写明的话默认是1,从左往右 print(aa[::-1]) #hgfedcba 步长也可以为负数 print(aa[0:1:-1]) #空 步长也可以为负数 ,但相应方向要从右往左,不然取不到值 print(aa[-1::-1]) #hgfedcba 步长也可以为负数
-
原生字符串 【字符串前面加 r】一般在路径前面使用
aa = "abcd\nabcd" bb = r"abcd\nabcd" print(aa) # abcd # abcd print(bb) # abcd\nabcd
3.2.2 str常用方法
-
大小写
#大写 name = 'abcd' res = name.upper() print(name) #abcd print(res) #ABCD #小写 name = 'ABCD' res = name.lower() print(name) #ABCD print(res) #abcd
-
isdecimal 判断字符串内容是不是整数,返回True、False
aa= "222" print(aa.isdecimal()) #True bb = "asdf" print(bb.isdecimal()) #False
-
startswith/endswith 判断是否以,,开头/以,,结尾,返回True、False
aa = "222223333444" bb = "adnhdhksuijhks" print(aa.startswith("s")) #False print(aa.startswith("2")) #True print(bb.endswith("k")) #False print(bb.endswith("s")) #True
-
replace 替换
text = "峡谷河道battle之王" text1 =text.replace("王","D") print(text1)
-
split 切割 把一个字符串切割成列表返回
text = "中国,陕西省,西安市" data_list = text.split(",") print(data_list) #['中国', '陕西省', '西安市'] #指定最多切几个 data_list = text.split(",",maxsplit=1) print(data_list) #['中国', '陕西省,西安市']
-
rsplit 从右边开始切割
text = "中国,陕西省,西安市" data_list = text.rsplit(",") print(data_list) #['中国', '陕西省', '西安市'] #指定最多切几个 data_list = text.rsplit(",",maxsplit=1) print(data_list) #['中国,陕西省', '西安市']
-
join 拼接 把列表拼接成字符串返回
data_list =['中国', '陕西省', '西安市'] str1 = ",".join(data_list) str2 = '|'.join(data_list) str3 = "".join(data_list) print(str1) #中国,陕西省,西安市 print(str2) #中国|陕西省|西安市 print(str3) #中国陕西省西安市
-
strip 去除 字符串两边的空格, lstrip 去除左边的\rstrip 去除右边的
aa = " 中国陕西 " str1 = aa.strip() print(str1) #中国陕西 print(aa) # 中国陕西 str2 = aa.lstrip() print(str2)#中国陕西 str3 = aa.rstrip() print(str3)# 中国陕西
-
包含
info = "中国陕西省西安市" bool1 = info.__contains__("中国") #返回一个bool值 print(bool1) if "中国" in info: #另一种判断方法 print("包含") else: print("不包含")
-
索引 index\find、 长度len()
aa = "abcdef" print(aa[1]) #索引,下标 print(len(aa)) #长度 print(aa.index("c")) #获取某个字符的下标 print(aa.find("c")) #获取某个字符的下标 print(aa.index("c",1,3) ) #在一个下标区间内查找 某个字符的下标,在区间内找不到会报错 print(aa.find("c",3,3)) #在一个下标区间内查找 某个字符的下标,在区间内找不到会返回 -1
-
count
aa = "abcdef" print(aa.count("ab")) #查找某个/段字符,在字符串出现的次数 print(aa.count("ab",2,3)) #在一个下标区间内 查找某个/段字符,在字符串出现的次数
-
center
aa = "abcdef" print(aa.center(10,"@")) #以@字符填充字符串到10位,左右两边填充 print(aa.center(10,"@!")) #填充的字符有多个会报错
3.3 布尔类型 bool (true\false)
res = (1 == 2)
print(res) #False
res = (1<2)
print(res) #True
转换: None、0 和空(空字符串空列表等) 转换后为 False,其他为True
bool1 = bool(“dsfwww”)
print(bool1) #True
bool2 = bool(“中国”)
print(bool2) #True
bool3 = bool(101)
print(bool3) #True
#-------------
bool4 = bool()
print(bool4) #False
bool5 = bool(0)
print(bool5) #False
bool6 = bool(“”)
print(bool6) #False
#空字符创中加了空格,转换为True
bool7 = bool(" ")
print(bool7) #True
3.4 列表 list
列表是python中最长用的数据类型之一,也是最灵活的数类型之一,其可以包含任何种类的对象:数字、字符串、元组、字典、也可以嵌套其他的列表。当然与字符串不同的是,列表是可变的,可变指的是我们在原处修改其中的内容,如删除或增加一个元素,则列表中的其他元素自动缩短或者增长,也正因如此,在列表元素过多时,如果你删除靠前的(如第一个)元素,其他的元素都要向前移动,会导致性能有所下降。
列表创建:
aa =[]
bb = [1,2,‘1’,‘aad’]
3.4.1 list操作
- 列表拼接
l1 = [1,2,3]
l2 = ['a','b','c']
l3 = l1 + l2
print(l3) #[1, 2, 3, 'a', 'b', 'c']
- 列表相乘(列表中的元素允许重复)
l1 = [1,2,3]
l2 = l1 * 3
print(l2) #[1, 2, 3, 1, 2, 3, 1, 2, 3]
-
列表成员字符判断 返回bool值
l1 = [1, 2, 3, 'a', 'b', 'c'] print(1 in l1) #True print('a' not in l1) #True
-
通过索引取值
l1 = [1, 2, 3, 'a', 'b', 'c'] print(l1[1]) # 2 print(l1[-2]) # b
-
切片
l1 = [1, 2, 3, 'a', 'b', 'c'] print(l1[0:3]) #[1, 2, 3] 【前包后不包】 print(l1[:3]) #[1, 2, 3] print(l1[-5:]) #[2, 3, 'a', 'b', 'c'] print(l1[-1:-5])#[] print(l1[-5:-1]) #[2, 3, 'a', 'b'] print(l1[-5:1])#[] print(l1[0:-1:2])#[1, 3, 'b'] 带步长的切片,每隔2个切一次,如果不写明的话默认是1,从左往右 print(l1[::-1]) #['c', 'b', 'a', 3, 2, 1] 步长也可以为负数 print(l1[0:1:-1]) #[] 步长也可以为负数 ,但相应方向要从右往左,不然取不到值 print(l1[-1::-1]) #['c', 'b', 'a', 3, 2, 1] 步长也可以为负数
-
用于for 循环取值
l1 = [1, 2, 3, 'a', 'b', 'c'] for i in l1: print(i) #1 #2 #3 #a #b #c for ix in range(0,len(l1)): print(ix) #0 #1 #2 #3 #4 #5 for ix in range(len(l1)-1,-1,-1): #最后一个-1 表示从右往左以步长1取值 print(l1[ix]) #c #b #a #3 #2 #1
-
修改指定索引位置的元素
l1 = [1, 2, 3, 'a', 'b', 'c'] l1[0]="d" print(l1) #['d', 2, 3, 'a', 'b', 'c'] l1[-1] = 4 print(l1) #['d', 2, 3, 'a', 'b', 4]
-
通过del 删除列表中的元素
l1 = [1, 2, 3, 'a', 'b', 'c'] del l1[0] print(l1) #[2, 3, 'a', 'b', 'c'] del l1[1],l1[-1] print(l1) #[2, 3, 'b'] del l1 #删除整个列表
3.4.2 list 常用方法
-
count 返回某个元素在列表中出现的次数
l1 = [1, 2, 3, 'a', 'b', 'c'] print(l1.count('a')) #1
-
index
l1 = [1, 2, 3, 'a', 'b', 'c'] print(l1.index("b")) # 查找元素在列表中的位置(下标) #4 print(l1.index("b",0,len(l1))) # 在一个限制的下标区间内查找元素出现的位置 #4
-
pop
l1 = [1, 2, 3, 'a', 'b', 'c'] res = l1.pop() #列表l1中的最后一个元素删除,且赋值给变量res print(res) #c print(l1) #[1, 2, 3, 'a', 'b']
-
remove
l1.remove("a") #指定一个元素进行删除,如果指定的元素不存在会报错 print(l1)#[1, 2, 3, 'b', 'c']
-
append
l1 = [1, 2, 3, 'a', 'b', 'c'] l1.append("d") #指定一个元素进行删除,如果指定的元素不存在会报错 print(l1)#[1, 2, 3, 'a', 'b', 'c', 'd'] l1 = [1, 2, 3, 'a', 'b', 'c'] res = l1.pop(1) #指定列表l1中的元素元素位置删除,且赋值给变量res print(l1) #[1, 3, 'a', 'b', 'c']
-
insert
l1 = [1, 2, 3, 'a', 'b', 'c'] l1.insert(1,"x") #将某个元素插到某个下标之前 print(l1)#[1, 'x', 2, 3, 'a', 'b', 'c']
-
clear #清除列表里面的元素
-
sort 排序 会改变原列表
l1 = list(range(10)) print(l1) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] import random random.shuffle(l1)#打乱顺序 print(l1) #[5, 4, 0, 1, 2, 7, 8, 9, 6, 3] l1.sort()#正向排序 print(l1) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] l1.sort(reverse=True)#反向排序 print(l1) #[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
-
sorted 排序 不会改变原列表()
l1 = list(range(10)) print(l1) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] import random random.shuffle(l1)#打乱顺序 print(l1) #[1, 7, 8, 0, 6, 9, 5, 3, 4, 2] l2 = sorted(l1)#正向排序 print(l2) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(l1) #[1, 7, 8, 0, 6, 9, 5, 3, 4, 2] l2 =sorted(l1,reverse=True) #反向排序 print(l2) #[9, 8, 7, 6, 5, 4, 3, 2, 1, 0] #------------------- #字符串也可以使用这个方法,只不过返回的是列表 str = 'jhnfmkiyg' l3 = sorted(str) print(l3) # ['f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'y'] print(''.join(l3)) #fghijkmny
3.4.3 list赋值给变量
# 变量个数与列表内元素个数对应
v1,v2,v3,v4,v5 = [1,2,3,4,5]
print(v1,v2,v3,v4,v5) # 1 2 3 4 5
#变量个数与列表内元素个数不对应
v1,v2 = [1,2,3,4,5] # 报错too many values to unpack (expected 2)
print(v1,v2)
#变量个数与列表内元素个数不对应,但最后一个变量前面加*,代表剩余的所有内容
v1,v2,*v3 = [1,2,3,4,5]
print(v1,v2,v3) #1 2 [3, 4, 5]
3.5 元组(tuple)
元组和列表,字符串有很多的共同属性,像索引和切片,它们都是序列数据类型的两个基本组成
3.5.1元组操作
-
创建元组
python中,元组用一堆小括号()来表示,元组内的各元素以逗号分隔
t = () print(type(t)) #<class 'tuple'> t = ('good',) print(type(t)) #<class 'tuple'> t = ('good') #需注意这里定义元组时,如果不加逗号很容易定义成字符串 print(type(t)) #<class 'str'>
-
切片/索引与字符串和列表的操作一样
-
元组与字符串一样是不可变的,即不能修改元组的顶层元素的值
-
但元组中的某些元素是可变类型的话,就可以修改这些可变类型元素的值
l1 = [4,5,6] t = ('1',2,'b','w',l1) print(t)#('1', 2, 'b', 'w', [4, 5, 6]) #可以修改可变元素的内容,但也需要指到这个可变元素再修改其里面的值 t[-1][0]='x' print(t)# ('1', 2, 'b', 'w', ['x', 5, 6]) #顶层元素不能修改 t[1]='x'#报错'tuple' object does not support item assignment t[-1]='x' #报错'tuple' object does not support item assignment #元组中单个元素也不能删除,只能删除整个 t1 = (1,2,3) del t1[1] # 报错 'tuple' object doesn't support item deletion del t1 #可以
-
拼接、相乘、成员资格都与字符串、列表类型一样
t1 = (1,2,3) t2 = ('a','b','c') t3 = t1 + t2 print(t3) #(1, 2, 3, 'a', 'b', 'c') print(t2 * 2 ) #('a', 'b', 'c', 'a', 'b', 'c') print('a' in t1)#False print('a' not in t1)#True
-
打包、解包
t = 'a','b',1 print(t) #('a', 'b', 1) a,b,c = t print(a,b,c) #a b 1
-
平行赋值
x,y = 'a','b' print(x)#a print(y)#b
-
max(),min(),len()等公共方法
t1 = (1,2,3) print(max(t1))#3 print(min(t1))#1 print(len(t1))#3
-
元组转换
print(tuple(['a','dd',1])) #('a', 'dd', 1) print(list((1,2,3))) #[1, 2, 3]
3.5.2 list与tuple
首先下载ipython模块
终端执行
#配置国内的镜像地址
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
清华:https://pypi.tuna.tsinghua.edu.cn/simple
阿里:https://mirrors.aliyun.com/pypi/simple/
豆瓣:https://pypi.douban.com/simple/
华中理工大学:https://pypi.hustunique.com/
山东理工大学:https://pypi.sdutlinux.org/
中国科学技术大学:https://pypi.mirrors.ustc.edu.cn/pip install ipython
进入ipython交互模式
有此可见,元组的性能要高于列表
-
哈希的应用
一般来说,Hash,一般翻译做“散列“,也有直接音译为”哈希“,就是把任意长度的输入(又叫做映射,pre-image),通过散列算法,变换成固定的长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是散列的空间通常远小于该输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值,简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
Python中可哈希(hashable)的类型:字符串,元组(所有元素都需不可变),对象。可哈希类型就是我们常说的不可变类型,优点是性能经过优化,多线程安全,不需要锁,不担心恶意篡改或者不小心修改了。
不可哈希类型:字典,列表,集合相对于可哈希类型,使用起来相对灵活。
import hashlib md52=hashlib.md5() file_path = r"E:\pycharm\workspace\Project1\file1\xxx.txt" f = open(file_path,'rb') for i in f: md52.update(i) print(md52.hexdigest()) #8c6f9574be701a962a0ee334280a7b9e
-
练习
""" 1 生成一副扑克牌(自己设计扑克盘结构,大小王用14 ,15 代替等) 2 3个玩家 3 发牌规则:默认先给优化发三张一张牌,其中J、Q、K、A 大王小王 代表的值是 0.5,其他是牌面值 4用户根据自己的选择继续要牌 要在给他发一张(可以一直要牌,但手里的牌总分大于11就会清空手中的得分) 不要,开始发个下个玩家(没有要牌得分则加0) """ poker_list = [] user_list = ["张三", '李四', '王五'] #user_list = ["张三"] color_list = ['方块', '梅花', '红桃', '黑桃'] list1 = [("大王", '0.5'), ("小王", '0.5')] poker_dict = {} for color in color_list: for i in range(2, 11): poker = (f'{color}{i}', i) poker_list.append(poker) for x in ("J", "Q", "K", "A"): poker = (f"{color}{x}", 0.5) poker_list.append(poker) [("大王", 0.5), ("小王", 0.5)] poker_list += [("大王", 0.5), ("小王", 0.5)] # print(len(poker_list)) # print(poker_list) import random cishu = 0 while True: for name in user_list: flag = input(f"{name}Y/N:").strip() if not flag: continue if flag.upper() == "Y": index = random.randint(0, len(poker_list) - 1) poker = poker_list.pop(index)#发的牌 totalnum = poker[1] + poker_dict.setdefault(name,0) #牌面总和 print(f'本次给{name}发牌{poker},当前牌面总和为{totalnum}') if totalnum >11: poker_dict[name] = 0 print(f"{name}牌面总和大于11,清0!!") else: poker_dict[name]=totalnum else: poker_dict.setdefault(name,0) print(f'{name}选择不抽取,得分加0') print(poker_dict) cishu +=1 if cishu == 3: break #print(max(poker_dict))
3.5 字典 (dict)无序
我们知道,无论字符串、列表、元组都是将数据组织到一个有序的结构中,然后通过下标所以处理数据,这几种数据结构虽然已经满足大多数场景了,但是依然不够丰满,现在了解一种通过键(key)值(value)来处理数据的数据类型–字典(dict),这种键值对应的关系我们称之为映射关系。字典是目前为止,Python唯一的内建的映射类型的数据类型。需要说明的是,从Python3.6开始,字典的元素存储顺序由各键值对根据存储的顺序而定,但依然不支持索引取值。
字典是无序的可变数据类型,通过一个{}创建,格式为key:value,key是唯一的
字典相较于有序类型,它有更优查询性能
字典的key只能是可哈希类型,即只能是不可变类型
#列表
goods = ['apple','orange','banana']
price = ['20','30','40']
#字典
dict1 = {"apple":"20","orange":"30","banana":"40"}
print(dict1["apple"]) #20
#创建字典
dict1= {}
print(dict1)#{}
dict1 = dict()
print(dict1)#{}
dict1 = dict(apple=20,banana=30)
print(dict1)#{'apple': 20, 'banana': 30}
dict1 = {'apple': 20, 'banana': 30}
print(dict1)#{'apple': 20, 'banana': 30}
3.5.1增删改查 (通过key来操作)
#增
dict1 = {}
dict1["name"] = "张三"
print(dict1) #{'name': '张三'}
#修
dict1["name"] = "李四"
print(dict1) #{'name': '李四'}
#删
del dict1["name"]
print(dict1)#{}
dict1 = {'name': '张三','name2': '李四'}
del dict1["name"],dict1["name2"]
print(dict1)#{}
del dict1 #删除整个字典
#查
dict1 = {'name': '张三','name2': '李四'}
print(dict1["name"]) #张三
- 成员资格 只判断key
dict1 = {'name': '张三','name2': '李四'}
print( "name" in dict1) #True
print("张三" not in dict1 ) #True
-
for 循环
dict1 = {'name': '张三','name2': '李四'} for a in dict1: print(a) ''' name name2 ''' for key in dict1.keys(): print(key) ''' name name2 ''' for value in dict1.values(): print(value) ''' 张三 李四 ''' for items in dict1.items(): print(items) ''' ('name', '张三') ('name2', '李四') ''' for key,value in dict1.items(): print(key,value) ''' name 张三 name2 李四 '''
3.5.2 常用方法
-
update
dict1 = {'name': '张三','name2': '李四',"name3":"万物"} d = {"name":"aa","name4":"cc"} dict1.update(d) print(dict1) # {'name': 'aa', 'name2': '李四', 'name3': '万物', 'name4': 'cc'}
-
get
dict1 = {'name': '张三','name2': '李四',"name3":"万物"} print(dict1["name"])#张三 print(dict1.get("name"))#张三 print(dict1.get("name4")) #取不存在的key值,返回null print(dict1["name4"]) #取不存在的key值,报错 print(dict1.get("name4","没有这个key时,返回这部分值")) #没有这个key时,返回这部分值 print(dict1.get("name4",False))#没有这个key时,返回这部分值 print(dict1.get("name3",False))#万物
-
setdefault(key,value) 如果存在这个key,就返回对应的value,没有就这个字典添加这个key
dict1 = {'name': '张三','name2': '李四',"name3":"万物"} print(dict1.setdefault("name"))#张三 print(dict1.setdefault("name4"))#None print(dict1)#{'name': '张三', 'name2': '李四', 'name3': '万物', 'name4': None} print(dict1.setdefault("name5","aa")) print(dict1)#{'name': '张三', 'name2': '李四', 'name3': '万物', 'name4': None, 'name5': 'aa'} print(dict1.setdefault("name","xx"))#张三 print(dict1)#{'name': '张三', 'name2': '李四', 'name3': '万物', 'name4': None, 'name5': 'aa'}
-
pop/popitem
dict1 = {'name': '张三','name2': '李四',"name3":"万物"} res = dict1.pop("name") print(res)#张三 print(dict1)#{'name2': '李四', 'name3': '万物'} dict1 = {'name': '张三','name2': '李四',"name3":"万物"} res = dict1.popitem() print(res)#('name3', '万物') print(dict1)#{'name': '张三', 'name2': '李四'}
练习
# 获取用户名和密码,生成字典值
# 用户名不能重复
user_dict = {}
num = 0
while True:
user = input("user:").strip()
if not user:
continue
if user in user_dict:
print("已存在用户,请重新输入")
continue
pwd = input("pwd:").strip()
user_dict[user] = pwd
num +=1
if num == 3:
break
print(user_dict)
3.6 集合 (set)
Python 2.3版本时 引入了一种新的类型–集合(set)
集合是由序列(也可以是其他的可迭代对象)构建的,是无序的可变的数据类型
Python 中,集合用“{}”表示,集合内元素用逗号分隔
#定义一个空的{},表示定义的空的字典类型
a = {}
print(type(a)) #<class 'dict'>
#定义一个集合 必须按照如下定义
s = set()
print(type(s))#<class 'set'>
-
集合会将元素自动去重,集合内每一个元素都是唯一的
-
集合的元素只能是不可变类型数据,也就是可哈哈希类型,而比如列表、字典集合本身是不能作为集合的元素
-
集合不支持:索引,切片,拼接,复制
-
集合支持:成员运算,for循环
-
集合去重
l1 = [1,2,2,3,3,4] print(set(l1)) #{1, 2, 3, 4}
4 变量
昵称、外号、由变量来代指数据。
a = “中国陕西西安未央区大明宫”
print(“中国陕西西安未央区大明宫”) = print(a)
-变量名称中只能包含:字母、数字、下划线
-数字不能作为变量开头
-不能使用python内置的关键词:and/as/break/class/def…
-创建变量名时,做到见名知意
-多个单词可用_连接:name_color
-变量赋值时与 = 号有空格:name = “无敌”
5 输入
需求:输入姓名,提示“欢迎姓名访问XXXX系统”
name = input(“请输入姓名:”)
print(name)
–输入两个数字,让它们的相加结果输出
num1 = input("请输入数字1:") print(type(num1)) num2 = input("请输入数字2:") print(type(num2)) result = int(num1) + int(num2) print("它们的相加结果是:"+str(result))
6 注释
表明代码功能,使代码易于理解
python中 有 # 单行注释、“”“ ”“” 或 ‘’’ ‘’’ 多行注释
# # -*- coding:gbk -*- # print("账户错误!","账户正确,密码错误!","账户密码正确!") # print("账户错误!","账户正确,密码错误!","账户密码正确!",sep="-") # #------------------ # print("账户错误!","账户正确,密码错误!","账户密码正确!",end="") # print("账户错误!","账户正确,密码错误!","账户密码正确!",sep="-") ''' num1 = input("请输入数字1:") print(type(num1)) num2 = input("请输入数字2:") print(type(num2)) result = int(num1) + int(num2) print("它们的相加结果是:"+str(result)) ''' """ num1 = input("请输入数字1:") print(type(num1)) num2 = input("请输入数字2:") print(type(num2)) result = int(num1) + int(num2) print("它们的相加结果是:"+str(result)) """
7 条件语句
7.1 单条件判断
if 0: #0 这里代表条件,根据布尔值转换关系得知它为False,所以输出的是else分支
print("1")#python代码层级用缩进,一个tab键 4位
else:
print(2)
#也可以不用加else,条件成立就走、不成立就不走
开始
if 提交:
print("..........")
print("..........")
print("..........")
结束
7.2 多条件判断
name = "小明"
if name == "小M":
print("1.8米")
elif name == "小D":
print("1.6米")
elif name == "小明":
print("0.1米")
else:
print("Other")
7.3 条件嵌套
if 条件:
if 条件:
pass
else:
pass
else:
pass
8 循环语句
8.1 while 循环,适用于未知循环次数
#条件一直为真,进入死循环
print("开始")
while True:
print("while 循环")
print("结束")
# 让条件达到一定值得时候,返回False,从而退出循环
print("开始")
num1=1
while num1<10:
print("while 循环")
num1 +=1
#num1=num1+1
print(num1)
print("结束")
print("strat")
flag = True
while flag:
num1 = input("请猜数字:")
if num1=="1":
print("猜对了")
break #跳出循环
#flag = False
else:
print("猜错了,请继续")
continue #跳出当前循环,不在执行循环中后续代码,执行下次循环
print("123")
print("end")
8.2 for 循环,有限次数的循环 (遍历容器中的每一个对象)
for i in [1,2,3,4,5]:
print (i)
for循环一般与range 函数一起来使用:
v1 = range(5) #[0,1,2,3,4]
v2 = range(1,6) #[1,2,3,4,5]
v3 = range(1,10,2) #[1,3,5,7,9]
v4 = range(10,1,-1) #print(list(range(10,1,-1)))=[10,9,8,7,6,5,4,3,2]
v4 = range(10,-1,-1) #print(list(range(10,1,-1)))=[10,9,8,7,6,5,4,3,2,1]
for v1 in range(5):
print (v1)
for v2 in range(1,6):
print (v2)
for v3 in range(1,10,2):
print (v3)
for v4 in range(10,1,-1):
print (v4)
9 pass
保持语法的完整性,用于代替暂未实现的代码
if aa:
pass
else:
print("pass")
10 字符串格式化
10.1 %
#按顺序填充
name = "未央广场"
mj = 10000
text ="未央区有个%s,它的面积是平方%s米" %(name,mj)
print(text)
#按名称填充
name = "未央广场"
mj = 10000
text ="未央区有个%(name)s,它的面积是平方%(mj)s米" %{"name":name,"mj":mj}
print(text)
10.2 format
name ="未央广场"
mj=1000
#以下标去填充
text = "未央区有个{0},它的面积是平方{1}米".format(name,mj)
print(text)
text = "未央区有个{0},它的面积是平方{1}米,大家都喜欢去{0}跳两年半的广场舞".format(name,mj)
print(text)
#按顺序填充
text = "未央区有个{},它的面积是平方{}米".format(name,mj)
print(text)
-
无论是%还是format,含有站位符的字符串都是可以服用的
v1 = "未央区有个%s,它的面积是平方%s米" v2 = v1 %("大明宫","10000") v3 = v1 %("盛龙广场","1000") print(v2,v3,sep="\n") v1 = "未央区有个{},它的面积是平方{}米" v2 = v1.format("大明宫","10000") v3 = v1.format("盛龙广场","1000") print(v2,v3,sep="\n")
10.3 f-string (py3.6+)
name = "qwe"
age =3322
text = f"他叫{name},今年{age}岁"
print(text)
#还可以对字符串拼接,数字运算等
text = f"他叫{'asd'+name},今年{1000*age}岁"
print(text)
-
需求
- 实现用户输入用户名和密码进行登录;成功输出登录成功;否则登录失败
- 用户名=admin1,密码=password1
- 最多尝试3次,展示剩余次数
for i in range(3): admin = input("请输入用户名:") password = input("请输入密码:") if admin =="admin1" and password == "password1": print("登录成功") break else: print("失败") falg = f"剩余次数{2-i}" print(falg)
二 三元表达式和推导式
1 三元表达式
a = 1
if a == 2:
b = a
else:
b = 3
print(b) #3
###########################
b = a if a == 2 else 3
print(b) #3
2 列表推导式/列表生成式
l1 =[]
for i in range(10):
l1.append(i)
print(l1) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l2 = [i for i in range(10) ]
print(l2) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#可以加点条件
l3 = [i for i in range(10) if i % 2 == 0]
print(l3) #[0, 2, 4, 6, 8]
3 字典表生成式/字典推导式
d = {i : "xx" for i in range(10)}
print(d) #{0: 'xx', 1: 'xx', 2: 'xx', 3: 'xx', 4: 'xx', 5: 'xx', 6: 'xx', 7: 'xx', 8: 'xx', 9: 'xx'}
d = {i : "xx" for i in range(10) if i % 2 ==0}
print(d) #{0: 'xx', 2: 'xx', 4: 'xx', 6: 'xx', 8: 'xx'}
4 集合表生成式/集合推导式
s = {ss for ss in range(10)}
print(s) #{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s = {ss for ss in range(10) if ss % 2 != 0}
print(s) #{1, 3, 5, 7, 9}
5 元组没有推导式,类似推导式写法的是生成器表达式
三 字符编码
我们都经历过,在编写一份文档的时候,因为各种原因,电脑关机罢工了,然后你辛辛苦苦编写的内容都没了,只好从新编写,那你有没有想过这是为什么呢?因为我们打开word软件的时候,系统就将word中的内容读取到内存中,继续编写内容,这些内容此时其实也在内存中,而不是直接输入到了硬盘里面,只有你在做保存操作的时候,它才会在硬盘里面录入,二电脑关机导致断电,内存有断电数据丢失的特性,这些数据也就没了。我们现在了解下打开和保存,这其中的原理。
我们都知道电脑祥云工作必须通电,即用"电"驱使计算机干活,也就是电的特性决定了计算机的特性,电的特性即高电低平(人类从逻辑上将二进制数1对应高电平,二进制数0对应低电平),那我们就得出结论:计算机只认识数字。那么在使用计算的过程中,用的都是人能读懂的字符,如何让计算机也能读懂人类的字符呢?这必须经历一个过程:
字符 ----翻译过程----数字
而这个过程(如word保存数据的过程)实际就是一个字符如何对应一个特定数字的标准(过程),这个标准称为字符编码。
…
四 文件操作
通过open函数打开文件,其语法如下:
open(
file,
[mode = "r",buffering = None , Encoding=None,errors=None,newline=None,closefd=True]
)
open函数打开文件或文件描述并返回文件对象没如果无法打开则返回OSError错误
encoding参数指以什么方式操作文件,改参数只适用于文本模式
mode为可选参数,用于指定打开文件的模式,默认“r”,以读的方式打开文件常用的mode模式。
- r:读模式
- rb:二进制读模式:二进制一般在网络传输的时候使用,网络传输一般是二进制内容,此时就需要这种模式去操作
- w:写模式
- wb:二进制写模式
- a:追加写模式
- ab:二进制追加写
1 写文件
- 要写入的文件不存在,会自动创建,但不会创建文件夹
覆盖写
f1 = open("t1.txt",mode='w')#不加具体路径的话,会在运行程序同级目录下自动生成,有同名文件的话,会被直接覆盖掉
f1.write("1111111111111111111")
f1.write("2222222222222222222222")
f1.close()
f1 = open("t1.txt",mode='w')#不加具体路径的话,会在运行程序同级目录下自动生成,有同名文件的话,会被直接覆盖掉
f1.write("1111111111111111111\n")#加入换行符
f1.write("2222222222222222222222\n")
f1.close()
f1 = open("t1.txt",mode='w',encoding="utf-8")#加入以什么方式打开
f1.write("1111111111111111111\n")#加入换行符
f1.write("2222222222222222222222\n")
f1.close()
追加写 就是在原本的文件内容后面写入内容,但本身没有文件的话也会自动生成
f1 = open("t1.txt",mode='a')
f1.write("1111111111111111111")
f1.write("2222222222222222222222")
f1.close()
f1 = open("t1.txt",mode='a')
f1.write("1111111111111111111\n")#加入换行符
f1.write("2222222222222222222222\n")
f1.close()
f1 = open("t1.txt",mode='a',encoding="utf-8")#加入以什么方式打开
f1.write("1111111111111111111\n")#加入换行符
f1.write("2222222222222222222222\n")
f1.close()
二进制写文件实例,下载视频
import requests
res = requests.get(
url= "http://vd3.bdstatic.com/mda-nf36b2gy2d5wvk7z/360p/h264/1654316883201680366/mda-nf36b2gy2d5wvk7z.mp4"
)
#print(res.status_code)#请求结果
#print(res.encoding)
#print(res.headers)
#print(res.content) #二进制的文件内容
file_size = int(res.headers["Content-Length"])
print(file_size)
file_object = open("./file1/shiping1.mp4",mode="wb")
download_size = 0 #下载大小
#分块读取请求到的文件内容(最多一次128字节),并逐一写入袋文件中,len(chk)表示实际地区到每块的文件大小
for chk in res.iter_content(128):
download_size += len(chk)
file_object.write(chk)#写入文件
file_object.flush()#把 内存中的信息加载到文件,这个每块内容加载一下、
message = f'视频总大小为{file_size},目前下载进度为{download_size}/{file_size}'
print(message)
file_object.close()#关闭文件流
res.close()#关闭请求
- 如果是图片,音频,视屏这类二进制类型文件,直接使用"wb"、“ab”模式
- 注意如果是二进制写入模式打开的文件,千万不要指定encoding参数,包括读和写都有这个规则。
- 注意,如果是非二进制文件,务必要指定encoding,包括读和写都有这个规则。
2 读文件
read()
f = open(r"./file1/test1")
data = f.read() #读取文件,默认读取所有
print(data)
data1 = f.read()##同一个文件流只能读取一次,否则第二次读取的内容是不存在第一次读取的内容
print(data1)#结果为空
#---------------------------------------------
f = open(r"./file1/test1")
data2 = f.read(3)#读取文件,指定读取多少个字符
print(data2)
readline() #读一行
readlines()#以列表的形式读取所有行,每一行就是列表的一个元素
f = open(r"./file1/test1")
print(f.readline())#读第一行
f = open(r"./file1/test1")
print(f.readlines())#读取所有行,返回的是一个列表
f = open(r"./file1/test1")#同一个文件流只能读取一次,否则第二次读取的内容是不存在第一次读取的内容
print(f.readlines()[1])#按照列表下标读取到哪一行的内容
seek tell
f.seek(3) #移动光标到指定的字节后面,注意中文对应3个字符,比较难计算,不推荐使用
f.tell() #返回此时光标的位置
for 循环
f = open(r"./file1/test1")\
for i in f:
print(i)
f.close()
3 with 语句
收到关闭用close(),但每次手动关闭文件比较麻烦,Python有提供了with语句解决这个问题
with语句
with open(...) as f:
f.write("ssssssssss")
with open(...) as f:
f.read()
五 函数
在之前的学习中,只是使用了Python的一些简单功能,这些功能也只是有简单的流程控制语句配合数据类型实现,但是这些出现有着无法避免的缺陷,比如说:
- 代码的耦合性太差,各功能都耦合在一起,干湿 不分离
- 扩展性差,由于代码都揉在一起,如果要添加新功能的话,需要费很大的劲
- 代码冗余,比如实现一个语法功能,那么当别处还需要这个功能的话,还要写实现这个功能
- 可读性差
这种情况下,就需要引入函数来规避这些问题
1 函数的定义和调用
通过def 关键词来定义,
fundction_name 函数名,必须存在
()必须有,里面的入参可以有,也可以没有
paas 表示函数实现具体功能的部分
执行结果可以视情况选择使用return,如果不使用,则默认返回None
虽然dsf为关键字,但def也是可执行的语句,就是说当定义王函数之前,这个函数此时是不存在的
def <function_name>[arg1,arg2...argn]:
""" functional annotation"""
pass
return
定义完函数,调用需加括号
#定义
def sumab(a,b):
print(a + b)
#调用
sumab(1,2) #3
#可以指向其他变量
fun1 = sumab
#和sumab一样调用
fun1(1,2)#3
2 返回值
return后面的代码不执行
def sumab1(a,b):
r1 = a + b
return r1
res1 = sumab1(1,2)
print(res1) #3
#多个返回值时,以元组的类型返回
def sumab(a,b):
r1 = a + b
r2 = a - b
r3 = a * b
return r1,r2,r3
res = sumab(1,2)
print(res) #(3, -1, 2)
3 函数的对象
在Python中,函数可以被当做书序传递,也就是说。函数可以被引用,被传递,也可被当做返回值,也可当做容器类型(元组,列表)的元素
函数被引用
#定义
def sumab(a,b):
print(a + b)
#可以指向其他变量
fun1 = sumab
#和sumab一样调用
fun1(1,2)#3
函数可以被当做函数的参数
def bar():
a=1
print(a)
def foo(b):
b()
foo(bar)
# bar函数被当做foo函数的实参传递给形参b
#-------------------
def bar():
a=1
return a
def foo(b):
c = b()
print(c)
foo(bar)
# bar函数被当做foo函数的实参传递给形参b
函数可当做容器类型的元素
def jia():
print("start add")
def jian():
print("start jian")
def chen():
print("start chen")
dict1 = {"jia":jia,"jian":jian,"chen":chen}
content = input("Enter inst:").strip()
if content in dict1:
#dict1[content]()
fun = dict1[content]
fun()
else:
print("NO this inst")
4 函数的参数
有参函数的参数传参方式一般为按位置传参,按关键字传参,接收可变长度的参数,命名关键字参数。而在传递参数的时候,一般根据参数的实际意义来划分,函数接收的参数为形式参数,调用函数的参数为实际参数。
def foo(value):#value 形参,形式参数
pass
foo(3) # 3实参,实际参数
-
常规参数,按位置传参
-
必须被传值
-
传入的实参与形参个数须一致
-
def foo(v1,v2,v3):
print(v1,v2,v3)
foo(1,2,3)
- 按关键字传参,通过变量名匹配传参,
def foo(value=None,value1=None):#实参与形参个数无须一致
print(value)
print(value1)
foo(2)
#2
#None
foo(value1=2,value=3)#实参与形参顺序无序一致
#3
#2
#可以和位置传参搭配使用,但需注意顺序须一致
def foo1(value,value0,value1=None):
print(value)
print(value0)
print(value1)
foo1(2,2,3)
# 2
# 2
# 3
foo1(2,3,value1=1)
# 2
# 3
# 1
- 接收任意长度的参数,传入的是元组类型
def foo(*args):
print(args)
foo(1,2,3) #(1, 2, 3)
foo(1) #(1,)
foo("aa","ccss",1,3) #('aa', 'ccss', 1, 3)
# 和按位置传入搭配
def foo(value,*args):
print(value)
print(args)
foo(1,2,3,4)
# 1
# (2, 3, 4)
- 接收不固定长度的关键字参数,传入的是字典类型
def foo(**kwargs):
print(kwargs)
foo()# {}
foo(a=1,b=2)# {'a': 1, 'b': 2}
#常在一起用
def foo(*rags,**kwargs):
- args的聚合和打散
def foo(*args):#聚合
print(args)
#(1, 2, 3, 4)
print(*args) #打散
#1 2 3 4
foo(1,2,3,4)
def foo2(values):
print(values)
#[1, 2, 3, 4]
print(*values) #打散
#1 2 3 4
foo2([1,2,3,4])
-
利用聚合打散的特性,使用*rags,**kwargs 作为实参传入函数
#输入的参数不打散的情况 def foo(*args,**kwargs): print(args) # ([1, 2, 3], {'aa': '123', 'bb': '456'}) print(kwargs) #{} foo([1,2,3],{"aa":"123","bb":"456"}) #不打散 #输入的参数打散的情况 def foo1(*args,**kwargs): print(args) # (1, 2, 3) print(kwargs) #{'aa': '123', 'bb': '456'} foo1(*[1,2,3],**{"aa":"123","bb":"456"}) #打散
-
函数参数的坑
函数参数的默认值设置成了可变类型
不可变:None,int,float,bool,str,tuple
可变:list,dict,set
def foo(v1,v2=[]):
v2.append(v1)
print(v2)
foo(1)#[1]
foo(1,[22,33])#[22, 33, 1]
foo(3)#[1, 3] 坑
foo(4)#[1, 3, 4] 坑
所以注意:函数的默认值尽量不要设置成可变类型
- 函数的参数—引用or值?
- 引用,内存地址同一个
- 值,新创建一个数据
def foo(v1):
print(id(v1))
name ="root"
print(id(name))
foo(name)
#发现是同一个地址,多以函数的参数是引用
def foo(v1):
v1.upper()
print(v1)
print(id(v1))
name ="root"
print(id(name))
foo(name)
print(id(name))
print(name)#root
#函数传递是,默认不是拷贝一份,而是同一个引用
#字符串中执行某个方法,不会对原来的数据进行改变会新生成一个数据改变。
def foo(v1):
v1.append(999)
print(v1)
print(id(v1))
name =[11,22]
print(id(name))
foo(name)
print(id(name))
print(name)#[11, 22, 999]
#函数传递是,默认不是拷贝一份,而是同一个引用
#列表执行某个方法,不会新生成一个新列表,而是改变原来的列表
5 函数作用域&global
-
作用域,一块内存区域,里面存储了一些数据,在这块区域的人就可以共享区域中的数据。
-
在python中,执行函数时,就会创建一个作用域。
-
函数默认执行时,会有一个全局作用域。
-
根据缩进关系,一个变量被操作时,如果在本身层级找不到这个变量的原始定义,就会在父集中查找
global全局变量
# 全局变量 name = "陕西省西安市" num1 = "10000" def func(v1, v2): # 局部变量 num1 = 300 v3 = v1 + v2 print(v3) func(10, 20) #30 print(num1) #10000
# 全局变量 name = "陕西省西安市" num1 = "10000" def func(v1, v2): global num1 #把这个值定义成全局变量,其实是对它父级同名变量的重新赋值 num1 = 300 v3 = v1 + v2 print(v3) func(10, 20) #30 print(num1) #300
-
注意,字符串这些不可变数据类型的操作
# 全局变量 name = "abcd" num1 = "10000" def func(v1, v2): # 局部变量 global name name.upper()#因为这里根据字符串特性其实是新创建了一个变量,并没有修改原来的变量 v3 = v1 + v2 print(v3) func(10, 20) #30 print(name) #abcd #所以这里还是输出小写的字符串
-
注意,列表这些可变数据类型的操作
name = [1,2,3] num1 = "10000" def func(v1, v2): # 局部变量 global name name = ["a","b","c"]#根据列表特性其实是修改了原来的变量 v3 = v1 + v2 print(v3) func(10, 20) #30 print(name) # ["a","b","c"]#所以这里输出的是新的列表值 #------------ # 全局变量 name = [1,2,3] num1 = "10000" def func(v1, v2): name.append("a")#这里是因为在子集(同级)里面没有找到这个变量的原始定义,所以去它的父级查找了,再根据列表的特性操作了此变量 v3 = v1 + v2 print(v3) func(10, 20) #30 print(name) # [1, 2, 3, 'a'] #所以这里的name变量的值变了 #------------ # 全局变量 name = [1,2,3] num1 = "10000" def func(v1, v2): name=["a","b"] name.append("c")#这里是因为在子集(同级)里面找到了这个变量的原始定义,所以没去它的父级查找了 v3 = v1 + v2 print("子集name:",end="") print(name) #子集name:['a', 'b', 'c'] func(10, 20) #30 print("父级name:",end="") print(name) # 父级name:[1, 2, 3] #所以这里的name变量的没有变
-
一般情况下,global用于进行重新赋值
# 全局变量 name = [1,2,3] num1 = "10000" def func(v1, v2): global name name = 1111 v3 = v1 + v2 print(v3) func(10, 20) #30 print(name) # 1111
6 函数的嵌套
1 嵌套
def func1():
print("第1层")
def func2():
print("第2层")
def func3():
print("第3层")
def func4():
print("第2层2")
func1()
# 第1层
>>>只输出这个
def func1():
print("第1层")
def func2():
print("第2层")
def func3():
print("第3层")
def func4():
print("第2层2")
func1()
#
# >>>输出为空
def func1():
print("第1层")
def func2():
print("第2层")
def func3():
print("第3层")
func3()
func2()
def func4():
print("第2层2")
func4()
func1()
# 第1层
# 第2层
# 第3层
# 第2层2
# >>>全部都输出了
由上可知,嵌套函数调用,是由外到内,且每个函数想要执行都需要在同层级被调用,如果外层函数没有调用,就算内层函数有被调用也不会执行
2 嵌套加返回值
n1 =0
n3 =0
def func1(v1):
n1 = v1 +10 #20
def func2(v2):
n2 = v2+20 #40
return n2
n3 = func2(n1)
return n1 +n3 #60
res = func1(10)
print(res) #60
3 闭包
def func1(v1):
def func2():
return v1 + 1
return func2 #注意 想要闭包这里返回的一定是函数名,如果加上括号,那返回的是结果,是不能再次被调用的
f1 = func1(10) #闭包
f2 = func1(20) #闭包
f3 = func1(30) #闭包
res1 = f1()
res2 = f2()
res3 = f3()
print(res1,res2,res3) #11 21 31
7 装饰器
1 装饰器的本质
Python中的装饰器本质上就是对闭包的应用:
# 发送邮件功能
def send_email(toemail,name,content):
print("发送给:",toemail,name,content)
send_email(" 1234@163.com","zhangsan",'年薪100W')
#需求,在每次发送邮件之前,进行一个操作,例如:print("发工资了!!")
# 1 先用闭包原理实现send_email功能
def outer(func):
def inner(toemail,name,content):
func(toemail,name,content)
return inner
f1 = outer(send_email) #利用闭包原理,把send_email函数放入另一个函数里面
f1(" 1234@163.com","zhangsan",'年薪100W') # 这里的调用就实现了send_email(" 1234@163.com","zhangsan",'年薪100W')的调用
# 2 然后在闭包函数里面在send_email功能之前或者之后,实现一些其他的功能
def outer(func):
def inner(toemail,name,content):
print("发工资了!!") # 根据需求在发送邮件之前进行某种操作
func(toemail,name,content)
return inner
f1 = outer(send_email) #利用闭包原理,把send_email函数放入另一个函数里面
f1(" 1234@163.com","zhangsan",'年薪100W') # 这里的调用就实现了send_email(" 1234@163.com","zhangsan",'年薪100W')的调用,且在这个功能前后添加一些其他操作
- 以上代码看似复杂且无用,,但其实它有一个很大的优势:即在不改变原函数的情况下,可以对此函数从入参,输出上进行扩展和修改。
2 @语法、装饰器的入参、返回值
在python中内部支持@函数语法 + 闭包
def outer(func):
def inner(toemail,name,content):
print("发工资了!!") # 根据需求在发送邮件之前进行某种操作
func(toemail,name,content)
return inner
@outer
def send_email(toemail,name,content):
print("发送给:",toemail,name,content)
send_email(" 1234@163.com","zhangsan",'年薪100W') #然后调用它就相当于,outer(send_email)(" 1234@163.com","zhangsan",'年薪100W')
以上代码可以在优化一下
def outer(func):
def inner(*args,**kwargs):#有时候不知道被包裹的函数有哪些入参,可以使用这种写法,灵活对应参数,注意这是形参
print("发工资了!!")
func(*args,**kwargs)#注意这是实参
return inner
@outer #加上这个之后,就等价于 send_email = outer(send_email)
def send_email(toemail,name,content):
print("发送给:",toemail,name,content)
send_email(" 1234@163.com","zhangsan",'年薪100W')
还可以在优化一下返回值
def outer(func):
def inner(*args,**kwargs):#有时候不知道被包裹的函数有哪些入参,可以使用这种写法,灵活对应参数,注意这是形参
print("发工资了!!")
res = func(*args,**kwargs)#注意这是实参
return res #在这里加上返回值,如果这个函数没有返回值,则返回的是None
return inner
@outer #加上这个之后,就等价于 send_email = outer(send_email)
def send_email(toemail,name,content):
print("发送给:",toemail,name,content)
return "发送成功"
result = send_email(" 1234@163.com","zhangsan",'年薪100W')
print(result)
#执行结果
# 发工资了!!
# 发送给: 1234@163.com zhangsan 年薪100W
# 发送成功
所以装饰器是什么?
-
作用:在不修改原来代码的基础上,在代码前后执行自定义操作
-
如何实现?
-
创建嵌套函数
def outer(func): def inner(*args,**kwargs): res = func(*args,**kwargs) return res return inner
-
应用在被装饰的函数中
@outer def send_email(toemail,name,content): print("发送给:",toemail,name,content) return "发送成功"
-
3 网络请求异常重试案例
import requests
def recover1(func):
def inner(*args,**kwargs):
num1 =3
for i in range(num1):
try:
res = func(*args,**kwargs)
except Exception as e:
print(e)
print("请求异常重试第{}次".format(i+1))
continue
return res
return inner
@recover1
def request1(url):
res = requests.get(url,timeout=3)
print(res.status_code)
res.close()
8 内置函数
Python内部为我们提供的功能
https://docs.python.org/zh-cn/3/library/functions.html
#1
abs #绝对值
pow #次方
sum #求和
divmod #商和余数
v1,v2 =divmod(93,10)
print(v1,v2) #9 3
round #保留小数点后几位,四舍五入
v3 = round(1.234444,3)
print(v3) #1.234
#2-------------
min #求最小值
max #求最大值
#注意这求最大值和最小值得函数入参有一个key,这个入参可输入也可以不输入,输入之后就会以key的表达式代表的条件去取最大值或者最小值
#且这个key的值必然是个可执行的函数,key前面的参数会作为入参传入到到这个可执行的表达式中
#比如,在如下字典中得到年龄最大或者最小的人
dict1 = {"张三":11,"李四":22,"王五":24}
print(max(dict1.items(),key=lambda x:x[1]))#dict1.items()是实参,x是形参,,这里dict1.items()作为入参传入到这个匿名函数里面
all #判断内部元素转换成布尔值,都为true返回True,否则返回false
any #判断内部元素转换成布尔值,只要存在True,则返回false
#3------进制之间的转换
#二进制和十进制
# 10 ---> 2
bin1 =bin(100)
print(bin1) #0b1100100
# 2----> 10
int1 = int("0b1100100",base=2)
print(int1)#100
#八进制和十进制
#10 ---> 8
oct1 = oct(100)
print(oct1)
#8 ---> 10 #0o144
int2 = int("0o144",base=8)
print(int2) #100
#十六进制和十进制
#10 ---> 16
hex1 = hex(100)
print(hex1) #0x64
#16 ---> 10
int3 = int("0x64",base=16)
print(int3)#100
#4--------unicode码点
#ord 根据文本获取对应的十进制数
v1 = ord("A")
v2 = ord("陕")
print(v1)#65
print(v2)#38485
#转换成其他进制
print(hex(v1))#0x41
print(hex(v2))#0x9655
#chr 根据十进制数转换成对应的文本
v3 = chr(65)
v4 = chr(38485)
print(v3)#A
print(v4)#陕
#5-----常见的数据类型函数
str
bool
list
dict
tuple
int
float
set
bytes
#6-------
len
print
input
open #文件
range
type #查看类型
id #查看数据内存地址
callable #是否可执行
def fun1():
pass
v1 = 123
print(callable(fun1)) #True
print(callable(v1)) #False
enumerate #循环过程中自动生成一列(序号)
goods = ["a","b","c"]
for i in goods:
print(i) # a b c
for idx,i in enumerate(goods,10):#10这里表示生成的列从10开始
print(idx,i)
#10 a
#11 b
#12 c
sorted #排序
#注意字符串的排序是根据收个字符的大小(Unicode)进行操作的
#数字和字符串是无法进行排序的
#注意这排序的函数入参有一个key,这个入参可输入也可以不输入,输入之后就会以key的表达式代表的条件去取排序,且这个key的值必然是个可执行的函数,key前面的参数会作为入参传入到到这个可执行的表达式中
#比如,按照第一个字符的大小进行排序
list1 = [
"1 raaewaa.txt",
"4 wdddd.txt",
"7 3feeee.mp3",
"2 ggbbbb.txt",
"3 w2cccc.txt"
]
#普通实现方法
def fun0(v0):
return int(v0.split(" ")[0])
ret = sorted(list1,key=fun0)
print(ret)
# ['1 raaewaa.txt', '2 ggbbbb.txt', '3 w2cccc.txt', '4 wdddd.txt', '7 3feeee.mp3']
#用匿名函数实现
ret1 = sorted(list1,key=lambda list1:int(list1.split(" ")[0]))
print(ret1)
# ['1 raaewaa.txt', '2 ggbbbb.txt', '3 w2cccc.txt', '4 wdddd.txt', '7 3feeee.mp3']
9 lambda表达式
lambda表达式也可以称作匿名函数。
-
创建简单的函数(一行代码表示+ 内置return)
#普通函数 def fun1(a1): return a1 +99 print(fun1(1))#100 #通过匿名函数表达 fun2 = lambda a2:a2+99 print(fun2(1))#100
-
匿名函数
def fun1(): return 100 def fun2(): return 200 func_list = [fun1,fun2]
func_list = [lambda : 100,lambda : 200]
案例
-
对字符串进行切割并获取局部数据,定义函数接收参数,处理得到后缀名并返回
name = "filename_xxx.txt" def fun1(v1): return v1.split(".")[-1] print(fun1(name)) #txt #用匿名函数实现 fun2 = lambda v1:v1.split(".")[-1] print(fun2(name)) #txt
-
函数当做参数进行传递
# 按照第一个字符的大小进行排序 list1 = [ "1 raaewaa.txt", "4 wdddd.txt", "7 3feeee.mp3", "2 ggbbbb.txt", "3 w2cccc.txt" ] #普通实现方法 def fun0(v0): return int(v0.split(" ")[0]) ret = sorted(list1,key=fun0) print(ret) # ['1 raaewaa.txt', '2 ggbbbb.txt', '3 w2cccc.txt', '4 wdddd.txt', '7 3feeee.mp3'] #用匿名函数实现 ret1 = sorted(list1,key=lambda list1:int(list1.split(" ")[0])) print(ret1) # ['1 raaewaa.txt', '2 ggbbbb.txt', '3 w2cccc.txt', '4 wdddd.txt', '7 3feeee.mp3'] #还可以取第一个字符值最大的一个元素 ret2 = max(list1,key=lambda list1:int(list1.split(" ")[0])) print(ret2) #7 3feeee.mp3
10 推导式+lambda表达式
-
lambda表达式本质是函数 + 未执行则里面的代码不会被调用
#没有入参的匿名函数 size = 19 func_list = [lambda:1+size,lambda:2+size,lambda:3+size] res = func_list[0]() print(res)#20
#没有入参的匿名函数 size = 19 func_list = [lambda:1+size,lambda:2+size,lambda:3+size] size = 20 res = func_list[0]() #这里执行函数,就从这里往上找size的值是多少 print(res)#21
#有入参的匿名函数 #没有入参的匿名函数 size = 19 func_list = [lambda x:x+1+size,lambda x:x+2+size,lambda x:x+3+size] res = func_list[0](100) print(res)#120
-
lambda +range
#没有入参的匿名函数 func_list = [lambda : 666 for i in range(10)] #res = func_list[0](100) print(func_list) #[<function <listcomp>.<lambda> at 0x0000000002880158>, <function <listcomp>.<lambda> at 0x00000000028808C8>, <function <listcomp>.<lambda> at 0x0000000002880950>, <function <listcomp>.<lambda> at 0x00000000028809D8>, <function <listcomp>.<lambda> at 0x0000000002880A60>, <function <listcomp>.<lambda> at 0x0000000002880AE8>, <function <listcomp>.<lambda> at 0x0000000002880B70>, <function <listcomp>.<lambda> at 0x0000000002880BF8>, <function <listcomp>.<lambda> at 0x0000000002880C80>, <function <listcomp>.<lambda> at 0x0000000002880D08>] #可见,利用for循环和range函数生成了10相同的个匿名函数,它们都等价于lambda:600 #调用其中一个 print(func_list[1]())#600
#给返回结果加上i后 func_list = [lambda : 666 + i for i in range(10)] #res = func_list[0](100) print(func_list[-1]) = print((lambda : 666+9)()) #这个可能好理解,但不一定理解的正确 #注意 print(func_list[0]) 不等于 print((lambda : 666+0)()) print(func_list[0]) 等于 print((lambda : 666+9)()) #因为在调用函数的时候,i已经等于9了
11 生成器函数
#1.生成器函数
def info():
v1 = 100
yield v1+10
v2 = 200
yield v2+10
v3 = 300
yield v3+10
return v1 +v2 +v3
#2.执行生成器函数,不会执行函数内部代码,而是返回生成器对象
print(info()) #<generator object info at 0x00000000028637D8>\
#3.想要执行生成器内部的代码,用next(),但也只会执行到第一个 yield,后面的不执行
print(next(info()))# 110
#4.想要执行继续执行,我们用for循环
ret = info() #把这个生成器赋值变量
for item in ret:
print(item) #相当于第一次执行yield v1+10,保持这个状态继续执行后面的 yield
# 110
# 210
# 310
# 由这个结果可知,在生成器函数中, return表示出现结束,并不能返回什么内容
#5.生成器函数的作用主要是在程序运行时减少内存的使用,在其 使用时才会创建一部分数据
六 模块
1 模块及导入规则
本质上就是创建一个py文件,或者一个文件夹下面一些py文件,使用import导入后使用
-
有内置模块,python自带的,可以直接import使用
-
有第三方模块,需要 pip下载,下载后一般在Lib\site-packages目录下面,或者在python安装目录+site-packages目录下面
-
自定义模块,我们自己编写的py文件
- 一般类似的功能(函数)放在一个(模块)py文件里面,而类似的模块放在同一个包(文件夹)里面
- python2中的包需要在文件夹下面放入
__init__.py
文件才能表示这个文件夹是一个python包,而python3之后就不需要了 - 导入模块是执行的这个py文件,导入包其实就是执行的
__init__.py
文件,所以可以在导入包的时候可以在__init__.py
里面设置一些其它属性
-
导入模块根据sys.path路径寻找相关文件
脚本所在的目录
python安装目录
python安装目录下 lib ,site-packages
1 注意同级py文件使用的话,可以直接 import 文件名
不同级的话,直接导入报错
此时需要加上文件路径
或者使用 from
2 注意 如果from的是一个py文件,则后面的import 可以直接导入这个文件里面的函数
-
导入问题1
直接import一个模块,它首先是找的是同级目录下的py 文件,没有的话,会在python的内置模块路径lib下面去找,所以这时如果在同级目录下有一个你导入内置模块同样名字的py文件,他就会找到这个文件作为导入的内容,不会再去内置lib路径下去寻找,而这个py文件一般是没有你想要导入的内置模块的内容,导致出错
-
导入问题 2
导入一个模块时,如果没有加上路径,优先会在同级陌路去寻找,然后去lib目录和site-packages等目录寻找 ,python 本身不会根目录去寻找,但使用pycharm时,会自动生成一个sys.path 从而找到根目录下存在的内容
-
pychram生成的sys.path
-
pychram生成的可以在根目录寻找到py文件
-
但python其实是不能导入上级目录的,我们使用cmd运行上面的py文件看看
-
所以为了防止我们在pycharm能运行的项目,打包到其他地方因为这个原因不能运行的话,我们需要主动添加sys.path
-
-
相对目录,绝对目录
from . import test4 # . 代表当前目录 from .. import test1 # .. 代表上级目录 from ..test1 import add # .. 代表上级目录
- 注意相对目录写法不能在根目录下使用
2 主文件和__name__
-
主文件:启动的文件
def run(): pass run()
def run(): pass if __name__ == "__main__":#注意是双下划线 run() """ __name__ 是一个内置变量 - 当运行当前文件时,__name__ 等于 __main__ - 当被导入后调用时,__name__ 等于 模块名称 一般情况下,主函数在项目中只有一个,其他函数都是被主函数所调用,则利用__name__这种机制就就可以作为启动程序 """
3 冲突
-
导入模块重名时,后面的模块会把前面的覆盖掉,为防止这种情况 我们使用 as 关键字取别名
import common.common1.test4 as m1 import test4 as m2
-
成员
from xxx.py import xxx,xxx,xxx,xxx #py文件里面的一些方法
4 内置模块
4.1 random
import random
# 1 在一个范围内生成随机整数
num1 = random.randint(1,10)
print(num1)
# 2 在一个范围内生成随机小数
num2 = random.uniform(1,10)
print(num2)
# 3 在一个容器内随机选择一个
choise1 = random.choice((1,10)) #只能有一个对象,可以使列表,元组,字符串,字典等
print(choise1)
choise2 = random.choice("abcgdha") #只能有一个对象,可以使列表,元组,字符串,字典等
print(choise2)
# 4 在一个容器内随机选择指定个数,返回列表类型
choise3 = random.sample((1,3,"cc","中国"),2) #只能在一个对象,可以使列表,元组,字符串,字典等 中选择
print(choise3)
# 5 随机打乱顺序
data_list = [11,22,33,44,55]
str1 = "abcde"
print(data_list)
random.shuffle(data_list) #打乱顺序,修改了原数据,无返回值,所以不可变类型数据无法使用这个方法打乱
print(data_list)
4.2 hashlib
此模块用于实现文本加密,例如MD5
#1 将文本加密
import hashlib
data = "中国上海"
obj = hashlib.md5() #加密成 md5 格式
obj.update(data.encode("utf-8")) #将数据加密
ret = obj.hexdigest()
print(ret)
#2 加密后再加盐
#md5 是无法反推的,网络上说的MD5解密其实是吧一些常见的密码和与其对应的MD5密文提前列出来,然后在这些数据里面去找的,这就叫所谓的撞库
#所以通常在对明文”加密“后需要再“加盐”(随机数据),也就是在密文的基础上面加一些随机数据来加大被撞库的难度
import hashlib
data2 = "中国上海"
obj = hashlib.md5("随机字符dhfhfhujui;'dsd".encode("utf-8")) #加密成 md5和 加盐 格式
obj.update(data.encode("utf-8")) #将数据加密
ret1 = obj.hexdigest()
print(ret1)
#既然MD5密文无法反推,那其实我们也是无法根据MD5密文来知道明文的,,所以我们一般是根据密文比对校验的,数据库也一般直接存储的密文密码
4.3 json
json:本质上是个特定的字符串格式
python中的一些数据类型转换为json后,会有吧区别:
类型 python json
tuple () []
空 None null
布尔 True true
布尔 False false
意义:打通不同编程语言之间进行相互通信时的数据格式问题
-
序列化(python数据格式–>json 数据格式)
info = {"v1":"123","v2":"sdsdfsf","v3":334} import json data_json = json.dumps(info) #转换成json格式 print(data_json) print(type(data_json))#<class 'str'> 本质是个字符串格式
-
反序列化(json 数据格式–>python数据格式)
data_json = '{"v1":"123","v2":"sdsdfsf","v3":334}' import json info = json.loads(data_json) print(info) print(type(info))#<class 'dict'>
- 网络请求,简单爬虫
import requests import json res = requests.get( url = "https://wenku.baidu.com/goods/interface/getgoodsinfo?goods_type=3&cashier_type=1&platform=pc&referDocId=1bcaf609660e52ea551810a6f524ccbff121caf0" ) #反序列化,把数据转换成json格式 data = json.loads(res.text)["data"] for item in data: print(item,data[item])
- 提供请求api,被其他程序可调用
from flask import Flask import json app = Flask(__name__) @app.route("/index") def index(): data_dict1 = {"v1":"123","v2":"sdsdfsf","v3":334} data_json1 = json.dumps(data_dict1) return data_json1 if __name__ == '__main__': app.run()
-
中文序列化
import json data_dict1 = {"v1":"123","v2":"sdsdfsf","v3":"中文"} data_json1 = json.dumps(data_dict1) #这里可以看见中文转换成json后 是一个unicode 编码 print(data_json1) #{"v1": "123", "v2": "sdsdfsf", "v3": "\u4e2d\u6587"} #增加参数让它正常显示中文 data_json2 = json.dumps(data_dict1,ensure_ascii=False) print(data_json2) #{"v1": "123", "v2": "sdsdfsf", "v3": "中文"}
-
python默认支持序列化的类型及转换结果
+-------------------+---------------+ | Python | JSON | +===================+===============+ | dict | object | +-------------------+---------------+ | list, tuple | array#数组=列表| +-------------------+---------------+ | str | string | +-------------------+---------------+ | int, float | number | +-------------------+---------------+ | True | true | +-------------------+---------------+ | False | false | +-------------------+---------------+ | None | null | +-------------------+---------------+
Python Json字符串 {"v1":"123","v2":"sdsdfsf","v3":"中文"}
{"v1":"123","v2":'sdsdfsf',"v3":"中文"}
'{"v1":"123","v2":"sdsdfsf","v3":"中文"}'
python中的单引号转换后变成双引号,也就是json字符串中不可能存在单引号[11,22,33]
(11,22,33)
[11,22,33]
[True,False]
[true,false]
-
文件
import json data_dict1 = {"v1":"123","v2":"sdsdfsf","v3":"中文"} with open("json_file1.json",mode="w",encoding="utf-8") as f: json.dump(data_dict1,f,ensure_ascii=False)
#反序列化 import json with open("json_file1.json",mode="r",encoding="utf-8") as f: data_dict1 = json.load(f) print(data_dict1)
-
缩进展示
import json data_dict1 = {"v1":"123","v2":"sdsdfsf","v3":"中文"} print(json.dumps(data_dict1,ensure_ascii=False)) #{"v1": "123", "v2": "sdsdfsf", "v3": "中文"} print(json.dumps(data_dict1,ensure_ascii=False,indent=2)) #indent=2) 表示缩进几个字符 # { # "v1": "123", # "v2": "sdsdfsf", # "v3": "中文" # }
-
python默认不支持转换为json格式的类型怎么处理?
如下,发现datetime类型转换为json 是报错
import json from datetime import datetime data_list = [ {"name":"王五","age":19,"ctime":datetime.now()}, {"name":"张六","age":20,"ctime":datetime.now()} ] ret = json.dumps(data_list,ensure_ascii=False) print(ret) #TypeError: Object of type 'datetime' is not JSON serializable
-
方法1 把不支持的类型转换为支持的类型
import json from datetime import datetime data_list = [ {"name":"王五","age":19,"ctime":datetime.now().strftime("%Y-%m-%d")},#转换为字符串格式 {"name":"张六","age":20,"ctime":datetime.now().strftime("%Y-%m-%d")}#转换为字符串格式 ] ret = json.dumps(data_list,ensure_ascii=False) # print(ret) # [{"name": "王五", "age": 19, "ctime": "2023-07-18"}, {"name": "张六", "age": 20, "ctime": "2023-07-18"}]
-
方法2 改写底层代码 JSONEncoder中的default函数
我们查看源码发现,dumps有个参数cls它默认为空,其实就是默认 cls=JSONEncoder,而JSONEncoder这个类里面有个default函数 ,就是它来控制—如果不是支持的类型则返回异常
则我们对这个default函数进行扩展,来让它支持datetime类型
import json from datetime import datetime from json import JSONEncoder data_list = [ {"name":"王五","age":19,"ctime":datetime.now()},#转换为字符串格式 {"name":"张六","age":20,"ctime":datetime.now()}#转换为字符串格式 ] class MyJSONEncoder(JSONEncoder): def default(self, o): #return super().default(o) #直接调用父类中的default if type(o) == datetime: #判断是否和datetime 同一个类型 return o.strftime("%Y-%m-%d") #返回规定的格式 ret = json.dumps(data_list,ensure_ascii=False,cls=MyJSONEncoder) # print(ret) # [{"name": "王五", "age": 19, "ctime": "2023-07-18"}, {"name": "张六", "age": 20, "ctime": "2023-07-18"}]
-
-
非标准格式的json数据转换为 python
import json from datetime import datetime from json import JSONEncoder json_data = '{"name":"小五","bool":False,"NULL":None}' #我们知道 json中 是false null 这种格式 #python_data = json.loads(json_data) #直接转换会报错 #此时我们用 eval() 函数来处理一下这个数据 ret = eval(json_data) #eval() 把入参当做函数执行 print(ret)#{'name': '小五', 'bool': False, 'NULL': None}
4.5 时间相关
-
time
import time #1 获取时间戳(自19700101) v1 = time.time() print(v1) #2 主动停止 while True: time.sleep(1) #程序运行到这里 主动暂停1秒 print("123")
-
datetime
from datetime import datetime as Datetime # 1 date1 = "2023-05-05" res1 = Datetime.strptime(date1,"%Y-%m-%d") print(res1) # 2023-05-05 00:00:00 #2 转换成固定格式的字符串 data2 = Datetime.now() print(data2) #2023-07-02 01:01:59.566563 res2 = Datetime.strftime(data2,"%Y/%m/%d") print(res2) #2023/07/02 #3 把时间戳转换datetime 类型 import time date3 = time.time() print(date3) # 1688231192.6871855 res3 = Datetime.fromtimestamp(date3) print(res3) #2023-07-02 01:06:32.687186 #把datetime类型转换成时间戳 date4 = Datetime.now() print(date4) #2023-07-02 01:11:05.118767 res4 = date4.timestamp() print(res4) #1688231465.118767
-
datetime 进行运算
from datetime import datetime, timedelta ctime = datetime.now() value1 = ctime + timedelta(hours=10,minutes=20,seconds=30)#表示给当前时间ctime 加上了10小时20分钟30秒 print(value1)
from datetime import datetime v1 = "2023-05-06 18:01:11" start_date = datetime.strptime(v1,"%Y-%m-%d %H:%M:%S") v2 = "2023-05-06 18:01:20" end_date = datetime.strptime(v2,"%Y-%m-%d %H:%M:%S") res_date = end_date - start_date print(res_date.seconds) #9
-
4.6 os
-
路径的拼接
import os path1 = os.path.join("db","demo","xxx.txt") print(path1) #db\demo\xxx.txt win系统 #db/demo/xxx.txt mac系统
-
路径的上级目录
import os path1 = os.path.join("db","demo","xxx.txt") print(path1) #db\demo\xxx.txt win系统 #db/demo/xxx.txt mac系统 path2 = os.path.dirname(path1) #获取此路径的上级目录 print(path2) #db\demo path3 = os.path.dirname(path2) #获取此路径的上级目录 print(path3) #db
-
绝对路径
import os path4 = os.path.abspath("t1.xtx") #它会在本程序的当前系统目录加上括号里面内容 print(path4) #E:\pycharm\workspace\Project1\t1.xtx path5 = os.path.abspath("aas") print(path5) #E:\pycharm\workspace\Project1\aas path6 = __file__ #表示本程序的系统路径(绝对路径) print(path6) #E:/pycharm/workspace/Project1/day1.py 注意:这里获取到的是正斜杠路径 path7 = os.path.abspath(__file__) #与path6取得路径一样只不过是反斜杠路径 print(path7)#E:\pycharm\workspace\Project1\day1.py
-
注意,我们说的程序执行的当前路径,是指的python运行这个py文件时的路径,并不是这个py文件本身的路径
-
判断路径文件是否存在,返回True/False
import os bool = os.path.exists("路径") print(bool)#False
-
创建文件夹
import os def mkdir(): os.makedirs("file2/file3")#相对路径下创建,就是在程序运行的当前目录开始 mkdir()
注意程序在什么地方开始运行
import os
def mkdir():
os.mkdir("E:/pycharm/workspace/Project1/common/file4")#指定绝对路径去创建
if __name__ == '__main__':
mkdir()
-
判断一个路径是文件夹 还是文件
import os bool = os.path.isdir("E:/pycharm/workspace/Project1/")#判断是否是个文件夹,不是或者不存在返回False,是则返回True print(bool)
-
删除文件夹 和 文件
import os os.remove("文件路径") #删除文件
import shutil shutil.rmtree("文件夹路径") #删除文件夹
-
查看目录下的文件或者文件夹,单级目录访问【只访问一级目录,嵌套在里面的文件夹不访问】
import os name_list = os.listdir("路径")
-
查看目录下的文件或者文件夹,多级目录访问【嵌套在里面的文件夹也访问】
# from common.test1 import mkdir # mkdir() import os path1 = os.path.abspath(__name__) paht2 = os.path.dirname(path1) g_walk = os.walk(paht2) print(os.walk(paht2))#<generator object walk at 0x00000000028D46D0>,发现这个是个生成器 for pathitem in g_walk: print(pathitem)
我们发现这个生成器每次生成的是一个元组,元组里面有三个元素,第一个字符串表示当前查找的目录路径,第二个列表元素表示当前查找的目录下面存在的文件夹,第三个列表元素表示当前查找的目录下面存在的文件;然在第二行开始就会把之前查到的第二个列表元素中的文件夹继续作为查找目录查找,以此递归下去
我们在上面的基础上修改一下代码,就可以得到查找目录下及它层层子目录下面所有文件的路径
import os
path1 = os.path.abspath(__name__)
paht2 = os.path.dirname(path1)
g_walk = os.walk(paht2)
print(os.walk(paht2))#<generator object walk at 0x00000000028D46D0>,这个是个生成器
for base_path,folder_path,filenames in g_walk: #将元素拆分
#print(base_path, folder_path, filename)
for filename in filenames:
print(base_path+"\\"+filename) #拼接目录和文件名称
4.7 sys
1 sys.path #导入模块时,查找的目录
2 sys.argv #运行脚本时输入的参数
3 程序打包后运行与sys的关系
python本身不支持打包,需要借助第三方模块pyinstaller
pip install pyinstaller
-
3.1 多文件打包
pyinstaller -D client.py
运行打包命令后,可见文件夹生成了 build,dist文件夹及client.spec文件
进入dist里面的cilent文件夹后可以看到client.exe的可执行文件
我们修改一下client.py文件内容后,再次使用同样的命令打包
然后在dist里面的cilent文件夹中找到client.exe 双击运行
- 3.2 单文件打包
pyinstaller -F client.py
运行打包命令后,可见文件夹生成了 build,dist文件夹及client.spec文件,但dist文件夹下面只有一个client.exe文件
双击运行client.exe 效果与多文件打包一样
-
3.3 这里说打包的原因就是,单文件打包后,双击运行它,它其实会在电脑里面的一个临时目录下去运行,,如果这个时候,代码中使用先获取文件本身路径在拼接绝对路径的时候,运行就会出问题
如下,本身py运行没问题的程序
打包后运行exe文件,可见它其实是在临时目录下去找这个文件,所以运行会报错
如何解决上述问题?可以利用sys.argv
如下,我们先看一下sys.argv第一个参数sys.argv[0]默认是什么
加入语句后打包,运行exe
可以看到,sys.argv[0]在这里就表示的是:exe文件的系统路径,而不是临时目录
利用这个机制稍加修改代码,就可以正常运行了
4.8 configparser
-
专门用于对.ini格式的文件 进行操作【一般用于项目的配置文件】
ini文件
[sercive] ip1 = 1111111 ip2 = 222222 ip3 = 33333 [client] c1 = aaa c2 = 222 c3 = 333
import configparser #1 打开文件 obj = configparser.ConfigParser() obj.read("myconfig1.ini",encoding="utf-8") #2 获取节点。返回列表 v1 = obj.sections() print(v1) #['sercive', 'client'] #3 获取节点里面的键值对,返回一个列表,里面是元组装着键值对 v2 = obj.items("sercive") print(v2) #[('ip1', '1111111'), ('ip2', '222222'), ('ip3', '33333')] # for k,v in v2: # print(k,v) # # ip1 1111111 # # ip2 222222 # # ip3 33333 #4 获取某个节点下某个键(变量)的值 v3 = obj.get("client","c1") print(v3) #aaa #5 包含 返回布尔值 v4 = obj.has_section("client") print(v4) #True v5 = obj.has_option("client","c4") print(v5) #False #6 添加 obj.add_section("app") obj.set("app","a1","baidu") obj.set("app","a2","xiaOMI") obj.set("app","a3","HEISHA") #此时只是添加到内存中,还需要写入文件 with open("myconfig1.ini",mode="w",encoding="utf-8") as f: #当然也可以写入其它文件中 obj.write(f)#需注意的是,obj包含之前本身存在的内容,所以写入后包含其他内容,不仅仅是添加的这一部分 #7 删除 obj.remove_option("app","a3") obj.remove_section("app") #此时只是删除内存中的内容,还需要更新文件 with open("myconfig1.ini",mode="w",encoding="utf-8") as f: obj.write(f) #8 修改 obj.set("client","c3","444") with open("myconfig1.ini",mode="w",encoding="utf-8") as f: obj.write(f)
4.9 xml
一种特殊的格式,用于表示或存储数据
text = """
<data>
<city name="上海" id="0011">
一线大城市
</city>
<erea>10000</erea>
</data>
"""
from xml.etree import ElementTree
root = ElementTree.XML(text)
node = root.find("city")
print(node)#<Element 'city' at 0x00000000028A6A98>
print(node.attrib)#{'name': '上海', 'id': '0011'}
print(node.text) # 一线大城市
4.10 re(正则表达式)
- 正则表达式,提取or校验你的数据。
- re模块Python中内置的模块,用于和正则表达式搭配。
1 正则表达式
text = “zheshiyiduanzifuchuan,我们可能需要提取里面的一些东西比如qq:111122233,邮箱:123@162.com,手机号:11111111111”
需求:
1 提取手机号: \d{11}
2 提取邮箱: \w+@\w+.\w+
- 提取一段字符串中符合正则表达式的内容 re.findall
import re
text = "zheshiyiduanzifuchuan,我们可能需要提取里面的一些东西比如qq:111122233,邮箱:123@162.com 123@163.com,手机号:12232324567"
res = re.findall(r"\d{11}",text)
ews = re.findall(r"\w+@\w+.\w+",text,re.ASCII)
print(res) #['12232324567']
print(ews) #['123@162.com', '123@163.com']
-
判断一段字符串是否匹配正则表达式,不匹配则返回None
import re email1 = "xxxccddff" email2 = "123@123.com" email3 = "123@123.com 2222222" res1 = re.match(r"\w+@\w+.\w+",email1) res2 = re.match(r"\w+@\w+.\w+",email2) res3 = re.match(r"\w+@\w+.\w+",email3) print(res1)#None print(res2)#<_sre.SRE_Match object; span=(0, 11), match='123@123.com'> print(res3)#<_sre.SRE_Match object; span=(0, 11), match='123@123.com'> #email3其实不是一个邮箱格式,所以我们需要在修改一下正则表达式,让它更加精准的判断,比如加上起始符^,结束符$ res4 = re.match(r"^\w+@\w+.\w+$",email3)#这样就规定这串字符串必须从开到结束都要满足这个表达式 print(res4)#None
1 正则表达式中字符相关
-
固定文本
import re text = "zheshiyiduanzifuchuan,我们可能需要提取里面的一些东西比如qq:111122233,邮箱:123@162.com 123@163.com,手机号:12232324567" res1 = re.findall(r"zheshiyiduanzifuchuan",text) print(res1) #['zheshiyiduanzifuchuan']
-
[]
#1 []表示[]内的某一个 [1cd]#表示 可以是1,可以是c,可以是d [1-9]#表示可以是1-9其中的某一个数字 [a-z]#表示可以是a-z其中的某一个字母
-
\d
# \d 表示任意的一个数字
-
\w
#表示 字母、数字、下划线、汉字 #如果加了 re.ASCII,就只表示 字母、数字、下划线 text = "zheshiyiduanzifuchuan,我们可能需要提取里面的一些东西比如qq:111122233,邮箱:123@162.com 123@163.com,手机号:12232324567" ews = re.findall(r"\w+@\w+.\w+",text,re.ASCII) print(ews) #['123@162.com', '123@163.com']
-
.
# . 表示除换行符之外的任意字符
2 正则表达式中数量相关
-
{n} 、 {n,} 、{n,m}
# 1 {n}表示匹配满足表达式n位的内容 -比如 \d{11} 表示匹配11位数字,小于11位不匹配,大于n位只匹配11位 # 2 {n,}表示匹配满足表达式大于等于n位的内容 -比如 \d{n,} 表示匹配大于等于11位数字,小于11位不匹配,大于11位有多少位匹配多少位 #3 {n,m}表示匹配满足表达式n-m数量的内容 -比如 \d{11,12} 表示匹配11位到12位的数字,小于11位不匹配,大于12位只匹配12位 import re text = "10位=1234567890,11位=11111111112,12位=222222222223,13wei=3333333333334" re1 = re.findall(r"\d{11}",text) re2 = re.findall(r"\d{11,}",text) re3 = re.findall(r"\d{11,12}",text) print(re1)#['11111111112', '22222222222', '33333333333'] print(re2)#['11111111112', '222222222223', '3333333333334'] print(re3)#['11111111112', '222222222223', '333333333333']
-
‘*’
# * 表示出现0次或者n次(任意次数) -比如 \d* 表示匹配0个数字或者多个数字
-
‘+’
# + 表示出现1次或者多次(大于等于1次) -比如 \d+ 表示1位或者多位数字
-
?
# ? 表示出现0次或者1次 -比如 \d? 表示0位或者一位数字,大于1位重新计算 import re text = "2222" text1 = "t位,t1位,t12位" print(re.findall(r"\d?",text))#['2', '2', '2', '2', ''] print(re.findall(r"t\d?位",text1))#['t位', 't1位']
3 分组
-
在正则中匹配成功,再去提取局部数据 ( )
import re text ="谁的身份证是620502199903011234,或者是62050219950406234X" #1 匹配身份证 res = re.findall(r"\d{6}\d{4}\d{2}\d{2}\d{3}[\dX]",text) print(res)#['620502199903011234', '62050219990301234X'] #2 提取除年、月、日并分别展示 res1 = re.findall(r"\d{6}(\d{4})(\d{2})(\d{2})\d{3}[\dX]",text) print(res1)#[('1999', '03', '01'), ('1995', '04', '06')] #3 提取出年月日、生日 单独展示 res3 = re.findall(r"\d{6}(\d{4}(\d{2}\d{2}))\d{3}[\dX]",text) pri
-
或关系 |
# | -例如 r"1770987(2\d{3}|3\d{3})" #表示1770987开头后4位尾数是2开头或者3开头的手机号
4 起始和结束
-
^
# ^ 表示文本开头的位置 re.findall(r"^\d{11}")
-
$
# 表示文本结束的位置
注意:反斜杠+字符表示字符本身
2 re模块
-
re.findall,在整个文本查找所有符合正则表达式的文本。
-
re.search,在整个文本匹配符合正则表达式的文本,只返回第一个,且返回的是一个match对象,并不是具体值。
import re text = "aaa,aaa,ccc,dddd,aaa" print(re.findall(r"aaa",text))#['aaa', 'aaa', 'aaa'] print(re.search(r"aaa",text))#<_sre.SRE_Match object; span=(0, 3), match='aaa'> print(re.search(r"aaa",text).group())#aaa
-
re,match.在文本的开头匹配,只返回第一个,且返回的是一个match 对象,,相当于在正则表达式中默认加了起始字符 ^
import re text = "aaa,aaa,ccc,dddd,aaa" print(re.findall(r"aaa",text))#['aaa', 'aaa', 'aaa'] print(re.match(r"ccc",text))#None print(re.match(r"aaa",text))#<_sre.SRE_Match object; span=(0, 3), match='aaa'> print(re.match(r"aaa",text).group())#aaa
-
re.split,根据正则表达式内容切割
import re text = "aaa,aaa,ccc-dddd%aaa" print(text.split(","))#['aaa', 'aaa', 'ccc-dddd*aaa'] print(re.split(r",",text))#['aaa', 'aaa', 'ccc-dddd%aaa'] print(re.split(r"[,\-]",text))#['aaa', 'aaa', 'ccc', 'dddd%aaa'] print(re.split(r"[,|\-|%]",text))#['aaa', 'aaa', 'ccc', 'dddd', 'aaa']
5 第三方模块
pip install
pip uninstall
pip list #查看下载了那些第三方模块
pip freeze > xxx.txt #把第三方模块名称生成到一个文件
pip install -r xxx.txt #按照文件列表 安装第三方模块
#配置国内源
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
清华:https://pypi.tuna.tsinghua.edu.cn/simple
阿里:https://mirrors.aliyun.com/pypi/simple/
豆瓣:https://pypi.douban.com/simple/
华中理工大学:https://pypi.hustunique.com/
山东理工大学:https://pypi.sdutlinux.org/
中国科学技术大学:https://pypi.mirrors.ustc.edu.cn/
1 requests
- 分析请求,利用浏览器等抓取请求信息
有时候,对方服务器会识别我们请求的模式,直接访问url可能无法获取想要内容,这个时候就需要加上User-Agent内容等内容伪造是设备的正常请求
import requests
res = requests.get(
url="https://hpd.baidu.com/v.gif?logFrom=searchlist&ct=2&sid=26350&ssid=&logid=&tid=11545",
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36"
}
)
-
数据返回格式
-
json
import requests import json res = requests.get( url="https://hpd.baidu.com/v.gif?logFrom=searchlist&ct=2&sid=26350&ssid=&logid=&tid=11545", headers={ "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36" } ) data_json = json.load(res.text) data_json = res.json()
-
jsonp
名字({"errno":0,"errmsg":"ok","IsPrint":false})
-
去除两边的部分
text = 'demo({"errno":0,"errmsg":"ok","IsPrint":false})' text.strip("demo(").strip(")")
-
eval,将一段字符创当做python代码进行编译执行。
def demo(arg): print(arg) eval('demo({"errno":0,"errmsg":"ok","IsPrint":"false"})') #{'errno': 0, 'errmsg': 'ok', 'IsPrint': 'false'}
-
-
html格式
<meta content="汽车,汽车之家,汽车网,汽车报价,汽车图片,新闻,评测,社区,俱乐部" name="keywords"/>
这里利用第三方模块beautifulSoup4
pip install beautifulSoup4
import requests from bs4 import BeautifulSoup res = requests.get( url= "https://www.autohome.com.cn/beijing/" ) res.encoding = "gb2312" #这里防止返回中文乱码设置一下编码,因为默认是utf-8 #1 用BeautifulSoup按照html格式处理一下响应文本,返回一个对象,据这个对象的内置方法就可以获取一些内容,比如.text,.attrs,.get bs4soup = BeautifulSoup(res.text,features="html.parser") #2 使用对象根据特征寻找标签,返回的是一个html对象 tag = bs4soup.find(name='meta',attrs={"name":"keywords"})#name 表示标签名字,attrs表示标签属性,这里的 print(tag) #<meta content="汽车,汽车之家,汽车网,汽车报价,汽车图片,新闻,评测,社区,俱乐部" name="keywords"/> #3 继续在此标签下找其子标签 tag.find() tag.find_all()
-
2 excel操作 openpyxl
pip install openpyxl
-
注意 openpyxl只能操作 .xlsx 的excel
-
1 读取
import openpyxl
#1 打开excel文件
work_excel1 = openpyxl.load_workbook(r"E:\pycharm\workspace\Project2\src\newtext2.xlsx")
#2 读取excel文件中的sheet
sheet1 = work_excel1.worksheets[0] #根据下标获取
# 有时我们需要根据sheet页的名称 来获取数据
# sheet_list = work_excel1.worksheets #获取到s所有的sheet对象
# for sheet2 in sheet_list:
# print(sheet2.title) #输出sheet页的名称
#3 获取sheet页中单元格的数据
cell1 = sheet1.cell(1,1) #根据横,纵坐标表先获取对应单元格的对象
#sheet[1] #获取某一行
#sheet1.rows #获取所有行
#sheet.iter_rows(min_row=2,max_row=10) #获取2 - 10 行的数据
#sheet.iter_rows(min_row=2) #获取2 - n 行的数据
#sheet.iter_rows(max_row=10) #获取0 - 10 行的数据
value1 = cell1.value #获取对象的值,就是单元格具体的值
print(value1)
-
2 写入
from openpyxl import workbook, load_workbook wb = workbook.Workbook() #创建一个excel文件的对象 #wb = load_workbook("xxx/xxx.xlsx") #打开一个存在文件 sheet = wb.worksheets[0] #创建一个sheet页的对象 cell = sheet.cell(1,1) #创建逗哥单元的对象 cell.value = "中国上海" #给单元格赋值 wb.save("xxx.xlsx") #把这个文件对象保存为.xlsx 的文件
-
3 设置表格样式
from openpyxl import workbook, load_workbook wb = workbook.Workbook() sheet = wb.worksheets[0] cell = sheet.cell(1,1) cell.value = "中国上海" from openpyxl.styles import Alignment # 1 设置对齐方式 # horizontal 设置水平方式,vertical 设置垂直方式 # horizontal -> left center right # vertical -> top center bottom cell.alignment = Alignment(horizontal="left",vertical="center") #表示水平居左,垂直居中 from openpyxl.styles import Border,Side # 2 设置边框 cell.border = Border( top=Side(style="thin",color="FF8000"),#表示上边框 样式为实线,颜色为“FF8000”(这个是RGB颜色对应编码) right=Side(style="thin",color="FF8000"),#表示右边框 样式为实线,颜色为“FF8000”(这个是RGB颜色对应编码) bottom=Side(style="thin", color="FF8000"),#表示下边框 样式为实线,颜色为“FF8000”(这个是RGB颜色对应编码) left=Side(style="thin", color="FF8000") # 表示左边框 样式为实线,颜色为“FF8000”(这个是RGB颜色对应编码) ) from openpyxl.styles import Font # 3 设置字体 cell.font = Font(name="微软雅黑",size="40",color="FF8000") # 表示字体为微软雅黑,大小为40,颜色为“FF8000”(这个是RGB颜色对应编码) from openpyxl.styles import PatternFill # 4 设置背景 cell.fill = PatternFill("solid",fgColor="FF8000") #表示样式为 solid, 颜色为 FF8000 # 5 设置高度和宽度 sheet.row_dimensions[2].height = 30 #表示第二行的高度是 30 sheet.column_dimensions["B"].width = 130 # 表示第B 列的宽度是 130 from openpyxl.utils.cell import get_column_letter#也可以使用数字来定位列 sheet.column_dimensions[get_column_letter(2)].width = 130 # 表示第B 列的宽度是 130 wb.save("xxx.xlsx") #把这个文件对象保存为.xlsx 的文件
-
excel公式
from openpyxl import workbook, load_workbook wb = workbook.Workbook() sheet = wb.worksheets[0] cell = sheet.cell(1,1) cell.value = "=A1*B1" cell.value = "=SUM(A1,A4)" wb.save("xxx.xlsx")
-
读取合并的单元
from openpyxl import workbook, load_workbook wb = load_workbook("xxx.xlsx") sheet = wb.worksheets[0] # 比如合并的是 第一行的 A B C 三列 cell1 = sheet.cell(1,1) print(cell1) #<Cell 'Sheet'.A1> print(cell1.value) #中国上海 cell2 = sheet.cell(1,2) print(cell2) # <MergedCell 'Sheet'.B1> print(cell2.value) # cell3 = sheet.cell(1,3) print(cell3) #<MergedCell 'Sheet'.C1> print(cell3.value) #None #我们发现,只有cell1的对象类型是 Cell,且能获取到值,其他的单元格类型是MergedCell,且获取不到值 #也就是说,合并的的一块单元格中,只有左上角那个单元格存储了文本 wb.close()
from openpyxl import workbook, load_workbook wb = load_workbook("xxx.xlsx") sheet = wb.worksheets[0] print(sheet.merged_cells.ranges) #这个sheet 所有合并单元格的区域 # {<MergedCellRange A1:C1>} cell = sheet.cell(1,1) print(cell.coordinate) #这个单元格的坐标 # A1 wb.close()
-
把某些单元格合并
from openpyxl import workbook, load_workbook wb = load_workbook("xxx.xlsx") sheet = wb.worksheets[0] # sheet.merge_cells("B4:C6") #这里代表的是吧B4:C6的单元格合并为一个 sheet.merge_cells(start_row=3,start_column=2,end_row=4,end_column=4)#表示从第3行开始到第4行,第2列开始到第4列 合并为一个单元格 #需注意已经合并的单元格不能再次合并,会报错 #同样写入内容的话,给合并单元格区域的左上角那个单元格赋值就可以了 cell1 = sheet.cell(3,2) cell1.value ="给合并单元格赋值" wb.save("new2.xlsx") #保存为文件
3 importlib
-
以字符串的格式导入 模块
import importlib module1 = importlib.import_module(r"src.db") #这里就等价于 import src.db text1 = module1.sum() print(text1) #add
4 pyinstaller
- 写代码
- 打包 见 6.4.7.3 章节
-
但是当程序中使用反射的形式在配置文件中设定字符串导入模块的话,就会出现找不到模块的错误
-
可以使用如下办法导入模块
-
且打包代码也要变一下
-
5 beautifulSoup4 处理html格式的返回报文
见 6.5.1
7 虚拟环境
虚拟环境+第三方模块
不同项目之间需要的第三方模块版本可能版本不一样,所以通常开发的时候需要把项目环境独立出来,此时就会引入虚拟化python解释器的概念,为每个项目单独设定一个解释器环境,从而把项目需要的第三方模块加入到虚拟化出来的lib\site-packages下面。
1 虚拟化的本质
-
首先需要存在python的系统解释器(就是你安装的)
D:\python\ -pyhton.exe -Scripts\ -pip.exe -Lib\ -re.py -random.py -site-packages\ -requests==3.2
-
然后创建项目,比如aas系统
D:\aasSystem\ -common\ -utils\ -app.py
-
这个项目的虚拟python解释器环境,可能创建在这个路径下面(这个看具体情况)
E:\env\aasSystem\ -python.exe -Scripts -pip.exe -lib #虚拟解释器下面是没有内置模块的,代码中调用都是调用的系统解释器下面的 -site-packages\#这个项目需要的第三方模块就在这个目录下面 -requests==5.9 #对应的如果要下载到这个目下面就需要这个虚拟解释器下的pip.exe,比如上面的这个requests==5.9模块的下载命令就是:E:\env\aasSystem\Scripts\pip install requests==5.9
2 创建虚拟环境 -命令
1 创建
-
内置方式创建虚拟环境
>>>python -m venv 虚拟解释器名称
可以看到,在哪里执行这个命令,这个解释器就生成在哪里
-
第三方工具virtualenv 创建虚拟环境
#先安装virtualenv pip install virtualenv
#重新打开终端 >>>virtualenv bbb --python=python3.6
同样,在哪里执行这个命令,这个解释器就生成在哪里
2 激活+使用
就是进入到创建后的解释器环境 执行python程序,不需要每次执行指定是哪个解释器
找到虚拟解释器Scripts下面的activate文件yunx
退出虚拟环境 deactivate
3 命令-使用场景
- 线上部署使用
- 开发环境一般不使用
3 创建虚拟环境-Pycharm
- 运行一个程序可以看到默认是虚拟解释器运行的代码
-
也可以看到命令台这里已经默认激活这个解释器环境(主要这个命令太需要是cmd模式,不是powershell模式,且路径不存在中文)
4 环境与项目的绑定 -pycharm
1
-
当想在一个项目更换或者添加解释器环境时
-
更换
-
添加
-
然后根据弹窗设置解释器的类型及生成位置
5 协调开发 or 代码拷贝
-
给别人代码的时候是两个东西:
-
代码
-
requirements.txt
pip freeze>requirements.txt
#这个代码就会把项目中的第三方模块及版本就会生成到requirements.txt文件中,其他人按照这个文件安装第三方模块即可(注意执行这个命令时,列出的第三方模块和此时激活的python解释器环境有关系)
-
-
打开别人的代码
-
代码
-
requirements.txt
pip install -r requirements.txt
#这个命令就会按照requirements.txt列出的模块及版本自动安装
-
使用pycharm打开项目的时候 就会识别到requirements.txt
-
当然也可以打开项目后先创建虚拟python解释器环境,然后在这个环境里执行命令安装第三方包
6 无外网问题
就是一般大型公司为了安全问题,开发环境一般都是封闭的内网模式,是不不能与互联网交互的,这种情况下就不能利用pip命令去下载第三包了,此时就需要把第三方模块打包后给对方
-
打包第三方模块
pip freeze>requirements.txt #先生成第三方模块列表 pip download -d package -r requirements.txt #在按照列表去打包
-
安装打包后的第三方模块
pip install --no-index --find-links=package -r requirements.txt #这个代码的意思就是,按照requirements.txt中提供的列表去安装,但是安装的第三方模块来自package(就是之前打包后生成文件的路径)
8 面向对象
-
面向过程
从上到下运行,代码没什么重用性
-
函数
【重用性】【可读性】
1 初识面向对象
def sendmail(name,num):
print(f'发送给{name}一份邮件,内容是中了{num}万的大奖')
sendmail("小明",300)
基于面向对象实现上述功能
#定义类
class messageinfo:
#方法
def sendmail(self,name,num): #可以看到,与单一函数不同就是入参里面多了个self
print(f'发送给{name}一份邮件,内容是中了{num}万的大奖')
###调用
#先创建类的对象
obj1 = messageinfo()
#再调用类中方法
obj1.sendmail("小明",300)#调用时不用管self的参数,它其实默认把obj1这个对象穿给它了
2 对象是什么?
对象可以理解为开辟的一段内存,里面有这个对象的一些属性及方法。
1 创建的对象(内存块)是单独存在的
如下同一个类创建两个不同的对象,运行时在各自的内存中取数和方法
#定义类
class messageinfo:
#方法
def sendmail(self,name,num):
print(f'{self.company}发送给{name}一份邮件,内容是中了{num}万的大奖')
#创建对象obj1
obj1 = messageinfo()
#给这个对象添加一个变量和值
obj1.company = "体彩中心"
obj1.sendmail("小明",300) #体彩中心发送给小明一份邮件,内容是中了300万的大奖
#创建对象obj2
obj2 = messageinfo()
#给这个对象添加一个变量和值
obj2.company = "福利中心"
obj2.sendmail("小明",300) #福利中心发送给小明一份邮件,内容是中了300万的大奖
2 类中的初始化方法__init__
类中存在 初始化方法__init__
,只不过在上面的代码中没有体现出来,如果在初始化方法中加入了入参,则创建对象的时候就需要给入参赋值,否则会报错,需注意self无需传入,因为他默认传入的是你创建的这个对象
class messageinfo:
#初始化
def __init__(self,timedate):
self.timedate=timedate
#方法
def sendmail(self,name,num):
print(f'{self.timedate}{self.company}发送给{name}一份邮件,内容是中了{num}万的大奖')
#创建对象obj1,此时就需要给类中的初始化方法传入参数,其中self其实传入的是对象obj1本身,无需传入
obj1 = messageinfo("当天")
#给这个对象添加一个变量和值
obj1.company = "体彩中心"
obj1.sendmail("小明",300) #当天体彩中心发送给小明一份邮件,内容是中了300万的大奖
#创建对象obj2,此时就需要给类中的初始化方法传入参数,其中self其实传入的是对象obj2本身,无需传入
obj2 = messageinfo("昨天")
#给这个对象添加一个变量和值
obj2.company = "福利中心"
obj2.sendmail("小明",300) #昨天福利中心发送给小明一份邮件,内容是中了300万的大奖
小结
-
编写面向对象代买时,方法中的self是什么?
本质是一个形参
在执行方法时,由python内部进行传递值,传的值就是创建的对象
-
__init__
方法初始化方法,创建对象时这个方法会自动执行,所以这个方法加入了其它入参,就必须在创建对象时给它传入参数值。
用于给对象进行数据的初始化。(self其实就是代表你创建的对象,self.xxx 就表示这个这个对象里面的东西,可以是变量也可以是方法)
-
类中方法的调用
先创建对象
再由对象执行方法
-
对象有什么用
对数据进行打包(封装)
后续执行方法时,可以在将数据读取出来
3 应用场景
1 利用对象实现一个用户注册
# 定义一个类
class info():
def __init__(self,name,pwd):
self.name=name
self.pwd=pwd
def show(self):
print(f"名字是{self.name},密码是{self.pwd}")
#实现一个用户注册
user_list = []
while True:
user = input("user:")
pwd = input("pwd:")
if user.lower()=="q":
break
obj1 = info(user,pwd)#创建对象,把输入的name和pwd当做入参给对象
user_list.append(obj1)#把创建的对象当做元素加入到列表中
#循环列表就可以得到创建的对象,再根据对象里面的属性值得到name和pwd
for item in user_list:
item.name
item.pwd
#还可以执行这个对象里面的方法,因为每个对象其实都是独立的内存块,所以每次执行里面的方法时,都是在各自的内存块中取值执行
for item in user_list:
item.show()
4 面向对象三大特性
三大特性:
- 封装-将数据打包放入对象中。
- 继承-类之间可以有关系,子成父业。
- 多态-python默认支持多态。
1 封装
-
将数据封装到对象
class User: def __init__(self,name,age): self.name = name self.age = age obj = User("王五",11)
-
将同一类的方法,封装到一个类中
class Messgae: def sendmail(): pass def senddingding(): pass def sendchat(): pass
2 继承
- 子类继承父类的所有方法,且父类也有其继承的类,则子类同样可以使用
class Base: #父类,基类
def showname(self,name):
self.name=name
print(f"对面有个人,他叫{self.name}")
class Info(Base): #子类,派生类
pass
obj1 = Info()
obj1.showname("王麻子")#对面有个人,他叫王麻子
-
继承对象调用时一定要分清传入的self是哪个,也就是传入的对象是哪个(哪个对象调用,传入的self就是哪个对象)
-
也就是说,在代码中self指的不一定就是当前类,要看哪个对象调用的它
class Base: def f1(self): print("Base:f1") def f2(self): print("Base:f2") def f3(self): print("Base:f3") self.f1() class Info(Base): def f1(self): print("Info:f1") def f2(self): print("Info:f2") self.f1() obj1 = Base() obj1.f3() # Base:f3 # Base:f1 obj2 = Info() obj2.f3() #注意,虽然执行继承于父类Base的函数f3,但本身传入的对象是Info类,,也就是传入的self是obj2 而 obj2 = Info() # Base:f3 # Info:f1
-
继承多个时,遵循先找第一个父类的内容,如果父类也继承了(父父)类,就还要找父父类里面的内容,一直找到底,,如果还没有找到,就从继承的第二个父类里面找,如此类推
class Base1: def user_name(self): print("name1") def user_age1(self): print(11) def user_age(self): print(33) class Base2: def user_name(self): print("name2") def user_age2(self): print(22) class Info1(Base1): pass class Info2(Base2): def user_age(self): print(44) class Mas(Info1,Info2): pass obj1 = Mas() obj1.user_name()#name1 obj1.user_age()#33 obj1.user_age2()#22
3 多态
- 比如java,定义函数入参时需要指定入参的类型,且传入参数时,类型也需要一致,否则会出错
class Base{
}
class Info extends Base{
}
Base v1 =new Base(); //创建对象时,也需要指定类型,也就是这个类
Info v2 =new Info();
class Mine{
public void getname(String v1){
}
}
Mine v3 = new Mine();
v3.getname("111");//正确
v3.getname(111);//错误
- python 语言的特性,天生支持多态,定义函数时无需指定入参的类型,自然入参也可以支持所有类型。
def fun1(a,b)
print(a,b)
fun1(1,"22222")
python这种语言,支持鸭子模型(闭眼听,只要能呱呱叫的就是鸭子)
def func(data):
data.__contain__
func([111,222,333])#可以传列表
func((111,222,333))#可以传元组
func("111222333")#可以传字符串
5成员
python内部一般有三类成员:
- 变量
- 方法
- 属性
1 变量
class info:
city = "北京" # 放在类中的叫做 类变量
def __init__(self, name):
self.name = name # 放在__init__ 中的叫做 实例变量
self.age = 14
print(info.city) #北京
#创建的对象也是可以访问这个类变量
obj1 = info("小明")
print(obj1.city) #北京
2 方法
-
绑定方法
-
静态方法
-
类方法
class Info: def fetch(self): #绑定方法;需创建对象,通过对象调用;至少需要一个self参数,self指的是调用它的对象 pass @staticmethod def push(): #静态方法;类可以直接调用,也可以通过创建的对象调用;任意个数的参数 pass @classmethod def pull(cls): #类方法;类可以直接调用,也可以通过创建的对象调用;至少需要一个cls参数,cls指的这个函数存在的类 pass obj = Info() #绑定方法调用 obj.fetch() #静态方法的调用 Info.push() obj.push() #类方法的调用 Info.pull() obj.pull()
-
适合绑定方法的场景:在对象中封装值,在方法中读取对象的值。
-
适合静态方法的场景:方法中不使用对象的值,则直接使用静态方法。
-
适合类方法的场景:方法内部如果想要使用当前类的值的话
3 属性
一般调用
class Info:
def get_name(self):
return "小明"
obj = Info()
res = obj.get_name()
print(res) #小明
加上property的属性后调用
class Info:
@property
def get_name(self):
return "小明"
obj = Info()
res = obj.get_name #加入@property,规定为属性后就不用加() 调用了
print(res) #小明
还有常见的 .setter, .deleter
class Info:
@property
def get_name(self):
return "小明"
@get_name.setter
def get_name(self,value):
print("设置",value)
@get_name.deleter
def get_name(self):
print("del")
obj = Info()
res = obj.get_name
print(res) #小明
obj.get_name = "xxxx" #设置 xxxx
del obj.get_name #del
还有一种写法
class Info:
def get_name1(self):
return "小明"
def get_name2(self,value):
print("设置",value)
def get_name3(self):
print("del")
x = property(get_name1,get_name2,get_name3)
obj = Info()
res = obj.x
print(res)#小明
obj.x = "xxx" #设置 xxx
del obj.x #del
4 特殊成员
-
__init__
,初始化方法 -
__new__
,构造方法,创建对象class Foo: def __init__(self,name): self.name = name def __new__(self): empty_object = object.__new__(self) return empty_object ### 创建对象时 # 1 创建空对象 __new__ # 2 再去执行 __init__ 做初始化 obj = Foo("小明")
-
__call__
,当类被创建为对象后,调用这个对象本身就会执行__call__
方法class Context: def __init__(self,name,age): self.name = name self.age = age def __call__(self, *args, **kwargs): print(f"这是call方法被调用了:{self.name}") print(f"这是call方法被调用了:{self.age}") obj = Context("小明","11") obj() #对象加(),就会调用类中的call方法 # 这是call方法被调用了:小明 # 这是call方法被调用了:11
-
__dict__
用于获取对象中的成员class Context: def __init__(self,name,age): self.name = name self.age = age obj = Context("xiaom",11) print(obj.name) #xiaom print(obj.age) #11 print(obj.__dict__) #{'name': 'xiaom', 'age': 11}
-
__str__
,指定 对象 的(类型)未指定前
class Context: def __init__(self,name,age): self.name = name self.age = age # def __str__(self): # return f"{self.name}-{self.age}" obj = Context("xiaom",11) print(obj) #<__main__.Context object at 0x0000000002848E80>
指定后
class Context: def __init__(self,name,age): self.name = name self.age = age def __str__(self): return f"{self.name}-{self.age}" obj = Context("xiaom",11) print(obj) #xiaom-11
-
__getitem__
,__setitem__
,__delitem__
一般我们写的类是不支持 obj[0], obj[1] = 1, del obj[0] 这些功能,但我们加上面的成员方法后就可以了
class Context:
def __init__(self,name,age):
self.name = name
self.age = age
def __getitem__(self, item): #加入它就可以支持obj[0]
pass
def __setitem__(self, key, value): #加入它就可以支持obj[0] = 1
pass
def __delitem__(self, key): #加入它就可以支持 del obj[0]
pass
obj = Context("xiaom",11)
obj[0]
obj[0] = 1
del obj[0]
-
__enter__、__exit__
上下文操作, 让创建的对象支持with语句(就像open文件操作时,在前面加个with一样)class Context: def __init__(self,name,age): self.name = name self.age = age def __enter__(self): #功能程序执行前进行的操作 print("enter") return "return_enter" #返回的值 def __exit__(self, exc_type, exc_val, exc_tb): #功能程序结束后进行的操作 print("exit") obj = Context("xiaom",11) with obj as xx: #这里xx接收了 __enter__ 返回的内容(当然也可以不用as xx 去接收这个值) print(xx) print(obj.name) # enter # return_enter # xiaom # exit
-
__add__
实现对象之间的相加没加之前报错
class Sum: def __init__(self,num): self.num=num obj1 = Sum(10) obj2 = Sum(20) print(obj1 + obj2) # Traceback (most recent call last): # File "E:/pycharm/workspace/Project2/src/test1.py", line 239, in <module> # print(obj1 + obj2) # TypeError: unsupported operand type(s) for +: 'Sum' and 'Sum'
加上之后,进行对象之前的相加,其实就是执行的这个
__add__
方法class Sum: def __init__(self,num): self.num=num def __add__(self, other): return self.num + other.num obj1 = Sum(10) obj2 = Sum(20) print(obj1 + obj2) #这里其实就把 obj2 传给了 __add__(self, other) 的 other # 30
5 修饰符
-
__?
名称前面加双下划线 表示私有属性,只能在内部访问
class Sum:
city = "上海" #公共变量
__ct = "北京" #私有变量,不能被外部访问
print(Sum.city)
print(Sum.__ct)
# 上海
# Traceback (most recent call last):
# File "E:/pycharm/workspace/Project2/src/test1.py", line 251, in <module>
# print(Sum.__ct)
# AttributeError: type object 'Sum' has no attribute '__ct'
class Sum:
city = "上海" #公共变量
__ct = "北京" #私有变量,不能访问
def __init__(self,name,age):
self.name = name
self.__age = age #不能访问
obj = Sum("小明",12)
print(obj.name)
print(obj.__age)
# 小明
# Traceback (most recent call last):
# File "E:/pycharm/workspace/Project2/src/test1.py", line 255, in <module>
# print(obj.__age)
# AttributeError: 'Sum' object has no attribute '__age'
-
类的私有变量只能在类的内部访问
class Sum: city = "上海" #公共变量 __ct = "北京" #私有变量,不能被外部访问 def __init__(self,name,age): self.name = name self.__age = age #不能被外部访问 def show(self): print(self.name) print(self.__age) print(self.city) print(self.__ct) obj = Sum("小明",12) obj.show() # 小明 # 12 # 上海 # 北京
-
如果非要在访问外部访问,python有非常规操作
class Sum: city = "上海" #公共变量 __ct = "北京" #私有变量,不能被外部访问 def __init__(self,name,age): self.name = name self.__age = age #不能被外部访问 obj = Sum("小明",12) #在外部硬要访问 print(obj._Sum__ct) #北京 print(obj._Sum__age) #12
5 嵌套
class Student: #学生信息
def __init__(self,name,age):
self.name = name
self.age = age
s1 = Student("xiaoming",11)
s2 = Student("zhangyang",22)
s3 = Student("liuche",33)
class Cls:#班级信息
def __init__(self,title):
self.title = title
self.student_list = []
c1 = Cls("一年级1班")
c2 = Cls("二年级2班")
c1.student_list.append(s1)
c1.student_list.append(s2)
c2.student_list.append(s3)
class SchoolErea: #学校信息
def __init__(self,city,cls_obj):
self.city =city
self.cls_obj = cls_obj
e1 = SchoolErea("北京紫禁",c1)
e2 = SchoolErea("上海徐汇",c2)
#需求,根据 e1 输出学校里面班级及学生信息
for item in e1.cls_obj.student_list:
print(e1.city,e1.cls_obj.title,item.name,item.age)
# 北京紫禁 一年级1班 xiaoming 11
# 北京紫禁 一年级1班 zhangyang 22
6 其他
-
callable() 判断是否可以执行
#callable() def func(): pass class Foo: pass class Foo1: def __call__(self, *args, **kwargs): pass obj1 = Foo() obj2 = Foo1() print(callable(func))#True print(callable(Foo))#True print(callable(obj1))# False 对象默认是不可执行的 print(callable(obj2))# True 对象类中加入了__call__ 方法后,是可执行的
-
issubclass 判断是不是子类
class Base: pass class Info(Base): pass class Mark: pass res1 = issubclass(Info,Base) print(res1) #True res2 = issubclass(Mark,Base) print(res2) #False
-
isinstance #判断对象 是不是 这个类创建的
class Base: pass class Info(Base): pass class Mark: pass obj = Base() res = isinstance(obj,Base) print(res) #True res1 = isinstance(obj,Info) print(res1) #False
-
super 根据类的继承关系,向后继续找成员;需注意 super是由哪个对象触发的(和self差不多)
class Base: def f1(self): print("f1") def f2(self): print("f2") class Foo(Base): def f1(self): print("Foo.f1") super().f1() obj = Foo() obj.f1() # Foo.f1 # f1
7 约束
不成文的规定,需要必须实现某些规定名称的函数
raise NotImplemented(“必须实现此方法”)
class Message(object):
def excute(self):
raise NotImplemented("必须实现此方法") #表示继承这个类的子类必须实现excute方法
class Dingding(Message):
def excute(self):
print("发送Dingding消息")
class Wechat(Message):
def excute(self):
print("发送Wechat消息")
obj1 = Dingding()
obj1.excute()
9 反射
1 利用三个内置函数实现反射,本质是通过字符的形式 去操作对象/模块中的成员
getattr() 获取对象中的成员,返回成员
setattr() 设置对象的成员
hasattr() 判断对象中是否存在成员
-
当有一个db.py模块,我们利用getattr()调用里面的一些方法
-
一般调用
from src import db def run(): #访问成员 db.dels() db.sum() if __name__ == '__main__': run()
-
利用getattr 在对象中根据字符串找到成员,再调用
from src import db def run(): func = getattr(db,"sum") # 在db模块对象中找到 sum 成员,赋值给 func func() #再调用,等价于db.sum() func1 = getattr(db,"sums") #但如果这个模块中不存在 这个成员,就会报错 func1() #AttributeError: module 'src.db' has no attribute 'sums' if __name__ == '__main__': run()
-
-
利用hasatter 判断对象中是否存在某个成员,返回bool值
from src import db def run(): bool1 = hasattr(db,"sum") print(bool1) #True bool2 = hasattr(db,"sums") print(bool2) #False if __name__ == '__main__': run()
-
利用setatter 给对象内存中设置一些变量 (需注意,这里改变的是对象内存中的数据,而不是程序本身的n内容)
模块对象
-
设置模块对象内存里面的全局变量
from src import db def run(): setattr(db,"city","北京") #可以添加不存在的 print(db.city) #北京 print(getattr(db,"city")) #北京 setattr(db,"name","class") #也可以修改已存在的 print(db.name) if __name__ == '__main__': run()
-
设置模块对象内存里面的函数
from src import db def run(): setattr(db,"get_num",lambda x:x+100) #可以添加不存在的 print(db.get_num(1)) #101 setattr(db,"sum", lambda x:"sum函数变了") #也可以修改存在的 print(db.sum("这里只是因为必须输入一个参数")) #sum函数变了 if __name__ == '__main__': run()
-
2 应用场景
1 配置文件+反射
# 利用 importlib模块(见6.5.3) 和反射三函数的特性,就可以在配置文件中以字符串的格式规定导入的模块和要执行的方法
2 python中一切皆对象
from src import db #模块,对象=包裹
db.sum() #函数,对象=包裹
db.info #类,对象=包裹
obj = db.Info() #类对象,对象=包裹
反射–本质上就是通过字符的形式去操作 对象/模块 中的成员。