Python---基础学习

Python学习---基础篇

预习课

环境搭建

python解释器      
	这里安装的是Python3.9
python编辑器
1、使用激活码放射式激活:隔一段时间需要找新的激活码
2、使用破解文件激活:先试用三十天,再进入pycharm界面,把破解文件拖进入

职业规划

1、web开发
	Django框架
	flask框架
	tornado框架
2、爬虫
3、数据分析
4、自动化运维
5、人工智能

第1天

认识python

高级语言

解释型:一边翻译一边执行(python,java,javascript)---方便移植,效率低
编译:全部编译完之后再执行(C,C++)---不方便移植,效率高
交互式:不需要经过复杂的保存和编译阶段
面向对象:万物皆对象

phthon的特点

易于学习
	关键字少,语法简单
有丰富的库
	库:实现某些功能的代码
	函数、属性、import 导入
易于阅读
	语法语义比较简单
	缩进
数据库
	提供非常多的商业数据库的接口
可移植
	Windows Linux

强类型的动态脚本语言

强类型	
	不允许不同类型相加
动态
	不用显示数据类型的声明
脚本语言
	一般是解释型语言,运行代码只需要一个解释器

第1个程序

print("hello")

编写的四种方式

1、cmd输入python进入交互模式
2、使用ptyhon自带的IDE
3、创建txt文档,修改后缀名为py,cmd命令运行
4、打开pycharm,右键新建一个python file

bug

常见问题
	缩进问题
	拼写问题
	pycharm中在代码左边打红点---断点

遇到bug怎么办

多思考
	这里代码有问题,为什么有问题,那里有问题
多观察
	细心,如果有红色波浪线那么肯定有报错的,如果没有红色波浪线提示,这个时候就要根据信息在第几行,再找错误
多记录
	写代码的过程中出现bug是很正常的事情,如果你这个问题出现了一次出现第二次第三次,你自己还找半天找不到问题在哪里,那么就是你的问题了

Debug

1、在你要打断点的地方打断点	单击(行号右边)空白处
2、使用调试模式来运行这个python程序   右键---debug运行
3、使用单步调试(F8)

作用

线程切换	查看所有变量 调试按钮

什么时候调试

1、如果代码逻辑比较难懂,debug调试
2、如果程序出现问题,但是不知道问题在哪,debug调试

注释

增加程序的可读性
单行注释   #
多行注释(3对单引号或双引号---3引号)  ''' '''     """   """"

输入与输出

输入

input()接收用户信息
name=input("请输入一个名字")

输出

转移字符
	python中将各种表达式中\符号,都看作转义符
	\n:换行,将当前位置移到下一行开头
	\t:水平制表,调到下一个tab位置
	\r:将当前位置移到本行开头
	\':代表一个单引号
	\":代表一个双引号
	\\:代表一个反斜杠字符'\'
输出语句参数
	1、sep
		用来间隔多个对象,默认值是一个空格
		print(123,456,789,sep='\')
	2、end
		用来设定以什么结尾,默认值是换行符\n,我们可以换成其他字符串
		print(456,end=‘*’)

第2天

print(type(a)) 可以使用type函数查看类型

快捷方式

Ctrl+d:复制单行代码
Ctrl+/:多行注释,取消注释
Ctrl+C:复制
Ctrl+V:粘贴

变量

变量定义格式:变量名=值
在python中,只要定义一个变量,而且它有数据,那么它的类型就已经确定了,不需要开发者主动去说明它的类型,系统会自动辨别
可以使用type(变量),来查看变量的类型

标识符

标识符的命名规范

标识符由字母、下划线和数字组成
不能以数字开头
不能跟关键字重名
区分大小写

命名约定

下划线命名法:多个单词组成的名称,使用小写字母,中间使用_分开,user_name,first_name,card_id
大驼峰命名法:多个单词组成的名称,每个单词的首字母大写,其余字母小写。UserName,FirstName,CardId

什么是关键字?

python一些具有特殊功能的标识符,这就是所谓的关键字
关键字,是python已经使用了,所以不允许开发者自己定义好关键字相同的名字的标识符

import keyword
print(keyword.kwlist)

False:布尔类型的值,表示假,与True相反
None:None比较特殊,表示什么都没有,它有自己的数据类型,None Type
True:布尔类型的值,表示真,与False相反
and:用于表示式运算,逻辑与操作
as:用于类型转换,取别名
assert:断言,用于判断变量或者条件表达式的值是否为真
async:声明一个函数为异步函数
await:声明程序挂起
break:中断循环语句的执行
class:用于定义类
continue:跳出本次循环,继续执行下一次循环
def:用于定义函数或方法
del:删除变量或序列的值
elif:条件语句,与if,else结合使用
else:条件语句,与if,else结合使用,也可用于异常和循环语句
except:except包含捕获异常后的操作代码块,与try,finally结合使用
finally:用于异常语句,出现异常后,始终要执行finally包含的代码块,与try,except结合使用
for:for循环语句
from:用于导入模块,与import结合使用
global:定义全局变量
if:条件语句,与else,elif结合使用
import:用于导入模块,与form结合使用
in:判断变量是否在序列中
is:判断变量是否为某个类的实例
lambda:定义匿名函数
not:用于表达式运算,逻辑非操作
or:用于表达式运算,逻辑或操作
pass:空的类,方法或函数的占位符
raise:异常抛出操作
try:try包含可能会出现异常的语句,与except、finally结合使用
while:while循环语句
with:简化python语句
yield:用于从函数依次返回值

数据类型

1、Number(数字)

int
float
bool		True、False
complex		1+4j

2、String(字符串)

单引号或双引号,三引号表示多行
单双引号不要冲突

3、List(列表)

4、Tuple(元组)

tu=(1,2,3)
tu=(1,)单个字符后面加,
不可更改 会报错
内部里面是可以修改的
查找
	index
		tu2=('a','b','c','a,'d',c')
		res=tu2.index('a',2)
	count
		res=tu2.count('a')

5、Set(集合)

集合是无序的,元素唯一
{}
set()	空集合
无序	数字有序,字符串无序

增
	add()	追加单一数据     s1.add(st) #作为整体,列表中是append
	update()	追加的是序列   s1.update(st)  #传入的元素会分开,列表中是extend

删
	remove()	删除指定数据,会报错   
	pop()	随机删除
	discard()	删除指定数据,不会报错

改
	
查	in	、not in	

交集 &  print(a & b)
并集 | print(a|b)

6、Dictionary(字典)

键值对
键是唯一的,值可以重复
{:,:}

增	和上面以上
	变量名[‘键名’]=值;键不存在,会新增
	
删	del	删除指定的键值对   del dic['name']
		clear	清空字典   dic.clear()
		del删除整个字典    del dic
		
改	变量名['键名']=值

查	keys()	查找所有键       print(dic.keys)
	value()	查找素有值       print(dic.values)
    items	查找所有键值对   print(dic.items())
    可以通过键名来获取值,print(dic['name'])
    通过get来获取值,不会出现异常,没有返回None

len()查看长度   print(len(dict))

enumerate() 函数

数据类型转化

int(x[,base])  将x转换为一个整数
float(x)	   将x转换为一个浮点数
complex(real[,imag])   创建一个复数
str(x)    将对象x转换为字符串
repr(x)    将对象x转换为表达式字符串
eval(str)   用来计算在字符串中的有效python表达式,并返回一个对象
tuple(s)    将序列s转换为一个元组
list(s)    将序列s转换为一个列表
set(s)    转换为可变集合
dict(d) 创建一个字典,d必须是一个(key,value)元组序列

运算符及字符串切片操作

运算符

算数运算符

** 幂 优先级最高
*   乘
/   除
//  取整除
%  取余数
+  加
-   减 优先级最低

赋值运算符

= 赋值
+= 加法赋值
-= 减法赋值
*= 乘法赋值
/= 除法赋值
%= 取模赋值
** =幂赋值
//= 取整数赋值

字符串下标

字符串运算符

+ 字符串连接
* 重复输入字符串    print(a1*4)

成员运算符

in:如果字符串中包含改字符,返回True,否则返回False
not in:如果字符串中不包含该字符,返回True

切片

语法:[起始:结束:步长] 左闭右开原则:步进表示选取间隔   print(c1[2:3])
左边:下标从0开始(正数);			右边:下标从-1开始(负数)
步进默认是1,绝对值决定了间隔;正负号决定切取方向
正好是从左往右,负号是从右往左
	print(d1[-1:-3:-1])  方向从右往左
	printf(d1[-3:-1])     方向是从左往右

格式化输出

%

%s	字符串
%d	有符号十进制整数
%f	浮点数
%u	无符号十进制整数(是过时的类型,与%d相同)
%o	把八进制整数
%x	十六进制整数(小写字母0x)
%X	十六进制整数(大小字母0X)
%f	浮点数
%e	科学计数法(小写'e')
%E	科学计数法(大写'E')
%g	%f和%e的简写

print('字符串是%s,整数是%s',%(su,a))
print('这个小数:%.2f',%b)   #保留两位小数

格式化f’’

print(f'数字是{20},字符串是{"we"}')
print(f'数字是{a:.2f},字符串是{b}')

占位符

# 有占位符时,两个百分符号只输出一个,比如要输出80%,print(%d%%,% a)

判断

比较运算符

==
!=
>
<
>=
<=

逻辑运算符

and
or
not

if 判断

if 条件1:
	代码1
elif 条件2:
	代码2
else:
	代码3

三目运算

表达式1 if 条件 else 表示式2
条件为真,结果为表达式1;条件为假,结果为表达式2
c = a if a>b else b

循环

while循环

while 条件:
	循环体
		改变变量

while嵌套
一个while面又有while

for循环

for 临时变量 in 可迭代对象:
	执行的代码

例 
st='11111'
for q in st:
	print(q)
	
range(开始位置,结束位置,间距);包前不包后,默认从0开始
例
for i in range(1,5,2)
	print(i)

break:直接结束所在的循环
continue:退出这一次的循环,下一次还会重复执行

字符串列表

编码解码

常见的编码格式:ASCII、GB2312(GBK)、Unicode
python3 默认编码是Unicode(万国码)

编码: 其他编码>Unicode
	  Bytes:前面带b
解码:Unicode>编码
 
encode编码:将字符串转换成Unicode编码
	例	a=''康康康'
	        a1=a.encode()   #()里面编码类型:utf-8/gbk

decode解码:将Unicode编码成字符串
			a2=a1.decode()  # 默认是utf-8

字符串的查找方法

find():返回首个位置,找不到返回-1
			print(st.find('o'))  # 返回索引值,找第一个
			print(st.find('o',5))  # 5代表从下表5开始寻找
			print(st.find('o',8))  # 不包含,找不到就返回-1
			
index():找到下标
		print(st.index('o',6))  #返回索引值,6代表从下标为6开始寻找
		print(st.index('a')      #如果找不到报异常
		
count():返回次数
		找不到返回0
		print(st.count('l'),5)    #从下标5开始寻找 
		
rfind() 
rindex()

字符串的修改方法

replace()替换    第三个参数,替换次数
		print(st.replace('l','a'))   # 把字符串中的l用a代替
		print(st,relpace('l','a',2))  # 2代表替换次数

split()分割		返回一个列表    第2个参数,分割次数
		print(st.split(','))  # 根据字符串分割字符串
		print(st.split('t'))  #
		print(st.split('t',1))  # 1代表分割次数
		print(st.split('o','0'))  # 分割次数如果为0,就不分割

capitalize()  
	print(ty.capitalize())  #第1个字符大写

startswtich()
	print(ty.startswitch('j'))  #检测以某字符开头,是返回为True,否则返回False

endswitch()
	print(ty.endswitch('e'))  #检测以某个字符结尾,是返回为True,否则返回False


join() 每个字符后面添加一个  最后一个字符没有,列表中常用
strip() 删除两边多余的字符,默认删除空格
center()	返回字符串居中,长度,填充字符
lower() 大写转小写
upper() 小写转大写
isupper() 是否是大写

列表的基本操作

列表:list,一种有序的集合,可以添加删除其中的元素,定义列表:[ ]

列表查找操作

index() 找不到会报错
find()
count()

列表修改方法

增
	append 追加 没有返回值
		   列表嵌套
	extend 逐一添加
	insert

删
	del 会报错
	pop 删除指定下标,默认删除最后一个,根据索引
	remove 移除第一个匹配项,根据内容
	clear 清空列表  不会报错
	
改		 
	重新赋值
	sort   排序
	reverse()   重新颠倒顺序
	
列表推导式 
	基本形式 [表达式 for 变量 in 列表]
	[i for i in range(5)]

排序
	sort  正序 
		li.sort(reverse=True)
		li.sort()
	revere 倒序
		li.reverse()
		li=sorted(li,reverse=True)
	生成新的列表
		li=sorted(li,reverse=True)
		#sorte()是函数,第一个参数是对象,第二个参数默认是reverse=False		 

if 解答课

imort random
#1、系统生成数字
n=random.randint(1,100)
print(n)

深浅拷贝

函数

def 函数名:
先定义后调用
优点  
	1、减少代码的重复性
	2、代码可读性更好

函数的参数

形参
	def add(a,b) :定义函数的位置是形参
		return a+b
实参
	函数的传参:将函数的实参交给形参的过程
		
必备参数
	写了几个形参,传几个实参
	
默认参数
	有默认的参数
	def test(name='zs'):
		
可变参数	*args	
	自动组装成一个元组
	args是一个普通的形参,前面加上*的话,才有特殊的意义
	传入的实参数量可以是任意多个,也可以没有
	def test(*args):
		print(args)
	

关键字参数	**kwargs	
	自动组装成一个字典
	**也是魔法作用,kwargs约定俗成作为形参
	传入的实参可以是任意多个,也可以没有
	def test(**kwargs):
		print(kwargs)
	test=(name='zs',a=23,age=18) #键=值的形式
	def funa(*args,**kwargs): #**kkwargs必须在*args后面
		print(args)
		print(kwargs)
	funa(1,'hello',a=1,b=2)

函数的嵌套方式
	封装
	贯彻
	闭包
	
def test(): #外函数
	print("这是test")
	def funa(): #内函数
		print('这是funa')
	funa()#调用内函数
test() #调用外函数

调用函数

函数的引用
te=test
print(id(te))
#通过引用调用函数
te()

返回值

return
return a,20,b,c
return一次性返回多个数据,以元组的形式返回
return 后面什么都不写,返回的结果是None

局部变量、全局变量

局部变量:在函数内定义的变量;作用范围就是函数内部
全局变量:在函数外部定义的变量;可以在一个函数中使用,也能在其他函数中使用
全局跟局部名字相同,此时理解为定义了一个局部变量,而不是修改全局变量

修改全局变量,global:在局部作用域中修改全局变量
例
c=20
def fune():
	global c #声明全局变量
	c=100
	print('函数内:',c)
	
global a1,b2  #一次性多个全局变量进行声明

global和nonlocal的区别

nonlocal在嵌套函数中使用

nonlocal

声明外层的局部变量
不能修改全局变量
只对局部起作用,离开嵌套函数,该变量就无效
在内层函数中修改外层的(非全局)变量
只能用于嵌套函数中,并且外层函数中定义了局部变量

例
a=10
def funa(): #外层函数 ---大哥
	a=20
	print('funa修改前':,a)
	def funb(): #内层函数---小弟
		nonlocal a
		a=40
		print('这是funb函数:',a)
	funb()
	print(‘这是funb的函数’,a)
funa()
print('这是funa的函数',a)
funb()
print('这是funb的函数',a)

匿名函数

匿名函数:没有名字的函数
语法:函数名=lambda 形参:返回值
funb = lambda a,b:a+b   # a,b是形参,a+b是返回的表达式

例
#取列表中下标为0和2的元素
li=['a','b','c','d']
print(li[0])
print(li[2])
等效
func = lambda x:(x[0],x[2])   # x是形参

例
#求平方值
def test(a):
	return a**2
等效
#语法:函数名=labmda 形参:返回值
te = lambda b:b**2

内置函数

查看所有内置的函数
import builtins
print(builtins)


abs绝对值	print(abs(-4))

sum求和	print(sum([1,2,3]))

min()最小值	print(min([1,2,3]))

max()最大值	print(max([1,2,3]))

list()会转换成列表	
a=[1,2,3]
b=['a','b','c','d','e']
print(list(zip(a,b)))

zip() 拉链函数
zip()就是把几个类型对齐,然后按列输出,里面是元组组成的内容;个数不一致,按长度最短的返回

map() 映射函数	
对对象中每一个元素进行映射,分别执行函数
map(函数,对象)
例
li2 = [1,2,3]
def funb(x):
	return x*2

mp=map(funb,li2)
print(list(mp))

reduce() 	对参数序列中元素进行累积
reduce(函数,对象)
例
from functools import reduce # 一定要先导入模块

def func(x,y):
	return x+y

res = reduce(func,[1,2,3])
print(res)

例  
from functools import reduce #一定要先导入模块

def func(x,y):
	return x**y

res=reduce(func,[1,2,3])
print(res)

拆包

li3=[1,2,3,4]
#a,*b=li3 	#取一个值,其他的都放在b中
#print(a,b)
#a,*b,c=li3  #a和c取开头和结尾的数据,中间的数据放到了b
print(a,b,c)

对于函数中多个返回数据,去掉元组,列表或者字典,直接获取里面数据的过程
#元组拆包
tu = (1,2,3,4,5)
a,b,c = tu
print(a,b,c)

print(*tu)  #使用*拆包
a,*b,c=tu
print(a,b,c)
d,e,f=b
print(d,e,f)

深浅拷贝

浅拷贝

拷贝了最外层的对象,内部的元素只拷贝了一个引用
浅拷贝只拷贝第一层,深层次的数据改变会影响其他

import copy
a=[1,2,3]
b=copy.copy(a)

1、浅拷贝:会创建新对象,其内容并不原对象的引用,而是原对象第一层的引用
a=[1,2,[3,4,5]]    #嵌套列表
b=copy.copy(a)
print('修改前:'a,b) 
print(id(a),id(b))  #父对象的id不同
print(id(a[2],id(b[2]))   #子对象的id一样
a.append('a')
print('修改后',al,b)
把a列表里的内层列表中的元素3---zs
a[2][0]='zs'
print(a)
print(b)

浅拷贝:a,b父对象是一个独立的对象,但是子对象指向同一引用。修改子对象的数据,会一起变化
浅拷贝只拷贝第一层,深层次的数据改变会影响其他

深拷贝

外层的对象和内部的元素都拷贝(赋值)了一遍
a,b对象是一个独立的对象,子对象也独立
 
import copy
copy.deepcopy(a)
2、深拷贝,a,b对象是一个独立的对象,子对象也独立

a=[1,2,[3,4]]
b=copy.deepcopy(a)
print(id(a),id(b))  #父对象ID不同
print(id(a[2]),id(b[2]))  #子对象的id也不同
a.append('a')
print('修改父对象:',a,b)
b[2].append('b')
print('修改子对象:',a,b)
深拷贝:完全拷贝,数据变化只影响自己本身,拷贝出来的对象是一个全新的对象

可变对象

可变类型:list/dict/set
变量对应的值,它的数据是可以被修改的,但是内存的地址保持不变

例
li=[1,2,3]
print(id(li))
li.append('a')
print(id(li))

stu={'name','zs','age':20}
print(id(su))
stu['age']=18
print(id(su))

存储空间保存的数据允许被改变
列表list
字典dict
集合set

不可变对象

存储空间保存的数据不允许被修改
数字类型	
	int,bool,float,complex
字符串	
	str
元组
	tuple

不可变类型:int/float/str/tuple
变量对应的值,他的数据不能被修改,如果修改就会分配新的内存空间
a=5
print(id(a))
a+=1
print(id(a))

元组是不可变类型中特殊的一种
tu=(1,2,3)
print(id(tu))
tu2=(1,2,3)
print(id(tu2))

异常、模块和包

异常捕获

捕获异常一
最简单的语法格式:
try:
	#被检测的代码块
except 异常类型:
	编写尝试失败的代码
例
try:
	print(123)
	print(a)
#except:
#except NameError as e:
	print('error')

捕获万能异常  Exception:可以捕获任意异常
li=[1,2,3]
try:
	print(li[3])
except Exception as e:
	print(e)

多分支:对不同的异常定制不同的处理逻辑
try:
	#print(li[3])
	print(a)
except NameError as n:
	print('nameError')
except IndexError as i :
	print('indexerror')

捕获异常二:else
else在if中,条件不满足才执行
捕获异常中,else在没有异常时才会执行
try:
	print('我们在学习异常处理')
	print(a)
except Exception:
	print('出现错误')
else:
	print('没有捕获到异常')

捕获异常三 finally
finally无论是否有异常,都会执行
try:
	print('我们在学习异常处理')
	pint(a)
except Exception:
	pint('出现错误')
finally:
	print('没有捕获到异常')

异常传递

从产生异常的地方开始传递到调用异常的地方
def funa():
	inp=int(input('请输入整数:'))
	return inp
def funb():
	print(funa())
try:
	funb()
except Exception as e:
	print(e)

def test():
	inp=int(input('请输入整数:'))
	print(10/inp)
def test2():
	test()
	
try:
	test2()
except ValueError:
	print('类型错误,输入不正确')
except ZeroDivisionError as e:
	print(e)
else:
	print('运行成功')
fianlly:
	print('最后执行,结束')

抛出异常 raise

主动抛出异常
1、创建一个Exception('xxx')对象,xxx是异常提示信息
2、raise抛出这个对象(异常对象)

raise Exception('这是抛出一个异常')
def test():
	raise Exception('在函数中抛出异常')   #异常被抛出后,下面的代码无法执行
	print('这是test函数')
test()
def login():
	pwd=input('请输入密码:')
	if len(pwd)==6:
		return pwd
	#创建异常对象
	ex=Exception('长度不符合')
	#抛出异常
	raise ex

捕获异常
try:
	print(login())
exception Exception as e:
	print('错误:%s' %e)

模块

就是py文件,里面定义了一些函数和变量,需要的时候,就可以导入这些模块

执行步骤
	1.在python模块加载路径中查找相对应的模块文件
	2.将模块文件编译成中间代码
	3.执行模块文件中的代码

分类
	1.内置模块
		import random #导入模块
		不需要下载,导入即可
	2.第三方模块
		必须通过pip install模块名,这个指令去安装
	3.自定义模块
		不要跟第三方或者内置模块重名
		模块起别名 as
			import test as t
		导入多模块
			import test
			import test1
		from...import...
		从模块中导入一个指定的部分到当前命令控件
			from test import login
			from test import * 不建议使用
		
		当执行文件跟模块不是在同一文件夹下
			1.先导入sys模块
			2.通过sys.path.append(路径) 函数来导入自定义模块所在路径(不需要具体到.py)

py文件

脚本:一个文件就是整个程序,用来被执行
模块:文件里面放着一堆功能,用来被导入使用
	作用:用来控制py文件在不同的应用常见下执行不同的逻辑
	如果模块是被直接运行,if __name__=='__main__'下方的代码块就会被执行
	模块是导入,就不会被执行
	if __name__=='__main__':
		def reg():
			pritn("用户注册")

包是一个含有__init__.py的文件夹
import te 导入包	
	首先执行_init_.py文件夹中的内容

总结

模块:包含变量、函数、类代码的.py文件
包:由多个模块/包组成的,对应文件夹及其中的文件
库:模块/包的结合

闭包、装饰器

递归函数

自己调自己
特性
	1.要有明确的结束条件
	2.进入更深一层的递归时,问题规模会比上次递归有所减少
	3.相邻两次重复之间有紧密的联系
例
	法1
		def funa(n):
			s=0
			for i in range(1,n+1):
				s+=i
			print(s)
		funa(7)
	法2
		递归深度是有限制的,默认是1000
		def funb(a): #a=7---a=6
			# 在a值为1的时候,不去调用
			if a==1: #设置一个结束条件
				return 1
			#每调用一次自身,相当于复制一份该函数
				return a+funb(a-1)  #return 7+funb(6)
		print(funb(4))
例
	斐波那契数列:1 1 2 3 5 8 13 21
	#从第三个开始,结束是前两个数之和
	def func(n)  #n=3  n=2/n=1
		if n<=1:
			return n
		return func(n-1)+func(n-2)  #func(2)+func(1)
	print(func(3))  #代表数列第几项的结果

闭包

条件
	1.函数中嵌套一个函数
	2.内部函数使用了外部函数的变量
	3.外部函数的返回值是内部函数的函数名

函数嵌套
	def outer():
		n=10
		def inner():
			n=20
		pint('inner',n)
		print('outer',n)
		inner()
	outer()

闭包一 print(outer())   #inner函数的引用
第一种写法
	outer()()
第二种写法
	ot=outer() #ot保存了inner函数的引用
	ot() #相当于执行inner函数

闭包二
	def test(): #外函数
		li=[] #空列表
		def test_in(val): #内函数
			li.append(val)
			res=sum(li) #列表中的元素进行求和
			pint(li)
			return res
		#外函数返回内部函数的引用
		return test_in
	#闭包的变量实际上只有一份,每次调用内函数都是在使用同一份闭包变量
	te=test()
	print(te(10))  #调用内函数test_in
	print(te(20))

装饰器

本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象
一般应用
	权限校验
	插入日志
	性能测试

标准装饰器

标准装饰器写法:
def wrapper(func):
	def inner(*args,**kwargs):
		res=func(*args,**kwargs)
		return res
	retrn inner

例子
def check(fn):  #外函数   
	#fn是形参(fn是需要修饰的函数名)   
	fn=speak
	def inner():#内函数
		print('请先登录')
		fn()   #speakl()
return inner #返回内函数的引用

第一种:使用装饰器来装饰函数
def speak():
	print('发表评论')
	ch=check(speak)   #speak是实参
	#print(ch)  #inner函数的引用ch()

check(speak)()

第二种:语法糖@
@check #等价于ch=check(speak)
def(speak):
	print('发表评论')
speak()

被装饰的函数无参数

def funa(fn): # fn是被修饰的函数名  fn=work
	print('这是funa')
	def inner():
	fn()  # work()
return inner

@funa     
#work是被装饰的函数
def work():
	print('我在上课')
	print('我在学习')
a=funa(work)
a()   #调用内函数inner

被装饰的函数有参数

def exam(fn) #外函数
	def inner():	#内函数
		print('inner函数中的值:{a},{b}')
		fn(a,b)
		print('结果是:',(a+b))
return inner

第一种
@exam
#被修饰的函数
def test(a,b)
print('这是test函数:',a,b)
test(3,4)

第二种
ex=exam(test) #ex=inner
ex(1,2) #ex()就是调用函数inner

被装饰的函数有不定长参数

def outer(func):
	def inner(*args,**kwargs):
		print("这是内函数")
		func(*args,**kwargs)
		print('执行完成')
return inner()

@outer
def add(*args,**kwargs):
	print(args)
	print(kwargs)
add(1,2,3,a='zs')

面向对象

面向对象是一种编程思想
面向对象编程简称OOP,是一种封装代码的方法
面向过程:看重的是开发的步骤与过程
面向对象:要理解对象为何物

class 关键字定义,类名使用驼峰命名法,首字母大写
class Test
	pass

三要素:类名、属性(对象的特征描述)、方法(对象的行为)
class Human: #定义一个类,类名为Human
	name='九歌'   #类属性
	# 对类中单个属性增删改查,通过万能的
	print(Human.name)   #查找
	Human.name = '旺仔炖雪蛤'  #修改
	del Human.name   #删除
	Human.name2='悟'   #增加

对象

	创建对象:对象名=类名()
	一个类可以实例化多个对象,对象互不干扰
	
	class Milk: #牛奶类
		name='蒙牛' #类属性,公共的
		def eat(self,name):	#self默认自带的,表示当前的对象,代表对象本身
		print(f'我在喝{name}牛奶')
	
	#实例化对象
	mk=Milk()
	print(mk)
	#对象调用类中的方法
	mk.eat("特仑苏")
	
	mk2=Milk()
	print(mk2)
	mk2.eat('旺仔')

init方法

构造方法,具有初始化的作用
#游戏中英雄的生命值、攻击力都不同
class Hero:
	def __init__(self,name,hp): #初始化
		self.name=name #self.name是实例属性,name是init方法中的参数
		self.hp=hp 
	def move(self) # 实例方法
		print(f'{self.name}在移动,打怪兽,生命值{self.hp}')
	
#实例化对象
hero=Hero('孙悟空',1000)
hero.move()

hero2=Hero('赛文',500)
hero2.move()

总结
	1、init方法通常是用来属性初始化或者赋值操作
	2、类里面没有写init方法,python会自动创建,但不执行任何操作
	3、需要的时候,可以自己定义init方法
	4、无论是否写init方法,一定会有init方法

析构方法

__del__
创建对象,默认调用init方法
删除对象,默认调用del方法

class Person:
	def __init__(self):
		print('我是init方法')
	def __del__(self):
		print('我是del方法')
pe=Person()
print('结束了')

pwe2=Person()
print('又来结束了')
#正常运行不会去调用del方法,当对象结束了,系统会自动执行析构方法,往往用来做清理善后工作的
#del pe语句执行的时候,del方法立即被调用
#删除对象的时候,会调用对象本身的析构方法,相当于手动释放内存

封装、私有

class Lesson: #定义一个类,类名Lesson
	ting='学习'  #类属性
	def __init__(self,name): #初始化,self代表实例对象本身
		print(''这是init')    #实例化对象时,会自动调用init方法
		self.name=name #实例属性
	def study(self):  # 实例方法
		print(f'{self.name}同学在学习')

#实例化对象
le = Lesson(''夜夜夜夜夜')
le.study()
#Lesson.study()  #类不能调用实例方法

#对象、类调用类属性
print(le.thing)
print(Lesson.thing)

#对象调用实例属性
print(le.name)
#print(Lesson.name)  #类不能调用实例属性

总结
	1、类属性:类可以访问到,实例对象也可以访问
	2、实例属性:类访问不到,实例对象可以访问
	3、类属性属于类的,所有实例对象共享一个属性;实例属性属于实例对象,互不干扰

封装

封装意义
	1、将属性和方法放在一起作为一个整体,然后通过实例化对象来处理
	2、隐藏内部实现细节,只需要和对象及其属性和方法进行交互就可以了
	3、对类的属性和方法增加访问权限控制

私有属性

不能在类的外部调用
python中定义私有属性或方法,需要在前面加上__(双下划线)
_name:单下划线开头,也是私有属性,实例化对象可以访问

class Tea:
	name='红茶'   #类属性
	__mike='奶茶' #私有属性
	_black = '黑茶'

	def find(self): #实例方法
		print(Tea.__mike)  #在类内部访问私有属性
		print(Tea.name) # 实例方法中访问类属性,类名.属性名
	
te=Tea()
te.find()
print(te.name)
print(te._black) 
print(te.__milk)  #报错,私有属性不能在类外部直接访问
#类名__属性名(了解)最好不要这样做
print(te._Tea.__milk)


class Person:
	def __init__(self):
		self.__name="十九歌"	
	def __speak():	#私有方法
		print('这是speak')
	def find(self):
		print(self.__name)# 类内部可以访问私有属性
		slef.__speak() #类内部调用私有方法

pe=Person()
pe.finid()

总结

	1.类中私有属性、方法,都不能通过对象直接访问,需要在类内部访问
	2._xx:单下划线开头,声明私有权限,但是实例对象可以访问
	3.__xx: 双下划线开头, 声明私有权限, 无法在类外部直接访问
	4.__xx__: 前后双下划线, 魔术方法,不用自己这样去定义名字

继承

子类拥有父类的所有方法和属性
 单继承
 双继承

calss Father: #父类
	name='张'
	def speak(self):
		print('会说话')
class Son(Father): #子类一 儿子
	def work(self):
		print('在工作')
class Daug(Father): #子类二 女儿
	pass

son=Son()
son.speak()
print(son.name)
son.work()

daug=Daug()
daug.speak()
继承的传递性
子类拥有父类以及父类中所有的属性和方法
class Person:#父类的父类  ---爷爷
	Sname='动物界'   #类属性
	def __init__(self,name,age):
		self.name=name # 属性方法
		self.age=age 
	
	def eat(self):实例方法
		print(f'{self.name}在吃东西,今年{self.age}')
	
class Jiuge(Person):父类 ---爸爸
	def study(self):
		print('我在学习')
实例化子类对象,对象执行父类的属性/方法
jiuge = Jiuge('九歌',18)
jiuge.eat()

class Jiuge19(Jiuge): #子类---儿子
	pass
jiuge19=Jiuge19('十九歌',19)
jiuge19.eat()
jiuge19.study()

重写

父类的方法不能满足子类的需求时,可以对方法进行重写

覆盖父类的方法
	如果复位的方法不能满足子类的需要,在子类中重新编写父类方法
覆盖
class Human: #父类
	def play(sel):
		print('我在玩电脑')
class ZS(Human): #子类一
	def pla(self):
		print('我张三不玩电脑,玩手机')
class LS(Human): #子类二
	pass
zs=ZS()
zs.play()
对父类的方法进行扩展
实现方式:使用super().父类方法(); 父类名.方法(self)
1、父类名.方法(self)
class Animal: #父类
	def eat(self):
		print('吃东西')
class Dog(Animal): #子类
	def eat(self):
		#父类名.方法(self) 在父类的基础上增加自己想要功能
		Animal.eat(self)
		print('啃骨头')
dog=Dog()
dog.eat()

2、supper().父类方法()
supper是一个特殊的类,supper()就是使用supper类创建出来的对象
class Animal:# 父类
	def bark(self,name):
		print(f'{self.name}动物都会叫')

class Dog(Animal): #子类
	def bark(self,name)	:
		supper().bark(name)
		print(f'{name}狗是汪汪叫')
		print('哈哈哈')
dog=Dog()
dog.bark('zs')

多继承

子类可以拥有多个父类,具有所有父类的属性和方法
1、多继承
class Father: #父类一
	def test(self):
		print('爸爸的双眼皮')
class Monther: #父类二
	def test2(self):
		print('妈妈的高鼻梁')
#多继承可以让子类对象,同时具有多父类的属性和方法
class Child(Father,Monther): #子类
	pass
ch=Child()
ch.test2()
ch.test()

父类中存在同名的方法
class Father: #父类一
	def test(self):
		print('爸爸的双眼皮')
class Monther: #父类二
	def test(self):
		print('妈妈的单眼皮')
#父类中存在同名的方法,谁先继承就用谁的
class Child(Monther,Father): #子类
	#子类重写了父类的方法,所以先用子类自己的
	#def test(self):
	#	print(‘变成了内双’)
	def test(self):
		supper().test() #调用父类方法,调用顺序遵循mro类属性的顺序(目前super不支持执行多个父类的同名方法)
		#扩展父类方法:super().方法名()   类名.方法名(self)
		Father.test(self) #继承faher的
ch=Child() 
ch.test()

#确定子类调用方法的顺序
#MRO--方法搜索顺序
print(Child.__mro__)  #使用内置属性可以查看顺序(知道)
总结
1、多继承可以继承多个类,也继承了所有父类的属性和方法
2、如果多个父类中有同名的,默认使用第一个父类的属性和方法(根据mro的顺序来调用)
3、如果子类和父类的方法名和属性名相同,默认使用子类的。(子类重写了父类的东西)

#继承举例
#一代
class Robot: #父类
	def __init__(self,year,name):
		self.year=year
		self.name=name
	def walk(self): #机器人的功能
		print(f'{self.name}只能行走,遇到障碍物会摔倒')
	def produce(self):  # 机器人的信息
		print(f'{self.year}年生产的,名字是{self.name}')	
#实例化对象
rt=Robot('2010','九歌一号')
rt.walk()
rt.produce()

#二代   ---单继承
class Robot2(Robot): #子类 ---单继承
	def walk(self):
		print('遇到障碍物会自己躲开')
	def sing(self):
		print('会唱歌')
rt2= Robot2('2020','九歌二号')
rt2.walk()
rt2.produce()
rt2.sing()

#三代 ---多继承
class Robot3(Robot2,Robot):   #三代继承了两个父类
	def fly(self):
		print(f'{self.name}会在天上飞')
rt3 = Robot3('2030','九歌三号')
rt3.walk()
rt3.sing()
rt3.fly()
rt3.produce()

多态

同一种事物的多种形态
+:同个加号可以用于不同的对象,体现了多态的功能
print(1+2)
print('he'+'llo')

len()计算长度 传入不同的参数,计算出不同的长度
li=[1,2,3]
print(len(li))
print(len('python'))

对象所属类之间的继承关系

class Pay: #支付类
	def pay(self,money):
		print(f'支付了{money}')
class Wechat(Pay): #微信支付
	def pay(self,money):
		print(f'使用微信支付了{money}')
class Alipay(Pay):  #支付宝支付	
	def pay(self,money):
		print(f'使用支付宝支付了{money}')
py=Wechar()
py=Alipay()
py.pay(300)

#举例一
class Animal: #动物类
	def run(self): 
		print('动物都会走')
class people(Animal): 
	def run(self):
		print('人在走')
class Pig(Animal):
	def run(self):
		print('猪在走')
class Dog(Animal):
	def run(dself):
		print('狗在走')
class Cat(Animal):
	pass
pe=People()
pig=Pig()
dog=Dog()
#不同对象条用同样的方法,做不同的事情
pe.run()
pig.run()
dog.run()


举例二
class Dog:
	def __init__(self,name):
		self.name=name
	def play(self):
		print(f'{self.name}在跑来跑去')
class Black(Dog):
	def play(self):
		print(f'{self.name}在啃拖鞋')
class Person:
	def __init__(self,pname):
		self.pname=pname
	def plays(self,dog):  #dog=xiaohei
		print(f'{self.pname}和{dog.name}在玩耍')   #dog.name是狗的名字
#创建狗对象
xiaohei=Black('小黑')
we=Black('小白')
ke= Blocak('柯基')
xiaohei.play()

#创建人对象
zs=Person('张三')
#代码执行的时候,传入不同的狗对象,就会产生不同的执行结果
zs.plays(xiaohe)
zs.plays(we)
zs.plays(ke)	

类方法和静态方法

新式类以及经典类
	python2.x版本中 存在两种:新式类和经典类
	python3.x版本中取消了经典类,使用的都是新式类
	class Person:
	class Person():
	class Person(object):  #推荐使用这一种
	#三种写法没有区别
	#object是python中为所有对象提供的基类
类方法:使用@classmethod
#类方法就是针对类对象定义的方法,内部可以直接访问类属性或者调用其他的类方法
#类方法中第一个参数是cls---类对象

class Person(object):
	name='森森' #类属性
	#类方法
	@classmethod
	def get(cls):
		print(cls) #cls就是代表类对象
		print('名字是:',cls.name)
    #类方法对类属性修改之后,再去访问就发生了变化
	@classmethod
	def set(cls,Name):
		cls.name=Name
p=Person()
print(p.name)  #实例对象查看类属性
p.get() #通过实例对象调用
Person.get() #通过类对象调用
p.get()
print(Person) #类对象
p.set('超超')
p.get()
静态方法 @staticmethod
静态方法就是类中函数,不需要实例
class Dog(object):
	#静态方法
	@staticmethod
	def eat():	#主要用来存放逻辑性的代码
	print('狗狗在啃骨头')
dog=Dog()
dog.eat()
Dog.eat()
总结
1、实例方法:默认self参数
	方法内部需要访问实例属性,调用实例方法
2、类方法:默认cls参数
	方法内部需要访问类属性
3、静态方法
	方法内部不需要访问实例属性和类属性

单例模式

new和init顺序
class Test:
	def __init__(self,name): #初始化
		self.name=name #实例属性
	def funa(self): #实例方法
		print(self.name)
#实例化对象
te=Test('旺仔好开森')
te.funa()

1.1顺序:最先调用的是__new__方法,然后是__init__
init是在类实例对象创建之后调用,new就是创建这个实例对象的方法
类中写了init和new,先调用new方法创建对象,再给init去用
因为我们重写了new方法,导致它原来的功能没有了,所以new还是可以调用,但是init不能

class Test2(object):
	def __new__(cls,*args,**kwargs): #左右两边双下划线
		print('这是new中的:',cls)
		print('森森同学')  #相当于重写了object里面的new方法
	def __init__(self):
		print('这是init中的:',self)
		print('旺仔同学')

te2=Test2()
print('这是类:',Test2)


1.2 new方法作用
	1、在内存中为对象分配空间
	2、返回对象的引用
	python解释器获取到对象的引用后,把引用作为第一个参数,传递给init方法
重写new
# 举例一:

class Person(object):
	def __init__(self):    # 3.利用这个实例对象来调用init方法
    print('李云龙同学')  # 4.执行init里面的代码

	def __new__(cls, *args, **kwargs):  # 缺少了创建对象的功能
    	print('Kylin同学')        # 1.先执行new方法的代码
    	# 重写父类方法:new  ---- 扩展
    	# 父类名.方法名(cls)
    	# return object.__new__(cls)
    	# super().方法名(cls)
    	return super().__new__(cls)  # 2.new方法返回Person类的实例对象

 p = Person()


# 举例二:
class Human(object):
	def __init__(self, name):
    	self.name = name
    	print('这是init方法中的self:', self)
    	print('名字是:', self.name)
    	print('这是init')

 	def __new__(cls, *args, **kwargs):
    	print('这是new方法中的cls:', cls)
    	print('这是new')
    	print('这是new方法中返回的值:', super().__new__(cls))
    	return super().__new__(cls)

print('这是类外面的:', Human)
hu = Human('悟')  # 实例化对象
print('这是实例化的对象:', hu)
		  
总结:
一个对象的实例化过程,先执行类的new方法
如果没有写,默认调用object里面的new方法,返回一个实例化对象
然后再调用init方法,对这个对象进行初始化

总结init和new的区别
1、new方法创建对象,init方法初始化对象
2、new返回对象引用,init定义实例属性
3、new控制生成一个新实例的过程,是类级别的方法
   init初始化一个实例,是实例级别的方法
4、先调用new方法再调用init方法
单例模式
单例:一种特殊的类,这个类只能创建一次实例
class Jiuge:
	def speak(self):
		print('九歌在说话')
jiuge=Jiuge()
jiuge.speak()
shige =Jiuge()
shige.speak()
print(id(jiuge))	
print(id(shige))

单例模式实现的几种方法:
总结
	单例模式保证了在程序的不同位置都可以取到同一个对象实例
	如果实例不存在,就会创建一个实例,如果已经存在就返回这个实例
类在实例化的时候,指向同一个内存地址,称之为单例模式

1、通过@classmethod
2、通过装饰器实现
3、通过__new__实现
	1、定义一个类属性,初始值是None,记录单例对象的引用
	2、重写new方法
	3、进行判断,如果类属性为空,调用父类方法分配空间,在类属性中记录结果
	4、返回类属性中记录的对象引用
		class Exam(object):
			# 记录第一个被创建对象的引用 -- 类属性
			ins = None
			def __new__(cls, *args, **kwargs):
    			# 1.判断类属性是否为空
    			if cls.ins == None:
        		# 2.类属性为空,调用父类方法,为第一个对象分配空间
        		cls.ins = super().__new__(cls)
        		# super().__new__(cls)   继承父类object里面的new方法,然后进行重写
   				 # 3.返回类属性保存的对象引用
    			return cls.ins

		# 每次实例化所创建的实例对象都是同一个(内存地址都是一样的)
		# 每次实例化都会去调用new方法
		print('未实例化前:', Exam.ins)
		exam = Exam()    # 第一次实例化
		print('第一次实例化后:', Exam.ins)
		print('第一次实例化的对象', exam)
		exam2 = Exam()  # 第二次实例化
		print('第二次实例化后:', Exam.ins)
		print('第二次实例化的对象', exam2)
		# print(id(exam))
		# print(id(exam2))
4、通过导入模块实现

property 属性、魔法方法

补充 1.私有属性

子类对象不能在自己的方法内部,直接访问父类的私有属性

class Test(object):  # 父类
	def __init__(self):
		self.name = '九歌'  # 实例属性
		self.__age = 18     # 私有属性
			
 	def funa(self):  # 实例方法
    	print(self.name)
	 	print(self.__age)

 	def __money(self):  # 私有方法
     	print('我有私房钱')

class Te(Test):   # 子类 
	def speak(self):
    	print('这是子类中定义的实例方法')		
    	# 子类对象中,不能直接调用私有属性和私有方法
	    # print('访问父类的私有属性', self.__age)
	    # self.__money()
	    
te = Te()
te.funa()
te.speak()
te.money()  # 不能直接访问

子类对象可以通过父类的公有方法,间接访问到私有属性和私有方法

class Test(object):  # 父类
	def __init__(self):
		self.name = '九歌'  # 实例属性
		self.__age = 18     # 私有属性

	def funa(self):  # 实例方法
		print(self.name)
		print(self.__age)
		print('我可以查看他的手机来知道私房钱的位置')
		self.__money()

	def __money(self):  # 私有方法
		print('我有私房钱')
			
class Te(Test):   # 子类
	def speak(self):
		print('这是子类中定义的实例方法')
		# 调用父类的公有方法
		self.funa()

te = Te()
te.speak()
补充 2、异常类
try:
	print(a)
	except Exception as e:
		print('哈哈哈哈,我就是错了怎么样')
		
# 自定义异常类,通常继承EXception类
# python中内置异常的名字都以Error来结尾,所以实际命名尽量跟标准的异常命名一样

st = 'wer'
print(st.isalpha())  # isalpha()如果字符串包含字母,返回为True

class JiugeError(Exception):
	def __init__(self):
    	print('这是九歌自定义的异常类, 出错了')
try:
	inp = input('请输入数字:')
	if inp.isalpha():    # inp.isalpha()判断输入的字符串里面是不是包含字母
    	raise JiugeError()  # 抛出异常
except JiugeError as e:
	print(e)
else:  # 没有异常就执行
	print('森森和旺仔')
finally:  # 有没有异常都执行
	print('九歌和廖俊涛')
property属性
1.property属性:用起来跟使用的实例属性一样的特殊属性

有两种方式
1.1 类属性:在类中定义值为property对象的类属性

property中有四个参数:
	1.方法名---查看属性自动触发执行的方法
    2.方法名---修改属性自动触发执行的方法
 	3.方法名---删除属性自动触发执行的方法
    4.字符串--调用对象.属性.__doc__, 属性的描述信息
     	
class A(object):
	def __init__(self):
    	self.name = '悟zs'
	# 查看
	def get_name(self):
    	return self.name
	# 修改
	def set_name(self, name2):
    	self.name = name2
	# 删除
	def del_name(self):
    	del self.name
# 定义一个属性
pro = property(get_name, set_name, del_name, '悟空空')

a = A()
print(a.pro)      # 调用get_name方法
a.pro = '陈浩南'  # 调用set_name方法
del a.pro
print(a.pro)      # 调用del_name方法
查看property属性的描述信息
print(A.pro.__doc__)

1.2 装饰器:在方法上应用装饰器

@property 、 @方法名.setter   @ 方法名.deleter
1.定义: 在实例方法的基础上添加@property 装饰器,并且仅有一个self参数
2.调用: 调用时,无需括号

class Person(object):
    def funa(self):
        print('彭于晏')

    @property
    def funb(self):
        print('权志龙')

pe = Person()
pe.funa()   # 调用实例方法
pe.funb     # 调用property属性

# 旺森店举例
class Milk_tea(object):
	def __init__(self):
    	# 旺仔原价
    	self.price = 10
    	# 活动折扣
    	self.dist = 0.9
    	
	# 查看
	@property
	def milk(self):
    	print('欢迎品茶')
    	print('旺仔的原价是:', self.price)
    	new_price = self.price * self.dist
    	print('活动价:', new_price)

	# 修改
	@milk.setter
	def milk(self, val):
    	self.price = val
    	print('店内生意好, 九歌决定调价, 旺仔价格变为:', self.price)

	# 删除
	@milk.deleter
	def milk(self):
    	print('价格太高,销量不好了,旺森店倒闭')
    	del self.price
    	
mt = Milk_tea()
mt.milk        # 获取旺仔价格
mt.milk = 20   # 修改旺仔价格
del mt.milk    # 删除旺仔价格
魔法方法
1. 魔法方法/魔术方法
class A(object):
	pass
 print(dir(A))  # 查看类里面的魔法方法

1.1 doc 表示类的描述信息

class B:
	''这是我打的注释'''
 	pass
 print(B.__doc__)

1.2 str :类中如果定义了str方法,那么打印对象时,默认输出该方法的返回值

通常是返回一个字符串,作为这个对象的描述信息
str输出是给人看的,repr输出是给程序员debug看的
class C:
	def __repr__(self):
    	return '嘻嘻'
    	
def __str__(self):
    return '哈哈哈'   # 返回值必须有,而且一定是字符串类型
     # 返回值必须有,而且一定是字符串类型

c = C()
print(c)  # 直接打印实例化的对象

1.3 module: 表示当前操作的对象是在哪个模块
和__class__:表示当前操作的对象的类是什么

import test

 py = test.Py()
print(py.__module__)   # 输出模块
print(py.__class__)    # 输出类

1.4 call : 允许一个类的实例像函数一样被调用

class B:
    def __init__(self):
        print('init')

    def __call__(self, *args, **kwargs):
        print('这是call')
        print(args)

b = B()
b('we')   # call方法的执行是由对象名后加括号触发   , 对象名()或者类名()()	
B()()

文件操作

文件操作
好记性不如烂笔头

1、文件操作

文本文件:使用文本编辑软件查看
二进制文件:提供给其他软件使用,不能使用文本编辑软件查看

2、 操作文件

1.打开文件
2.读、写文件
3.关闭文件

3、open(filename, mode)函数,创建一个文件对象
3.1 open()函数默认以只读方式打开文件

filename:文件的路径   mode:打开的方式

3.2 三个方法

read :读取
write: 写入
close:关闭

3.3 文件对象的属性

file.closed: 如果文件已关闭,返回True	
file.mode: 返回被打开文件的访问模式
file.name: 返回文件的名称

1.打开文件

f = open('we.txt')  # open函数创建一个文件对象,把这个文件对象赋值给了f

2.读取文件内容

print(f.read())

3.关闭文件

f.close()

print('文件名:', f.name)
print('访问模式:', f.mode)
print('是否关闭:', f.closed)

4.访问模式

4.1 关于其他

file = open('D:\\test10\\16单例模式\\旺仔.txt')
file = open('D:/test10/16单例模式/旺仔.txt')
print(file.read())  # 读取所有内容

read(num): num表示从文件中读取数据的长度,如果没有传值,就表示读取所有
print('第一次:', file.read(5))
print('第二次:', file.read())
file.close()

4.2 跟异常一起使用

 f = open('we.txt')
 try:
     print(f.read())
finally:
     f.close()

4.3 r w r+ w+

r:默认只读,文件必须存在
w:默认只写, 不存在就创建,存在就删除文件内容
+: 表示可以同时读写某个文件
r+:可读写, 文件不存在抛出异常
w+: 先写再读,会清空文件中的所有内容

f = open('ss.txt', 'w+')
f.write('Alpha456')
f.seek(0, 0)
print('第一次:', f.read())
f.close()

4.4 文件指针

1.文件指针标记从哪个位置开始读取数据
2.第一次打开文件的时候,通常文件指针指向文件的开始位置
3.执行了read方法,文件指针会移动到读取内容的末尾

tell()方法 :查看文件的当前位置
seek()方法: 改变当前文件的位置
seek(offset, from)	
offset 表示要移动的字节数, from指定开始移动字节的参考位置
如果from为0, 将文件开头作为参考位置
如果from为1, 将当前位置作为参考位置
如果from为2, 将文件末尾作为参考位置

f = open('we.txt', 'r+')
print('第一次读取:', f.read(5))
# 查看当前位置
pos = f.tell()
print('当前文件位置:', pos)
# 把光标重新定位到文件开头
f.seek(0, 0)

print('第二次读取:', f.read())
f.close()

4.5 文件复制举例

file = open('ss.txt', 'r')
content = file.read()
file.close()
name = input('请输入文件名:') # 新的文件名
# 把内容放进新文件里面
file2 = open(name, 'w')
file2.write(content)
file2.close()

4.6 with :with关键字, 离开with代码块的时候,系统会自动调用close方法

with open('wu.txt', 'r') as f:
	print(f.read())
print(f.closed)  # 会自动关闭文件
目录操作
import os

# 1.os.rename(原名, 新名)  文件重命名
os.rename('1.文件.py', '1.文件操作.py')

# 2.os.remove  删除文件
# os.remove('jiuge.txt')

# 3.os.mkdir  创建文件夹
# os.mkdir('九歌')

# 4.删除文件夹	
# os.rmdir('旺森')

# 5.os.getcwd  获取当前目录
# print(os.getcwd())
编码格式、读取操作

1.编码格式

# 如果写入的是中文,改变一下编码格式
with open('jiuge.txt', 'w', encoding='utf-8') as f:
     f.write('悟俊涛')

with open('jiuge.txt', 'r', encoding='utf-8') as f2:
     print(f2.read())

2.读取操作

readline :一次读取一行内容

with open('jiuge.txt') as f:
	while True:
		text = f.readline()
		if not text:  # 判断一下有没有读取完
			break     # 如果读取完了就跳出循环
		print(text)
		
readlines: 按照行的方式一次性读取文件内容,返回是一个列表

with open('jiuge.txt') as f:
	con = f.readlines()
	print(con)
    print(type(con))

for i in con:
    print(i)

迭代器

可迭代对象

1.可迭代对象 Iterable

for 临时变量 in 可迭代对象
数据类型:int str list tuple dict set
能被for循环取值:除了int都可以
迭代:对这些数据使用for循环语法从其中依次取出值来进行使用,这样的过程称为遍历,也叫迭代

可迭代对象: 泛指一类对象,满足以下条件的对象可以成为可迭代对象
1>.对象实现了__iter__方法
2>.__iter__方法返回了一个迭代器对象

li = ['执念', '田扬', '十笙', '森森', '伊凡']

for i in li:
    print(i)

2.for 循环工作原理:

1> 在内部对可迭代对象调用__iter__方法,获取到迭代器对象
2> 再一次次的通过迭代器对象调用__next__方法获取迭代结果

3.如何判断一个对象是否可以迭代: isinstance()

from collections.abc import Iterable

print(isinstance(100, Iterable))     # False
print(isinstance({1, 2}, Iterable))  # True
迭代器

1.迭代器 iterator

 iter()函数和next()函数

2.迭代器特性:

 1>访问者不需要关心迭代器内部结构,只需要不断执行next函数获取下一个元素
 2>不能随机访问对象中的某个值, 只能从头到尾顺序的读取
 3>访问到一半不能回退, 不能访问之前的值
 4>适合遍历很大的数据集合, 节省内存,提升速度

3.如果不用for循环迭代,可以这样做:

 li = ['悟', '太阳', '蓝天色', '旺森', '程越']  # 列表是可迭代对象
 it = iter(li)   # 1.通过iter方法转变成迭代器对象
 print(it)
 print(next(it))   # 2.对获取到的迭代器对象不断使用next()函数来获取下一个值
 print(next(it))
 print(next(it))
 print(next(it))
 print(next(it))
 print(next(it))   # 3.取完元素,再使用就会引发StopIteration

总结:

1> 先调用类型的iter()函数
   iter()函数直接调用该对象的__iter__方法,并把__iter__方法的返回结果作为自己的返回值
 这个用法通常被称为"创建迭代器"
 2>使用next()函数调用__next__方法
 3> 元素取完后再去, __next__方法将会引发StopIteration异常

 直接调用方法:
 it2 = li.__iter__()
 print(it2.__next__())

4.跟异常一起使用

 jiuge = {'韩非', '焰灵姬', '紫女', '卫庄', '弄玉'}
 tianxing = iter(jiuge)

 try:
     while True:  # 死循环
         print(next(tianxing))

 except StopIteration:
     print('角色很多,但是人满了,还是等下辆车')

5.可迭代对象和迭代器

 可迭代对象 Iterable      迭代器 iterator

 可以for循环的属于可迭代对象
 可以next()的是迭代器

 from collections.abc import Iterable, Iterator

 li = [1, 2, 3]

 print(isinstance(li, Iterable))  # True
 print(isinstance(li, Iterator))  # False

 my = iter(li)   # 转换为迭代器对象
 print(isinstance(my, Iterable))  # True
 print(isinstance(my, Iterator))  # True

 迭代器对象一定是可迭代对象, 而可迭代对象不一定是迭代器对象
 可迭代对象可以通过方法变成迭代器对象     (水果可以通过工厂加工变成水果罐头)
迭代器协议
概念:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,终止迭代

class Wu:
	def __init__(self):
		self.price = 10
	def add(self):
		self.price += 5
		return self.price

milk = Wu()  # 实例化对象
print(milk.add())
print(milk.add())
print(milk.add())
for i in milk:
	print(i)     # TypeError: 'Wu' object is not iterable

python中没有"迭代器"这个类的,具有以下两个特性的类可以称之为"迭代器"类
 1. 有__iter__方法,返回迭代器本身
 2. 有__next__方法, 返回下一个元素或抛出StopIteration异常

class Test:
	def __iter__(self):  # 类中定义了iter方法,这个类的实例就是一个迭代器,需要返回这个迭代器
    	self.price = 10
    	return self   # 返回self(实例对象本身)  表示自身就是自己的迭代器

	def __next__(self):
    	self.price += 5
    	return self.price

# 实例化对象
te = Test()

my_te = iter(te)
print(my_te)
print(next(my_te))
print(next(my_te))
print(next(my_te))

a = 0
while a < 5:
	print(next(my_te))
    a += 1

for i in te:
    if i <= 30:
        print(i)
    else:
        break

在next方法中加入结束条件:
class Test:
	def __iter__(self):  # 类中定义了iter方法,这个类的实例就是一个迭代器,需要返回	这个迭代器
    	self.price = 10
    	return self   # 返回self(实例对象本身)  表示自身就是自己的迭代器

	def __next__(self):
    	if self.price >= 30:
        	raise StopIteration('旺森奶茶店倒闭')
    	self.price += 5
    	return self.price

实例化对象
te = Test()
my = iter(te)
for i in range(5):
    print(next(my))

生成器

1.装饰器作业 编写装饰器,增加认证的功能

def outer(fn):  # fn是被修饰的函数名
	def inner():
    	name = input('请输入用户名:')
    	pwd = int(input('请输入密码:'))
     	if name == 'wu' and pwd == 123:
         	fn()
     	else:
         	print('你什么都捡不到')

 return inner

def add():
    print('捡到一把屠龙刀')

ot = outer(add)
ot()

2.生成器 – generator

在python中,使用了yield的函数被称为生成器
生成器就是一个迭代器

2.1 如何创建生成器

1.生成器表达式:类似于列表推导式

 [表达式 for 变量 in 可迭代对象]   ---  列表推导式的写法
 li = [i*5 for i in range(1, 20)]
 print(li)

 li2 = (i*5 for i in range(4))  # 生成器表达式
 print(li2)
 print(next(li2))

 for a in li2:
     print(a)

2.生成器函数

 yield:使函数中断,并保存中断的状态
 一次返回一个结果,在每个结果中间,挂起函数,方便下次从它离开的地方继续执行
 def jiuge():
     print('----开始----')
     yield '森森'
     yield '悟'
     yield '太阳'

 jiu = jiuge()   # 调用一个生成器函数
 print(jiu)    # 返回的是生成器对象
 取值方式一:
 print(next(jiu))
 print(next(jiu))
 print(next(jiu))

 取值方式二:
 for i in jiu:
     print(i)

2.2 举例
处理文件,用户指定要查找的文件和内容

def check(fname, word):  # fname是文件名   word是查找的内容

with open(fname, 'r+', encoding='utf-8') as f:
    for i in f:
        # print(i)  # 遍历出每行的内容
        if word in i:
            yield i

ch = check('jiuge.txt', '灰同学')

print(next(ch))
print(next(ch))
print(next(ch))

2.3 return 和 yield

 def funa():
     yield 1
     yield 2
     # return '这是return'  # 如果return返回了值,这个值就是StopIteration异常的说明

 a = funa()
 print(next(a))
 print(next(a))
 print(a)


 def funb():
     return 1
     return 2  # 执行完第一句return后,函数结束

 print(funb())

 总结:
 相同点:都是返回函数执行的结果
 不同点:return返回结果后结束函数的执行; yield让函数变成一个生成器,函数被冻结,唤醒后再产生一个值

线程

1.线程

1.1多任务:同一时间执行多个任务

多任务的执行方式:并发、并行

1.2 进程和线程

1.进程:打开一个程序至少就会有一个进程,是操作系统进行资源分配的基本单位
一个进程默认有一个线程,进程里面可以创建多个线程

2.线程:线程是CPU调度的基本单位,每个进程至少有一个线程,这个线程就是主线程;自己创建的是子线程

import time
print(123)
time.sleep(1)  # 睡眠, 以秒为单位
print(456)

2.1单线程

def drink():
     print('喝红牛')
     time.sleep(2)
     print('抗疲劳')

def eat():
     print('吃烧烤')
     time.sleep(2)
     print('奥利给')

drink()
time.sleep(1)
eat()	

2.2多线程

线程模块:threading
线程类Thread 参数:
     target:执行的目标任务名
     args:以元组的形式给执行任务传参
     kwargs:以字典的方式给执行任务传参

举例一:

from threading import Thread  # 导入线程模块

def drink():
    print('喝红牛')
    time.sleep(3)
    print('抗疲劳')

def eat():
    print('吃烧烤')
    time.sleep(3)
    print('奥利给')

if __name__ == '__main__':
    # 1.创建子线程
    # target:只需要告诉他函数名
    t1 = Thread(target=drink)  # 任务名后面不要加小括号
    t2 = Thread(target=eat)
    # 2. 开启子线程  -- start方法
    t1.start()
    t2.start()	

举例二:

import threading
def speak(name):
    print(f'{name}在说话')
    time.sleep(2)
    print('哈哈哈')

if __name__ == '__main__':
    for i in range(4):
        # 创建子线程, args传入参数,以元组的形式,只写一个参数需要后面加逗号
        t1 = threading.Thread(target=speak, kwargs=({'name': 'zs'}))
        t1.start()

多线程

# 导入线程模块
from threading import Thread
import time

#1. 多线程
# 线程模块:threading
# 线程类Thread 参数:
#     target:执行的目标任务名
#     args:以元组的形式给执行任务传参
#     kwargs:以字典的方式给执行任务传参


def study(**kwargs):
    print(f'{kwargs}在上课')
    time.sleep(2)


if __name__ == '__main__':
     for i in range(4):   # 循环四次,创建多个子线程
         # 创建子线程
         t1 = Thread(target=study, kwargs={'name': 'zs'})  # 任务是study
         # 启动子线程
         t1.start()

2.多线程步骤

 1.导入模块
 2.创建子线程
 3.守护线程 setDaemon
 4.启动子线程 start
 5.阻塞主线程 join	

def funa():
 	print('明月清风')
	time.sleep(2)
	print('今年不收礼')

def funb():
	print('信手斩龙')
	time.sleep(2)
	print('森思熟滤')

if __name__ == '__main__':
	# 1.创建子线程
	t1 = Thread(target=funa)
	t2 = Thread(target=funb)

# 3.守护线程:主线程执行完了,子线程也跟着结束; 要放在start前面
	t1.setDaemon(True)
	t2.setDaemon(True)


# 2.开启子线程
t1.start()
t2.start()

# 4.阻塞主线程:有暂停的作用, 等添加了join的子线程执行完,主线程才能继续执行
# 必须放在start后面; 加了join,守护线程功能还在,只是没有体现
t1.join()
t2.join()

# 6.修改名字
t1.setName('线程1')
t2.setName('线程2')

# 5.获取名字
print(t1.getName())
print(t2.getName())

print('旺仔思思森森, 这是主线程')

资源共享

1.run方法

from threading import Thread
import time

# 线程类:
class MyThread(Thread):  # 需要继承Thread类
	# 重构run方法, 规定是run这个名字, 表示线程活动的方法
	def run(self):
		print('耗子尾汁')
		time.sleep(2)
		print('头大如我')

 if __name__ == '__main__':
	#创建一个线程实例
	my = MyThread()
	# 启动线程   start会调用run方法
	my.start()

2.线程之间执行是无序的

import threading
import time

def work():
	time.sleep(1)
	current_thread()是线程模块的内置方法,返回当前的线程对象
	print('当前线程:', threading.current_thread().name)  # 打印一下当前执行的线程名
	
	if __name__ == '__main__':
		for i in range(5):
			# 创建子线程
			s1 = threading.Thread(target=work)
			s1.start()

3.多线程资源共享

举例一:

li = []  # 空列表

# 写数据
def write():
	for i in range(5):
   		li.append(i)
     	time.sleep(0.1)
 		print('写入的数据:', li)


# 读数据
def read():
    print('读取的数据:', li)

if __name__ == '__main__':
    # 创建写入数据的子线程
    w1 = Thread(target=write)
    # 创建读取数据的子线程
    r1 = Thread(target=read)
    w1.start()
    w1.join()  # 阻塞,等w1执行完
    r1.start()

举例二 : 资源竞争

a = 0
b = 1000000

# 循环一次给全局变量a+1
def jia():
    for i in range(b):
        global a  # 声明全局变量
        a += 1
 print('第一次:', a)

def jia2():
    for i in range(b):
        global a  # 声明全局变量
        a += 1
    print('第二次:', a)

if __name__ == '__main__':
    # 创建两个线程
    t1 = Thread(target=jia)
    t2 = Thread(target=jia2)

    t1.start()
    t1.join()  # 主线程等待第一个子线程执行完代码再继续执行
    t2.start()

4.资源竞争解决办法

同步:
     有两个线程, 线程A和线程B, A是用来写入的,B是读取A的值; A要先写入数据,B才能读取这些数据。
     线程A和B之间就是一种同步关系

线程同步的方式:线程等待(join) 、 互斥锁
互斥锁:能够保证多个线程访问共享数据不会出现数据错误的问题
对共享的数据进行锁定, 保证同一时刻只能有一个线程去操作

互斥锁使用:
    1.导入Lock
    2.创建全局互斥锁
    3.acquire(加锁)和release(解锁)方法之间的代码同一时刻只能由一个线程去操作

from threading import Thread, Lock

a = 0
b = 1000000

#1.创建全局互斥锁
lock = Lock()

#循环一次给全局变量a+1
def jia():
	lock.acquire()    # 2.加锁
	for i in range(b):
    global a  # 声明全局变量
    a += 1
print('第一次:', a)
lock.release()   # 3.解锁


def jia2():
	lock.acquire()
	for i in range(b):
    global a  # 声明全局变量
    a += 1
print('第二次:', a)
lock.release()

if __name__ == '__main__':
	# 创建两个线程
	t1 = Thread(target=jia)
	t2 = Thread(target=jia2)

	t1.start()

	t2.start()

总结:

1.acquire() 和release() 这两个方法必须成对出现
2.使用互斥锁,确保某段关键代码只能由一个线程从头到尾执行
3.使用互斥锁会影响代码的执行效率,多任务变成了单任务执行
4.互斥锁如果没有使用好容易出现死锁的情况

死锁:

1.一直等待对方释放锁的情况就是死锁
2.会造成应用程序停止响应, 不能再处理其他任务了
3.使用互斥锁的时候,注意死锁的问题,在合适的地方释放锁	

进程

1.进程的状态

就绪态: 运行的条件都已经具备,正在等CPU执行
执行态:CPU正在执行其功能
等待态: 等待某些条件满足

import time
print('程序开始')  # 程序开始,运行状态
name = input('请输入你的名字:')  # 用户输入,进入阻塞

print(name)

time.sleep(1)   # 睡眠1秒,阻塞状态
print('程序结束')   # 运行状态

2.进程语法结构 multiprocessing 模块 Process类

from multiprocessing import Process
import os

# 2.1 Process 参数:
#    target: 子进程要执行的任务
#     args:以元组的方式传递参数
#     kwargs:以字典的方式传递参数
#     name: 子进程名称,可以不设定

# 2.2 属性:name:当前进程的别名   pid:当前进程的进程号

os.getpid(): 获取当前进程的进程号
os.getppid(): 父进程号

def one():
    print('这是任务一')
    print(f'one子进程id:{os.getpid()}, 父进程id:{os.getppid()}')

def two():
    print('这是任务二')
    print(f'two子进程id:{os.getpid()}, 父进程id:{os.getppid()}')

if __name__ == '__main__':
    # 创建子进程
    # p1 = Process(target=one, name='酒鸽')  # 设置子进程名称
    p1 = Process(target=one)
    p2 = Process(target=two)

    # 启动子进程
    p1.start()
    p2.start()

    p1.name = '九歌'
    print('p1的子进程名:', p1.name)
    print('one中的进程号:', p1.pid)
    查看主进程的进程号
   print('主进程的id:%s, 父进程的id:%s' % (os.getpid(), os.getppid()))	

	在cmd中查看进程命令:tasklist	

2.3 常用方法

# start: 启动子进程
# is_alive: 判断子进程是否还活着, 存活返回True, 否则False
# join: 主进程等待子进程结束	

def sleep():
    print('赶紧起来,别睡了')

def play():
    print('赶紧学习, 别玩了')

if __name__ == '__main__':

    p1 = Process(target=sleep)
    p2 = Process(target=play)
	p1.start()
    p1.join()  # 主进程等待p1子进程结束
    p2.start()
    p2.join()
	print('p1的状态是:', p1.is_alive())
    print('p2的状态是:', p2.is_alive())

2.4 进程间不共享全局变量

from multiprocessing import Process
import time

li = []

# 写入数据
 def write():
     for i in range(3):
         li.append(i)
         time.sleep(1)
     print('这是write里面的li: ', li)

 # 读取数据
 def read():
     print('这是read里面的li: ', li)

 if __name__ == '__main__':
     p1 = Process(target=write)
     p2 = Process(target=read)

     p1.start()
     p1.join()
     p2.start()

进程池

1.进程间的通信 – Queue

q.put(): 放入数据
q.get(): 取出数据
q.empty(): 如果队列为空,返回True, 否则False
q.qsize(): 返回当前队列包含的消息数量
q.full(): 如果队列满了,返回True, 否则False

from queue import Queue

# 初始化一个Queue对象
q = Queue(4)  # 里面有参数,代表最多接收三条信息; 没有参数, 没有大小限制
q.put('a')
q.put('b')
q.put('c')

print('判断队列是否满了:', q.full())

#取出数据
print(q.get())
print(q.get())
print(q.get())

print(q.empty())
print('现在的消息数量:', q.qsize())

2.进程操作队列

from multiprocessing import Process, Queue

name = ['旺仔', '森森', '木木', '思思']

# 将名牌放入盒子中
def write(q1):  # q1是形参, 代表初始化的Queue对象
    for i in name:
        print(f'将{i}放入盒子中')
        q1.put(i)
# 读取盒子里面的名牌
def read(q2):
    while True:
        if q2.empty():
            break
        else:
            print('我们从盒子中看到:', q2.get())

if __name__ == '__main__':
    # 创建Queue对象
    que = Queue()
    p1 = Process(target=write, args=(que, ))
    p2 = Process(target=read, args=(que, ))

    p1.start()
    p1.join()
    p2.start()

3.进程池

概念:定义一个池子, 在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务;
等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务

apply_async: 异步非阻塞, 不用等待当前进程执行完毕,随机根据系统调度来进行进程切换
用法:主进程需要使用join, 用get收集结果

from multiprocessing import Pool
import time

def study(a):  # a是形参
	print('我们在学习')
	time.sleep(2)
  	return a  # 这个是老师给你们演示的代码

if __name__ == '__main__':
	# 定义一个进程池, 最大进程数是3
	p = Pool(3)
	li = []
	for i in range(6):  # range(6) 是0  1  2  3  4  5
    	# apply_async(执行的任务, 传递给任务的参数)
    	res = p.apply_async(study, args=(i, ))  # 根据进程池中的进程数, 每次最多3个子进程在执行
   		# res中保存的是任务执行后的结果,也就是study中返回的值
    	li.append(res)
# 关闭进程池
p.close()
p.join()

# apply_async 用get来收集结果
for i in li:
    print(i.get())

协程

1.协程

 对于协程来说,程序员就是上帝, 想让谁执行到哪里,他就执行到哪里

简单实现协程 – yield

import time

def work1():
    while True:
        yield 1
        time.sleep(1)

def work2():
    while True:
        yield 2
        time.sleep(1)

w1 = work1()
w2 = work2()
while True:
    print(next(w2))
    print(next(w1))

2.greenlet

是一个用C实现的协程模块,通过设置switch()可以实现任意函数之间的切换,这种切换属于手动切换。

** 切记: 不用用第三方模块、内置模块名作为自己的py文件命名!!!**

2.1 下载greenlet模块

安装库/模块命令  -- pip install 模块名
1. 进入命令提示符 --  输入 pip install greenlet
2. 在pycharm编辑器下方 ---  点击Terminal(终端) -- 输入 pip install greenlet
3. pip list      查看已经安装的库、模块
4. python -m pip install --upgrade pip   更新pip版本
# 'pip' 不是内部或外部命令,也不是可运行的程序  ---  检查一下解释器配置/修改一下环境变量

2.2 使用greenlet实现任务切换

from greenlet import greenlet

def study():
 	print('需要下载模块')
	g2.switch()
	print('下载完成')
	g2.switch()

def play():
	print('趣味运动会')
	g1.switch()
	print('跑完了')

# 实例化一个协程  :   greenlet(目标函数), 函数后面没有小括号	
g1 = greenlet(study)
g2 = greenlet(play)

#switch() 切换执行
g1.switch()      # 切换到g1中运行
g2.switch()    # 切换到g2中运行
协程—gevent

1.gevent模块

自动切换任务,在gevent中用到的主要模式是greenlet; gevent遇到IO操作,会自动进行切换,属于主动式切换。

2.gevent使用

下载gevent模块
安装库/模块命令  -- pip install 模块名    (pip install  gevent)

2.1 gevent.spawn()   创建一个协程对象
spawn() 第一个参数是函数名, 后面的参数是传值

2.2 join:等待、阻塞、直到某个协程执行完毕
2.3 joinall: 这个方法的参数是一个协程对象列表,会等待所有的协程都执行完毕后再退出

3.gevent举例

3.1 如果没有遇到能识别的IO操作,不会进行任务切换
 IO:指的是输入输出 input output, 比如说网络等待、文件操作等

3.2 gevent模块中自带了sleep耗时函数,当使用了sleep时,
CPU会跳转到另一个就绪的程序,达到人工设置让其自动切换的功能


import gevent

def write():
    print('开始写代码')
    gevent.sleep(1)   #  gevent.sleep(1)模拟的是gevent可以识别的io操作
    print('明月清风写完了')

def drive():
    print('森森开车了')
    gevent.sleep(3)
    print('Open cat')

def eat():
    print('吃烧烤')
    print('吃火锅')

# 创建协程对象
g1 = gevent.spawn(write)
g2 = gevent.spawn(drive)
g3 = gevent.spawn(eat)

g1.join()  # 等待g1结束
g2.join()  # 等待g2结束
g3.join()  # 等待g3结束

3.3 joinall: 这个方法的参数是一个协程对象列表,会等待所有的协程都执行完毕后再退出

def work(name):
    for i in range(3):
        print(f'函数名:{name}, i的值:{i}')

gevent.joinall([
    gevent.spawn(work, '旺仔'),
    gevent.spawn(work, '森森')
])

3.4 综合举例

import gevent

def boy():
    print('男生:打个电话:')        # 1
    gevent.sleep(2)
    print('男生:咦, 为什么挂电话,接着打...')  # 5

def girl():
    print('女生:主人来电话啦...')   # 2
    gevent.sleep(3)
    print('女生:主人那家伙又来电话啦...')   # 6

def content():
    print('今天吃饭没')  # 3
    gevent.sleep(1)
    print('多喝热水')    # 4

gevent.joinall([
    gevent.spawn(boy),
    gevent.spawn(girl),
    gevent.spawn(content)
])

协程遇到IO操作,会自动进行切换

3.5 给程序打补丁

如果需要用到time.sleep(), 需要打一个补丁

from gevent import monkey  # 导入模块
import gevent
import time

# 该语句必须放在前面
monkey.patch_all()  # 将程序中用到的耗时操作的代码,换为gevent中自己实现的代码

def work(ne):
    for i in range(3):
        print('函数名:%s' % ne)
        time.sleep(1)
gevent.joinall([
    gevent.spawn(work, 'ts'),
    gevent.spawn(work, 'we')
])

3.6 简单总结

1.线程是CPU的调度的单位,进程是资源分配的单位
2.一个程序至少有一个进程,一个进行至少有一个线程
3.进程切换任务资源比较大,效率很低
线程切换任务资源一般,效率一般
协程切换任务资源很小,效率较高

正则进阶

匹配单个字符
正则表达式是一个强大的字符串处理工具

1.正则用法:

import re  #  直接导入模块即可

match方法:从字符串的开始位置匹配正则表达式,返回match对象
如果起始位置没有匹配成功,返回None

re.match(正则表达式, 要匹配的字符串)

group方法:如果匹配到数据的话,可以使用group方法来提取数据

2.举例:

res = re.match('sixstar', 'sixstar')
print(res)  # 返回match对象
print(res.group())  # 没有匹配到,会显示:'NoneType' object has no attribute 'group'

3.匹配单个字符
. 匹配任意1个字符(除了\n之外)

res = re.match('.', '信手斩龙')
print(res.group())

[ ] 匹配[ ]中列举的字符

[0-35-68-9] 不匹配数字4和7
res = re.match('[0-9][123456789][0-35-68-9][信手]', '456信手斩龙')
res2 = re.match('[a-z][a-zA-Z]', 'aBcd')

print(res.group())
print(res2.group())

\d 匹配数字: 0,1,2,3,4,5,6,7,8,9

res = re.match('\d\d', '23#')

\D 匹配非数字, 既不是数字

res = re.match('\D', '#是23#')

\s 匹配空白, 即 空格 和 tab 键

\S	匹配非空白
res = re.match('\s\s\S', '  #是23#')
print(res)

\w 匹配单词字符, 即a-z,A-Z,0-9,_ ,中文

\W	匹配非单词字符
res = re.match('\w', '_AlphaZHUQILayman')
res = re.match('\w', '权志龙')
print(res)
print(res.group())
匹配多个字符
import re

1.* 匹配前一个字符出现0次或者无限次,即可有可无

res = re.match('\d*', '123sixstar')
# * 可以是0次,  \D*没有匹配到不会报错,是空字符串
res = re.match('\D*', '123sixstar')
print(res)

2.+ 匹配前一个字符出现1次或者无限次,即至少有1次

res = re.match('\d+', '123sixstar')
# 至少得1次,\D+ 没有匹配到会报错
# res = re.match('\D+', '123sixstar')

3.? 匹配前一个字符出现1次或者0次,即要么有1次,要么没有

res = re.match('[1-9]?\d', '6789')
# [1-9]?  匹配不出数据,不会报错,因为最少是0次
# res = re.match('[1-9]?', '06789')
# res = re.match('[1-9]?\d', '06789')
# res = re.match('[1-9]?', '6789')
# print(res)
# print(res.group())

4.{m} 匹配前一个字符出现m次

res = re.match('\w{4}', 'abc123_ert')
print(res.group())

5.{m,n} 匹配前一个字符出现从m到n次
最少是m次,最多是n次

res = re.match('\w{4, 6}', 'abc123_ert') # 里面需要是英文符号
res = re.match('\w{4,6}', 'abcertyu')
print(res.group())
匹配开头结尾、分组
import re

1.匹配开头结尾

^ 开头

一是表示以什么开头; 二表示对什么取反
注意:^在[]中才表示不匹配

res = re.match('^ab', 'abcd')

[^ab]:表示匹配除了'a','b'的字符
res = re.match('[^ab]*', 'jiugeabcd')
res = re.match('[^ab]', '9abcd')
print(res.group())

$ 结尾

res = re.match('\w*e$', 'jiuge')  # 字符e结尾符合
res = re.match('\w*t$', 'jiuge')    # # 字符t结尾符合
print(res.group())

2.匹配分组
| 匹配左右任意一个表达式

res = re.match('\d?\d$|100', '100')
res = re.match('\d$', 'abc')
res = re.match('\d$|\w*', 'abc')
print(res.group())
(ab)	将括号中字符作为一个分组
res = re.match('\w{4,20}@163.com', 'test@163.com')
res = re.match('\w{4,20}@(163|qq|129).com', 'test@178.com')
print(res.group())

\num 引用分组num匹配到的字符串

res = re.match('<.*>', '<html>jiuge</html>')
res = re.match(r'<(\w*)>.*</\1>', '<h2>jiuge</h2>')
res = re.match(r'<(\w*)><(\w*)>.*</\2></\1>', '<html><h2>jiuge</h2></html>')
print(res.group())

(?P) 分组起别名

(?P=name)	引用别名为name分组匹配到的字符串
res = re.match(r'<(?P<n1>\w*)><(?P<n2>\w*)>.*</(?P=n2)></(?P=n1)>', '<html><h2>jiuge</h2></html>')
print(res.group())
高级用法

1.匹配变量名是否有效: 不能以数字开头

import re
name_li = ['jiuge', '4jiuge', 'jiu', '_jiuge']

for i in name_li:
    # print(i)
    res = re.match('\D+', i)  # \D匹配非数字  +:匹配前一个字符出现1次或者无限次
    if res:
        print('正确的变量名:', res.group())
    else:
        print('非法的变量名:', i)

2.高级用法
1.search()会扫描整个字符串并返回第一个成功匹配的字符串

res = re.search('\d+', '九歌老师翻车翻了108次, 上课上了25次')
print(res)
print(res.group())

# match从开始位置匹配, search扫描整个字符串查找匹配

2.findall()以列表形式返回匹配到的字符串

res = re.findall('\d+', '九歌老师翻车翻了108次, 上课上了25次, 开车开了361次')
print(res)
print(type(res))

总结:

match     从头开始匹配       返回object    匹配一次   不常用
search    仅返回第一个匹配    返回object    匹配一次   较常用
findall   从头到尾匹配        返回列表      匹配所有   最常用

3.sub() 将匹配到的数据进行替换

sub(正则表达式,新内容,字符串, 指定要替换的个数)
res = re.sub('\d+', '43', '小希的尺码是42码, 太阳的尺码是40码, 木木的尺码是42码')
res = re.sub('\d+', '43', '小希的尺码是42码, 太阳的尺码是40码, 木木的尺码是41码', 2)
print(res)

4.split()根据匹配进行切割字符串,并返回一个列表

split(正则表达式, 字符串)
res = re.split(' ', 'a b; c 12')
print(res)

5.贪婪与非贪婪
贪婪匹配:

在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配.

非贪婪匹配:

在满足匹配时,匹配尽可能短的字符串,使用?来表示非贪婪匹配.
在*、+、{m,n}等后面加上?, 使贪婪变成非贪婪

 *: 最少0次,最多n次
+:最少1次,最多n次
?: 最少0次,最多1次

res = re.match('ab*', 'abbbc')  # abbb

?修饰的是前面的*, *最少是0次,b的0次没有值
res = re.match('ab*?', 'abbbc')   # a
?修饰的是前面的+, +最少是1次,b的1次就是一个字符b
res = re.match('ab+?', 'abbbc')   # ab
print(res.group())


res = re.match('a*', 'aaaa')  # aaaa
res = re.match('a?', 'aaaa')    # a
res = re.match('a*?', 'aaaa')    # a
print(res.group())

6.原生字符串

python中字符串前面加上r表示原生字符串

print('abc123')     # abc123
print('abc\n123')
print('abc\\n123')  # abc\n123
print(r'abc\n123')  # abc\n123

如果需要匹配字符串中的"\", 在正则表达式需要4个反斜杠
因为在正则表达式中,'\\'表示一个反斜杠
res = re.match('\\\\', '\def')

res = re.match(r'\\', '\def')
res = re.match(r'\\*', r'\\def')
res = re.match(r'\\\\', r'\\def')
print(res.group())

内置模块

作业

代码:

class Jiuge(object):  # 烤酒鸽
    def __init__(self, level):
        self.level = level
        self.mat = '生的'

    def cook(self):
        if 0 <= self.level <= 3:
            self.mat ='生的'
        elif 4 <= self.level <= 6:
            self.mat = '半熟'
        elif 7 <= self.level <= 9:
            self.mat = '熟了'
        elif self.level >= 10:
            self.mat = '烤糊了'
        else:
            print('出错了')

    def add(self, ment=1):
        if ment == 1:
            print(f'酒鸽烤了{self.level}分钟,不想加酱料')
        else:
            print(f'酒鸽烤了{self.level}分钟, {self.mat},添加的酱料是{ment}')

jiu = Jiuge(7)
jiu.cook()
jiu.add()

2.文件操作作业

with open('test.txt', 'w+') as f:
    f.write('hello python')
    f.seek(0, 0)
    print(f.read())
内置模块

1.os模块 包含普遍的操作系统功能

import os

1.1 os.getenv() 读取环境变量

 print(os.getenv('path'))

1.2 os.path.split() 把路径分为两部分, 第一个是目录路径,第二个是文件名

os.path.dirname() : split分割出的第一个元素
os.path.basename() : split分割出的第二个元素

print(os.path.split(r'D:\test10\26内置模块\2.内置模块.py'))
print(os.path.dirname(r'D:\test10\26内置模块\2.内置模块.py'))
print(os.path.basename(r'D:\test10\26内置模块\2.内置模块.py'))

1.3 os.path.exists() 判断路径是否存在, 存在返回True, 不存在返回False

print(os.path.exists(r'D:\test10\26内置模块\2.内置模块.py'))  # True
print(os.path.exists(r'D:\test10\26内置模块\3.内置模块.py'))  # False

1.4 os.path.isfile() 判断一个文件是否存在; 存在返回True, 不存在返回False

os.path.isdir() 判断一个文件夹是否存在
print(os.path.isfile(r'2.内置模块.py'))
print(os.path.isdir(r'D:\test10\26内置模块'))

1.5 os.path.abspath(path) 返回path的绝对路径

print(os.path.abspath('.'))  # 返回当前路径的绝对路径
print(os.path.abspath('../'))  # 返回上一层路径的绝对路径

2.sys模块 负责程序跟python解释器的交互

import sys
print(sys.path)  # 返回环境变量的路径
print(sys.platform)  # 返回当前系统平台
print(sys.version)  # 查看目前系统python的版本

3.time 模块 :处理时间

import time

3.1 time.time() 时间戳

print(time.time())

3.2 time.localtime() 将时间戳转换为当前时区的struct_time, 时间数组格式
struct_time:结构化时间 :包含了年月日时分秒的多元元组

print(time.localtime())
t1 = time.localtime()
print(t1)
print(t1[0])
print(t1.tm_year)

3.3 time.asctime(): 把时间元组表示为 Sat Dec 19 21:25:19 2020

print(time.asctime())

3.4 time.strftime(格式化字符串, struct_time对象) :struct_time对象转成时间字符串, 使用字符串表示当地时间

print(time.strftime('%Y-%m-%d', time.localtime()))
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))

3.5 time.strptime(时间字符串, 格式化字符串) : 将时间字符串转成struct_time对象

stime = '2015-09-12 12:13:23'  # 时间字符串
ftime = time.strptime(stime, '%Y-%m-%d %H:%M:%S')
print(ftime)   # struct_time对象

linux基本命令

ctrl+shift+ +   :放大终端字体
Ctrl+ -         :缩小终端字体

基本命令:

pwd    显示当前工作路径 
ls     查看目录中的文件  -a显示隐藏的文件-和目录
cd     切换目录     cd ..   回到上一级
clear  清除屏幕   
reset  真正地清空终端屏幕
tab    自动补全命令

mkdir  创建目录/文件夹   -p参数可以递归创建目录
tree  以目录树的方式显示  : 如果显示了这句:sudo apt install tree,安装一下即可
rmdir  删除文件夹    删除为空的文件夹
rm     删除文件    rm -rf:删除一个非空目录
					 -r: 递归删除目录及其内容   -f强制删除
touch  创建文件
cat    查看文件内容
echo   写入内容
一个> , 没有文件则创建;有文件就重写
两个>, 没有文件则创建,有文件新内容会添加在原内容后面


cp     拷贝文件    -a:会保留文件原有属性
		cp t1/ t2/ -a   把文件夹t1拷贝到t2目录里,/的后面有空格
which  查看命令位置
mv     移动文件/重命名
	1.重命名:mv 旧名 新名
	2.移动文件:mv jiuge/ t1/   把jiuge文件夹移动到t1文件夹下  
	-v:显示移动进度

find   查找文件    -name 代表按文件名查找

cd     cd ~   切换到当前用户目录

vim编辑器

三种模式:
1.命令行模式:复制、粘贴、删除、移动光标
2.编辑模式:编辑文本   按i开始编辑
3.末行模式:保存、退出、替换   %s/abc/123/g   : 把文件中的所有abc替换成123

怎么切换模式:

编辑好以后,按esc后,shift+: ,输入wq保存退出。
按esc键回到命令行模式
按shift+: 回到末行模式

命令行模式:

将光标移到行尾:$
将光标移到开头:^
删除光标所在行:dd
撤销上一步:   u
复制当前光标所在行:yy
粘贴:       p

编辑模式:

i 当前光标前编辑
a 当前光标后编辑
o 当前光标的下一行进行编辑

末行模式:

退出:q
保存:w
保存并退出:wq
强制退出:q!

python安装第三方库:

pip install  模块名: 安装模块
pip uninstall  模块名: 卸载模块

Linux中安装工具包:

sudo apt install  安装包名
输入sudo后的密码:123 (输入密码的时候不会显示,直接回车)

ctrl+z / ctrl+c 退出
有趣的命令: Ctrl+C / ctrl + Z退出

1.sudo apt install libaa-bin 
aafire  跳动的火
2.sudo apt moo    羊
3.sudo apt install sl
sl     跑火车
4.sudo apt install cmatrix
cmatrix  黑客帝国  
5.sudo apt install bastet
bastet   俄罗斯方块
6.sudo apt install ninvaders
ninvaders  太空入侵者
7.sudo apt install nsnake
nsnake     贪吃蛇
8.sudo apt install oneko
oneko   小猫跟着鼠标移动

sudo apt install fortune  
fortune   英文名言
sudo apt install fortune-zh
fortune   英文名言/中文名言/古诗词
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值