编译文件的执行顺序,先将源文件进过解释器然后通过指令到cpu最后输入到页面
Python中只有换一行就是下一条语句,不需要分号,
单词:
源文件与交互式的区别
声明变量的类型,及其举例
变量的声明,以及打印,
执行的顺序:由于python是解释性的语言,解释一行然后解释一行前往内存去开辟空间,然后再将值放如其中
在python中所有的变量你赋值为什么,那么他就是什么类型的,这就是python弱类型
打印类型
变量的命名规则(区分大小写)
查看python的关键词
错误的命名规则
Print(value,sep=””,end=””)默认的用法sep中间是空格,end=”\n”默认是换行字符
可以通过使用help(print)查看用法
转义字符以及单双引号的套用
转义字符只有预定的时候才会出现变颜色,没有预定的时候就不会出现变颜色
如果要打印出转义字符的话,在print(r”value”)加上r就可以了r表示raw,表示原样输出
声明字符串的形式都有单引号
在python中,命名为大写的时候那么我们就认为是常量
字符串的表达形式:
三引号是的作用:1.保证字符串的原样输出2.注释多行
单词:
拼接字符串变量:
使用+号拼接的缺点(+号可以拼接字符串和字符串但是不可以字符串和整型)
但是可以使用+号将其转化为字符串的类型,利用str()函数,这是内置函数
简便性的拼接字符串(中间既有输出字符串也有整型的时候用这种)(通过%s占位[利用str()进行转换然后再放到%s占位的地方去,四个单引号可以打印出一句话,只是先后顺序不同了而已],后面在通过%(变量)进行补位)中间没有逗号,名称:格式化输出
除了%s,可以占位以外,%d也可以占位意思是degit:数字,【相当是%d占位是int()转换成整型(取整),如果是浮点数的话也会转成整型】【并且%2d,和%d取值是一样的】
%f也可以占位【其中%.1f表示的是保留小数点两位,%.2f表示保留小数点两位,后面的进行四舍五入】
案例【注意缩进,以及三引号的用法】
格式输出用format()函数来
Input()函数得到的数据就是字符串类型的
对*号与字符串相互结合的时候那么他们的即使将字符串输出n次
运算符:算数运算符(+= -= **(次方)//(取整)%取余 ) 赋值运算符
内存地址赋值运算符【即只要值一样那么他们制的地方是同一个地址,是指向的地址】
关系运算符(将输入的与数据库的进行比较)
关系运算符(结果只有true和false)input输入的默认是字符串,关系运算符,不仅可以用于整型,还可以用于字符串型(==,!=,>,<, is)
关系运算符(is)比较是内存引用地址
为什么在交互式下,某时一样的值他们引用的地址为什么不一样呢?为什么在源文件里面引用为什么会一样的?
原因是:在源文件中:将所有的代码都是一次性放入解释器中执行,所开辟的内存空间是这一次的,在交互式的情况下,默认有一个小整数对象池【-5,256】,如果赋予的值在这里面那么他就会直接指向他的地址,(他是一句一句交给解释器的不回去寻找以前的地址,所见即所得 (每次执行一次))
逻辑运算符 (and or not)
进制转换python中得到二进制是bin()函数,二进制表示0b八进制0o十六进制0x int()得到十进制
位运算符位运算符,与或非(~)异或
三目运算符在python 表达式?”真”:”假”,不能这样用第二种情况才可以用
运算符的优先级:
Python的语句;(条件语句,for循环语句,跳转语句)
判断语句的应用场景:(if语句注意如果是if内部的语句是时需要打一个table键)
If语句的形式(使用形式第一种):(if 表达式或者是变量【表达式与表达式之间需要有空格】(逻辑运算符或关系运算符): 执行的语句)注意:只有字符创为空字符串就默认为假,如果变量为0或者是None的话这样也是默认为假
If语句的练习:
If语句使用形式第二种:(出现else:,但是要注意缩进 )
If语句是允许嵌套的,但是缩进必须的控制好
随机数的生成需要导入其他模块(import random),random.randint(初值,末值),其中生成的数值是大于等于初值小于等于最大值并且为整数【注意:导入的模块名字不能和文件名一样,否则导入的模块会优先导入本地文件名字,就未导入模块】
练习:猜数字
多层if语句嵌套:elif多个选项
if : elif : else : 语句的练习
If语句总结:
Else:
条件
循环语句【for和while 】)以及单词
Sequence :序列
Include:包含
Exclude:不包含
循环语句:循环用几何来实 range(20)大于等于0并且小于等20会产生0~19的数值,二十个数字,循环二十次)
pip install redis :默认是安装最新的
pip install redis==3.2.1 :安装指定版本,卸载不切合的版本
pip list :列出包管理
pip fresh --help :查看命令如何用
pip -V :查看版本
pip freeze >requirement.txt :将list包写入文件
pip install -r requirements.txt :安装这个文本里面的包
python -m pip install --upgrade pip :升级 pip班
python 是解释性的语言需要解释器(可以跨平台),还有编译性语言(不能跨平台在那种环境下开发,就只能在那种环境选运行),
python3.6.5就是(解释器+lib+pip)
pip安装的包安装在site-package里面的
查看函数的作用
help(print)
单词:
built-in:内置的
module:模块
stream:输出流
print(value,age,sep='#',end='')默认的分割是空格且换行
\n 换行 ,\t 制表符 \' \" \r 回车 \\
print('乔治说:"想吃冰激凌"')
可以双的套单的,也可以用转义字符\'或者\"
------------------
第二方式(不在存在类型):格式化输出:用format,字符串中的函数
例如:(其中的点表示调用的意思)
age=3
s='已经上'
message='乔治说:{},{}幼儿园'.format(age,s)
print(message)
--------
输入:input函数是一个输入流#阻塞式
例如:name=input("请输入名字")
print(name)
raise:抛出
operator:运算符
赋值运算符:= :后面的给前面的赋值,name=‘admin’name=name1 print(id(name)),print(id(name1)),两者输出的id是一样的地址是一样的
首先在内存中建立一个存admin的内存,然后把内存地址复制给容器,然后复制给宁外一个容器,所以id的话是一个地址
==:是否相等?(有哪些扩展符:+= -= /= *= ** // %例如:a=a**b 即a乘以b的次数 例如:a=a//b 表示整除a//b即取整 %取余数)
print("*" * 50):表示五十个字符串
算数运算符:-=,+=,**,//
关系运算符
逻辑运算符
位运算符==for 语句
第一:for 变量名 in 集合:
语句
第二种:for 变量名 in 集合:
语句
Else:
语句
【当for语句中集合部分没有数字时,就执行else:语句】
例如:for i in range(3)
print("你好----》",i)
产生0~3的数字,3次
range(3):集合出现的是包头不包尾
range(1,3):集合出现1,2,包头不包尾
关键字:pass 空语句不会报错
if 10>7:
print("是大于气的")
else:
pass【如果这里不写语句的话会报错缩颈的错误,但是写pass就不会报出语法错误】
print("结束")
【pass 空语句,只要有缩进的内容时,但是缩进的内容还不确定的时候,为了保证语法的正确性可以用pass占位置,即在循环体里什么都不写时,应当用pass 关键词】
for I in range(4):
Pass【占位置】
Print("你好")
break:中断循环语句,跳出循环
【例如】
for i in range(4)
username=input()
password=input()
if username == 'admin' and password == '123':
print('登陆成功')
print('轻松购物')
break
else:
print('登录失败')
else:
print("需要激活")
【break可以跳出循环体,】
if语句是判断,符合条件的话就走第一条,不符合条件的就执行else:语句
【死循环】
【while循环】
while 条件:
语句
改变n的值(n+=1)
例子:
i = 1
while i<20:
if i%2 == 0:
print(i)
i+=1
【打印*号】python独有
num = 1
while num<=5:
print("*"*num)
num+=1
【打印*号】嵌套
num = 1
while num<=5:
i=1;
while i<=num:
print("*",end='')
i+=1
print()
num+=1
【补充细节】
a,b=2,4
b=c=5
print(c-a>b-a)得到的值为布尔类型
【补充】
【字符串】== 比较的是内容 is 比较的是地址
S1='abc'
S2="abc"
S3="'
abc
"'
地址只有s1和s2的地址是一样的,第三个不一样,因为三引号需要保存格式主要看有没有换行,不换行的时候他们就是一样的
【字符串注意】
S1=input()
S2=input()
print(S1==S2) true
print(S1 is S2) false (常亮赋值is是true,input输入底层是做了处理的地址不一样的)
【字符串用到的运算符】
+ * :分别是连接字符串,和字符串的倍数
name = daaiuioiytri
(not) in :result= 't' in name 表示是否存在它里面返回值true false连接在一起的
print(result)
%s:替代符
r:保留原格式 (即只不发生转义字符) print(r'name1\'')
[]:获取字符串中的某一个字符,相当于数组
Name="nihao"
print(Name[1])----->i 下标是从零开始的,只能提取一个字符
[0:7]:可以获取多个字符,7第七的一个字符 和range一样也是包前不包后(截取字符串)[初始:结束]
Name="nihao"
print(Name[0:5])---->nihao
注意:前面可以省略,默认表示0开始取值,后面不写表示取到末尾
负数:反序末尾默认为-1 表示最后一个字符[-1:]得到的是最后一个字符,
[::-1]:表示倒叙输出,-1表示方向还表示步长,2表示方向从左到右而且还步长为2即先看方向,如果有两个表示冒号,则最后的表示的方向
[:]:输出所有字符串字符,
【python的字符串常用的内建函数】:申明了一个字符串函数,默认可以调用内建函数
capitalize():将字符串第一个字符转换为大写
例如:字符串.capitalize()
title():将每一个单词首字母都大写其余的小写用法和capitalize一样,
istitle():判断每一个首字母是否大写,返回值true 或者是false
upper():全部大写
lower():全部小写
内置函数:len():获取字符串的长度:(len(str))
【产生验证码以及校验】
import random
s="qwertyredfgdsxcvxzcvcdsf231456754"
for I range(4)
code=str(s[random.randint(0,len(s)-1)])
code+=code
print('验证码:',code)
user_input=input()
if user_input.lower() == code.lower() :
print("成功")
else:
print("失败")
【字符串内置字符串的查找】
find(str,beg=0【数字或者是变量】,end=len(str)):如果不写开始和结束,那么默认是查找的全部,如果找到则返回第一次出现的索引值,如果找不到就返回-1【下标默认是0开始】,也可以指定位置去找,
s='eryuioioiuytui'
print(s.find('r',0,len(s)-1))
rfind():从右边开始找
lfind():从左边开始找
s='fghjasha/asas'
s.rfind('/')
s[s.rfind('/')+1:]
index
():s.index('x')假如找不到的时候这个时候就会报出异常
【字符串的替换】
replace():s.replace('str1','str2',次数):用字符串1区替换字符串2,最大替换次数不能超过次数值
【字符串编码】
gbk:中文
gbk2312:简体中文
utf-8:是国际通用的是unicode的升级版
例:msg="上课了"
Result=msg.encode('utf-8')
print(Result) 打印的是utf-8的码
encode():msg.encode("utf-8"),将msg里面的字符转换为utf-8的编码
decode():msg.decode("utf-8"),将已经编码的字符串比那成了字节进行解码操作,如果编码和解码的方式不一样则会出现问题
【验证字符串以什么开头或者是以什么结束返回值是布尔类型】判断上传的是否是指定的png或者txt
starstwith():以某一个字符串开始
endswith():以某一个字符串结束
例:filename="nihao.txt"
result=filename.endswith("txt") 验证是否已txt结尾
print(result) true
【转义字符】
\r \n \\ \' \" \t
print(r'\') 这样是错误的,如果加上r后面必须的加上\和字母或者其他东西
例如:print(r'\rt')
【判断字符串只包含数字或者字母】类似正则表达式(返回值是布尔型)
isalpha():是否只包含字母
isdigit():是否只包含数字
isnumeric():只包含数字字符
isspace():只包含空白字符
issupper():包含字符串中至少一个区分大小写的字符
join():用指定的字符串连接字符串,构成新的字符串
max();返回最大的
min();返回最小的
例如:new_str='-'.join(asd)
print(new_str)----->a_s_d
例如:s='123213'
Result=s.isalpha()
print(Result)---->false
【列表进行验证码的拼接】可以在字符串中间加上一些特定的字符,和+号见大的拼接不一样
list1=['q', 'q','e','q']
result=' '.join(list1)
print(result)---->q q e q
【截掉空字符串字符串】
lstrip():去掉字符串中左边的空格
rstrip():去掉右边的字符串的空格
strip():同时去掉左边的空格和右边的空格
例如:s=' 2323232'
s=s.lstrip():去掉左边的空格
【分割字符串以及得到这样的字符串在字符串中出现的个数】
split('以什么切割',切割的次数):用利用指定的字符串进行分割并且可以指定切割几次
例如: s="hell nihao owew"
result=s.split(' ',2)
print(result)--->将用空格直接分割字符串,得到的是一个列表
count:s.count(" ") :的到s的字符串中得到空格(指定的参数)的出现个数
【for语句不能直接控制次数字符串也可以放在循环里面,while语句可以直接控制次数】
【列表 list】(in在字符串或者是列表里面都可以实现)
#申明:names=['a','b']
列表的下标和字符串的下标是一样的,下标从0开始,-1表示的是最后一个 利用len()函数进行获取长度,type()获取类型,names[0],获取列表的内容
for i in语句可以是字符串,也可以是列表
【查询里表里面是否有a(查)】
for i in names:
if i == "a":
print(有啊)
break
else:
print("没有")
【简便方法】底层使用的就是第一种方法
if 'a' in names :
print("在")
else:
print("不在")
【增删改】
改:例如
Name=['12','34','35']
Name[-1]='43'
print(Name)
删:del name[2]
【列表中的函数】
添加:append:末尾追加 extends:连接 insert:在指定位置添加列表元素
list.insert(index, 元素)
删除:del remove(), pop(), clear()
name.remove('小红'):删除找到的第一个返回none 如果找不到就报出异常
del name[1]
name.pop();name.pop(2)可以指定删除
pop()中没有指定要删除元素的位置时,便自动删除列表中的最后一个元素。指定了要删除元素的位置,便删除了指定元素。调用了pop()函数后,它会返回要删除的元素。
clear():name.clear():删除所有的值,且没有返回值
【列表反转】
Name.reverse():把列表中的颠倒,改变列表中的结构,然后name[::-1]:这是取值为反转但是没有改变列表中的值
【数据结构】
队列:先进先出 FIFO(先进先出):相当于排队
栈(刷盘子手机页面返回):先进后出,就是
【列表中的排序】
(内建函数)sort():name.sort():改变列表中的值,默认是升序,降序的话加上reverse=Ture
(内置函数):sorted(name):进行排序方法和sort()中的参数是一样的但是在这个位置的话,这个会有返回值,对列表不会进行修改
【次数】
count():name.count("xx"):统计出现次数
【冒泡排序】进行n-1次,每次进行n-
mylist=[12,3,5,7]
for i in rang(0,len(mylist)-1):
for j in range(len(mylist)-1-i)
if mylist[j]>mylist[j+1]:
tmp=mylist[j]
mylist[j]=mylist[j+1]
mylist[j+1]=tmp
print(mylist)
【 列表回顾】
+ ,* ,in ,not in ,is ,
内置函数:len(),sorted(),max(),min(),list(),enumerate(list),将下标和值组成一新的列表,这个列表需要list()来转一下
内建函数:append(),extends(),insert(),del, pop(),remove(),clear(),count(),reverse(),sorted(),
算法:选择排序 ,冒泡排序
【交换Python中的列表的项目值】
a[x],a[y]=a[y],a[x]
for i in range(len(alist)):
min_index = i
for j in range(min_index+1,len(alist)):
if alist[j] < alist[min_index]:
min_index = j
if min_index != i:
alist[i],alist[min_index] = alist[min_index],alist[i]
【元组类似列表只能看不能改】
例:name=(1,)------->元组
【元组中有没有内置的函数】
index():name.index(3):从元组中找到3的下标并且返回,如果找不到就会报错,也是0开始
count():name.count(3):返回出现摸个值得个数
【元组的拆包】意思就是把元组里面的值取出来赋值给其他的即,变量个数和元组个数不一样的时候报出的错误
例:tuple1=(1,2,3)
a,b=tuple1 报出:tuple1中的值就是值,报出的错误
a,b,c,r = tuple1 都会报错
【元组中值得个数和赋值的变量个数不一样的时候】用*号代替未知的个数
新的写法 : *_ 或者(* 表示通配符)将元祖中剩余的内容变成列表其他的变量就得到值
例(元组的元素大于变量了):a,*_,b =tuple1 ---> a =1 ,b=3 ,*_=[2]
a,*c,b =tuple1 ---> a =1 ,b=3 ,*c=[2]
例(元组的元素大于变量了)写法是一样的,*c表示的是如果有多的就全部放在里面(这是由于*c是一个变量也表示未知,由于c是一个变量就把剩余的变成列表,*c就是另外一个变量那么这就可以直接直接把列表去掉变为直接提取数字出来),如果没有多的那么就是为空列表,如果打印*c那就是元组里面的元素,打印c出现的就是列表
总而言之:*[2,3,5] 就是拆包,有一堆值付给他的时候那就是和起来用列表装
【元组的设计到的东西】:
符号:+:连接两个元组
*:倍数和合并和拆包
is:地址是否相同
in:是否在里面
len();
sorted():排序之后列表了
【字典dictionary】
=================2.23白============================
【字典增加空字典】
Dict1=dict() 空字典 其他的也可以元组 列表都可以使用这种方法 ,但是比较不常用
【字典中dict()函数】
dict(list((),())):只有二维的元组或者是列表才可以转换
【字典的增删查改】
增加:dict[key]=value ; dict[age]=18
改:dict[age]=23 :相同的key值不同的value值会进行覆盖 :如果没有出现同名的key值时那么就是添加功能
【用于保存登录和注册的账号信息】列表中套用字典
list1=list()
while True:
username=input("输入用户名")
password=input("请输入密码")
repassword=input(''请输入确认密码")
email=input("输入邮箱")
phone=input("请输入电话")
user={}
user['username']=username
if password == repassword:
user["password"]=password
else:
print("两次的输入密码不一致")
continue
user[email]=email
user[phone]=phone
list1=list1.append(user)
answer = input("是否继续y/s")
if answer != y:
print(list1)
break
【字典中的查询数据】字典中不存在下标一说
key是唯一的,value不是惟一的
列表中寻找值时根据下标找值得,字典里面找值得时候那就是根据key来的:dict[key]
得到的结果为这个key值得value值
【字典中的便利】
在字典中for in循环,拿到的字典的key
【字典里面的函数】
items() values() keys()
items():dict1.items():转换为列表里面包含元组的形式,就可以遍历了,通过for in遍历
【函数遍历字典内建函数items()】
就可以这样遍历:
for key value in dict1.item():
if value >= 90 :
print(key)
得到的结果是字典的key 和value单独存在的 ,例如; 张三 213321 分数
【字典函数values()】
values:dict1.values():获取字典中的所有values值,保存成为列表
【字典内建函数keys()】
keys():dict.keys():得到字典中所有的key值然后,得到的是列表也可以获取key值
【字典中用in】
print("王五" in dict2): in查询的是字典的key,只能用于判断
【字典里面的get()函数】
也是取值,和print(dict1["飞哥"]) 和dict1.get("赵飞")一样的效果,只不是get函数不报错,其中返回值为none,其中还可以设置默认值 ,dict1.get("飞哥(key)",99),如果找不到还可以给他赋予默认值
【字典中的删除】
del dict1["飞哥"]:del dict1[key]:删除数组的下标,如果找不到key的那么就会报出keyerror错误,
内建删除函数:pop():可以用于删除 dict1.pop("李四(key)",defalut),返回的是删除成功的value的值,默认值是可写可不写,意义就是找不到的时候不报错(默认报错找不到时),返回默认值,也可以是字符串提示语时
popitem():dict.popitem()随即删除(一般是从末尾删除的)会返回删除的键值对
clear():dict1.clear():删除列表里面所有的东西
【字典中其他的内置函数】
result=dect1.update(dict2):就是更新字典,用后面的去更新前面的,如果值时相同的就覆盖,如果不同的话,那就加进去相当于增加的意思,字典不直接支持+号,所以update()就相当于合并操作
fromkeys():dict.fromkeys(list,默认值):将列表转换为字典,一维的数组就可以转换 (这里的dict 并不是字典 而是关键词不能更改),默认值可以加也可以不加,加了之后key就是list里面的值,value就是默认值
【字典中的注意事项】
【集合】
关键字set
=================2.24.2021白=======================
【集合的删除】
remove(): pop()随机删除,clear(),discard()
【集合中其他的符号操作】不支持 + 号 和字典一样 ,* 号也不支持
in:6 in set1:字符是否在集合中的
== :set1 == set2比较的是内容是否相等
!=:不等于
-:set2 –set1: 取差级,difference()内建函数,set3.difference(set2):这样的形式类似于set3-set2,得到的差值
&:set1 & set2交集 intersection()内建函数,set3.intersection(set2):这样的形式类似于set3 & set2 取得交集
| : set3 |set2 :并集 set2.union(set3)内建函数,这样的形式类似于去并集
对称差:
Result=(s1|s2)-(s1&s2):对称差或者 ^ 这个也叫做是对称差集 内建函数symmetric_difference()
s1.difference_update(s2):s1中减去s2然后赋值给s1
s1.intersection_update(s2):s1交集之后然后在赋值
【集合知识点】
关键字:set
特点:去掉重复和无序
【集合中用到的符号】
|,&,-,^
【集合内置函数】
增加:add(),update()
删除:remove(),pop():由于set是无序的,所以随即删除的都会删除左边第一个,discard(),clear()
运算:difference(),intersection(),union(set3),symmetric_differce()
【可变和不可变】【注意:内存里面有小整形】
不可变:对象指向的内存中的值是不可以改变的
不可变的类型: int str float 元组tuple和集合frozenset()(不会随着更改里面的数值且不会改变地址)针对于地址,只要变量里面的值改变那么就会更改其地址的值
【可变的】对象所指向的内存中的只是可以改变的
可变的类型,字典 和 列表,集合(改变里面的值他的地址不变)
【类型转换】
str() int() list() dict() set() tuple()
str –能够正向转换也能逆向转换->int list set tuple dict float
s = "asdf" ---> list(s)--->['a','s','d,'f']
【列表转换】
list—能够相互转换->set tuple 可以转换为字典必须为二维 set
字典转换为列表的话,用fromkeys(list,默认值)
【pychar】
包:python pake :独立的包可以在里面写很多东西
【python 函数】
将重复的代码封装到函数里面,只要使用直接找函数就可以了
格式:
def 函数名([参数,参数….]): 参数可有可无
函数体(重复代码)
【函数的例子】生成随机数(如果下面出现黄色就是表示没有遵守条件)
【自动格式化】快捷键 Ctrl +shift +f:自动格式化 Ctrl +alt +I 也可以
import random
def generate_random():
for i in range(10):
ran=random.randint(0,20)
print(ran)
print(generate_random)—》function generate_random at 0x00000324
打印的东西是:函数名字和这个函数申明的函数地址
【调用函数】
函数名():调用函数,有参数就填写参数没有的话,就不写
【函数执行的流程】
如果有包的话,就导入包
第一步:加载函数 第二步:分配地址
如果只是写函数名的时候:那就是找函数的地址
如果加了括号那就是找到地址里面的函数体了执行
【带参数的函数】
格式:def 函数名(参数,….):
函数体
import random
def generate_random(num):
for i in range(num):
ran=random.randint(1,45)
print(ran)
generate_random(5)
【快速生成提示包名快捷键】
Alt +enter
【有参数的调用】
generate_random():需要实参 ,其实就是具体的值,上面函数是指的是形参,即形式的参数,相当于一个房子里面需要一个门,而实际参数就是实际参数
【程序调试bug】
就先给代码加上断点,然后运行的时候就进行debug 文件名字
【获取类型并且判断】怎么查看源码,ctrl健再点击函数,就可以进行查看源码
type():只能是查看是什么类型,但是不能判断
isinstance():isinstance(变量,类型):判断这个变量是否是是什么类型 返回值是Ture 或者 False(可以用在判断里面)
【函数的可变参数】
def add(*args):
print(args) args就是元组,
这里传递的参数个数是可以变的,传递的任意个数都可以,最后会变成元组来接参数,即是把实参装到元组里面,进行*args()获取,*号是底层中的和装包的重要信息
【不变参数,可变参数】
如果在可变参数里面再加上不变参数,就可以把不变的值放在前面,可变参数放在后面,根据元组的赋值的情况,
例如:def add(name,*args):
函数体
调用:add("飞哥",4,5,6)
【函数(可变参数 + 关键字参数)可以与字典同步,可以用字典进行接关键字参数】
关键字参数:key = value
def add(a,b=10): 关键字参数
函数体
add(2):得到的是 a=2 ,b=10
add(2,5):得到了是a=2,b=5:原来有b=10,默认的值就没有了
例:(如果只传两个值,并且不想要b为第二个值(默认是赋值给b),想要c为第二个值,那么可以直接指定)
def add(a,b=3,c=4):
函数体
add(2,c=3)
【函数参数的(**)只能接受关键字的形式如果直接是字典过去,就先要先转换为key,value的形式,就是给上面加上变量加上**就可以了】
def func(**kwargs):
print(a,b,c) ----->默认保存为字典,送的值也必须为key=value这种形式
调用
func(a=1,b=2,c=3) 关键字参数
func(): func(a=1,b=2)都不会报错
如果想传递字典过去那么,就得 func(**dict):意思是就先拆包,然后在装包
详细过程:
第一步:将字典进行拆包(变成key=values的形式)
function('001'='python')
第二步:
将已经拆分的值给**kwargs 然后
第三步:进行装包给形参
【自己理解的拆包和装包一个*号表示元组,两个*表示字典】
拆包:就是将值赋值给别人,多余的全部放在有*变量的中以列表或者元组的形式存在,当没有了*号就是一个一个的值
装包:将拆分的值,用该种类型转换这种为该种类型
【函数的返回值】
返回值:将在函数中的运算结果通过return 关键字丢出来,原因是因为函数体内部的变量在函数体的外部是拿不到的,只有通过return进行返回出来,在外面才可以用的,在外部就要用一个变量来接受这个变量,就是返回函数的地址
def add(a,b):
result = a +b
return result ---->{当然不仅仅只能丢一个变量出来,可以是多个的,但是得出来是元组的方式来装的,当然如果只有一个变量来接的话那么这个元组的话,那他就是元组,如果是有连个变量来接的时候那他就是元组的赋值}
理解就是开创了地址空间之后,有一个传递参数的进口,和有一个丢出窗口的出点,
【函数嵌套调用】
islogin =False --------->判断用户登录的状态,默认是没有登录的
def add_shopingcart(goodsName)
if islogin and goodName:
print("成功将%s加入购物车" %goodName)
else:
print(请先登录或者没有商品)
def login(username,password):
global islogin------------------------>【就是函数内部不能更改函数外部的值,加了global就可以了】
if usernaem=='admin' and password =='123':
return Ture
goodName=input("请输购买的商品")
add_shopingcart(goodsName)
else:
aswer=input("账户或者密码错误 是否重新输入 y/n")
return=False
if aswer == 'y'
username=input("请输入用户名")
password=input("请输入密码")
islogin=login(username,password)
else:
print("很遗憾")
username=input("请输入用户名")
password=input("请输入密码")
islogin=login(username,password)
【函数的加载】
默认函数应该放在最前面,避免为调用就加载
【全局变量和局部变量】
局部变量:在函数内部的变量:是局部变量外面的变量无法调用内部的局部变量
全局变量:在函数外部的变量:是全局变量,内部的变量正常是无法改变全局变量的,但是可以用全局变量,所有的函数都可以访问
【函数变量的就近原则】
当全局变量和局部变量的变量名字都是一样的时候,在函数内部使用变量,那么优先使用的是离这里最近的变量,修改值,也只能修改局部同名的变量值,并不在局部函数里面更改全局变量,
如果需要在函数里面更改全局变量的值的时候就需要加上 global 变量名 之后才可以更改
【可变和不可变的类型的时候】
当全局变量是可变类型的时候,函数内部使用全局变量的时候不用使用global 变量名,而不可变的类型的时候是需要改变的
【嵌套函数-内部函数(在函数的里面在声明一个函数)】
特点:
1.可以访问外部函数的变量
2.内部函数可以修改外部函数可变类型的变量
3.在内部函数要要改变外部函数的值得时候,这个时候就需要在内部函数加上 nonlocal 外部变量名,然后内部函数里面才可以改变外部函数的变量名的值
4.内部函数修改全局变量的不可修改变量时,需要在函数内部函数声明 global变量名
内部函数修改外部函数的不可变的变量时,需要在函数内部函数中声明nonlocal 变量名
第一,两者的功能不同。global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量,而nonlocal关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal位置会发生错误(最上层的函数使用nonlocal修饰变量必定会报错)。
第二,两者使用的范围不同。global关键字可以用在任何地方,包括最上层函数中和嵌套函数中,即使之前未定义该变量,global修饰后也可以直接使用,而nonlocal关键字只能用于嵌套函数中,并且外层函数中定义了相应的局部变量,否则会发生错误(见第一
def func():
n=100
list1=[3,4,5,6]
def inner_func():
nonlocal n
for index,i in enumerate(list1):
list[index]=i+5
list1.sort()
n += 100
print(n)
inner_func()
print(list1)
【嵌套函数的变量访问】
函数的申明是一步一步的,,但是他们不会再其中的得内部穿件地址,但是会在其他地方创建地址,但是创建其他地址是有不同的地址的且不同的不同的标识的
def func():
b =99
def inner_func():
global a
nonlocal b
c= 88
b += 100
a += 100
inner_func()
print(locals())---->获取当前的函数中声明的函数有哪些详细信息
当在内部函数调用的时候,只有在当前函数里面添加,nonlocal 变量名 和 global 变量名来修改外部函数的值或者是去哪聚变量的值
【locals()查看当前函数中的声明的内容有哪些】
其中的的得到的类型为字典的类型
内置函数:locals():调用的话,直接在函数体的内部打印就可以了得到的值为 key:value
【globals()-->获取本地的全局变量的】
直接打印,你内置函数,globals() :
【闭包】针对于函数来说的
def func():
a=99
def inner_func():
b=99
print(a,b)
return inner_func ---->将函数跌倒外面去,就不仅仅在外部函数才可以访问
x=func()
x()
-----------------------------3.1白-------------------------------------------
【闭包,同级函数的调用】
def func():
a=100
def inner_func1():
b =90
s=a + b
print(s)
def inner_func2():
inner_fun1() //调用
return inner_func2
x=func() /有返回值就需要接住。没有返回值就不需要接
print(x)
【闭包总结】
【闭包】
就是外部想修改内部变量的值,使用return出来,我的理解是平常的语句和函数的语句变量不同,分别放在两个池子里面
【装饰器】
函数作为参数实质及时地址的指向,可以理解闭包的返回值,和地址的指向
def func(number):
a= 100
def inner_func():
nonlocal a
for i in range(number):
a+=1
print(a)
return inner_func
f=func(5)
f()
【定义一个装饰器并且调用】
def decorate(func):
a=100
def wrapper(x): --------->在之前传递的参数,和被装饰的函数参数是一样的
print("111111")
func(x) ------>调用被装饰的函数 这是传递的参数,有装饰器的特性,在返回的地址是闭包是实现的地址返回,在里面的函数执行了一次原函数,所以在装饰器的原函数先用wrapper传递,然后再放到原函数里面,就实现了参数的传递,也可以加入*args 来实现不确定个数的参数
print("2222",a)
return wrapper
@decorate -->装饰器用在哪个函数的上面谁就是装饰哪个函数
def house(5):
print("你好")
house()
装饰器:满足闭包,和函数作为参数
【使用装饰器】
@decorate @加上函数名字就是使用装饰器
1. 被装饰的函数,就会被装饰器把函数当做参数传到装饰器decorate中,
2. 执行装饰器函数
3. 将返回值赋值给被装饰器命名的名字 赋值一个return 的函数地址
4. 最后调用被装饰器的函数就显示为返回的那个函数
【多个装饰器】
@hzuan1
@hzuan2
def house():
距离被转函数近的是先装,然后在装远的,把前面装完了再装后面的,将前面的当成一个整体,然后在进行新的去装
【灵活的装饰器参数设置】
def decorate(func):
a=100
def wrapper(*args,**keys):
print("111111")
func()
print("2222",*args)
return wrapper
【带有参数的装饰器】带参数的装饰器必须为三层
def outer(a): ---->专门负责接收参数的
def decorate(func): ----->负责接收函数的
def wrapper(*arge,**kwargs):------>负责接收函数参数的
retuen wrapper
return decorate
@outer(2)--->直接传递参数
def house():
【变量作用域】
变量作用域:LEGB—访问同名的变量
L:Local:在本地变量的查询
E:encloseing:嵌套
G:全局
B:Bilut—in:内置的
嵌套函数:
【闭包】:
【装饰器】
=====================3.2白=========================
【匿名函数作为参数】
作用:简化函数的定义
关键字:lambda 参数1,参数2:运算 ---->这就是匿名函数
def fun():
print("你好")
x=fun ------>得到的值是函数fun的地址
s=lambda a,b(参数):a+b(返回的结果) ---->先把函数的地址给s 相当于就是return,或者直接给函数名字,然后通过s(1,2)调用,用值去装然后得到结果
匿名函数可以作为参数 ---->装饰器的底层原理
def func(x,y,fun):
print(x,y)
s=func(x,y)
func(1,2,lambda a,b:a+b) ---->传递参数的时候为匿名函数
list2=[{'a':10,'b':20},{'a':10,'b':20}]
m=max(list2,key=lambda x:x['a'])------>先将字典中的数据取出来,在比较
print(m) 当列表里面出现了字典,还需要比较的时候就需要用匿名函数,先取出来,然后在进行比较,最后返回的值是key values的形式,因为先调用的是后面的值key values这个值
【内置函数】lambda函数用于简单的匿名函数可用于其他内置函数的参数
lambda x : x if x% 2 ==0 else x+1,在匿名函数里面也可以写条件判断
map():map(list)map对象可以转换为list对象,map函数就是可迭代的元素进行每一个元素的操作
from functools import reduce导入一个模块
reduce():对列表(可迭代)中的元素进行加减乘除运算的函数
reduce(lambda x,y:x+y,tuple,默认值数字):进行累加
filter(函数条件,可迭代的值): result =filter(lambda x :x>10,list1)
result =filter(lambda x:x['age']>20,students)
【递归函数】recursion error 递归错误
普通函数:def
匿名函数:lambda
递归函数:普通函数的一种
特点:自己调用自己
def sum(n):
if n==0:
return 0--->没有调用函数了表示是出口
else:
return n+sum(n-1)
【总结函数】
普通函数:def fuction(): pass
参数:
def fun():
pass
调用fun()
def fun(w):
调用:fun(1)
可变参数:
def func(*args,**keys):
默认参数:调用的时候没有给值也不会报错,需要的话就会直接传递参数就行,如果有多个的话就指定b=12
def fun(a=10,b=2):
返回值:return
如果没有返回值,还要哪一个东西去接他的时候,那么他们的值就应该为None
有返回值:
return a
如果有值得话,那么用变量去接的话,那就是他返回的值
【嵌套函数】
闭包,装饰器,变量的作用域LE嵌套GB
global nonlocal globals(),locals()
装饰器:单层装饰器,两层装饰器,三层装饰器个数
装饰器带参数,递归函数
【文件操作之open函数】注:如果流已经被读了,那么流里面那就什么都没有了
内置函数:open(),在函数里面写上三个引号,然后的函数就是加上文档说明
mode : r w :纯文本文件
r :读 rb:binary
w:写 wb:binary 都是针对于有图案的,也包括文本的,音乐,mv,底层都是二进制拿去做的
r w x a b t + U
stram=open(file,mode,buffering,encoding) ---->返回值:流对象,相当于管道
stram.read()---->去读取针对流
print(stream)
read():内建方法,stream.read():获取内容
readable():stream.readable()判断是否能够读取 返回值为ture 和false
stream.readline():只读取一行同时读完了会有一个换行(可能是文本本身有一个换行)
stream.readlines():将所有的内容全部放在一个列表里面里面有换行
stream.name:获取这个管道的具体路径可以用find,[]去截取字符串的文件名
【读文本】
stream=open(r"C:\Users\penzhou\Desktop\daima.txt")
content=stream.read()
print(content)
【读取图片或者其他的】必须使用二进制的方式mode="rb"
stream=open(r"C:\Users\penzhou\Desktop\daima.txt",'rb')
content=stream.read()
print(content)
【文件的追加和写入的操作(write)/和os模块都是内建函数除了open】write是一个无中生有的模式
【注意点:】
首先mode模式为w模式为写方式
write():如果写东西的话,就会把源文件覆盖掉
只有一个流没有关闭,那么在此基础上的写都会在上一个末尾追加内容
writelines(可迭代的列表或者其他):内建没有换行的效果,如果要换行的话,就只能在没有个元素里面加上\n
writeable():判断是否能够写入
mode='a'模式:和写是一样的操作,只是追加内容,不会删除原来的内容
open():只能定位到具体的文件,不能是文件夹
stream =open("路径",'w')
s="'
你好!
"'
Sset
tream.write("你不好")
result=stream.write(s)
print(result)
stream.close() 释放流的资源
【文件的复制】实质上就是读和写的操作
with 结合open使用可以帮助我们自动释放资源
with open(r"地址",'rb') as stream:
content=stream.read()
with open(r"新地址包括名字",'wb') as wstream:
wstream.write(content)
print("复制成功")
【os模块】
模块:os
import os :导入模块
os.path:
os.path.dirname(_file_):获取当前文件所在的目录文件地址返回当前所在的路径目录
os.path.getcwd():获取当前文件的所在的目录,和dirname一样的
os.path.join(path,"追加的字符串"):追加字符变成字符串,返回新的路径
os.path.dirname(_file_):获取当前所在的目录获取到的是绝对路径,但是不能直接把这个路径放在open的路径里面,因为需要具体的文件,并不是文件目录,所以需要用os.path.jion()的方法
result=os.path.join(path,追加的):就是在path后面自动追加\字符串,可以和上面的代码替换一下write的位置也可以,得到的是一个文件路径名,可以追加多个字符串
【相对路径和绝对路径在os.path里面】
os模块里面有path的方法,点进去就可以了查看有哪些方法
absolute:绝对的
c:\p1\a.png
os.path.isabs(r'xx'):判断是否是绝对路径
os.path.isfile():
os.path.dir():
相对路径:
../:表示当前文件的上一层返回上一级
【获取相对路径的绝对路径】
os.path.adspath("文件名相对的文件名"):--->得到绝对路径的地址 通过相对路径得到绝对的路径
【获取当前文件的绝对路径】
os.path.abspath(__file__):获取当前文件的绝对路径,__file__:表示当前文件
【os模块之split获取文件名】
result=os.path.split(path):这里的path为绝对路径,得到的结果是一个元组,前面是文件目录名字,后面是文件名,可以直接取回来用[1],也可以通过文件rfind的函数返回值然后[]可以截取到文件名,
【os模块之splitext获取文件名】
result=os.path.splitext(path)--->path是绝对路径,得到的是文件的后缀名,
【os模块之getsize获取文件大小】
result=os.path.getsize(path):path为路径,得到的单位是字节,
【总结os模块os.path】
dirname(__file__):jion():split():splitext():getsize():isabs():isfile():isdir()
【os模块之exists判断文件目录是否存在】
os.path.exists('path'):如果存在就返回ture,否则就是false
【os模块之多重赋值文件】
Result=os.listdir(r' D:\python ')---->返回文件这个文件夹里面所有的文件夹下的文件名称和文件夹,返回的值为列表装着
【os模块之mkdir创建文件夹】
os.mkdir(r'c:\nihao'):新建目录文件夹
【os模块之rmdir删除目录文件并只能删除空的文件夹】
os.rmdir(path):删除空的文件夹
【os模块之remove删除文件】
os.remove(r'path'):path必须是指定到某个文件,例如从c:\a.txt
删除目录包含里面的文件
import os
path =r'c:\p1\p2'
filename=os.listdir(path)
for file in filename:
path1=os.path.join(path,file)
os.remove(path1)
else:
os.rmdir(path)
print("删除成功!")
【os模块之切换目录chdir()切换目录】
os.chdir(r'path'):切换目录
【复制文件夹和文件和粘贴复制文件夹】
递归加上新建文件目录
【异常机制exception】
【语法错误和异常】
【异常】
异常:在程序运行的时候报出来的,XXXError
异常处理:
try:
可能出现异常的代码
except:
如果有异常执行的代码
finally:
无论有没有异常都会执行的代码
try:try也是算一个代码块,
【异常代码】
def func():
try:
n1=input("请输入")
n2=input("请输入")
sum=n1+n2
print("sum")
except ZeroDivisionError:--------->可以有多个异常处理 但是错误的类型不能相同
pass
except valueError:--------->当出现这种异常的时候,执行相应的语句,不会直接报错
pass
except Exception:
func()
【异常捕获】
异常的所有基础都是来至于对象,向下
老祖宗object-->BaseException---->Excepttion--->Error 新的类型异常
ZeroDivisionError:
ValueError:
FileNotFoundError:
【异常的最大长辈Excepttion】
def func():
try:
n1=input("请输入")
n2=input("请输入")
sum=n1+n2
print("sum")
except ZeroDivisionError:--------->可以有多个异常处理 但是错误的类型不能相同
pass
except ValueError:--------->当出现这种异常的时候,执行相应的语句,不会直接报错
pass
except Exception as err:
print("出错了",err) -------->能够进行异常捕获,就是把它的错误类型给一个变量
异常处理是从上往下,只要异常是属于他的字辈,那就是直接就执行他下面的语句
如果有多个异常except,顺序要注意,最大的异常放在最后面
【try:except:else:和try:finally结构】
如果使用else则在try代码中不能出现return,因为return 在函数里面可以结束函数,但是出现finally的时候,那个return就不会当成真的return,会直接去执行finally里面的语句return,但是于finally里面的return会覆盖前面的return里面的值
【return不能出现在try except esle】
def fun():
try:
语句
return 1-------------->这种用法是错误的,因为他们return就直接结束啦
except ZeroError:
语句
else:
语句
当try语句出现问题的时候那么就会执行else中的语句
【try except finally】
def func():
stream=None
try:
pass------------>由于try算是一个代码块,所以在try里面的变量在外面访问不到可以在,try上面声明变量,为None
except Exception as err:
pass
finally:----------->无论成不成功都会执行 关闭流
if stream:
stream.close()
====================3.8白====================
【抛出异常这是自己写的,并不是是系统报的错误这是手动往外面扔】raise 抛出
def register():
username=input("")
if len(username) < 6:
raise Exception("用户长度必须为六位") --------------->抛出异常,使用的是异常的父类,在运行错误的时候,不仅会报出原有的信息,而且还会报出抛出的异常提示条件
else:
print("成功")
调用:输出提示信息
try:
register()
except Exception as err:
print(err)
else:
print("成功")
【特别注意】抛出异常只是自己手动抛出来的,就算自己不手动抛出来,只有出现异常,都会到except 中执行语句
【列表推导式】旧的列表---》新的列表,简化函数的书写
格式:[表达式 for 变量 in 旧的表达式]或者[表达式 for 变量 in 旧的表达式 if 条件]
[x for name in names ]
【这里有包含if 和for语句的】
result=[name for name in names if len(name) > 3]
得到的结果是,列表的数据长度大于三的元素,形成的是一个新的列表
第一个表达式,是要对符合条件的元素进行操作的,相当于就是将符合条件的进行添加最后输出一个新的列表
result=[i for i in range(100) if i %3 == 0 and i %5 ==0 ]
[(x,y) for x in range(5) if x%2==0 for y in range(10) if y %2!=0]
【如果出现了if else的语句的时候就会更改其中的顺序 if语句就写在for语句的前面了】
字典工资的声明变量放在列表里面list1
newlist = [employee[]gongzi]+200 if employee[gongzi]>500 else employee[gongzi]+100 for employee in list1] 前面的变量是最后加入列表的东西,后面才是条件和循环 注意:这里如果没有else 语句的时候则if语句是写在后面的
【集合推导式】(功能是去掉发重复项)的功能】
set1 ={ x for i in list1 if x>5}
【字典推导式】
newdic={value:key for key,value in dict1.items()}相当于列表的推导式,得到新的字典
【生成器和迭代器】(生成器)由于列表推导式可以生成很大的列表,但是使用只是用一点点,从而浪费了空间
【生成器的创建方法】
例:g=(x*3 for x in range(10)) 可以打印一下,type(g)--->generator 没有生成元素
g._next_():有返回值,需要接,或者直接打印,有下划线
2.内置函数 next()
next(g):里面的g就是一个generator对象和上面是一样的生成下一个数值生成器
如果超出了generator对象的下限,就会报错,就算再就行调用next()也没用异常为:StopIteration异常
【生成器和异常处理】
g=(x*3 for x in range(10))
while ture:
try:
e=next(g)
print(e)
except Exception as err:
print(err)
else:
break
【生成器yield】
只要函数中出现了yield 关键字,说明函数就不是函数了,就变成了生成器了
步骤:
定义一个函数 ,函数中使用yield关键字,
调用函数并且接受函数
得到结果就是生成器
借助next(),_next_得到元素
def fun():
n=0
while True:
n+=1
yield n
g=fun()
next(g)
【杯莫纳契税额】 ---代码
g=fun()
next(g)
def fun(length):
a,b=0,1
while i<length:
yield b ----------->作用是:返回b的值并且,暂停到这个位置下次再次调用的时候,那就是冲下一句开始执行
a,b=b,a+b
n+=1
return "没有了"------>提示信息,以报错信息的的形式反馈
g=fun(34)
next(g)
如果在生成器中没有了多余的可以申请了,那么不想让他报错,就会把提示的信息放在return中
【生成器3】
def gen():
i = 0
while i < 5:
i+=1
print(i)
tmp = yield i
print(tmp)
【生成器调用的方法】
next(g)
g._next_()
g.send('呵呵')---->第一次调用send的时候,必须传输为None,否则会报错
因为在执行到赋值的时候,就会返回一个值,并且暂停,所以第一个值相当于是一个初始化的意思
【生成器赋值yied】
def gen():
i = 0
while i < 5:
i+=1
print(i)
tmp = yield i
print(tmp)
g=gen()
g.send(None)
g.send("您好")
g.send("种植") --------->相当于把里面的值,赋值给里面yield的时候的值,第一次的none必须为空,因为像一个初始化的那种
【生成器的方法】
__next__():获取下一个元素
send(value):向每次生成器中去调用传递值:注意第一次调用的时候必须传递None否则第一次就不会得到值 里面的到的tmp可以继续进行运算新的循环
【进程 线程 协程是用生成器来进行做的生成器的应用】---交替执行可以充分利用cpu的功能
在一个线程里面有多个协程,就是一个线程做作为主体,然后将一个线程里面继续分成多个分支,那么就是协程
yield:可以只用这个关键词,这个也是一个生成器,只是只返回值,但是进行传递值
def task(n):
for i in range(n):
print("正在搬砖")
yield None
def task2(n):
for i in range(n):
print("正在搬砖")
yield None
g1=task()
g2=task()
while Ture:
next(g1)
next(g2)
这样可以得到两个函数交替执行
【可迭代的对象,迭代器】
可迭代的对象:生成器 列表 字典…
判断数据类型isinstance(list,Iterable),这里是可迭代的 使用的时候需要导入某些模块
就是 from collections import Iterable 这就是使用Iterable (可迭代的)
【迭代器】
迭代是访问元素集合的一种方式,迭代器十一个可以记住遍历位置的对象
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完成结束
迭代器只能往前不会后退
可以被next()内置函数,并且不断返回下一个值得对象被称为迭代器:Iterator
可迭代的 是不是 肯定是迭代器呢?不是
生成器地可迭代,是迭代器
list是可迭代的,但是不是迭代器
【内置函数 iter()】
iter():这个内置函数,将可迭代的但不是迭代器,转换为迭代器
【什么是生成器,什么是迭代器】
可以被next()内置函数调用并且返回下一个元素的都是迭代器,
迭代器是一个大的范围,生成器只是属于迭代器,但是可以迭代的但是不是迭代器,也可以通过iter()内置函数变成一个迭代器
【面向对象的简介】
程序中的对象,现实中的具体的实物,
面向过程的话就是一步一步的做,不是全局的,但是面向对象的话,那么把他们全部写成一个对象,然后最后在才寻找对象之间的关系
好处:改动不是特别大,某一块出现问题了那么就只会更改某一块,但是如果是面向过程的话,那么这个出现了问题就需要全部更改
【面向对象需要涉及到】
类 对象 属性 方法
【什么是对象】
所有的类的名字必须大写,多个单词使用帕斯卡命名法
class Phone():
属性和方法
默认是Phone括号里面是使用的是object对象,但是在py3中可以不写括号都可以不要例如
class phone:
属性和方法
【对象的属性】--定义
class phone:
x="你哈"
yd=Phone() ---->对象实例化,相当于把模型(类)变为新的对象出来 就是相当于赋值,就是对象实例化
每次构建出来的对象,得到的地址都是不同的,就算是空的类,也可以进行实例化
【类进行模子刻画出来之后,得到的数据就是对象】
怎么调用对象,用实例化的东西.属性或者是方法,就可以得到值(就是调用)
yd.x:得到其中的属性,得到实例化的属性
【类的属性】
class Student: --- >定义类
name='华为' -------->类属性
age=2
xiaowei=Student()
xaiwei.name---->华为
xaiowei.name='不好' 这是对象属性,属于动态添加 是在本身的内存里面创建的 ,这样的属性被称之为对象属性 ---------->这是属于赋值操作,只会针对与本身去进行的去进行操作的,
(底层的做法):由于xiaowei是通过Student()类进行创建的,2.当访问xiaowei的属性的时候,会先去xaiowei本身对象的里面去找,当本身的对昂找不到的时候,就回去进行class的那个模子里面去找,这个是有先后顺序的
【更改类里面的值,必须要用类名去调用使用】
class Student: --- >定义类
name='华为' -------->类属性
age=2
Student.name="新的属性"---->更改为新的属性
【写在类里面的方法和函数】
类中的方法:动作
种类:普通方法 类方法 静态方法 魔术方法
class Phone:
band="你好"
price=499
def call(self): ----->系统会自动生成一个参数self 这个是不用传递参数的,这个self表示的是自己的当前自己的这个对象,因为每一个类实例化出来都会有新的空间,新的地址,然后self表示的就是当前的这个对象(当前的对象地址地址)执行的地址
print("正在打电话")
phone1=Phone()
phone1.call() --->这里可以传递参数,也可以不用传递参数 调用这个class里面的方法就是相当于调用模子里面的方法
注:如果在类里面的有定义的方法,并且在方法里面还有访问类里面未定义的变量但是这个变量在类里面并没有,但是在后面的实例化对象之后,针对于不同的地址对象在对象中添加的变量,并且在对象里面调用,在对象里面的方法,可以直接表示出来,但是其他实例化的对象并不会有这个变量,其他对象访问的时候就会报错
【构造器和__init__方法】
魔术方法:def __init__(self): --->初始化,不管掉不掉函数,都会执行的函数,只要类的实其中类实例化的在内存中的运行步骤:
class phone:
def __init__(self): ------->相当于动态添加给开辟的地址,添加类的属性或者方法
self.brand="jaid"
def eat(self,food):
print(food)------>普通方法也可以去添加参数,
phone1=phone()
phone1.eat("肉")------------------->那么通过对象去调用普通方法的时候就需要就行进行传递参数
【对象方法一个魔术方法】
class phone:
def __init__(self,name,age): ------->这里初始化可以写需要传递参数,就是动态给对象添加属性,这个参数,是在开始实例化的时候就必须传递进去的,否则就会报错
self.name=name
self.age=age
self.brand="jaid"
phone1=phone("张三",21)---->这就是魔术方法的传递的参数,这里传递的参数,默认是传递到__init__(),里面
【类方法】
class Dog:
@classmethod
def test(cls) ----->cls 是class的简写
【类方法的代码解释】
class Dog:
name="你好"
def __init__(self,name):
self.name="比不好"
def eat(self):
print("吃饭")
def run (self):
self.eat() ------------------>要在类中调用自己的方法的话,就要使用self.方法名来调用普通的方法
print("出去跑")
@classmethod ------------->类方法的时候就需要加上@classmethod 并且在参数哪里写上cls—>表示当前的类
def tset(cls):
print(cls)----->得到的是自己的类的地址,默认会把自己传递进去
特点:
【类方法的定义和使用 和调用】
类方法的定义得参数是cls和加上@classmethod 然后类中只能调用类的属性,不能调用普通方法,其中cls表示的是当前类的地址,普通方法的在参数里面需要加上self,在类中调用需要用self.方法名,这和函数中调用不一样,self还可以在init中,初始化对象动态添加属性
【类方法和作用】
因为只能访问类的属性和类方法,所以在对象创建之前,如果需要完成一些动作,可以用类方法使用
【类属性的私有化】
在类中使用,__属性名,就可以将属性私有化,就是只能在类中才可以访问,出了这个类外面就访问不了(这是针对于对象还没有创建好的时候)
class Dog:
__name="你好"---->这就是私有的方法
def __init__(self,name):
self.name="比不好"
def eat(self):
print("吃饭")
def run (self):
self.eat()
print("出去跑")
@classmethod
def tset(cls):
cls.__name="不好" ----->在对象还没有是实话之前,可以直接在类方法里面修改私有方法
print(cls)----->得到的是自己的类的地址,默认会把自己传递进去
【调用类方法的作用已经方法】
也可以在类外面去调用类方法(在对象没有实例化之前)Dog.test(),可以去修改类的私有属性,
【静态方法的申明】
1.在方法之前加上装饰器名加上@staticmethod
2.在函数名的参数没有参数
3.也只能访问类的方法和属性,对象的属性是无法访问的
4.都可以在对象没有创建之前访进行类.方法名访问的
4.加载的时间和类方法相同
如下:
@staticmethod
def test():
print("静态方法")
【各大方法的调用情况】
【普通方法和两中其他方法的区别】
不同:
1.没有装饰器
2.普通方法永远是依赖对象的,否则无法使用
3.只有创建了对象才可以调用普通方法
【总结 】
只有实例方法是必须实例化之后才可以调用的,如果没有实例化,谁都调用不了,类方法和静态方法都是可以通过类来调用的或者对象来调用的,属性是都可以调用
【魔术方法】
__init__(self):初始化魔术方法
触发时机:初始化对象时触发,但是在实例化在一个操作中
def __init__(self)
print("----------->init")
__new__:实例化的魔术方法
触发时机:在实例化对象的时候触发 –比init的魔术方法先执行
def __new__(cls,*args,**kwargs):
print("new")
class Person:
def __init__(self,name)
print("----------->init")
def __new__(cls,*args,**kwargs): ---->new 新开辟的空间
print("new")
x=object.__new__(cls)
return x
申请开辟内存空间,并且返回地址给init中的self
p=Person()
【魔术方法的new方法执行的过程】
__new__(cls):new方法是用来开辟地址的方法,这个方法,如果不写的话系统自动执行,如果写了的话就需要return把值返回出来,然后与给self的值就是那个return的地址,最后在将这个地址赋值给对象,总之开辟__new__(cls)就是用当前类来开辟地址的
def __call__(self,*arge,**kwargs):在对象后来进行函数调用的的时候,才执行call,例如对对象,执行,p(),这个时候就会执行,类中的call方法里面的东西,如果只进行p(),并且不写__call__()方法的话,这样就会报错,直接报错,(这是想将对象当函数使用的时候)
__del__:delete的缩写,析构魔术方法
查看地址引用数需要导入一个包,import sys 这个模块 print(sys.getrefcount(p)):找p的地址,有几块地方对他有引用.会多一次,因为调用这个函数的时候会进行再次利用这个地址所以得到的引用地址会多一次,对象赋值,del就可以删除对地址的引用 当没有变量指向这个值得时候,这时候就会执行__del__(self):方法,,还有一种方法,当每次python解释器将所有的代码解释完成之后会进行本次运行产生的所有的内存空间进行回收,这时先执__del__(self):方法,在进行回收(注意: 删除引用的空间的代码是 del 引用的地址名字)
【python中自带垃圾回收的机制】
简而言之,垃圾回收就是python中自带的机制,简而言之就是内存回收内存释放,当有一块地址没有被引用的时候就会进执行定义得__del__(self)的方法,通常不要写,会打乱系统中的垃圾回收的机制
__str__(self):在只打印对象的时候return里面的东西 )(魔术方法就是在特定的时刻,自动测法)
def __str_(self):
return self.name -------->需要返回的东西,写在return中
这个方法就是在打印这个对象地址里面存在的东西,,对于没有__str__(self):方法的时候,这个打印对象的地址,这对于程序员来说没有什么意义
【私有化】
【私有化】
封装1.私有化属性
【私有化的好处】
class Student:
def __init__(self,name,age):
self.__name=name
self.__age=age
self.__socre=23
def __str__(self):
return str(self.__socre)
def setAge(self,age):
if age>0:
self.__age=age
else:
print(不能赋值)
def getAge(self):
return self.__age
p=Student("小王","15")
p.setAge(25)
print(p.getAge())
【@property装饰器】
dir(类名或者对象名):打印出在这块地址下面出现的属性,为什么对象里面访问不到私有属性,因为在底层出现了一个东西,只要是私有属性,在系统底层里面就会默认给这个属性加上_类名__属性名,所以在对象里面访问不到,是因为在对象里面没有这个东西,其实这里的四有并不是真正的四有,而是你可以通过他真正的名字来访问他的私有属性
对象.__dir__():这个方法也可以查看这块地址出现的属性
【在开发中私有化并不是使用__属性名来实现的,而是通过装饰器来实现的】
@property -------->就是相当于得到某个私有属性的方法
def age(self):
return self.__age ---------->正常状态下,如果对象可以直接调用函数来实现访问私有属性,但是调用的时候需要加上 对象.age()----进行调用,这是没加装饰器的情况下,加了装饰器之后,调用的时候就可以不用加括号了,变成对象.age 可以直接调用把他当成属性调用,
更改其中的值的话就需要在写一个承接上面的一个装饰器
@age.setter -------->要先有age这个对象
def age(self,age):
self.__age=age
需要改变值的话,就可以用对象进行调用,对象.age=”58”,就可以修改私有属性的值
和访问非私有属性一样
----------------------------------3.15白---------------------------------------------
【关联关系】
import random
class Road:
def __init__(self,name,len):
self.name=name
self.len=len
class Car:
def __init__(self,brand,speed):
self.brand=brand
self.speed=speed
def get_time(self,road):
ran_time=random.randint(1,10)
msg="{}品牌的车在{}以上{}速度行驶{}小时".format(self.brand,road.name,self.speed,ran)
print(msg)
r=Road('清账高原',12222)
audi =Car("奥迪",120)
audi.get_time(r)
类型:有系统提供的对象,字符串,列表以及等等,以及自定义的类型,那就是类
知识点:
has a
一个类中使用了另外一种自定义类型新的类对象
自定义类型:
就是自己定义一个新的类,然后把这个类当成一个新的类型
【继承关系 supper()】
is a base class 父类 基类
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
class student(Person):--------------->这一个叫做继承,要把继承的类放在类的括号里面,那就会继承括号里面类的名字的方法
pass
继承的示意图 :
最上面是对象 然后是person 这个父类,然后在类里面还有是哪个类
1、 继承,就是把其他类里面有重复的直接放在基类里面,然后让其他都需要有这个的方法的去继承这个基类
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
class Student(Person):
def __init__(self):
print("init")
supper().__init__() ---------->调用父类的init方法 使用的supper().父类方法
stu=Student()----->这里会调用Student对象里面的__init__(self):
当类里面有init方法,以及父类也有init方法的时候为了调用父类的,就是在创建对象的时候进行supper().父类的方法,去调用父类和子类同名的方法否则的话就是就是就近原则
【继承父类的传递参数的问题,可以通过子类的__init__魔术方法来传递参数,也并不是要将所有的参数都传递过去,也可以给自己一些独有的属性,都是一层一层的把参数拨出来】
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
class Student(Person):
def __init__(self,name,age):
print("init")
supper().__init__(name,age)
stu=Student("nas1","23")--------------->传递参数,就是一层一层往上传递,先通过init方法去传递参数,
再用supper().init方法的参数传递到父类调用的init方法里面,最后传递到父类的init里面
总结:
1.如果类中不定义__init__(),就会调用父类的)__init__
2.如果类继承父类也需要定义自己的init方法,就要在当前类的init中调用一下父类的init方法
3.调用父类的__init__()
supper().__init__(参数)
supper(类名,对象).__init__(参数)
这种叫重写,override:重写(覆盖)
【多重继承与MRO-9】
在python的类中不会出现重载的概念,如果出现同名的函数的话,那么后面一个函数会把前面一个函数覆盖掉,没有所谓的重载
【多重继承】
class A(B,C): ------------>这就是python中的多继承,就是在括号继承里面有多个继承的父类
【可以查看多继承里面搜索同一方法的先后顺序】
导入包: import inspect
Inspect.getmro(D) ----------->返回多继承的搜索先后顺序,D表示是他们的子类
也可以使用D.__mro__:得到搜索的排行顺序
Python中允许多继承,如果父类里面有相同的方法他们的搜索顺序是:这里分为 经典类 (从做导游深度优先)和 新式类(广度优先)这是在python2中 ,在python3中已经没有区别了,现在都是新式类(广度优先)
【property装饰器】
class hell:
@property ---------------->这是装饰器,返回私有属性return
def age(self):
return __age
@age.setter------------>更改了私有属性的方法,有参数,就是更改私有属性
def age(self,name):----->这里的名字一定要相同,和property的装饰器修饰的函数
self.__name=name
这样的好处就是,如果要赋值的话,直接进行s.age=78 这样的时候,就直接把这个当成属性用(把方法当成属性用会,自动进行函数中进行需要有参数的方法的调用),直接用的话,就是s.age,这里就是默认调用的是没有参数的哪一个,直接就行return的值
【多态】类就是自定义的类型
面向对象的三大特点:封装 继承 多态
在python中,多态就是类似于has a 讲对象当成参数,到其他类里面去,在python中,制定了传递的对象传递到类中都是可以接到的(不管是否是某种类型的子类),这和其他语言不同,
这里只有加上isinstance(obj,类)函数来判断是否是某种类型的(判断这个类,是否是这个类的对象,或者是否是这个类的子类的对象)
【单例模式】属于开发模式---自始至终这里的所得到的对象的地址都是一个样子,没有改变,对于内存的优化
class Singletion:
__instance=None
def __new__(cls):
if cls.__instance=None:
cls.instance=object.__new__(cls)----->__new__(cls)方法是在创建对象的时候,new方法是用来创建对象的地址的时候的,
return cls.__instance
else:
cls.__instance
s=Singletion()
print(s)
s1=Singletion()
print(s1)----->打印出来的地址是同一个地址,因为在类声明的时候,那时候__instance:得到了之前的建的那个地址
【模块的导入和使用第一种方法】
模块是代码的一种方式,把功能相近的函数或者类放在一个文件中,文件是(.py)就是一个模块,模块名即是文件名去掉后缀.py,这样做的好处是:
-提高代码的可复用,可维护性,一个模块编译完毕后,可以很方便的在其他项目中导入,
解决了命名冲突,不同模块中相同的命名不会冲突
还有常用的一些标准库
【自定义模块】
就是一个新建的一个xx.py文件,在里面定义一些函数就是一个模块,里面可以包含变量可以包含类可以包含函数
导入模块:
import xx ---->import 模块名
xx.add()
xx.name----->调用的是模块里面的变量值
y=xx.类名()----->调用类进行实例化,里面也有类方法
这里就通过导入的模块名字然后.方法可以调出模块里面的方法
【模块的导入第二种方法】导入模块就相当于在当前文件里面写了模块里面的东西
from 模块名 import add ----------->直接导入模块中的某一部分并且使用的时候就不需要模块名.方法了,直接用 方法或者类
from 模块名 import add,reduce ------>这是导入同一模块中的不同方法,可以直接在后面跟上逗号,如果要导入模块里面全部的东西的话,就直接用 *号 from 模块import *
在模块中也可以限制 * 号取到的东西,可以再模块里面加上首行加上__all__=['add',"number"],列表里面写*导入的常用的方法或者是类,这样在尽管是导入*,只要__all__=[只需要名字就可以了]列表里面没有的就会报错,这就是限制*号导入所有的方法,
【import方法加载的时候就是将里面的所有东西都加载到当前内存里面来】尽管是在模块中已经调用的,模块里面的也会在导入进来的就会先执行,里面有函数的调用
add(list1)--->使用的话就是直接是方法名
【导入模块就会先加载函数里面的调用函数和调用】
xx.py
def hello():
pass
def nihao1():
pass
if __name__="__main__": ------------>这里就会就行判断。__name__在当前文件表示的是__main__,在其他模块的时候就显示为导入的模块名字
hello()---->模块里面的调用
from xx import hello --------->这里面就会就先进行hello函数的调用,但是在模块里面加入了if __name__="__main__"就可以避免导入模块的时加载执行函数,
注意:即是导入的东西,里面没有涉及到要调用的函数,尽管如此,导入加载的时候也会执行调用的函数
------------------------3.17----------------------------------------------------------
【包的导入】
文件夹里面放包或者其他东西,非py文件
包里面放的是py文件,包里面默认会有一个__init__.py的文件,一个包里面有多个模块
当模块存在于单个文件的时候,这时候,如果需要导入包中的模块的话
语句是: from 包名 import 模块名 ------------>这种方法不能精确到模块里面的东西调用的话:
用法:模块名.方法
语句二:from 包名.模块名 import 类或者方法 -------->
用法:使用的时候就是和本身的一样,直接hell():函数直接进行调用或者其他的东西可以直接用不需要在进行模块名.类名
【导入包里面的模块】
只要不是裸露在项目里,不管是都属于当前包里面导入还是不属于当前包,导入的方法都是from .模块名--->其中的.表示当前包,当前目录(由于所有的from都是基于当前的项目下)
只能通过 from 包名 import 模块 或者from 包名.模块 import 函数或者类名,来导入属于包里面的模块,,,不仅可以导入模块,还可以直接 import 包名,,
【包文件里面__init__.py文件的作用】
__init__.py:有这个文件就是包,没有这个文件就是文件夹
user.hello();
3.可以结合__all__来使用
【__init__.py的作用 模块中】:
【__all__=[]的作用】
【__all__对于包名来说】
from 包名 import *,在这里只还需要在__init__.py文件里面写上__all__=['暴露的模块名',]列表里面是暴露给*号的模块名字,必须要写上这个__all__=[],否则就不会导入包里面所有的模块,只有在__all__=[]里面的东西才可以是导入的东西,才可以访问。
【模块中的循环导入的问题】
原因:就是在a模块里面要调用模块b,然后b模块里面需要调用模块a,然后就会进行报错
【循环导入模块的解决办法】
【导入sys模块,这是系统模块】可以查看python中导入包的执行顺序
import sys
print(sys.path)----->打印出搜索模块的先后顺序,返回的是绝对路径 也可以通过 做标记 将寻找包路径进行变化以及更改 最后找模块最后才是第三方库里面去找 ,第一找的是当前的项目下
sys.version:打印出python解释器的版本
sys.argv:运行程序时,出现的参数,获取执行这个接的参数 这是当前文件的地址,还可以在解释器里面传递参数,在edit编辑路径里面有,parameter空格,如果传递的参数,获取的就是得到的参数,是一个列表
【time模块】时间戳
import time
time.time():获取时间戳
time.sleep(3):停留3秒钟
time.ctime(time.time()):将时间戳字符串,转变为一个本地的时间的字符串格式
time.localtime(time.time()):将时间戳转为元组的格式的格式
time.mktime(time.localtime(time.time())):将元组的时间格式转变为时间戳的格式
获取元组里面的东西,
t.tm_day:获取当前时间这个元组里面的东西
time.strftime("%Y-%m-%d"):将元组格式转换为括号里面定义得函数,这里默认取得就是当前的本地时间,
time.strptime('2019/2/3',"%Y/%m%d"):就是把当前的字符串转换为元组
【datetime模块】
里面得到的大多是对象,不是一个值
Datetime.date.tody():得到的是当前的一个日期
Timedel=datetime.timedelta(hours=2)或者传递weeks=3也可以是两个一起传递,中间用逗号隔开:求时间差得到的是时间差值,就是三周的时间
datetime.datetime.now():得到当前的时间 这个可以和时间差进行运算
可以将当前的时间和时间差进行运算,可以设置保存缓存多长时间和缓存一样,这和session一样,只不过session是保存在内存里面
【random 模块】
import random
ran=random.random() :随机生成0-1之间的小数
random.range(1,12,2):得到1到12之间步长为2,的整数,随机生成
random.randint(a,b):产生一个a到b之间的整形的数字
list1=['薛强','菲菲',"佳伟"]
random.choice(list1):产生list1中需要随机的元素
pai=['红桃A','方块K','梅花8']
random.shuffle(pai):将pai这个元组里面的东西进行乱序,
产生验证码:
code=""
for i in range(4):
ran1=random.randint(0,9)
ran2=chr(random.randint(65,90))----->chr()会将整形转换为它对应饿ascc码
ran3=chr(random.randint(97,122))
code+=random.choice([ran1,ran2,ran3])----------->随机选择数字还是大小写字母
print(code)
chr(95):将码变为字符
ord("W"):将字母转换为码---->Unicode 码
ord("上"):19979
【平常所用的内置模块就是 标准库】
【hashlib模块】涉及到加密
【主要的加密算法】
import hashlib
msg=鸟"
hashlib.md5(msg.encode("utf-8"))----->除了中文其他的都要进行进制转换
x=hashlib.md5():但是在md5里面不能直接写字符串,必须写变量并且进行编码
print(x.heidigest())----->打印出将字符串加密的字符串
x=hashlib.sha256(x.encode("utf-8"))
print(x.hexdigest())------->得到加密的值,SHA256=64位比MD5=32位加密更加长
hashlib.shar256():
【可以逆方向进行编码和解码】
base64
【不能进行逆方向算法】
SHA1,SHA224,SHA256SHA348,SHA512,MD5。其中SHA越大,加密的越长
【第三方模块】需要在第三方下载 终端输入pip install 第三方模块名
【request 模块】
import requests----> request模块相当于第三方的浏览器模块
response=requests.get("http://www.baidu.com")---->打开一个网址,得到的是这个网站的源代码
response.text---->得到这个响应的源代码
【pillow 模块图片处理的模块】
【正则表达式 用这个正则的时候需要用到re模块 介绍】
正则表达式针对的是字符串是一种过滤的逻辑规则
import re
msg="后低位启动前我都"
patter=re.compile("启动")--->会返回一个对象
patter.match(msg)---------->match从头开始匹配,如果第一个没有匹配上没有就会返回none,否则返回他的所在位置一个对象
【真正的正则】
import re
s="侧ID核武器的未取到"
result=re.match("未",s)
print(result)--->只要是match 都是从头开始匹配,没有匹配上就会返回none
【search方法】
import re
s="侧ID核武器的未取到"
result=re.search("武器",s)---->不是重头开始匹配,能匹配就行,如果没有匹配到那么就是None,但是要是找到了一次就不会进行下一次查找了
print(result)
result.group():进行提取已经匹配的内容
result.span():将匹配的值返回他们出现的位置 从0开始
【正式的进入正则】
【正则的符号】
[]:表示的是一个范围,范围里面就是指定要匹配的内容
import re
s='哈哈3e'
result=re.search("[0-9][a-z]",s)
print(result)---->得到匹配到的正则的下标位置
result.group():得到匹配到的值
【re模块的findall()】
import re
s='哈哈3e'
result=re.findall("[0-9][a-z]",s)--->会找出所有匹配的,只要匹配就会进行往列表里面放,列表里面得到的是已经匹配到的内容,不需要再用group的方法提取
【正则之 * + ?{m,n}】全部是验证正则匹配到的字数次数的
+:re.search("[0-9]+[a-z]",s):+号跟在谁的后面就针对于谁来说表示>=1
*:>=0
?:0,1
【{m}:表示多少位】
//验证QQ号码 5~9位,开头不能是0
re.match(^[1-9][0-9]{4}$,s):默认是字符串匹配,重头开始匹配
^:表示用整个正则式与字符串的开头开始匹配
$:表示用整个正则式与字符串的结尾匹配
{m}:表示多少位
{m,}:表示>=m次
{m,n}:表示大于等于m位,小于等于n位
【正则表达式的使用和分组操作】
import re
username="udwgui3243"
result=re.match('[a-zA-Z][0-9a-zA-Z]{5,}',username)---->表示有范围里面可以叠加,
print(result)
注意:re.match():只能从开始找,re.search():不重开始找,能找到匹配的就会返回,不会把整个字符串作对比re.findall():找到所有的匹配项
\d:表示的是[0-9]
\D:匹配非数字字符,等价于[^\d]
\s:匹配任意空白字符
\S:匹配任意非空白字符等价于[^\s]
\w:匹配字母数字和下划线:只能匹配单个字符
\W:匹配任意非字母数字下划线,等价于[^\w]
\\:匹配原意的反斜杠\
\b:匹配一个单词的边界,也就是单词和空格的位置 例如:re.findall(r'\w*\.py\b',msg):匹配以.py结尾的并且以空格分隔的文件名
.:匹配的是除了换行里面的任意字符(\n)
^:开头
$:结尾
[]:范围
【匹配0~100的值】
result=re.match(r'[0-9]?\d?$|100$'):匹配一位或者两位或者100这里表示两个正则二选一,
|:表示或者前面的正则或者是后面的正则
[]:[123|234]表示或则是1,或者2,表示的是单个
():小括号表示(asd|wqeqw|sdsq):表示或者是asd或者是另外一个,表示的是一个word或者是另外一个word,表示的是整体,这个只能从这三个选其一
【非连续的数字】
re.match(r'1\d{9}[0-35-689]',phone):[]可以在里面写一不连续的
【分组】
result=re.match(r’\d{3}|\d{4}’)-(\d{8}$)
分别提取,必须要结合()来分组,
Result.group()------->默认提取全部的东西
Result.group(1)----->提取第一个正则里面的东西
Result.gruop(2)----->提取第二个正则里面的东西
【提取标签里面的东西】
msg =‘<html>saddsa<html>’
msg 1=‘<h1>saddsa<h1>’
result=re.match(r"<\w+>(.+)<\w+>$")---->.表示匹配任意字符
result.group(1) ---------->获取字第一个括号里面的内容
【引用之前已经屁屁到的值/1 表示的是第一次匹配到的值】
result=re.match(r"<(\w+)>(.*)</\1>$")--------->这里\1其中1表示的是w匹配到的内容表示的是匹配之前在\w+匹配到的值,然后进行引用之前的值,意义是为了匹配到相同的标签
result.group(1)--->调用第一一个括号匹配到的值
result=re.match(r”<(\w+)><\w+>(.*)</\2></\1>”)------->这里就是为了匹配到前后标签一对的出新,并且出现的位置可以根据之前匹配的值进行引用,这里添加的组可以()可以在引用的时候不用写,匹配值写之前匹配到内容
【给正则之前的起名字】起名(?P<name>\w)给\w起名字放在一个组里面就是放在一个括号里面引用的话,就是(?P=名字)
result=re.match(r"<(?P<name1>\w+)><(?P<name1>\w+)>(.*)</(?P=name1)></(?P=name2)>",msg)
【引用标签】
?P<name>\w ------------>这里相当于给/w起一个别名,好在后面引用的时候好引用,(?P=name1)引用之前的名字,引用/(?P=name1)这里的?P相当于一个名字的标识,引用【re.sub】替换
result=re.sub(r"\d+","90","java:915")
print(result) ------->java:90
用90来替换在字符串中匹配到的数字
格式:re.sub(正则,要替换的类容,要替换的字符串)
def func(temp):
num=temp.group()
num1=int(num)+1
return str(num1)
result=re.sub(r"\d+","func",java:10,python20")---->这里就是用将匹配到的东西传递个函数,然后函数就会返回值+1,这里的函数调用不需要用(),因为直接给地址就可以了,参数也不需要,直接写上函数名字就行了
【re.split】
格式:re.split(r”正则”,”字符串”)
result=re.split(r"[, :]","kjajsas:,wqdw,")-->按照正则匹配到的进行分割
这会返回切割的内容并且会放在一个列表里面result=re.split(r"[, :]","kjajsas:,wqdw,")
【总结】
re:模块的五个函数
match search findall sub split
re:模块的基础
. [] | ()
re:模块的量词
* +? {m}
预定义:
\w \d \s ...
分组:
group():取值,只针对于有匹配到值
number:
(\w+)(\d+)------>\1 \2引用
name
(?P<name>\w) ------->引用(?P=name)
【贪婪匹配惰性匹配】
贪婪就是出现量词的时候,只有后面符合条件就会一直匹配下去
非贪婪的就是,按照最少的来匹配,只要达到量词的最低标准就不继续匹配了,
非贪婪就是在写上的量词后面加上?就可以了
【爬虫下载图片】
先把图片的地址拷贝下来,通过正则获取下来
path ='<img src="https://img02.sogoucdn.com/app/a/100520020/5b70f8180691c1eebd63106ffb80cd3e" style="height:auto;width:100%;margin-top:--19px;margin-left:0px;">'
import re
result =re.match(r'<img src="(.*?)"',path)
print(result.group(1))
import os
import urllib.request
responds=urllib.request.urlopen(result.group(1))
with open("aa.png",'wb') as wstream:
wstream.write(responds.read())
【进程描述】
并发:当有多个线程在操作的时候。如果系统只有一个cpu那么则他不可能同时进行一个以上的线程,他只能把cpu的运行时间分成若干个小的时间段去执行不同的线程
并行:cpu有多个核,一个cpu执行一个线程
【实现多任务的方式】
多进程模式:
优点:稳定性高,一个进程崩溃了不会影响另外一个进程,
缺点:花销巨大,操作系统能同时运的进程数目有限
多线程模式:
协程:
【linux中进程的创建】
在linux中直接fork();属于内建函数需要从os模块中导入
import os
pid =os.fork()
【windos中创建进程】
在windows里面创建
【进程的代码】
from multiprocessing import Process
from time import sleep
def task1(s,name):
import os
while True:
sleep(s)
print("这是task1",os.getpid(),name)----->这属于主进程,得到该进程的pid
def task2(s,name):
while True:
sleep(s)
print("这是task2",os.getpid(),name)----------->这属于主进程,得到该进程的pid
if __name__==__main__:
p=Process(target=task1,name="任务1",args=(1,aa))---------->这属于子进程,这属于python给开启的,这里为什么要写参数的关键字因为,里面的参数并不是按照里面的参数顺序传递进去,所以要写关键字参数的形式
p.start() ---------------->就是调用这个进程开始执行
print(p.name)------------>
p1=Process(target=task2,name="任务2"args=(2,bb))---------->这属于子进程,这属于python给开启的
p1.start()
print(p1.name,os.getpid())
os.getpid():得到当前进程的pid
os.getppid():得到当前进程的父进程的pid
【对象的调用】
对象.satrt():启动进程并且执行任务
对象.run():只是执行任务没有进行启动进程
对象.terminate():终止改进程
【多进程针对于系统的全局变量的访问】
每一个进程都会在自己的里面生成一个全局变量,对于可变类型和不可变了类型一样的,相互不影响,每个子进程执行的顺序(如果没有设置程序时间的话时间的话)那么执行的顺序就是交给cpu去进行
【自定义进程】
class Myprocess(Process):
def __init__(self):
self.name=name
super.__init()
def run(self): -------------->需要重写run方法,因为这里start在底层里面调用的是run方法来执行的
n=1
wihile True:
print("进程的名字")
n=n+1p1.start()
print(“”,self.name)
p=Myprocess("小明")
p.start()
P1=Myprocess("小妹")
【进程池之非阻塞式】
进程池:初始化Pool时,可以指定一个最大的进程数,当有新的请求提交到Pool中时,如果进程数还没有满,那么就会创建一个新的进程来执行该请求,如果池中的的进程数已达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行
【进程池创建分为两种】
非阻塞式:全部添加到队列中,立刻又返回(指的是将任务放在新城里面就走了)并没有等待其他进程执行完毕,但是回调函数是等待其他任务完成之后才调用的
from multiprocessing import Pool
from time import sleep
from random import random
def task(task_name):
print("开始做任务",task_name)
start = time.time()
time.sleep(random())
end=time.time()
return str(end-start)------------->必须要有return 才能调用回调函数
def callback_1(n):---------------------->必须要有参数
print(n)
if __name__==__main__:
pool=Poll(5)
tasks=["进程1","进程2","进程3","进程4","进程5","进程6","进程7","进程8"]
for task1 in tasks:
pool.apply_async(task,args=(task1,),callback=callback_1)------------->这是用进程池来创建非堵塞式的进程,注意这里的子进程是依赖主进程的,callback=回调函数的名字,不需要加上括号,回调函数是最后执行的,这里当所有的进程中执行完毕之后才会进行回调函数的执行(只有非堵塞式的时候才会有这个方法)
pool.close()--->添加任务结束
pool.join() ------------->必须等子进程运行完成之后才可以开始主进程
print("over")---->主进程结束
【阻塞式】
阻塞式:就是必须等前面一个任务做完了之后才会添加后面一个,尽管进程池里面还有很多剩余的,这就不需要加入队列(之前的那个已经完后的线程闲着)
特点:来一个等前面一个执行完毕之后才可以执行其他的
pool.apply()
【queue 队列,进程之间的交换实现】
from multiprocessing import Queue
q = Queue(5)---------->生成一个队列有五个值
q.put("A")
q.put("B")
q.put("C")
q.put("D")
q.put("E")
print(q.qsize())---->获取队列里面的长度
q.put("F")------>put(方法如果queue满了则会一直等)
if not q.full():------------> 判断队列是否是满的,如果满了就会返回0
q.put("F",timeout=3)-------------->这个方法可以加上超时的选项
else:
print("队列已满")
q.empty():判断队列里面是否是空的
q.full():盘对队列是否满了
q.get(timeout=2):取队列里面的只,并且可以进行超时设置
q.put_nowait():
q.get_nowait(): 不堵塞
【进程之间的通行】
代码:
from multiprocessing import Process,Queue
def download():
images=["a.png","b.png","c.png"]
for image in images:
sleep(0.5)
q.put(image)
def getfile():
while True:
try:
file=q.get()-------------->取队列里面的值,如果取不到就一直是堵塞状态
print("取值成功{}".format(file))------------>
except:
break
if __name__==__main__:
q=Queue(5)
p1=Process(target=download,ages=(q,))
p1.join()-------------->堵塞,不让主线程结束,先执行
p2=Process(target=getfile,ages=(q,))------>如果主线程结束了之后那么这里的空间就会进行回收,然后就不会继续了
p2.join() -------------->堵塞继承不让他执行完毕
【多线程】
线程是依赖进程的,线程之间是占用同一块地址
【threading 线程】
import threading
import threading
from time import sleep
def download():
images=['gril.png','b.png']
form image in images:
sleep(3)
print(image)
def listenMusic():
listens=['sad','asda','sad']
for listen in listens:
sleep(1.5)
print(listen)
if __name__==__main__
t=threading.Thread(target=download,name="aa")---->开线程
t.start()---->运行
t1=threading.Thread(target=listenMusic,name="aa")
t1.start()--->运行
【线程的状态】
新建状态-----start--->就绪----到cpu 运行状态--------结束状态
当线程一睡觉就会把cpu里面的资源,让出来处于堵塞状态,睡了之后就会进入就绪状态,
【线程二】
线程是可以共享全局变量的:例子就是买火车票的例子,
因为线程是共享那块空间的所以他们是共享的,只需要加上golbal 变量名就可以更改全局变量
【GIL锁】
GIL:全局解释器锁 线程同步会延迟时间(因为这个时候会等待前面一个线程执行完成之后才会执行下一个)
如果没有锁的话多个线程抢占一个资源的时候会发生抢占的状态就是一个还没执行完成,另外一个就开始执行了,
加锁的是保证数据安全,但是缺点是延长了时间,所有共享数据都需要加锁,不然
【那为什会进行数据大得时候回传重复的数据数据小的时候就不会出现重复的数据了呢】
python底层只要用线程默认枷锁,当cpu运算达到一定的值得时候这个所就会自动解除
线程:耗时操作,保证数据的准确性
进程:计算密集型,注重的是效率
由于当线程原酸到了一定的程度之后共享数据的锁会默认解除,所以的手动加锁
【加锁和释放锁】
import threading
list=[0]*10
lock = threading.Lock()---->创建一个锁对象
def task1():
lock.acquire() 阻塞 ----------->获取线程锁,如果已经上锁,则等待的锁的释放,如果不释放锁,其他状态就一直是就绪的状态
执行的语句,持续暂用空间
for i in range(len(list)):
list[i]=1
time.sleep(0.5)
lock.release()释放锁
def task2():
lock.acquire()
for i in range(len(list1)):
print(i)
time.sleep(0.5)
lock.relase()
if __name__=__main__:
t1=threading.Thread(target=task1)
t2=threading.Thread(target=task2)
t1.start()
t2.start()
prrint(list)
【死锁】
一个资源需要利用另外一个资源才可以做资源的,如果这个资源被暂用了,就回复发生死锁
避免死锁:
from threading import Thread,Lock
lockA = Lock()
lockB = Lock()
class MyThread(Thread):
def run(self):
if lockA.acquire():---------->如果能够获取到锁则犯规True
print(self.name+"获取了A锁")
time.sleep(0.1)
if lockB.acquire():
print(self.name + "又获取锁B,原来还有A锁")
lockB.release()---->释放b锁
lockA.release()-------->释放a锁
class MyThread1(Thread):
def run(self):
if lockA.acquire():---------->如果能够获取到锁则犯规True
print(self.name+"获取了B锁")
time.sleep(0.1)
if lockB.acquire(timeout=5):---->就可以直接解决死锁
print(self.name + "又获取锁a")
lockB.release()---->释放b锁
lockA.release()-------->释放a锁
if __name__='__main__':
t1=MyThread()
t2=MyThread1()
t1.start()
t2.start()
解决:1.获取锁可以在里面加上timeout参数进行解决
【生产者和消费者】
两个消费者之间的通信
【协程】
协程:微线程
协程在底层里面就是通过生成器去做的
【协程】
协程:耗时操作的时候用协程
耗时操作:网络请求 网络下载 网络上传(爬虫)文件的读写,堵塞
【生成器去做协程】
def task1():
for i i nrange(3);
print('A'+ str(i))
yield
time.sleep(0.2)
def task2():
for i i nrange(3);
print('B'+str(i))
yield
time.sleep(0.2)
if __name__=="__main__":
g1=task1()
g2=task2()
while True:
try:
next(g1)
next(g2)
except:
break
【greenlet但是不够智能】
使用greenlet完成协程任务 pip install greenlet
def a():
for i in range(5):
print("A"+str(i))
gb.switch()---------->一发现下面有阻塞状态就会切换到下一个协程里面去
time.sleep(0.1)
def b():
for i in range(5):
print("B"+str(i))
gc.switch()---------->一发现下面有阻塞状态就会切换到下一个协程里面去
time.sleep(0.1)
def c():
for i in range(5):
print("C"+str(i))
ga.switch()---------->一发现下面有阻塞状态就会切换到下一个协程里面去实现交替执行,就是类似于生成器
time.sleep(0.1)
if __name__="__main__":
ga=greenlet(a)
gb=greenlet(b)
gc=greenlet(c)
ga.switch()
【gevent 智能协程】一遇到堵塞状态就会进行自动感知
import gevent
from gevent import monkey--------->gevent的补丁
monkey.patch_all()---------->猴子补丁,将所有的耗时操作变为自己内部提供的耗时时间进行替换
def a():
for i in range(5):
print("A"+str(i))
gb.switch()---------->一发现下面有阻塞状态就会切换到下一个协程里面去
time.sleep(0.1)
def b():
for i in range(5):
print("B"+str(i))
gc.switch()---------->一发现下面有阻塞状态就会切换到下一个协程里面去
time.sleep(0.1)
def c():
for i in range(5):
print("C"+str(i))
ga.switch()---------->一发现下面有阻塞状态就会切换到下一个协程里面去实现交替执行,就是类似于生成器
time.sleep(0.1)
if __name__="__main__":
ga=gevent.spawn(a)---->调用方法这里是类方法,不需要实例化对象
gb=gevent.spawn(b,还可以用参数例如url[1])
gc=gevent.spawn(c)
ga.jion()----------->依赖主进程,避免主进程结束
gb.jion()
gc.jion()
或者堵塞主线程
gevent.joinall(g1,g2,g3)
【下载源码】
先定义一个下载的函数
然后在用gevent.spawn(a),里面是一个函数,进行循环调用就可以了