Python

1.1 计算机硬件基本认知

	cpu:   中央处理器.   相当于人的大脑.运算中心,控制中心.
	内存:  临时存储数据.  优点:读取速度快。 缺点:容量小,造价高,断电即消失.
	硬盘:  长期存储数据.  优点:容量大,造价相对低,断电不消失。 缺点:读取速度慢.
	操作系统:统一管理计算机软硬件资源的程序

1.2计算机文件大小单位

	b = bit  位(比特)
	B = Byte 字节
	1Byte = 8 bit   #一个字节等于8位  可以简写成 1B = 8b
	1KB = 1024B
	1MB = 1024KB
	1GB = 1024MB
	1TB = 1024GB
	1PB = 1024TB
	1EB = 1024PB

1.3进制转换

	二进制:由2个数字组成,有0 和 1  			   例:  0b101 
	八进制:由8个数字组成,有0,1,2,3,4,5,6,7        例:  0o127
	十进制:有10个数字组成,有0,1,2,3,4,5,6,7,8,9   例:  250
	十六进制:有16个数字组成,有0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f(字母大小写都可以,分别代表10,11,12,13,14,15) 例:0xff  0Xff  0XFF	
	
	*2-8-16进制转十进制用逐一乘法再相加*
	十进制向2-8-16进制转换用除法取余数算作0 1 转成二进制拼接
	2变8则三位一隔开
	2变16则四位一隔开

1.4原码,反码,补码

1.原码 或 补码 都是二进制数据  
  原码: 二进制的表现形式
  反码: 二进制码0变1,1变0叫做反码,[原码][补码]之间的转换形式.(首位符号位不取反)
  补码: 二进制的存储形式     

数据用[补码]形式存储
数据用[原码]形式显示
[原码] 和 [补码] 可以通过[反码]互相转化,互为取反加1

2.提出补码的原因
补码的提出用于表达一个数的正负(可实现计算机的减法操作)
计算机默认只会做加法,实现减法用负号: 5+(-3) => 5-3
乘法除法:是通过左移和右移 << >> 来实现

3.[原码]形式的正负关系:
原码特点: 第一位是1
       00000000 1  表达数字正1
       10000000 1  表达数字负1
   
 4.[补码]形式的正负关系:
补码特点: 高位都是1
       00000000 1  表达数字正1
       11111111 1  表达数字负1

5.运算顺序:
补码 -> 原码 -> 最后人们看到的数
***进制转换的时候需要先把内存存储的补码拿出来变成原码在进行转换输出***

转换规律:
    如果是一个正数:  原码 = 反码 = 补码
    如果是一个负数:  原码 与 反码 之间 ,  互为取反加1 
                   原码 = 补码取反加1   给补码求原码
                   补码 = 原码取反加1   给原码求补码

2.1python认知

python 简介
89年开发的语言,创始人范罗苏姆(Guido van Rossum),别称:龟叔(Guido). 
python具有非常多并且强大的第三方库,使得程序开发起来得心应手. 
Python程序员的信仰:人生苦短,我用python!
开发方向: 机器学习人工智能 ,自动化运维&测试 ,数据分析&爬虫 ,python全栈开发

python 版本
python 2.x 版本,官方在 2020 年停止支持,原码不规范,重复较多
python 3.x 版本,功能更加强大且修复了很多bug,原码清晰,简单

编译型与解释型语言区别:
编译型:一次性,把所有代码编译成机器能识别的二进制码,在运行
	代表语言:c,c++
	优点: 执行速度块
	缺点: 开发速度慢,调试周期长
	
解释型:代码从上到下一行一行解释并运行 
	代表语言:python,php
	优点: 开发效率快,调试周期短
	缺点: 执行速度相对慢
*linux 操作系统默认支持python语言,可直接使用

python的解释器:
(1)Cpython(官方推荐)
	把python转化成c语言能识别的二进制码
(2)Jpython
	把python转化成java语言能识别的二进制码
(3)其他语言解释器
	把python转化成其他语言能识别的二进制码
(4)PyPy
	将所有代码一次性编译成二进制码,加快执行效率(模仿编译型语言的一款python解释器)

2.2注释:就是对代码的解释,方便大家阅读代码,同时注释不会被解释器编译运行

#注释的种类:
1.单行注释
#print("hello world")

2.多行注释

print("#",end=""),print("#",end=""),print("#",end="\n")
'''
print("#",end=""),print("#",end=""),print("#",end="\n")
print("#",end=""),print("#",end=""),print("#",end="\n")
'''
print("#",end=""),print("#",end=""),print("#",end="\n")

3.多行注释的嵌套
"""
'''
如果外层使用三个单引号,里面使用三个双引号
如果外面使用三个双引号,里面使用三个单引号
'''
"""

4.注释拥有一定的排错性
先将一部分代码注释掉不去运行,以此划分错误区间
可以更高效率的进行排错

2.3变量: 可以改变的量,实际具体指的是内存中的一块存储空间

1.变量的概念
	a=1
	a=2
	print(a)
	2
2.变量的声明
	#1
	a=1
	b=2
	print(a)
	print(b)

	#2
	a,b=1,2
	print(a,b)

	#3
	a=b=3
	print(a,b)

3.变量的命名

字母数字下划线,首字符不能为数字
严格区分大小写,不能使用关键字
变量命名有意义,不能使用中文

import  引入  keyword模块
import keyword
print(keyword.kwlist)
['False', 'None', 'True', 'and', 'as', 'assert', 
'break', 'class', 'continue', 'def', 'del', 'elif', 
'else', 'except', 'finally', 'for', 'from', 'global', 
'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 
'or', 'pass', 'raise', 'return', 'try', 'while', 
'with', 'yield']
以上都不准作为变量的名称

python支持中文命名变量但是严禁使用

4.变量的交换
通用写法
	a=1
	b=2
	tmp=a
	a=b
	tmp=b
	print(a,b)

python 特有的交换变量法
	a=1
	b=2
	a,b=b,a
	print(a,b)


定义常量:名称必须全为大写,而且永远不能改变

2.4python六大标准数据类型:

数据类型分类:

####(1)Number   数字类型 (int  float  bool  complex)
##int  整型(正整数 0 负整数)
	intvar=1
	print(intvar)
	print(type(intvar))

#type  获取一个值的类型
	res=type(intvar)
	print(res)

#id  获取一个值的地址  在计算机中的地址
	res=id(intvar)
	print(res)

#二进制整形
	intvar=0b11
	print(intvar)
	print(type(intvar))
	print(id(intvar))

#八进制整型
	intvar=0o314
	print(intvar)
	print(type(intvar))
	print(id(intvar))

#十六进制整型
	intvar=0x1e3
	print(intvar)
	print(type(intvar))
	print(id(intvar))
	

##float  浮点型数据  小数

#表达方式1
	floatvar=3.14
	print(floatvar)
	print(type(floatvar))

#表达方式2  科学计数法
	floatvar=5.1d4
	print(floatvar)

#bool 布尔型  true真   false假  只有这两个值
	boolvar=true
	boolvar=false
	print(boolvar)
	print(type(boolvar))

##complex  复数
	complex是复数,一个实数加一个虚数
	5为实数,20j为虚数
	如果有个数的平方为-1,那这个数就是j,就是虚数,表达为一个高精度的类型

#表达方式1
	complexvar=5+20j
	complexvar=3j
	print(complexvar)
	print(type(complexvar))

#表达方式2
	complex(实数,虚数)
	complexvar=complex(3,-5)
	print(complexvar)
	print(type(complexvar))


####(2)str	字符串类型    
		
		特点:可以获取,不能修改,  有顺序
		
		正向索引   0 1 2 3
		strvar=   "你还睡呢"
		逆向索引 -4 -3 -2 -1

	#获取字符串中的元素
		res=strvar[1]
		print(res)

	#空格也是字符,可以被提取
	#可以有空字符串
	用引号引起来的就是字符串

	#转义字符:\ + 某个字符
	将有意义的字符变成无意义
	将无意义的字符变成有意义

	\n 换行
	\t 缩进,水平制表符,和TAB的功能一样
	\r 将\r后面的字符直接拉到当前行行首

#单引号字符串
	strvar='没有可以思考的心智'
	print(strvar)
	print(type(strvar))

#双引号字符串
	strvar="没有可以屈从的意志"
	print(strvar)
	print(type(strvar))

#三引号字符串  支持跨行效果
	strvar="""没有为苦难哭泣的声音,
	生于神与虚空之手,
	你必封印在众人梦中散布瘟疫的障目之光
	你是容器"""

#元字符串  r"字符串"不转义字符.原型化输出字符串
	strvar=r"D:\py:\py.avi"
	print(strvar)

#格式化字符串
	语法:"字符串" % (值1 ,值2 ,值3)

  	%d  整型占位符
	%2d  占两位,默认居右
	%-2d  占两位,默认居左
	strvar="今天是学习python的day%d" % (2)
	print(strvar)


  	%f  浮点型占位符
	%.2f  小数点后保留两位
	%f  存在四舍五入的情况
	strvar="今天学习了python的%f" % (0.1)
	print(strvar)


  	%s  字符串占位符
	strvar="%s" % ("prprprprprprprpr")
	print(strvar)

#综合案例

	strvar="%s今天又学了一天python,学了%d天,还剩下%f的内容学完" % ("李天兆",2,99.9)
	print(strvar)

	里面的所有占位符都可以用%s进行取代




####(3)list 列表类型      
	特点:可以获取,可以修改,有顺序

#定义一个空列表
	listvar=[]
	print(listvar)
	print(type(listvar))
	print(id(listvar))
	
	#正向索引 0    1     2      3     4
	listvar= [10,0.1."出师表",3-2j,false]
	#逆向索引 -5  -4    -3    -2     -1


#获取列表中的值
	res=listvar[2]
	res=listvar[-3]
	print(res)

#获取列表中的最后一个元素
#python特有(直接通过-1标取元素)
	res=listvar[-1]
	print(res)

#其他语言通用写法

#len  获取容器类型数据的长度,元素的总个数
	res= len(listvar)
	print(res)
	res=listvar[res - 1]
	print(res)

#2.修改列表里的值
	listvar[2]="三顾茅庐"
	print(listvar)





####(4)tuple	元组类型     
	可以获取,不可修改,有顺序

#定义一个空元组
	tuplevar=()
	print(tuplevar)
	print(type(tuplevar))


#定义一个普通的元组
正向索引    0          1        2
tuplevar=("辐光","苍白","空洞")
逆向索引   -3        -2      -1
	print(tuplevar)
	print(type(tuple))


#获取元组中的元素
	res=tuplevar[1]	
	res=tuplevar[-2]		
	print(res)
	不能修改元组中的元素

#逗号是标识是否是元组的标识符
	tuplevar=2,
	tuplevar=(2,)
	print(tuplevar)
	print(type(tuplevar))



###(5)set		集合类型   
# 特点:没有顺序,不能修改,不能获取,自动去重
	定义一个集合
		setvar={"锅","碗","嫖","盆",}
		print(setvar , type(setvar))


1.集合无序
	res = setvar[0]#表示想要获取setvar中的第一位元素
	print(res)#结果为error,集合无序不能获取
	setvar[0] = "abc"#表示想修改集合中的第一位元素,结果为error,不能修改
	#以上皆因为集合无序

2.自动去重
	setvar={"锅","碗","嫖","嫖","嫖","嫖","盆",}
	print(setvar)

3.定义一个空的集合
	setvar = set()
	print(setvar , type(setvar))


###(6)dict		字典类型  

	特点:键值对存储的数据,表面上有序,实际上无序

	语法:dictvar = {键1:值1 , 键2:值2 , 键3:值3 , ...}

	#字典的键:推荐使用变量命名的字符串进行使用
	#字典的键 和 集合的值 有数据类型上的要求
	'''
	#如何类型才可以: (可哈希的数据类型)

	Number(int,float,bool,complex),str,tuple

	#不被允许的类型(不可哈希的数据类型)

	list,set,dict
	'''
# 但凡提到哈希算法(hash),都是典型的无序特征
	目的:为了更加均匀的把数据分配到内存中,底层用了取模类似的算法
	python3.6版本对字典做了优化,储存数据的时候用哈希算法,
	但是拿出来数据的时候,重新按照定义的顺序做了排序,所以看起来有序,实际上无序

#1.定义一个空的字典
	dictvar = {}
	print(dictvar , type(dictvar))

#2.定义一个普通的字典
	dictvar = {"人族":"hum" , "兽族":"orc" , "不死族":"ud" , "暗夜精灵":"ne"}
	print(dictvar)

#3.获取字典的值
	res = dictvar["人族"]
	print(res)
#4.修改字典的值
	dictvar["人族"] = "king"
	print(dictvar)


#5.字典的键有一定的要求
	dictvar = {3:"aaa" , false:"bbb" , 9+3j:"ccc" , (1,2,3):"ddd"}
	res=dictvar[(1,2,3)]
	print(res)
	print(dictvar)

	# dictvar = {[1,2,3]:"abc"} error # TypeError: unhashable type: 'list'
	# setvar = {"a",1,{"a":1,"b":2}} error  # TypeError: unhashable type: 'dict'
	字典中的键值对必须为可哈希的数据类型,不能使用不可哈希的数据类型

变量的缓存机制(仅对python3.6)

number部分
#1.对于整型而言,-5~正无穷范围内的相同值id一致
	intvar1 = 100
	intvar2 = 100#以上两个变量id一致,因为是在-5~正无穷范围内
	
	intvar1 = -100
	intvar2 = -100#以上两个变量id不一致,因为不在范围内
	
	print(id(intvar1) , id(intvar2))
#2.对于浮点数而言,非负数范围内的相同值id一致
	intvar1 = 3.5
	intvar2 = 3.5#这两个变量id一致,因为都是在非负数范围内的相同值
	
	print(id(intvar1) , id(intvar2))
#3.对于布尔值而言,值相同的情况下,id一致
	intvar1 = True
	intvar2 = True#两个值相同,所以id一致
	
	print(id(intvar1) , id(intvar2))
#4.复数在 实数+虚数 这样的结构中永不相同(只有虚数的情况下例外)
	intvar1 = 3+4j
	intvar2 = 3+4j#这两个变量属于实数+虚数的结构,所以即便是相同值id也不一样
	
	intvar1 = 3j
	intvar2 = 3j#这两个变量属于只有虚数的结构,所以是例外情况则相同
	print(id(intvar1) , id(intvar2))


容器类型部分

#5.字符串和空元组相同的情况下,地址相同
	var1 = ("哦")
	var2 = ("哦")#地址相同
	
	var1 = ()
	var2 = ()#地址相同
	print(id(var1) , id(var2))
	
#6.列表,元组,字典,集合无论在什么情况下,id标识都不相同,[空元组除外(上面有提到空元组相同地址相同)]
	var1 = [1,2,3]
	var2 = [1,2,3]#这是两个列表,id标识不相同
	
	print(id(var1) , id(var2))

强制类型转换

Number(int float  bool complex)
	var1 = 12
	var2 = 3.14
	var3 = True
	var4 = 5-8j
	var5 = "123"
	var6 = "abc123"
	
	# int  强制转换成整型
		res = int(var2)		#3,直接去尾取整数
		res = int(var3)		#True => 1   False => 0
		res = int(var4)			#NO  error,不能把复数转成整型
		res = int(var5)		#纯数字的字符串直接去掉引号
		res = int(var6)		#error ,只能强转纯数字的字符串
		print(res)


	# float 强制转换成浮点型
		res = float(var1)		#12.0,在末尾加上小数点和0
		res = float(var3)		#1.0,bool型只有两种,false为0.0,true为1.0
		res = float(var4)		#不能把复数转换成浮点型
		res = float(var5)		#123.0  ,纯数字字符串可以转换成浮点型
		res = float(var6)		#只能转纯数字的字符串
		print(res)
	
	
	# complex 强制转换成复数
		res = complex(var1)		#12+0j,在整型的后面加上+0j
		res = complex(var2)		#(3.14+0j), 在浮点型的后面加上+0j
		res = complex(var3)		#如果是True,就是1+0j , 如果是False,就是0j
		res = complex(var5)		#(123+0j),纯数字字符串直接在后面+0j
		res = complex(var6)		#只能转换纯数字的字符串
		print(res)



	# bool  强制转换成布尔型
		bool类型为假的十种类型:
		#(除了这十种情况,bool在强制转换任何数据类型时都是True)
		0 , 0,0 , False , 0j , () , [] , {} , set() , "", None
		#None 是python的关键字,代表空的,什么也没有,一般用于初始化操作
		#例如 : a = None
		res = bool(None)
		print(res)
		
	
	PS: 
		int()  float()  complex()  bool()
		默认创建了一个该数据类型的值
		res = int()
		res = float()
		res = bool()
		res = complex()

自动类型转换 仅针对Number(int float complex bool)

res = True + 90
res = 3.5 + 2 + 3j + True
'''
精度从低到高  bool < int < float < complex
自动类型转换,默认从低精度向高精度进行转换(从低到高)
'''
#1.bool + int
	res = True + 100 #True = 1 , False = 0
	print(res) # 101

#2.bool + float
	res = True + 1.1 #True = 1.0 , False = 0.0
	print(res) # 2.1

#3.bool + complex
	res = True + 3-10j # True = 1+0j , False = 0j
	print(res) # (4-10j)

#4.int + float
	res = 1 + 1.1 # 1 = 1.0
	print(res) # 2.1

#5.int + complex
	res = 5 + (3-10j) # 5 = 5+0j
	print(res) # (8-10j)

#6.float + complex
	res = 2.3 + (1-1j) # 2.3 = 2.3+0j
	print(res) # (3.3-1j)

容器类型的强制转换 (str list tuple set dict)

strvar = "你是容器"
listvar = ["辐光","苍白","空洞"]
tuplevar = ("今天","明天","后天")
setvar = {"七日杀","老滚","大乱斗"}
dictvar = {"前天":"大乱斗","昨天":"七日杀","今天":"当狗"}
intvar = 23333

#1.str (容器类型数据/ Number数据 都可以转换)
	强转成字符串,无非就是在原有数据基础上套引号
		res = str(listvar)
		print(res,type(res)) #['辐光', '苍白', '空洞'] 
	
	repr 可以原型化输出字符串,不转义字符显示出引号
		res2 = repr(res)
		print(res2) # "['辐光', '苍白', '空洞']"

		res = str(dicevar)
		print(res , type (res)) # {'前天': '大乱斗', '昨天': '七日杀', '今天': '当狗'} 

		res2 = repr(res)
		print(res2 , type (res2)) # "{'前天': '大乱斗', '昨天': '七日杀', '今天': '当狗'}" 

#2.list : 强制转换成列表
	如果是字符串,会把每一个字符都单独作为一个元素放到新的列表中
	如果是字典,只保留键,形成一套新的列表
	如果是其他容器,只是单纯的在原有数据的基础上套上[]
		
		res = list(strvar)
		print(res,type(res)) # ['你', '是', '容', '器'] 
		
		res = list(tuplevar)
		print(res,type(res)) # ['今天', '明天', '后天'] 
			
		res = list(setvar)
		print(res,type(res)) # ['七日杀', '大乱斗', '老滚'] 
	
		res = list(dictvar)
		print(res,type(res)) # ['前天', '昨天', '今天'] 
		
		res = list(intvar)
		print(res,type(res)) # error
	

#3.tuple : 强制转换成元组
	如果是字符串,会把每一个字符都单独作为一个元素放到新的元组中
	如果是字典,只保留键,形成一套新的元组
	如果是其他容器,只是单纯的在原有数据的基础上套上()

		res = tuple(strvar)
		print(res,type(res)) # ('你', '是', '容', '器') 
	
		res = tuple(listvar)
		print(res,type(res)) # ('辐光', '苍白', '空洞') 
	
		res = tuple(setvar)
		print(res,type(res)) # ('七日杀', '大乱斗', '老滚') 
	
		res = tuple(dictvar)
		print(res,type(res)) # ('前天', '昨天', '今天') 
	

#4.set : 强制转换成集合
	注意:集合是无序,自动去重的特征
	如果是字符串,会把每个字符都单独作为一个元素放到新的集合中
	如果是字典,只保留键,形成一套新的集合
	如果是其他容器,只是单纯的在原有数据的基础上套上{}

	res = set(strvar) 
	print(res) # {'你', '是', '器', '容'}  无序

	res = set(listvar)
	print(res) # {'空洞', '辐光', '苍白'}

	res = set(tuplevar)
	print(res) # {'后天', '今天', '明天'}

	res = set(dictvar)
	print(res) # {'今天', '前天', '昨天'}



	#案例:如何去掉如下列表的重复值?
	lst = [1,2,3,4,'a','a','a','b','b','c']
	res = list(set(lst))
	print(res) 
	# [1, 2, 3, 4, 'c', 'a', 'b']

二级容器

#二级列表

	lst = [1,2,3,4,[5,6,7]]

#二级元组
	tup = (8,9,10,(11,12,13))

#二级集合
	setvar={"a","b","c",("d","e")}
	print(setvar) # {'b', 'c', 'a', ('d', 'e')}

#二级字典
	dic = {"a":"1","b":{"c":3,"d":4}}
	res1 = dic["b"]
	res2 = res1['c']
	print(res1)
	print(res2)
	简化:
		res = dic["b"]["c"]
		print(res)

###多级容器
container = [1,2,3,(4,5,6,{"a":7,"b":[8,9,"zzz"]})]
获取"zzz"
	过程:
	res1 = container[-1]
	print(res1)
	#(4, 5, 6, {'a': 7, 'b': [8, 9, 'zzz']})
	res2 = res1[-1]
	print(res2)
	#{'a': 7, 'b': [8, 9, 'zzz']}
	res3 = res2["b"]
	print(res3)
	#[8, 9, 'zzz']
	res4 = res3[-1]
	print(res4)
	#zzz
	
	简写方式:
	res = container[-1][-1]["b"][-1]
	print(res)
	#zzz
	

#dict  强制转换成字典
	强转成字典时,必须是等长的二级容器,元素个数为2个

等长的二级容器 : 里面的元素都是容器,每一个容器里面的元素个数都相同
	lst = [(1,2,3),(4,5,6)]
	二级列表只推荐tuple


1.外层可以是列表或元组或集合,里面的容器是元组或者列表(#推荐)
	lst = [("a",1),["b",2]]
	dic = dict(lst)
	print(dic)#{'a': 1, 'b': 2}
	
	tup = (("a",13),["b",23])
	dic = dict(tup)
	print(dic)#{'a': 13, 'b': 23}
	
	setvar = {("a",1),("b",2),("c",3),("d",4)}
	dic = dict(setvar)
	print(dic)#{'a': 1, 'b': 2, 'd': 4, 'c': 3}
	
2.如果里面是集合,语法上允许,但有局限性(#不推荐)
	lst = [("a",1),{"b",2}]
	dic = dict(lst)
	print(dic)#集合无序,因此键值对结果无法预估
	
3.如果用字符串,语法上允许,但是有局限性(#不推荐)
	lst = [("a",1),"c3"]#字符串长度只能是2个
	dic = dict(lst)
	print(dic)#{'a': 1, 'c': '3'}  如果字符串长度超过2个就会报错


总结:
	str() list() tuple() set() dict()
	默认创建一个该类型数据的值

python运算符

### 算数运算符: + - * / // % **

var1 = 6
var2 = 4

加法  +
res = var1 + var2
print(res)

减法  -
res = var1 - var2
print(res)

乘法  *
res = var1 * var2
print(res)

除法  /  (结果是小数)
res = var1 / var2
print(res)


地板除  //  (返回一个整数)
res = 5 // 3
print(res)

	# 如果除数或者被除数存在是小数,那么结果上加上.0
	res = 6 // 2.0
	print(res)


取余  %
res = 81 % 11   # 4
res = -81 % 11  # -4 + 11 = 7
res = 81 % -11  # 4 + (-11) = -7
res = -81 % -11 # -4 (如果被除数和除数都是负数,在正常得到的结果上加负号即可)


幂运算  **
res = 3 ** 4
print(res)

###比较运算符: > < >= <= == != 只会产生两个结果,要么是True 要么是False

var1 = 39
var2 = 39

res = var1 > var2
print(res)

res = var1 < var2
print(res)

res = var1 == var2   #注意点
print(res)
res = True


res = var1 != var2
print(res)


	#赋值  =   ,将右侧的值赋给左侧
	#比较  ==  ,比较等号两边的值是不是相等,相等返回True

###赋值运算符: = += -= *= /= //= %= **=

# = 从右向左,将右侧的值赋值给左侧变量

var1 = 2
var2 = 4

+=  (var1 = var1 + var2)
var1 += var2
print(var1)


-=  (var1 = var1 - var2)
var1 -= var2 
print(var1)


*=  (var1 = var1  * var2)
var1 *= var2
print(var1)

/=  (var1 = var1 - var2)
var1 /= var2
print(var1)


//=  (var1 = var1 // var2)
var1 //= var2
print(var1)

%=  (var1 = var1 % var2)
var1 %= var2
print(var1)


**=  (var1 = var1 ** var2)
var1 **= var2
print(var1)

###成员运算符 : in 和 not in (针对容器类型数据)

	字符串必须是一个连续的片段
	strvar = "今天又是一条狗"
	res = "今"  in strvar
	res = "天"  not in strvar 
	res = "又是"  in strvar
	res = "一狗"  not in strvar
	print(res)


list  tuple  set
lst = ["今天","昨天","明天"]
res = "今天"  in  lst
print(res)

tup = ("今天","昨天","明天")
res = "昨天"  in tup
print(res)

setvat = {"今天","昨天","明天"}
res = "明天"  not in setvar
print(res)


dict
	#in 和 not in 在字典中只判断键,不判断值
dic = {"今天":"1","昨天":"2","明天":"3"}
res = "1" in dic 
res = "今天"  in  dic 
res = "明天"  not in dic 
print(res)

###身份运算符 : is 和 is not (检测两个数据在内存中是否是同一个值)

	python3.6

整型  -5  ~ 正无穷
var1 = 89
var2 = 89
res = var1 is var2
print(res)


浮点型  非负数
var1 = -1.1
var2 = -1.1
res = var1 is not var2
print(res)



布尔型  只要值相同即可
var1 = True 
var2 = False
res = var1 is not var2
print(res)


complex  实数+虚数永远不同,(只有虚数的情况下例外)
var1 = 3+5j
var2 = 3+5j
res = var1 is not var2 
print(res)

容器类型
var1 =()
var2 =()
res = var1 is var2
print(res)

#逻辑运算符: and or not

and  逻辑与
	# 全真则真,一假则假
res = True and True  # True
res = True and False # False
res = False and True # False
res = False and False# False 
print(res)


or  逻辑或
	# 全假则假,一真则真
res = True or True   # True
res = True or False  # True
res = False or True  # True
res = False or False # False
print(res)

not  逻辑非
	#真变假,假变真
res = not True
res = not False
print(res)


# 逻辑短路: 如果出现了短路效果,后面的代码就不执行了
	(1) True or 表达式
	(2) False and 表达式

True or print(123)
# True or True => True
# True or False => True

False and print(123)
# False and False => False
# False and True => False


res = 5 or 6  #5
res = 5 and 6  # 6
res = 0 and 9  #  0
print(res) 

bool类型为假的十种情况
0 0.0 0j False 
'' [] () set() {}
None


先用大脑算一下布尔值真假,有没有短路情况
True and True => True
True and False => False


print(123) or True
# print是内置的函数,函数内部返回的是None,功能是打印
res = print(111)
print(res)

print(111) or True
res = None or True
print(res)




#逻辑运算符的优先级
 () > not > and > or
res = 5 or 6 and 7 # 5 or 7 => 5
res = (5 or 6) and 7 # 5 and 7 => 7
res = not(5 or 6) and 7 # not 5 and 7 => False and 7 => False
print(res)
res = 1>2 or 3<4 and 5>10 or 11<12 and 13>16
# res = False or True and False or  True and False
# res = False or False or False
# res = False or False
# res = False
print(res)

#位运算符 : & | ^ << >> ~

按位与  &

var1 = 19
var2 = 15
print(var1 & var2)

	19的二进制
	000 ... 10011
	15的二进制
	000 ... 01111

	000 ... 10011
	000 ... 01111
	000 ... 00011



按位或 |

var1 = 19
var2 = 15
print(var1 | var2)

	19的二进制
	000 ... 10011
	15的二进制
	000 ... 01111

	000 ... 10011
	000 ... 01111
	000	...	11111


按位异或  ^   两者之间不一样返回真,一样返回假

var1 = 19
var2 = 15
print(var1 ^ var2)

	19的二进制
	000 ... 10011
	15的二进制
	000 ... 01111

	000 ... 10011
	000 ... 01111
	000 ... 11100



左移  <<
	左移相当于做乘法: a * 2的n次幂
	res = 5 << 4
	res = 5 << 3   # 40
	res = 5 << 2 # 20
	res = 5 << 1 # 10
	print(res)
		000 ... 101
		000 ...1010  移动一位
		000 ..10100  移动两位



右移  >>
	右移相当于做除法: a // 2的n次幂
	res = 5 >> 1
	res = 5 >> 2
	print(res)
		000 ... 101
		000 ... 010 移动一位
		000 ... 001 移动两位





~ 按位非 [针对于补码进行操作,按位取反,包括符号位]
	# 公式 : -(n+1)
		var = ~19
		print(var)
		"""
		原码:000 ... 10011
		反码:000 ... 10011
		补码:000 ... 10011

		补码:   000 ... 10011
		按位非: 111 ... 01100

		给补码求原码:
		补码: 111 ... 01100
		反码: 100 ... 10011
		原码: 100 ... 10100  -20
		"""
		var = ~(-19)
		print(var)
		"""
		原码: 100 ... 10011
		反码: 111 ... 01100
		补码: 111 ... 01101

		补码:   111 ... 01101
		按位非: 000 ... 10010

		正数 : 补码 = 反码 = 原码
		000 ... 10010  => 18
		"""

# 总结

个别运算符
	优先级最高的是** 幂运算
	优先级最低的是  =  赋值运算符
	()括号可以提升运算的优先级


整体  一元运算符  >  二元运算符
	一元运算符: 同一时间,只操作一个值  -  ~
	二元运算符: 同一时间,操作两个值  +  -  *  /  


同一层级
	逻辑: () > not > and > or
	算数: 乘除 >  加减
	位运算: (<< >>) > & > ^ > |

其他情况
	算数运算符  >  位运算符  >  比较运算符  >  身份运算符  >  成员运算符  >  逻辑运算符
	赋值运算符用来将算好的值赋值给等号左侧的变量,做收尾工作




		res = 5 + 5 << 6 // 3 is 40 and True
		"""
		10 << 2 is 40 and True
		40 is 40 and True
		True and True
		True
		"""
		print(res)
		# 能加括号的包起来,让别人能看懂;
		res = (5 + 5) << (6 // 3) is 40 and True

判断类型

语法:



用法一
isinstance(要判断的值,要判断的类型),返回的是真或假
	res = isinstance(3,int)
	res = isinstance("123",str)
	print(res)


用法二
isinstance(要判断的值,  (可能的类型1,可能的类型2))如果有一个类型满足,返回的是真,否则假
	var = "asd123"
	res = isinstance(var , (str , int ,list))
	print(res)

代码块 : 以冒号作为开始,用缩进来划分作用域

#作用域:作用的范围


#代码块含义
if 5 == 5:
	print("yes")

print("ohhhh")#这一行不在作用域中


#代码块注意点:
要么全都是一个TAB缩进,要么全都是4个空格,不能混合使用

if 9==9:
	print("ohh")
 print("o?")#这里用了一个空格缩进,报错为IndentationError


#了解一下php,js  等是使用花括号来表示作用域
	if( 5 == 5 ){
	print(1)
		print(2)
		print(3)
	print(4)
	}

流程控制

流程:代码执行的过程
控制:对代码执行过程的一种管控就是流程控制

三大结构
1:顺序结构:默认代码从上到下执行
2:分支结构:4种
3:循环结构:for  in   while循环



分支结构:
	1.单项分支
	2.双项分支
	3.多项分支
	4.巢状分支










# 1.单项分支
if  条件表达式 :
	code1
	code2

如果条件表达式成立,返回True条件成立,执行对应的代码块,反之不执行

today = "今天"
if today == "今天" :
	print("今天又是阴气满满哦!")
	print("那你明天呢?")
	print("那你后天呢?")



# 2.双项分支
if 条件表达式:
	code1
	code2
else:
	code3
	code4
如果条件表达式成立,执行if相对应的代码块
如果条件表达式不成立,执行else对应的代码块

if... 代码块也叫做真区间
else...代码块也叫做假区间


today = "今天"
if today == "今天":
	print("来整点阴间的东西")
else:
	print("GKD")


#input 等待用户输入字符串,接受的是字符串

name = input("告诉我你叫什么")
print(name , type (name))


'''
提示用户输入用户名和密码:
如果用户名是admin , 并且密码是000 , 
提示用户恭喜你,登陆成功
否则提示用户名或密码错误
'''


	name = "admin"
	passwrod = "000"

	username = input("请输入用户名")
	pswd =  input("请输入密码")


	if username == name  and  pswd ==passwrod :
		print("登陆成功")
	else:
		print("用户名或密码不对")

多项分支(多选一个)

语法:
if 条件表达式1:
	code
	code
elif 条件表达式2:
	code
	code
elif 条件表达式3:
	code
	code
else:


如果条件表达式1成立,返回True,执行对应的代码块,如果不成立,向下执行
如果条件表达式2成立,返回True,执行对应的代码块,如果不成立,向下执行
如果条件表达式3成立,返回True,执行对应的代码块,如果不成立,向下执行
直到最后,任何条件都不满足,执行else这个分支的代码块

elif 可以出现0次或者多次
else 可以出现0次或者1次


#双项分支
	man = True
	if man == True:
		print("你要活得像个阳间人一样")
	else:
		print("阴阳人,烂屁股")

#多项分支
	gao = True
	shou = True 
	youqian = True
	nuli = True
	
	if youqian ==True:
		print("你很有钱")
	elif gao == True:
		print("你很高")
	elif shou == True: 
		print("你很受")
	else:
		print("你很努力")
	

#巢状分支 (单项分支,双项分支,多项分支的互相嵌套)
	

	gao = True
	shou = True 
	youqian = True
	nuli = True
	
	
	if youqian == True:
		if gao == True :
			if shou == True :
				if nuli == True:
					print("你很努力")
				else:
					print("加油阴间人")
			else:
				print("你再练练吧")
		else:
			print("高有什么用?")
	else:
		print("你真的不行")

循环结构: while 循环

特征:减少代码冗余,提升代码效率

语法:
	while 条件表达式:
		code
		code

1.初始化一个变量
2.写上循环的判断条件
3.自增自减的变量值

#打印 1~100
i = 1
while i<=100 :
	print(i)
	i += 1

	"""
	初始化一个变量i
	第一次循环
	i = 1  , i <= 100 条件成立,执行循环
	print(i) 1
	i+=1 => 2

	第二次循环
	i = 2 , i <= 100 条件成立,执行循环
	print(i) 2
	i+=1 => 3

	第三次循环
	i = 3 , i <= 100 条件成立,执行循环
	print(i) 3
	i+=1 => 4

	....
	什么时候结束?
	当i = 101时候 判断 i <= 100 条件不成立False,不执行循环
	循环结束...

	"""


#计算1~100的累加和
	i = 1
	o = 0 
	while i <=100 :
		o += i
		i += 1
	print(o)  # 这行不在循环代码块中


	"""
	# 代码解析
	第一次循环
	i = 1 i<=100 条件成立,执行循环
	total += i => total = total + i => total = 0 + 1
	i+=1 => i = 2

	第二次循环
	i = 2 i<=100 条件成立,执行循环
	total += i => total = total + i => total = 0 + 1 + 2
	i+=1 => i = 3

	第三次循环
	i = 3 i<=100 条件成立,执行循环
	total += i => total = total + i => total = 0 + 1 + 2 + 3
	i+=1 => i = 3

	....
	依次循环

	什么时候结束?
	total = 0 + 1 + 2 + 3 + .... + 100 = 5050
	i+=1 => i = 101    i<=100 这个条件不成立 , 不执行循环体
	到此,循环终止

	"""


#死循环(条件永远为真)

while True :
	print(1)


方法二:
	i = 1
	o = 0
	p = True

while p == True:
	i += 1
	o += 1
	if i>100:
		p = False
print(o)

循环练习

#1.打印一行十个小星星


i = 0
while i<10:
#写代码逻辑
print("*",end="")

i+=1


#2.通过打印变量,直接输出一行十个小星星
i = 0
strvar = ""
while i<10:
	strvar += "*"
	i +=1
print(strvar)


# 字符串拼接 +
strvar1 = "你,"
strvar2 = "今天还是阴间人吗?"
res = strvar1 + strvar2
print(res)
res += ",真是有够好笑的呢"
print(res)



#3.打印一行十个小星星,奇数个打印★,偶数个打印	

"""
★☆★☆★☆★☆★☆
任意数和n取余,范围是多少? 0 ~ (n-1)***

n = 2
0 % 2 = 0
1 % 2 = 1
2 % 2 = 0
3 % 2 = 1
4 % 2 = 0
5 % 2 = 1

n = 4
0 % 4 = 0
1 % 4 = 1
2 % 4 = 2
3 % 4 = 3
4 % 4 = 0
5 % 4 = 1
6 % 4 = 2
7 % 4 = 3
8 ....
"""



i = 0
while i <10 :

if i%2 ==0:
	print("★",end="")
else:
	print("☆",end="")

i+=1



#4.一个循环打印十行十列小星星

"""
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********

0123456789
**********
10111213141516171819
* * * * * * * * * *
**********
20~29
**********
30~39
**********
40~49
**********

...
90~99
**********
 9 19 29 39 49 59 .. 99
if i % 10 == 9

"""



i = 0
while i<100:
	print("*",end="")
	if i % 10 == 9:
		print()
	i +=1



#5.一个循环打印十行十列隔列变色小星星


"""
★☆★☆★☆★☆★☆
★☆★☆★☆★☆★☆
★☆★☆★☆★☆★☆
★☆★☆★☆★☆★☆
★☆★☆★☆★☆★☆
★☆★☆★☆★☆★☆
★☆★☆★☆★☆★☆
★☆★☆★☆★☆★☆
★☆★☆★☆★☆★☆
★☆★☆★☆★☆★☆
"""




i = 0
while i<100:
	#打印星星
	if i % 2 == 0:
		print("★",end="")
	else:
		print("☆",end="")
	#打印换行
	if i % 10 == 9:
		print()
	i += 1





# 6.一个循环打印十行十列隔行变色小星星

#任意数和n进行地板除,会出现n个相同的数字
"""
★★★★★★★★★★
☆☆☆☆☆☆☆☆☆☆
★★★★★★★★★★
☆☆☆☆☆☆☆☆☆☆
★★★★★★★★★★
☆☆☆☆☆☆☆☆☆☆
★★★★★★★★★★
☆☆☆☆☆☆☆☆☆☆
★★★★★★★★★★
☆☆☆☆☆☆☆☆☆☆
"""
"""
***任意数和n进行地板除,会出现n个相同的数字***
0 // 2  = 0
1 // 2  = 0
2 // 2  = 1
3 // 2  = 1
4 // 2  = 2
5 // 2  = 2


0 // 5 = 0
1 // 5 = 0
2 // 5 = 0
3 // 5 = 0
4 // 5 = 0


5 // 5 = 1
6 // 5 = 1
7 // 5 = 1
8 // 5 = 1
9 // 5 = 1

10 // 5 = 2...
...

0 // 10 = 0
1 // 10 = 0
2 // 10 = 0
3 // 10 = 0
4 // 10 = 0
5 // 10 = 0
6 // 10 = 0
7 // 10 = 0
8 // 10 = 0
9 // 10 = 0


10 // 10 = 1
...
19 // 10 = 1

0 ~ 9    // 10  会出现10个相同的0
10 ~ 19  // 10  会出现10个相同的1
20 ~ 29  // 10  会出现10个相同的2
...
90 ~ 99  // 10  会出现10个相同的9

0 ~ 9 
"""

i = 0
while i<100:

if i //10 % 2 == 0:
	print("★",end="")
else:
	print("☆",end="")

if i % 10 ==9:
	print()

i+=1


	
世纪难题


z=1
while z<=3:
    q=3-z
    user = input("请输入用户名:")
    key = input("请输入密码")
    if user=="123" and  key=="456":
        print("登陆成功")
        break
    elif q==0:
        print("三次登陆失败,退出程序")
    else:
        print("用户名或密码错误,你还有",str(q),"次机会")
    z+=1
'''

双层循环练习

#十行十列小星星

j = 0
while j <10:
#打印星星
i = 0
while i<10:
	print("*",end="")
	i += 1
#打印换行
print()

j+=1





#十行十列隔列换色小星星

j = 0
while j<10:
#打印星星
i = 0
while i<10:
	if i % 2 ==1:
		print("★",end="")
	else:
		print("☆",end="")
	i+=1
#打印换行
print()

j+=1





#十行十列隔行换色小星星
# 外层循环动的慢j,内层循环动的快i

j = 0
while j<10:
#打印星星
i = 0
while i<10:
	if j % 2 ==1:
		print("★",end="")
	else:
		print("☆",end="")
	i+=1
#打印换行
print()
j+=1








#99乘法表
1~9升序  从小到大
9~1降序  从大到小

#方向一
j = 1
while j <= 9:
#打印里面的表达式
i = 1
while i <= j:
	print("%d * %d = %2d" % (i,j,i*j),end="")
	i += 1

print()
j += 1




#方向二

j = 9
while j >= 1:
#打印里面的表达式
i = 1
while i <= j:
	print("%d * %d = %2d" % (i,j,i*j),end="")
	i += 1

print()
j -= 1





#方向三


j = 1
while j <= 9:
#打印空格(一个表达式占了7个空格)
k = 9 - j
while k >= 1:
	#打印每组的空格
	print("           ",end="")
	k -= 1
#打印表达式
i = 1
while i <= j:
	print(" %d * %d = %2d" % (i,j,i*j),end="")
	i += 1
#打印换行
print()
j += 1



#方向四
j = 9
while j >= 1:
# 打印空格
k = 9 - j
while k > 0:
    print("           ", end="")
    k -= 1
# 打印表达式
i = 1
while i <= j:
    print(" %d * %d = %2d" % (i, j, i*j), end="")
    i += 1
print()
j -= 1






#求吉利数字

i = 100
while i <= 999:
ge = i % 10
shi = i // 10 % 10
bai = i // 100

if shi == ge and shi == bai :
	print(i)

elif shi == ge - 1 and shi == bai + 1:
	print(i)

elif shi == ge + 1 and shi == bai - 1:
	print(i)

i+=1


# 方法二 字符串形式

i = 100
while i <=999:
num = str(i)
ge = int(num[-1])
shi = int(num[1])
bai = int(num[0])
#求999...
if ge == shi and ge == bai:
	print(i)
#求321...
elif shi == ge + 1 and shi == bai - 1:
	print(i)
#求123...
elif shi == ge - 1 and shi == bai + 1:
	print(i)
i += 1





#百钱买百鸡

"""公鸡 母鸡 小鸡 
公鸡1块钱1只,母鸡3块钱一只,小鸡5毛钱一只
问: 用100块钱买100只鸡,有多少种买法?
"""
"""
穷举法: 把数据拿出来一个一个的试
x[1,2]
y[3,4]
z[5,6]
满足x+y+z = 10

1 + 3 + 5 = 9
1 + 3 + 6 = 10  bingo!
1 + 4 + 5 = 10  bingo!
1 + 4 + 6 = 11
2 + 3 + 5 = 10  bingo!
2 + 3 + 6 = 11
2 + 4 + 5 = 11
2 + 4 + 6 = 12

x 公鸡 y母鸡 z小鸡
x+y+z = 100
x + y*3 + z*0.5 = 100
"""


x = 0
while x<=100:
	y = 0
	while y<=33:
		z = 0
		while z<=100:
		
			if (x+y+z == 100) and (x + y*3 +z *0.5 == 100):
				print(x,y,z)
		
			z+=1
	
		y+=1

	x+=1

pass break continue

#1. pass 过  (在代码块中无代码可写时,用pass占位)
		if 5 == 5:
			pass

 2. break 终止当前循环,只能应用在循环里



#打印 1~10 ,遇到5终止循环
#单循环
i =1 
while i<=10:
if i == 5:
break
print(i)
i+=1



#多循环(终止当前循环)
i = 1
while i<=3:
j = 1
while j<=3:
	if j ==2:
		break
	print(i,j)
	j+=1
i+=1


3.continue 跳过当前循环,从下一次开始,只能应用在循环里
	打印1~10 不要5
	i = 1
	while i <= 10:
	if i == 5:
		#手动+1,防止跳过下面的代码,产生没有自增的情况,出现死循环
		i += 1
		continue
	print(i)
	i += 1


 打印 1~100所有不含4的数字
i = 1
while i <= 100 :
	if i // 10 == 4 or i % 10 ==4 :
		i += 1
		continue
	print(i)
	i += 1


 #方法二
	 #个位含有4  十位含有4 in not in
i = 1
while i <= 100:
	num = str(i)
	if str(4) in num:
		i += 1
		continue
	print(i)
	i += 1

for … in 循环

遍历,循环,迭代,都是把容器中的数据一个个获取出来


#用while循环遍历数据
lst = [1,2,3,4,5]
#lst = {"a","b","c"}
i = 0
while i < len(lst):
	print(lst[i])
	i += 1



#如果数据是无序的,while不能够遍历数据,for循环应用而生
语法:
for 变量 in 可迭代对象:
	code..
#可迭代的对象(容器类型数据,range对象,迭代器)


#遍历集合
container = {"a","b","c","d","e","f"}#集合无序
#遍历列表
container = ["a","b","c","d","e","f"]
#遍历元组
container = ("a","b","c","d","e","f")
#遍历字符串
container = "asd123"
#遍历字典 (默认遍历的是字典的键)
container = {"a":"1","b":"2","c":"3"}

for i in container:
	print(i)



遍历等长的二级容器
lst = [("a","b","c"),("1","2","3"),("4","g","5")]

for i in lst :
	print(i)#将lst遍历到变量i中打印出来
'''
('a', 'b', 'c')
('1', '2', '3')
('4', 'g', '5')
'''
	for j in i:
		print(j)#将i遍历到变量j中打印出来



#变量的解包
			
a,b = 1,2
a,b = [3,4]
a,b = {"a":111,"b":222}
a,b,c = ("李天兆","作业","还没交")
print(a,b,c)
			


for a,b,c in lst:
	print(a,b,c) #用for循环将等长二级容器中的数据解包遍历出来
'''
a b c
1 2 3
4 g 5
'''





#遍历不等长的二级容器
lst = [("a","b","c"),("1","2"),("GG")]
for i in lst:
	print(i)
	for j in i:
		print(j)





#range 对象(配合for循环使用)

reage(start,end,step)
start:开始值
end:结束值(最大值获取不到,获取到end这个数之前的那个值)
step:步长

res = range(10)
print(res)


#默认从0开始遍历
for i in range(10):
	print(i)

#最大值获取不到
for i in range(1,10):
	print(i)


#step=3 代表一次加3 => 1.4.7
for i in range(1,10,3):
	print(i)



#倒序 10~1
for i in range(10,0,-1):
	print(i)




#总结
while 一般用于复杂的逻辑操作
for  一般用在数据的遍历
多数情况下,while和for可以通用





#while循环写乘法表
j = 1
while j <=9:
	
i = 1
while i <=j:
	print("%d + %d = %2d " % (i,j,i*j) , end="")
	i += 1

print()
j += 1



#for循环写乘法表

for i in range(1,10):
	for j in range(1,i+1):
		print("%d*%d=%2d "  %  (i,j,i*j),end="")
	print()









#while 和 for 写法上的对比

i = 1
while i <= 10:
	if i == 5:
		#手动加1 ,防止跳过下面的代码,产生没有自增的情况,出现死循环
		i += 1
		continue
	print(i)
	i += 1



for i in range(1,11):
	if i == 5:
		continue
	print(i)

字符串的相关操作

#1.字符串的拼接 +
str1 = "李天兆"
str2 = "作业又没写"
res = str1 + str2
print(res)


#2.字符串的重复 *
str1 = "pr"
res = str1 * 5
print(res)



#3.字符串跨行拼接  \
str1 = "asdasdasdasdasdasdasd" \
"123123123123123123"
print(str1)



#4.字符串的索引

strvar = "李天兆"

print(strvar[1])



#5.字符串的切片:(截取)

语法:
	字符串[::]  完整格式: [开始索引:结束索引:间隔值]
	(1)[开始索引:]  从开始索引截取到字符串的最后
	(2)[:结束索引]  从开头截取到结束索引之前(结束索引-1)
	(3)[开始索引:结束索引]  从开始索引截取到结束索引之前(结束索引-1)
	(4)[开始索引:结束索引:间隔值]  从开始索引截取到结束索引之前按照指定的间隔截取字符
	(5)[:]或者[::]截取所有字符串


strvar = "你总得有一条后路"

#(1)[开始索引:]  从开始索引截取到字符串的最后
res = strvar[1:]
print(res)



(2)[:结束索引]  从开头截取到结束索引之前(结束索引-1)
res = strvar[:-2]	或者 [:6]
print(res)


(3)[开始索引:结束索引]  从开始索引截取到结束索引之前(结束索引-1)
res = strvar[1:-2]	或者 [1:6]
print(res)


(4)[开始索引:结束索引:间隔值]  从开始索引截取到结束索引之前按照间隔截取字符
res = strvar[::2]	或者 [::-2]
print(res)

正向截取就使用正数,逆向截取就使用负数


(5)[:]或者[::]  截取所有字符串
res = strvar[:] 	或者[::]
print(res)

字符串的相关函数

#capitalize  字符串首字母大写
str = "zker"
res = str.capitalize()
print(res)


 title  每个单词的首字母大写
res = str.title()
print(res)


#upper  将所有字母变成大写
res = str.upper()
print(res)


 lower  将所有字母变成小写
str = "ZKER ZKER"
res = str.lower()
print(res)


 swapcase  大小写互换
str = "AdC b"
res = str.swapcase()
print(res)


#len  计算字符串的长度
str = "asdasdasdqweqwe123"
res = len(str)
print(res)


 count  统计字符串中某个元素的数量
str = "assssssd"
res = str.count("s")
print(res)


#find  查找某个字符串第一次出现的索引位置
	#find(字符start,end) end的最大值取不到,取到它之前的那个数
strvar = "asdasdasd Aasdasdasd"
res = strvar.find("A")
res = strvar.find("Aas")
res = strvar.find("sd",7)
res = strvar.find(" A",9,-9)
print(res)
	# index 与 find 功能相同 find找不到返回-1,index找不到数据直接报错
	res = strvar.index("A") # 找不到就会报错






#startswith  判断是否以某个字符或字符串为开头
	#startswith(字符,start,end)
strvar = "who is your daddy?"
res = strvar.startswith("who")
res = strvar.startswith("is",4)
print(res)


#endswith 判断是否以某个字符或字符串结尾
res = strvar.endswith("daddy?")
res = strvar.endswith("daddy",-6,-1)
print(res)

is 系列函数

strvar = "ADC"
isupper 判断字符串是否都是大写字母
res = strvar.isupper()
print(res)

islower 判断字符串是否都是小写字母
res = strvar.islower()
print(res)


isdecimal 检测字符串是否以数字组成  必须是纯数字
strvar = "123123123"
res = strvar.isdecimal()
print(res)

split join strip replace 重点记忆

split  按某字符将字符串分割成列表(默认字符是空格)
strvar = "who is your daddy ?"
lst = strvar.split()
print(lst)

strvar = "who-is-your-daddy-?"
lst = strvar.split("-")
print(lst)

#可以选择分割几次(从左到右)
lst = strvar.split("-",1)	#['who', 'is-your-daddy-?']
print(lst)


#选择从右向左分割  rsplit
lst = strvar.rsplit("-",2)	#['who-is-your', 'daddy', '?']
print(lst)



**** join  按某字符将列表拼接成字符串(容器类型都可以)
lst = ["Z","k","e","r"]
strvar = "".join(lst)	#可以不用字符但至少要有引号,没有就直接拼接
print(strvar)



center  填充字符串,原字符居中(默认填充空格)
	#默认填充空格的长度 + 原字符串的长度 = 10
	strvar = "Zker"
	res = strvar.center(10)		#   Zker   
	print(res)

#指定字符填充
res = strvar.center(10,"^")	#^^^Zker^^^
print(res)



#strip  默认去掉首尾两边的空白符
strvar = "   Zker   "
res = strvar.strip()
print(res)


strvar = "$$$Zker$$$"
res = strvar.strip("$")
print(res)




#replace()  把字符串的旧字符换成新字符
strvar = "Zker zker zker"
res = strvar.replace("zker","z")	#Zker z z
print(res)


#可以选择替换的次数
res = strvar.replace("zker","z",1)	#Zker z zker
print(res)



替换掉所有的空格
strvar = "a b c e f g "
res = strvar.replace(" ","")	#abcefg
print(res)

format 格式化字符串

(1)顺序传参
(2)索引传参
(3)关键字传参
(4)容器类型数据(列表或者元组)传参

{} 代表占位符

(1)顺序传参
strvar = "{}和{}说早安"
res = strvar.format("我","你")
print(res)


(2)索引传参
strvar = "{1}和{0}说早安"
res = strvar.format("你","我")
print(res)


(3)关键字传参
strvar = "{a}又成为了{b}"
res = strvar.format(a="李天兆",b="阴间人")
print(res)



(4)容器类型数据(列表或元组)传参
strvar = "{0[0]}又当了{0[1]}的{1[0]}"
res = strvar.format(["今天","一天"],("阴间人",))
print(res)


	#方法二
	strvar = "{a[0]}又当了{a[1]}的{b[0]}"
	res = strvar.format(a=["今天","一天"],b=("阴间人",))
	print(res)



#方法三 (字典  '''在format当中,不要加上引号''')
strvar = "{a[jt]}又当了{a[yt]}的{b[yjr]}"
res = strvar.format(a={"jt":"今天","yt":"一天"},b={"yjr":"阴间人"})
print(res)



### format的填充符号的使用( ^ > < )
'''
^ 原字符串居中
> 原字符串居右
< 原字符串居左

{who:!<10}
who : 关键字
!   : 要填充的字符
<   : 填充的方向,原字符串居左
10  : 字符串的总长度10
总长度 = 原字符串长度 + 填充字符的长度
'''

strvar = "等{kd:#^4}的还{w:&<3}{zy:~>6}"
res = strvar.format(kd="看懂",w="我",zy="自由")
print(res)

(6)进制转换等特殊符号的使用(:d , :f , ,

:d  整型占位符  (要求必须是整型)
strvar = "今天是{:d}月{:d}日"
res = strvar.format(5,10)
print(res)


# :2d  占用2位,原字符串居右
strvar = "今天是学习python的第{:2d}天"
res = strvar.format(8)
print(res)


strvar = "今天是学习python的第{:^3d}天"
res = strvar.format(8)
print(res)


strvar = "今天是学习python的第{:<2d}天"
res = strvar.format(8)
print(res)



:f  浮点型占位符  (要求必须是浮点型)
strvar = "有一个小数是{:f}"
res = strvar.format(3.14)
print(res)


# :.2f 保留二位小数,存在四舍五入的情况
strvar = "有一个小数是{:.2f}"
res = strvar.format(3.14)
print(res)



:s  字符串占位符 (要求必须是字符串)
strvar = "{:s}"
res = strvar.format("你才不是一个没有故事的女同学")
print(res)




:,  金钱占位符
strvar = "{:,}"
res = strvar.format(123456789)
print(res)



综合案例
strvar = "有一个整型{:^3d},有一个浮点型{:.1f},有一个字符串{:s},有一个金钱数{:,}"
res = strvar.format(6,3.14,"呵呵",999999999)
print(res)

列表相关操作

一. 列表的拼接   (同元组)  +
lst1 = [1,2,3]
lst2 = [4,5,6]
lst = lst1 + lst2
print(lst)




二. 列表的重复   (同元组)  *
lst1 = [1,2,3]
lst = lst1 * 3
print(lst)


三. 列表的切片   (同元组)  
'''
语法 => 列表[::]  完整格式: [开始索引:结束索引:间隔值]
	1. [开始索引:]  从开始索引截取到列表的最后
	2. [:结束索引]  从开头截取到结束索引之前(结束索引-1)
	3. [开始索引:结束索引]  从开始索引截取到结束索引之前(结束索引-1)
	4. [开始索引:结束索引:间隔值]  从开始索引截取到结束索引之前按照指定的间隔截取列表元素值
	5. [:]或[::]  截取所有列表
'''

lst = ["a","b","c","d","e","f","g"]


# [开始索引:]  从开始索引截取到列表最后
res = lst[1:]
print(res)



# [:结束索引]  从开头截取到结束索引之前(结束索引-1)
res = lst[:-3]
print(res)




# [开始索引:结束索引]  从开始索引截取到结束索引之前(结束索引-1)
res = lst[1:-2]
print(res)



# [开始索引:结束索引:间隔值]  从开始索引截取到结束索引之前按照指定的间隔截取列表元素值
res = lst[0:-1:2]
print(res)


	#正向截取
	res = lst[::5]
	print(res)

	#逆向截取
	res = lst[::-2]
	print(res)



# [:]或[::]  截取所有列表
res = lst[:]
res = lst[::]
print(res)




四.列表的获取   (同元组)  ***
lst = [1,2,3,"a","s","d"]
print(lst[0])




五.列表的修改   (可切片)  ***
lst[0] = "111"
print(lst)


#赋值时,修改的数据要求是: > 可迭代性的数据 < iterable 

#利用切片进行修改(切一段,放进去所有值)
lst = ['z','t','r','e','w','q','d','s','a']
lst[2:3] = ["rrrrrrrrr"]
print(lst)

#带有步长的切片修改(切几个改几个)
lst[::2] = [1,1,1,1,1]
print(lst)



#六.列表的删除   (可切片)
lst = ['1','2','3','4','5','6']


#删除单个
del lst[1]
print(lst)



#删掉一段(通过切片)
del lst[1:-2]
print(lst)



#注意点: res是变量 del 删除的是res 不是列表
lst = ['1','2','3','4','5','6','7']
res = lst[2:4]
del res
print(lst)	#删除的只是那个变量,列表并没有变化

"""
地址:
	["猪八戒","唐僧","孙悟空","沙僧","白龙马"] => 0x101
	["唐僧","孙悟空","沙僧"] => 0x100
"""

列表的相关函数

#增
1. append  向列表的末尾添加新的元素

	lst = ["a","s","d"]
	lst.append("abs")
	print(lst)


2. insert  在指定索引之前插入元素

	lst = ['1','2','3']
	lst.insert(0,"0")
	print(lst)


3. extend 迭代追加所有元素

	lst = ['1','2','3']
	tup = ('a','s','d')
	lst.extend(tup)
	print(lst)



#删

lst = ['a','b','c','d']

1.pop 通过指定索引删除元素,若没有索引则移除最后一个  (推荐)

#默认删除最后一个
res = lst.pop()
print(res)
print(lst)


#可以指定下标删除
res = lst.pop(1)
print(res)
print(lst)



2.remove 通过给予的值来删除,如果多个相同元素,默认删除第一个

lst = ['a','b','c','d']
res = lst.remove('b')
print(res)	#会返回none
print(lst)


3.clear 清空列表

lst = ['a','b','c','d']
lst.clear()
print(lst)




#改查 : 可参考列表的操作  这个文件

1.index  获取某个值在列表中的索引

lst = ['a','b','c','d']
res = lst.index('a')	#当这个值不存在时,会报错
print(res)



2.count  计算某个元素出现的次数

lst = ['a','b','c','d','a','a','a']
res = lst.count('a')
print(res)


3.sort 列表排序(默认从小到大排序)

lst = [3,5,1,23,5,6,8]
lst.sort()
print(lst)

#从大到小排序
lst.sort(reverse = True)
print(lst)


#对字母进行排序 (字母排序依照ascii编码)
字母是一位一位的进行比较,如果第一位相同,再去比较第二位,以此类推
lst = ["kobe","james","oneal","jordon","iverson"]
lst.sort()
print(lst)


# 是否可以对中文进行排序,但是无规律可循
lst = ["王闻","周杰伦","罗志祥","蔡徐坤","王振"]
lst.sort()
print(lst)


4.reverse 列表反转操作

(嗯转)
lst = [2,5,11,1,5,6,5,4]
lst.reverse()
print(lst)





tuple 元组的函数只有两个, count  index  跟列表的方法使用一摸一样

tup = (1,2,3,4,[5,6,7])
tup[-1].append(8)	# 用append是因为操作的是里面的列表
print(tup)

tup = (1,2,3,[4,5,6,(7,8,9)])
tup[-1][-1] = 100
print(tup)

深拷贝 和 浅拷贝

a = 19
b = a
print(id(b),id(a)) # 这个时候id一样
a = 20 
print(b) #不一样



lst1 = [1,2,3]
lst2 = lst1
lst1.append(4)
print(lst2)  # 两个列表相同



浅拷贝 (只拷贝一级的所有元素,其他层级延续以前的数据)

#方法一
lst = [1,2,3]
lst2 = lst.copy()
lst.append(4)
print(lst)	#[1, 2, 3, 4]
print(lst2)	#[1, 2, 3]


lst2[0] = 2
print(id(lst[0]))
print(if(lst2[0]))


#方法二 (推荐)
import copy
lst = [1,2,3]
	#copy.copy()   copy模块.copy函数()
lst2 = copy.copy(lst)
lst.append(4)
print(lst)	#[1, 2, 3, 4]
print(lst2)	#[1, 2, 3]



深拷贝 (所有层级的元素都单独拷贝一份,形成独立的副本)
import copy
import copy
import copy
import copy
import copy
import copy
import copy
import copy
#如果要用拷贝,就提前把这个函数打上

语法: copy.deepcopy()


import copy
lst = [1,2,3,[4,5,6]]
lst2 = copy.deepcopy(lst)
lst[-1].append(7)
print(lst)	#[1, 2, 3, [4, 5, 6, 7]]
print(lst2)	#[1, 2, 3, [4, 5, 6]]

print(id(lst[-1])  ,  id(lst2[-1]))


# 深拷贝可以应用在字典中

dic = {"a":1,"b":[1,2,3]}
dic2 = copy.deepcopy(dic)
dic[b].append(4)
print(dic)	#{'a': 1, 'b': [1, 2, 3, 4]}
print(dic2)	#{'a': 1, 'b': [1, 2, 3]}



#copy 和 deepcopy 浅拷贝要更快


浅拷贝: 只拷贝第一层级所有的元素,copy.copy()
深拷贝: 拷贝所有层级的元素,都单独开启新的空间  copy.deepcopy()
(地址: [不可变数据]会暂时指向原数据,[可变数据会独立开辟新空间])

可变数据:   list  set  dict
不可变数据:  int  float  complex  bool  tuple  str

字典的相关函数

#增

推荐使用:
	dic = {}
	dic['a'] = "1"
	dic['b'] = "2"
	dic['c'] = "3"
	print(dic)


#fromkeys()  使用一组键和默认值创建字典
lst = ["a","b","c"]
dic = {}.fromkeys(lst,None)
print(dic)


注意点
dic2 = {}.fromkeys(lst,[1,2])
dic2["a"].append(3)
print(dic2)


改进方式
dic3 = {}
dic3["a"] = []
dic3["b"] = []
dic3["a"].append(1)
print(dic3)



#删
dic = {"a":"1","b":"2","c":"3","d":"4"}


#pop()  通过键去删除键值对  (若没有该键可设置默认值,预防报错)
res = dic.pop("a")
print(res)
print(dic)

#可以在pop当中设置默认值,预防报错
res = dic.pop("z","不存在哦")
print(res)


#  popitem()   删除最后一个键值对
res = dic.popitem()
print(res)
print(dic)


#  clear()   清空字典
dic.clear()
print(dic)

区分 默认形参 和关键字实参

函数的定义处 (默认形参在函数的定义处)
def z_ker(one="aaa",two="bbb"):
	print("a:{z}".format(z=one))
	print("b:{z}".format(z=two))
z_ker()
	# a:aaa
	# b:bbb


函数的调用处 (关键字实参在函数的调用处)

z_ker(one="aaaaa",two="bbbbb")
	#a:aaaaa
	#b:bbbbb

收集参数

收集参数:

# 1. 普通收集参数 :
	在参数的前面加上一个*,代表的是普通收集参数
	作用 : 收集多余的没人要的普通实参,构成一个元组
	def Zker(*args):
		pass
	#args => arguments(参数)


def Zker(a,b,c,*args):
	print(a,b,c)
	print(args)
	
Zker(1,2,3,4,4,4,4)




计算任意个数的累加和
def Zker(*args):
	j = 0 
	for i in args:
		j += i
	print(j)
Zker(11,22,33,44)





# 2. 关键字收集参数
	在参数的前面加上两个**,代表的是关键字收集参数
	作用 : 收集多余的没人要的关键字实参,构成一个字典
	
	def Zker(**kwargs):
		pass
		
	kwargs = keyword arguments

def Zker(a, b, c, **kwargs):
	print(a, b, c)
	print(kwargs)

Zker(11, 22, 33, z=1, x=2, v=3)
#Zker(a=1, b=2, c=3, q=1, w=2, e=3)





任意字符串的拼接

'''
	# 班长:张恒
	# 班花:刘思敏
	# 吃瓜群众:黄俊,王振...
'''


def func(**kwargs):
	strvar = ""
	strvar2 = ""
	dic = {"monitor":"班长","class_flower":"班花"}
	# {'monitor': '张恒', 'class_flower': '刘思敏', 'hj': '黄俊', 'wz': '王振'}
	print(kwargs)
	for k,v in kwargs.items():
		# print(k,v)
		# 判断键在字典中,在进行获取
		if k in dic:
			strvar += dic[k] + ":" + v	+ "\n"		
		# 如果不在,那就是吃瓜群众
		else:
			strvar2 += v + " , "
	print(strvar.strip())
	print("吃瓜群众:" + strvar2.strip(" , ") + "......")
func(monitor="张恒",class_flower="刘思敏",hj="黄俊",wz="王振")

命名关键字参数

def func(参数1,参数2,*,参数3)
	#1 跟在*号后面定义的参数就是命名关键字参数
def func(*args,参数,**kwargs)
	#2 在普通收集参数和关键字收集参数之间的就是命名关键字参数

如果是命名关键字参数,必须使用关键字实参的形式调用;


#1. 定义方式一
def func(a,b,*,c):
	print(a,b)
	print(c)

#这是函数的调用处
func(11,22,c=33)



#2. 定义方式二
def func(*args,a,**kwargs):
	print(args)
	print(a)
	print(kwargs)
func(1,2,3,a=111,b=222,c=333)




关于* 和 ** 的使用方法

在函数的定义处, * 和** 用来接收数据,*打包成一个元组, ** 打包成一个字典
在函数的调用处, * 和** 用来解包数据,*一半应用在列表或元组,**一般用在字典里



* 一个星星调用处的语法

def func(a,b,*,c,d):
	print(a,b)
	print(c,d)
	#下面是函数的调用处
lst = [1,2]
*lst => 把列表里面的每一个元素都单独拿出来,当成参数赋值给func进行调用
func(*lst,c=3,d=4)




**两个星星调用处的语法

	# func(1,2,c=3,d=4)
**dic => 把字典里面的键值对拿出来,转化成关键字实参的形式,当成参数赋值给func进行调用

dic = {"c":3,"d":4}
func(1,2,**dic)





综合

定义处的*号用法 和 调用处的* 号用法 是一对相反操作
一个是用来打包
一个是用来解包
优点: 控制了参数的个数

	# func(*lst,**dic)

参数的顺序

形参顺序

普通形参 > 默认形参 > 普通收集形参 > 命名关键字参数 > 关键字收集参数

	# 收集所有实参
	def func(*args,**kwargs):
		pass



参数练习
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

#以上两个函数 打印结果
#(一)
#f1(1, 2) # a =1 b=2 c=0 args=() kw={}
#f1(1, 2, c=3) # a=1 b=2 c=3 args=() kw={}
#f1(1, 2, 3, 'a', 'b') # a=1 b=2 c=3 args=(a,b) kw={}
#f1(1, 2, 3, 'a', 'b', x=99) # a=1 b=2,c=3 args=(a,b) kw={x:99}
#f2(1, 2, d=99, ext=None) # a=1,b=2,c=0 ,d=99,{ext:None}


#(二)
#args = (1, 2, 3, 4)
#kw = {'d': 99, 'x': '#'}
#f1(*args, **kw) # a=1,b=2,c=3,args=(4,) kw={d:99,x:#}

#(三)
#myargs = (1, 2, 3)
#mykw = {'d': 88, 'x': '#'}
#f2(1,2,3,d=88,x=#)
#f2(*myargs, **mykw) # a = 1,b=2,c=3,d=88 kw={x:#}

#(四)
def f1(a, b, c=0, *args,d,**kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
    print(d)

f1(1,2,3, 'a', 'b',d=67, x=99,y=77)
a =1,b=2,c=3 args=(a,b) kw={x:99,y:77} d=67

return 自定义返回值

函数可以自定义返回值,通过return,  return会把这个值返回到函数的调用处
 1 , return + 返回值 , 后面除了可以接六大标准数据类型之外,还可以返回函数和类对象
	如果没有定义任何返回值,将会默认返回None



 2 , 在函数中,如果执行了return , 意味着立刻终止函数 , 后面的代码统统不执行




1, return + 可以返回的类型

def func():
	return 100
	# return 3.13
	# return "23333"
	# return [1,2,3]
	# return {"a":1,"b":2}
	# 没有定义任何的返回值,将默认返回None
	# pass
res = func() # res =100
print(res)



2, 遇到return之后, 意味着立刻终止函数,后面的代码不执行

def func():
print("1")
print("2")
print("3")
return "4"
print("5")
res = func()
print(res) #  1  2  3  4  


# 注意点: 遇到return 会立刻终止函数
def func():
	for i in range(1,10):
		if i == 3 :
			return 333
		print(i)
res = func()
print(res)		# 1  2  333




#模拟一个计算器 +  -  *  /

def Zker(sign,num1,num2):
	if sign == "+":
		res = num1 + num2
	elif sign == "-":
		res = num1 - num2
	elif sign == "*":
		res = num1 * num2
	elif sign == "/":
		if num2 == 0 :
			return "学学小学数学吧"
		res = num1 / num2
	else:
		return "给爷爬"
		
	return res
res = Zker("-",121,22)
print(res)

全局变量和局部变量

局部变量 : 在函数内部定义的变量就是局部变量 (局部命名空间)
全局变量 : 在函数外面定义的变量 或者 在函数内部使用global关键字定义的是全局变量 (全局命名空间)


作用域 : 作用的范围
	局部变量的作用的范围仅仅限定在函数的内部
	全局变量的作用的范围是整个文件


生命周期: 
	内置命名空间 > 全局命名空间 > 局部命名空间
	内置变量 > 全局变量 > 局部变量



1 , 局部变量

def func():
	#定义一个局部变量
	a = 1
	#获取局部变量
	print(a)
	#修改局部变量
	a= 20
	print(a)
func()
print(a)   会报错,因为无法获取局部变量的值



2 , 全局变量

定义全局变量
a = 10
获取全局变量
print(a)
修改全局变量
a = 20
print(a)





3 , 在函数内部定义全局变量  global
def func():
	global a	#标记这个变量是一个全局变量
	a = 1 
	print(a)
func()
print(a)




4 , 在函数内部可以修改全局变量
a = 133
def func():
	global a
	a = 122
	print(a)
func()
print(a)



global  总结:
	如果函数外部有这个全局变量, 在函数内部使用global关键字,可以修改全局变量
	如果函数外部没有这个全局变量, 在函数内部使用global关键字,可以定义一个全局变量


在函数内部可以直接获取全局变量
但是无法直接修改全局变量,需要通过global

函数名的使用

# python中的函数可以像变量一样, 动态创建, 销毁, 当参数传递,作为返回值 , 叫做第一类对象,其他语言不能比拟,功能有限



# 1 函数名是个特殊的变量, 可以当作变量赋值


def func1():
	print("func1~")
	return 111
res = func1()
print(res)




动态创建函数
print(func1)
func = func1
func()


动态销毁函数

del func
func()




2 函数名可以作为容器类型数据的元素

def func2():
	print("func2~")
def func3():
	print("func3~")
def func4():
	print("func4~")
	return "func4"
lst = [func2,func3,func4]
for i in lst:
	i()



3 函数名可以作为函数的参数

def myfunc(f):
	res = f()
	print(res)

# f = func4    res = func4()   print(res)
myfunc(func4)




4 函数名可作为函数的返回值

def myfunc2(f):
	return f
	
f2 = myfunc2(func4) # f2 = func4
print(f2)
f2()





__doc__ 或者 help 查看文档

def hollw_night(xz,yz,sy,kdqs):
	'''
	功能:说话
	参数:自白
	返回值:说完了吗
	'''
	print("没有可以思考的{}".format(xz))
	print("没有可以屈从的{}".format(yz))
	print("没有为苦难哭泣的{}".format(sy))
	print("生于神与虚空之手")
	print("你必封印在众人梦中散步瘟疫的障目之光")
	print("你是容器")
	print("你是{}".format(kdqs))
	return "完"

res = hollw_night("心智","意志","声音","空洞骑士")
print(res)
	#函数 .__doc__  =>  可以获取函数的帮助文档
print(hollw_night.__doc__)

locals 和 globals (了解)

locals  获取当前作用域中的所有内容

locals  如果在函数外,调用locals(), 获取的是打印之前的所有变量,返回字典,全局空间作用域
locals  如果在函数内,调用locals(), 获取的是调用之前的所有变量,返回字典,局部空间作用域


例子1

a = 1
b = 2 
res = locals()
c = 3
print(res)
d = 4	#这个不在打印之前,所以获取不到


例子2

a = 1
def func():
	b = 2	#仅获取到了 b = 2,因为只有它是调用之前的局部变量
	res = locals() 
	c = 3
	print(res)
	d = 4
func()





globals  获取全局作用域的所有内容

globals  如果在函数外,调用globals(),获取的是打印之前的所有变量,返回字典,全局空间作用域
globals  如果在函数内,调用globals(),获取的是调用之前的所有变量,返回字典,全局空间作用域



例子3

a = 1
b = 2
res = globals()
c = 3
print(res)
d = 4	#只能获取打印之前的所有变量



例子4

a = 10
def func():
b = 11
c = 12
res = globals()
d = 13
print(res)
e = 14

f = 16
func()
g = 17

globals 返回的是系统的字典

1. 正常方式定义变量
aaa = "123"


2. 通过系统的全局字典添加键值对,可以动态创建全局变量
dic = globals()
print(dic)
	#传递字符串,创建一个变量
k = "hollw_night"
dic[k] = "kdqs"
print(hollw_night)



3. 批量创建全局变量,在函数中
def func():
	dic = globals()
	for i in range(1, 6):
		dic["z%d" % (i)] = i

func()
print(z1)
print(z2)
print(z3)
print(z4)
print(z5)

函数的嵌套

嵌套在函数外边的叫外函数
嵌套在函数里面的叫内函数



def outer():

def inner():
	print("111")

inner()
outer()


内部函数不可以直接在函数外部调用
调用外部函数后,内部函数依旧不可以在函数外部调用
内部函数可以在函数内部调用
内部函数在函数内部调用时,必须先定义再进行调用


最外层是outer, 中间是inner, 最里面是smaller, 调用smaller,执行里面的代码

def outer():
	def inner():
		def smaller():
			print(id)
			print("233333")
		smaller()
	inner()
outer()

LEGB 原则,(就近找变量的原则)

# 找寻变量的调用顺序采用LEGB原则(就近原则)

B —— Builtin(Python);Python内置模块的命名空间      (内建作用域)
G —— Global(module); 函数外部所在的命名空间        (全局作用域)
E —— Enclosing function locals;外部嵌套函数的作用域(嵌套作用域)
L —— Local(function);当前函数内的作用域            (局部作用域)
依据就近原则,从下往上 从里向外 依次寻找

nonlocal 关键字 用来修改[局部变量]

nonlocal  遵循LEGB
nonlocal 专门用来修改当前作用域上一级的局部变量
如果上一级找不到,那么继续向上寻找
全都找不到,直接报错


#1. nonlocal 专门用来修改当前作用域上一级的局部变量
def outer():
	a = 10
	def inner():
		nonlocal a
		a = 20

inner()
print(a)
outer()




2. 如果上一级找不到,那么继续向上寻找
	nonlocal 只能修改局部变量

	def outer():
	a = 10
	def inner():
	
	def smaller():
		nonlocal a 
		a = 20
		print(a)
	smaller()
	print(a)
	inner()
	print(a)
	outer()
	print(a)



#3. 全都找不到,直接报错

a = 10
def outer():

def inner():
	
	def smaller():
		nonlocal a 	#只能修改局部变量
		a = 20
		print(a)
	smaller()
	print(a)
inner()
print(a)
outer()
print(a)



#4. 不使用nonlocal  是否可以修改局部变量

def outer():
	lst = [1,2,3]
	def inner():
		lst[-1] = 4
	inner()
	print(lst)
outer()

闭包函数

内函数使用了外函数的局部变量
外函数将内函数返回出来的过程,叫做闭包
里面的内函数叫做闭包函数

1, 闭包函数用法

def outer():
	name = "ltz"
	def inner():
		print("我的名字叫{}".format(name))
	return inner

res = outer()
print(res)
res()



2, 升级
def cmaz():
	yan = "买烟"
	cai = "买菜"
	xue = "学费"
	money = 20100

def jintian():
	nonlocal money
	money -= 50
	print("今天买菜花了50,还剩下%d" % (money))
	
def mingtian():
	nonlocal money
	money -= 50
	print("明天买菜花了50,还剩下%d" % (money))

def houtian():
	return[jintian,mingtian]

return houtian
res = cmaz()
print(res)	# 获取houtian
lst = res()
print(lst)	#获取今天明天


#获取jintian的函数
jin = lst[0]
#获取houtian的函数
ming = lst[1]
jin()
ming()

获取闭包函数使用的变量 closure , cell_contents

tup = res.__closure__
print(tup)

#cell_contenta  功能:获取单元格对象里面的内容
jin = tup[0].cell_contents
ming = tup[1].cell_contents
print(jin)
jin()
ming()

闭包的特点

内函数使用了外函数的局部变量,该局部变量与内函数发生绑定,延长该变量的生命周期


#函数的定义处
def outer(val):
	def inner(num):
		return num + val
	return inner

函数的调用处

func = outer(5)
res = func(4)
print(res) 

"""
代码解析:
1.实参5  和 形参val 一一对应,进行接收 val = 5
因为内函数inner 和 val 进行绑定, 延长了val变量的生命周期,不释放

func = outer(5)  < == >  func = inner

2.实参4  和 形参num 一一对应,进行接收 num = 4
return num + val  < == > 4 + 5 = 9 
res = func(4)  <==> return 9
res = 9
"""

闭包的意义

闭包可以优先使用外函数的局部变量
局部变量在函数外部不能被直接使用
对局部变量实现了保护的作用,外部无法访问



#模拟鼠标点击操作

#方法一
click_num = 0
def click_func():
	global click_num
	click_num += 1
	print(click_num)

click_func()
click_func()
click_func()
click_num = 10
click_func()



#方法二
def outer():
	click_num = 0
	def inner():
		nonlocal click_num
		click_num += 1
		print(click_num)
	
return inner

#click_func = inner
#click_func = outer()
#click_func()
#click_func()
#click_func()
#click_num = 100
#click_func()

outer()()
outer()()
outer()()

匿名函数 (lambda 表达式)

用一句话来表达只有返回值的函数, 特点: 简洁  高效  方便

语法结构:
	lambda 参数 : 返回值


#1. 无参的lambda 表达式
def func():
	return ("aaa")

#改写lambda
func = lambda : "aaa"
res = func()
print(res)



#2. 有参的lambda 表达式
def func(n):
	return type(n)
	
#改写lambda
func = lambda n : type(n)
res = func("asd")
print(res)



#3. 带有判断条件的lambda 表达式
def func(n):
	if n % 2 == 0:
		return "偶数"
	else:
		return "奇数"

三目运算符

真值 if 条件表达式 else 假值
如果条件表达式成立,为真,返回真值
如果条件表达式不成立,为假,返回假值

n = 20
res =  "偶数"  if n % 2 == 0  else "奇数"
print(res)



改写lambda
func = lambda n : "偶数"  if n % 2 == 0 else "奇数" 
res = func(11)
print(res)



练习: 比较两个数当中最大值进行返回
def func(x,y):
	if x > y:
		print(x)
	else:
		print(y)
func(1,2)



func = lambda x,y : x  if x > y else y
res = func(3,4)
print(res)

迭代器 : 能被next调用 , 并不断返回下一个值的对象,叫做迭代器(迭代器是对象)

概念 : 迭代器指的是迭代取值的工具, 迭代是一个重复的过程,每次重复都是基于上一次的结果而继续,单纯的重复, 不是迭代

特征 : 不依赖索引,通过next指针迭代所有数据 , 一次只取一个, 可以大大节省空间 , 迭代无限量的数据


#1. 可迭代对象

如果成员中含有__iter__这个方法,就是可迭代对象
dir函数可以查看一个对象中的所有成员

setvar = {"a",1,2,3}
for i in stevar:
	print(i)
	
res = dir(setvar)	#查看setvar的成员
print(res)


#2. 迭代器

for循环遍历数据的底层实现就是用了迭代器,通过next方法进行调用,从而获取数据

可迭代对象 和 迭代器之间的关系 : 从不可被直接获取 => 可被直接获取的过程


如果是一个可迭代对象,不一定是迭代器
如果是一个迭代器,那一定是可迭代对象



#如何定义一个迭代器

iter(可迭代对象)
可迭代对象.__iter__()

setvar = {"a",1,2,3}
it =iter(setvar)
print(it)	#iterator



#如何判断一个迭代器

如果内置成员中含有__iter__和__next__两个方法,就可以判断是一个迭代器


print(dir(it))
res = "__iter__" in dir(it) and "__next__" in dir(it)
print(res)



#如何调用一个迭代器

next(迭代器)
迭代器.__next__()
迭代器通过next方法调用时,是单项不可逆的过程

res = next(it)
print(res)
res = next(it)
print(res)
res = next(it)
print(res)
res = next(it)
print(res)

#StopIteration是报错,为停止迭代



#重置迭代器
	next调用,单项不可逆,一条路走到黑

it = iter(setvar)	#重新定义可以重置
res = next(it)
print(res)


#使用iterator 和 iterable  来判断是否是迭代器

需要引入一个包,格式是 # from 从哪里... import 引入...
iterator  迭代器类型   iterable  可迭代对象

from collections import iterator,iterable

#判断setvar的迭代属性
setvar = {"a","b","c"}
res = isinstance(setvar,iterator)
print(res)	#False 它不是一个迭代器类型

res = isinstance(setvar,Iterable)
print(res)	#True  它是一个可迭代对象



#判断range的迭代属性
it = iter(range(5))
res = isinstance(it,Iterator)
print(res)	#True

res = isinstance(it,Iterable)
print(res)	#True




#更多的调用方式

#通过next获取迭代器中的数据
it = iter(range(10))
res = next(it)
res = next(it)
res = next(it)
res = next(it)
res = next(it)
res = next(it)

print(res)



#通过for循环,遍历迭代器
it = iter(range(10))
for i in it:
	print(i)




#for 和 next 配合调用迭代器
it = iter(range(100))
for i in range(10):
	res = next(it)
	print(res)	#遍历前0 - 9
for i in range(10):
	res = next(it)
	print(res)	#遍历10 - 19

高阶函数 : 能够把函数当成参数传递的就是高阶函数

map  filter  reduce  sorted

map

map(func,iterable)
功能 : 把iterable里面的数据一个个拿出来,放到func函数中进行处理,把处理的结果扔到迭代器中,返回迭代器
参数 : func 自定义函数 或者 内置函数
		interable 可迭代对象(容器类型数据,range,迭代器)
返回值: 迭代器


1.  ["1","2","3","4"] => [1,2,3,4]
	#常规
	lst = ["1","2","3","4"]
	lst1 = []
	for i in lst:
		lst1.append(int(i))
	print(lst1)
	
	# map 改写
	from collections import Iterator , Iterable
	it = map(int,lst)
	res = isinstance(it,iterator)
	print(res)
	print(list(it))
	
	
	#next 获取迭代器中的元素
	res = nexe(it)
	print(res)
	res = nexe(it)
	print(res)
	res = nexe(it)
	print(res)


	#for 获取迭代器中的元素
	it = map(int,lst)
	for i in it:
		print(i)
	
	
	
	
	#for + next 获取迭代器中的元素
	it = map(int,lst)
	for i in range(3):
		print(next(it))
	
	
	
	#list 强转成迭代器,返回一个列表
	it = map(int,lst)
	lst = list(it)
	print(lst)

	'''
	代码解析:
	首先拿出列表当中的"1",扔到int函数当中处理,处理的结果扔到迭代器当中
	首先拿出列表当中的"2",扔到int函数当中处理,处理的结果扔到迭代器当中
	首先拿出列表当中的"3",扔到int函数当中处理,处理的结果扔到迭代器当中
	首先拿出列表当中的"4",扔到int函数当中处理,处理的结果扔到迭代器当中
	最后把迭代器返回
	'''



2.[1,2,3,4] => [1,4,9,16]

	# 常规
	lst =[1,2,3,4]
	lst1=[]
	for i in lst:
		res = i **2 
		lst1.append(res)
	print(lst1)


	#map 方法一:
	def func(n):
		return n**2
	it = map(func,lst)


	#map 方法二:
	it = map(lambda n : n**2,lst)


	#强制转成列表,瞬间拿到所有数据
	ptint(list(it))



	3. dic = {97:"a",98:"b",99:"c"} 给你["a","b","c"] => 返回 [97,98,99]

	lst = ["a","b","c"]
	dic = {97:"a",98:"b",99:"c"}
	#将字典的键值对进行翻转
	dic1 = {}
	for k,v in dic.items():	#items将键值对分开
		print(k,v)
		dic1[v] = k
	print(dic1)
	#去获取键对应的值
	lst1 = []
	for i in lst:
		res = dic1[i]
		lst1.append(res)
	print(lst1)



	#map改写 
		#方法一
	lst = ["a", "b", "c"]
	dic = {97: "a", 98: "b", 99: "c"}
	def func(n):
		dic1 = {}
		for k, v in dic.items():
			dic1[v] = k
		return dic1[n]
	it = map(func, lst)
	print(list(it))


	#方法二
	lst = ["a", "b", "c"]
	dic = {97: "a", 98: "b", 99: "c"}
	def func(n):
		for k,v in dic.items():
			if n = v:
				return k
	it = map(func,lst)
	print(list(it))

filter

filter(func,iterable)
功能 : 
	在自定义的函数中,过滤数据
	如果返回True  代表保留数据
	如果返回False  代表舍弃该数据
参数 :
	func 自定义函数
	iterable 可迭代性数据(容器类型数据, range对象 , 迭代器)
返回值 :
	迭代器


from collections import iterable,iterator


#1.[1,2,3,4,5,6,7,8] => 要所有的奇数

#常规:
lst = [1,2,3,4,5,6,7,8]
lst1 = []
for i in lst:
	if i % 2 == 1:
		lst1.append(i)
print(lst1)


#filter改写
lst = [1,2,3,4,5,6,7,8]
def func(n):
	if n % 2 == 1:
		return True
	else:
		return False
it = filter(func,lst)
res = isinstance(lst,iterator)
print(res)


	#for
	it = filter(func,lst)
	for i in it:
		print(i)
	#for + next 
	it = filter(func,lst)
	for i in range(3):
		print(next(it))


	#list强转,瞬间得到所有数据
	lst = list(it)
	print(lst)


	#改写成lambda 表达式
	lst = [1,2,3,4,5,6,7,8]
	it = filter(lambda n : True  if n % 2 == 1  else False,lst)
	print(list(it))

reduce

reduce(func,iterable)
功能 :
	一次性从iterable中拿出两个值,扔到func函数中进行处理
	把运算的结果再和iterable的第三个值继续扔到func中做运算
	以此类推,最后返回结果
参数 :
	func 自定义函数
	iterable 可迭代性数据(容器类型数据,range对象,迭代器)
返回值:
	最后计算的结果
引入模块 :
	from functools import reduce

#1.  [5,4,8,8] => 5488
	#方法一
	lst = [5,4,8,8]
	strvar = ""
	for i in lst:
		strvar += str(i)
	print(int(strvar))


#方法二
lst = [5,4,8,8]
it = iter(lst)
num1 = next(it)
num2 = next(it)
j = num1 * 10 + num2
for i in it:
	j = j * 10 + i
print(j)


#reduce  进行改写
from functools import reduce

lst = [5,4,8,8]
def func(x,y):
	return x * 10 + y
res = reduce(func,lst)
print(res)


#优化成lambda 表达式写法
print(reduce(lambda x,y : x * 10 + y ,lst))


#2. "789" => 789 (禁止使用int)
strvar = "789"
	def func_dic(n):
		dic = {"7":7,"8":8,"9":9}
		return dic[n]

it  = map(func_dic,strvar)
res = list(it)

print(reduce(lambda x,y : x * 10 + y,res))

sorted

sorted(iterable,reverse=False,key=函数)
功能: 排序
参数:
	iterable 可迭代性的数据(容器类型数据,range对象,迭代器)
	reverse 代表是否倒序, 
	reverse = True 代表倒序 从大到小    
	reverse = False 代表正序  从小到大
	key  自定义函数或者内置函数
返回值:  排序后的列表



#默认从小到大的排序 : 返回新的列表

#排序列表
container = [100,200,13,-6,0]
lst = sorted(container)
print(lst)
#排序元组
container = (100,200,13,-6,0)
lst = sorted(container)
print(lst)

#排序集合
container = {100,200,13,-6,0}
lst = sorted(container)
print(lst)
#字符串(按照ascii编码排序)
container = "oneal"
lst = sorted(container)
print(lst)
#字典 (默认排序的是键)
container = {"a":1,"b":2,"c":3}
lst = sorted(container)
print(lst)



#从大到小排序

container = (1,2,3,4,5,6,7)
lst = sorted(container,reverse=True)
print(lst)


#通过内置函数排序
	#按照绝对值的大小排序
	lst = [-200,-300,9,20]
	lst1 = sorted(lst,reverse=True,key=abs)
	print(lst1)	#按照绝对值的大小排序



#通过自定义函数进行排序
lst = [19,27,35,48]
def func(n):
	return n % 5
lst1 = sorted(lst,key=func)
print(lst1)

res = sorted(lst,key=(lambda n : n%5))
print(res)

sort  基于原有的列表进行排序,只限定列表类型
sorted 所有容器类型数据都能排, 返回一个全新的列表(推荐)

推导式 : 用一行循环判断遍历出一系列数据的方式

推导式在使用时,只能用for循环和判断
而且判断只能是单项判断


lst = [1,2,3,4,5,6,7,8,9]
lst1 = []
for i in range(1,51):
	lst1.append(i)
print(lst1)


#基本语法
lst = [i for i in range(1,51)]
print(lst)




#普通推导式
	# [1,2,3,4] => [2,8,24,64]
	lst = [1,2,3,4]
	lst1 = [i<

关于推导式的练习

#{'x': 'A', 'y': 'B', 'z': 'C' } 把字典写成x=A,y=B,z=C的列表推导式
dic = {'x': 'A', 'y': 'B', 'z': 'C' }
lst = []
for k,v in dic.items():
	res = k + "=" + v
	lst.append(res)
print(lst)

lst =[ k + "=" + v for k,v in dic.items() ]
print(lst)


#把列表中所有字符变成小写  ["ADDD","dddDD","DDaa","sss"]
lst = ["ADDD","dddDD","DDaa","sss"]
lst1 = []
for i in lst:
	res = i.lower()
	lst1.append(res)
print(lst1)

lst1 =[ i.lower() for i in lst]
print(lst1)



#x是0-5之间的偶数,y是0-5之间的奇数 把x,y组成一起变成元组,放到列表当中
	#方法一
lst = []
for i in range(0,6):
	for j in range(0,6):
		if i % 2 == 0 and j % 2 ==1:
			res = i,j
			lst.append(res)
print(lst)

lst = [(i,j) for i in range(0,6) for j in range(0,6) if i % 2 == 0 and j % 2 ==1]
print(lst)



	#方法二
lst = []
for i in range(0,6):
	if i % 2 == 0 :
		for j in range(0,6):
			if j % 2 ==1 :
				res = i,j
				lst.append(res)
print(lst)


lst = [ (i,j) for i in range(0,6) if i % 2 == 0 for j in range(0,6) if j % 2 ==1 ]
print(lst)



#使用列表推导式 制作所有99乘法表中的运算
for i in range(1, 10):
	for j in range(1, i + 1):
		print("%d * %d = %2d " % (i, j, i * j),end="")
	print()

lst = [("{:d}*{:d}={:2d} ".format(i,j,i*j))for i in range(1, 10) for j in range(1, i + 1)]
print(lst)



# 求M,N中矩阵和元素的乘积
# M = [ [1,2,3], 
#       [4,5,6], 
#       [7,8,9]  ] 

# N = [ [2,2,2], 
#       [3,3,3], 
#       [4,4,4]  ] 
# =>实现效果1   [2, 4, 6, 12, 15, 18, 28, 32, 36]
# =>实现效果2   [[2, 4, 6], [12, 15, 18], [28, 32, 36]]
总结: 能控制下标等于控制了最后的结果

M = [ [1,2,3] , [4,5,6] , [7,8,9]]
N = [ [2,2,2] , [3,3,3] , [4,4,4]]
# 实现效果1
lst=[]
for i in range(0,3):
	for j in range(0,3):
		res = M[i][j] * N[i][j]
		lst.append(res)
print(lst)

lst = [ M[i][j] * N[i][j] for i in range(0,3) for j in range(0,3)]
print(lst)

# 实现效果2
lst = [ [] for i in range(3)]
print(lst)

外层i动的慢的,里层的j动的快的,所以下标M[i][j]
在拿出i的时候, 里面的for 循环了三遍 是在一个新的列表当中实现的;


lst = [[ M[i][j] * N[i][j] for i in range(0,3)] for j in range(3)]
print(lst)

集合推导式

# 案例:
# 满足年龄在18到21,存款大于等于5000 小于等于5500的人,
# 开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)	
# 把开卡的种类统计出来
listvar = [
	{"name":"王家辉","age":18,"money":10000},
	{"name":"王水机","age":19,"money":5100},
	{"name":"王鹏","age":20,"money":4800},
	{"name":"李站","age":21,"money":2000},
	{"name":"李小龙","age":180,"money":20}
	]

setvar = set()
for i in listvar:
	if 18< i["age"] <21 and 5000 < i["money"] < 5500:
		res = "尊贵VIP卡老" + i["name"][0]
	else:
		res = "抠脚大汉卡老" + i["name"][0]
	setvar.add(res)
print(setvar)

#三元运算符
setvar = { "尊贵VIP卡老" + i["name"][0]   if 18< i["age"] <21 and 5000 < i["money"] < 5500 else "抠脚大汉卡老" + i["name"][0]  for i in listvar}
print(setvar)

字典推导式

enumerate(iterable,[start=0])

功能 : 枚举 , 将索引号和iterable中的值,一个一个拿出来配对组成元组放入迭代器中
参数 : 
	iterable 可迭代性数据(容器类型数据, range对象 ,迭代器)
	start : 可以选择开始的索引号(默认从0开始索引)
返回值 : 迭代器

form collections import Iterable Interator
lst = ["a","b","c","d","e"]
# it = enumerate(lst)
#可以选择开始的索引号
it = enumerate(lst,start=1)# 选择从1号开始枚举
res = isinstance(it,Iterable)# 看它是不是可迭代性数据
print(it)

#for + next 迭代所有数据
for i in range(3):
	res = next(it)
print(res)


#list 强转迭代器
res = list(it)
print(res)


#通过推导式配合enumerate 实现
dic = { k:v for k,v in enumerate(lst,start=1)}
print(dic)

#通过dict强转成字典 实现
dic = dict(enumerate(lst,start=1))
print(dic)

zip

zip(iterable,... ...)
功能 : 
	将多个iterable中的值, 一个一个拿出来配对组成元组放入迭代器中
	iterable : 可迭代性数据(常用 : 迭代器,容器类型数据,可迭代对象range)
返回 : 迭代器
特点 : 不能匹对的多余值会被舍弃

#zip基本使用
lst1 = ["a","b","c","d","e"]
lst2 = ["A","B","C","D"]
lst3 = ["Z","X","C"]
it = zip(lst1,lst2,lst3)
print(it)

#list强转
res = list(it)
print(res)

#1.使用zip配合推导式实现
dic = { k:v  for k,v in zip(lst1,lst2)}
print(dic)

#2.通过dict强转成字典
dic = dict(zip(lst1,lst2))
print(dic)

生成器

生成器的本质是迭代器,允许自定义逻辑的迭代器
迭代器和生成器区别:
	迭代器本身是系统内置的,重写不了,而生成器是用户自定义的,可以重写迭代逻辑

生成器可以用两种方式创建 : 
	生成器表达式 (里面是推导式,外面用圆括号)
	生成器函数   (用def定义,里面含有yield)


from collections import Iterable,Iterator

#生成器表达式  定义一个生成器
gen = ( i*i for i in range(10))
print(gen)
print(isinstance(gen,Iterator))



#next 调用生成器
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)


#for 调用生成器
gen = ( i*i for i in range(10))
for i in gen:
	print(i)



#for + next 调用生成器
for i in range(5):
	print(next(gen))


#用list强转瞬间拿到所有数据
print(list(gen))

生成器函数

  yield

类似于return
共同点在于 : 执行到这句话都会把值返回去
不同点在于 : yield每次返回时,都会记住上次离开时执行的位置, 
			下次在调用生成器时, 会从上次执行的位置往下走
			而return直接终止函数,每次都重头调用
yield 6 和yield(6)两种写法都可以,yield 6 更像return 6的写法 ,推荐使用

from collections import Iterator,Iterable

#基本语法
def mygen():
	print("a")
	yield 1
	
	print("b")
	yield 2
	
	print("c")
	yield 3

#初始化生成器函数, 返回生成器对象, 简称生成器
gen = mygen()
print(isinstance(gen,Iterator))

#第一次调用
print(next(gen))#a 1
#第二次调用
print(next(gen))#b 2
#第三次调用
print(next(gen))#c 3
#第四次调用
print(next(gen))#报错 StopIteration 停止迭代





#优化代码
def mygen():
	for i in range(1,11):
		yield "--%d--" % (i)
#初始化生成器函数  生成器对象  简称生成器
gen = mygen()

#for + next 调用生成器
for i in range(5):
	res = next(gen)
	print(res)
for i in range(3):
	res = next(gen)
	print(res)





send  
可以发送数据,发送给上一个yield
send和next的区别:
	next 只能取值
	send 不仅能取值 还能发送值
send注意点 : 
	第一个send 不能给yield 传值 , 默认只能写None
	最后一个yield 接受不到send 的发送值


def mygen():
	print("start")
	yield 1
	
	yield 2
	
	yield 3
	
	print("end")
	

#初始化生成器函数  返回生成器对象  简称生成器
gen = mygen()

#第一次调用
#第一次只能默认发送None,因为第一次没有上一个yield
val =gen.send(None)
print(val)

#第二次调用
val = gen.send(111)
print(val)

#第三次调用
val = gen.send(222)
print(val)


#第四次调用  error
val = gen.send(333)
print(val)




  yield from : 将一个可迭代对象变成一个迭代器返回
def mygen():
	lst = ["a","b","c"]
	yield from lst
gen = mygen()
print(next(gen))


#案例 : 用生成器来写一个斐波那契数列
生成器应用在大数据的场景中,按照需求依次取值
切记不要直接迭代生成器所有数据
一旦数据量较大,类似于死循环

#1 1 2 3 5 8 13 21 34 55 ..... 

def mygen(maxlength):
	a = 0
	b = 1
	i = 0 
	while i < maxlength:
		yield b
		a,b = b,a+b
		i +=1

gen = mygen(10)
#按照需求量进行取值
for i in range(5):
	print(next(gen))

递归函数

递归函数: 自己调用自己的函数就是递归函数
递 : 去
归 : 回
有去有回叫做递归

#简单递归
def digui(n):
	print(n,"<===1===>")
	if n > 0:
		digui(n + 1)
	print(n,"<===2===>")
digui(5)


"""
去的过程:
n = 5 print(5 , "<===1===>") 5 > 0 digui(5-1) <=> digui(4) <=> 当前代码在第14行,代码暂停阻塞.
n = 4 print(4 , "<===1===>") 4 > 0 digui(4-1) <=> digui(3) <=> 当前代码在第14行,代码暂停阻塞.
n = 3 print(3 , "<===1===>") 3 > 0 digui(3-1) <=> digui(2) <=> 当前代码在第14行,代码暂停阻塞.
n = 2 print(2 , "<===1===>") 2 > 0 digui(2-1) <=> digui(1) <=> 当前代码在第14行,代码暂停阻塞.
n = 1 print(1 , "<===1===>") 1 > 0 digui(1-1) <=> digui(0) <=> 当前代码在第14行,代码暂停阻塞.
n = 0 print(0 , "<===1===>") 0 > 0 条件不满足,返回False,不执行调用,print(0,"<===2===>")

回的过程:
n = 1 从阻塞位置14行继续向下执行 print(1,"<===2===>")
n = 2 从阻塞位置14行继续向下执行 print(2,"<===2===>")
n = 3 从阻塞位置14行继续向下执行 print(3,"<===2===>")
n = 4 从阻塞位置14行继续向下执行 print(4,"<===2===>")
n = 5 从阻塞位置14行继续向下执行 print(5,"<===2===>")
到此代码全部执行结束   543210012345 
"""


递归函数有回的过程 , 有两种情况可以触发:
#当最后一层函数全部执行结束的时候,会返回上层函数的调用处

#遇到return 会返回值,直接返回上层空间的调用处


函数在运行时,需要内存开辟空间才可以,这个空间叫做栈帧空间
递归函数就是不停的开辟和释放栈帧空间的一个完整过程
回的时候有两种触发的机制,要么是最后一层函数空间全部执行完毕,要么是遇到return , 都会触底反弹
写递归函数的时候,必须给与跳出的条件,如果递归的层数过多,不推荐使用,容易内容溢出或蓝屏
递归调用每一层空间都是独立的个体,独立的副本,资源不共享,可以通过return来完成值的传递

#官方说法, 递归的最大深度是1000层,具体按照机器来看
def deepfunc():
	deepfunc()
deepfunc() #经典996







# 求任意数n的阶乘 : 5! = 5*4*3*2*1

#普通方法
def func(n):
	total = 1
	for i in range(1,n+1):
		total *= i
	return total
res = func(5)
print(res)



# 递归写法
def jiecheng(n):
	if n <=1 :
		return 1
	return n * jiecheng(n-1)
res = jiecheng(5)
print(res)

"""
# 代码解析:
# 去的过程
n = 5  return 5 * jiecheng(5 - 1) => 5*jiecheng(4)
n = 4  return 4 * jiecheng(4 - 1) => 4*jiecheng(3)
n = 3  return 3 * jiecheng(3 - 1) => 3*jiecheng(2)
n = 2  return 2 * jiecheng(2 - 1) => 2*jiecheng(1)
n = 1  return 1

# 回的过程
n = 2  return 2*jiecheng(1) => 2*1       [jiecheng(2)]
n = 3  return 3*jiecheng(2) => 3*2*1     [jiecheng(3)]
n = 4  return 4*jiecheng(3) => 4*3*2*1   [jiecheng(4)]
n = 5  return 5*jiecheng(4) => 5*4*3*2*1 [jiecheng(5)]
res = jiecheng(5) <=> 5*4*3*2*1 = 120
"""

尾递归(自己调用自己,并且非表达式) [把值放到参数中去运算] (推荐)

无论调用多少次函数,都只占用一份空间
好处 : 只需要考虑最后一层空间的结果是多少, 就不用额外考虑归的过程
cpython解释器目前不支持

def jiecheng(n,endval):
	if n <= 1:
		return endval
	return jiecheng(n-1,endval*n)
res = jiecheng(5,1)
print(res)

# 优化一 (防止用户乱传参数)
def outer(n):
	def jiecheng(n,endval):
		if n <= 1:
			return endval
		return jiecheng(n-1, endval*n)
	return jiecheng(n,1)
print(outer(5))

# 优化二 (防止用户乱传参数)
def jiecheng(n,endval=1):
	if n <= 1:
		return endval
	return jiecheng(n-1, endval*n)
print(jiecheng(5))

"""
# 代码解析:
# 去的过程
n = 5,endval = 1  
	return jiecheng(5-1,endval*n ) => return jiecheng(4,1*5)
n = 4,endval = 1*5
	return jiecheng(4-1,endval*n ) => return jiecheng(3,1*5*4)
n = 3,endval = 1*5*4
	return jiecheng(3-1,endval*n ) => return jiecheng(2,1*5*4*3)
n = 2,endval = 1*5*4*3
	return jiecheng(2-1,endval*n ) => return jiecheng(1,1*5*4*3*2)
n = 1,endval = 1*5*4*3*2
	if 1 <= 1  条件满足 return endval => return 1*5*4*3*2
	
# 回的过程
n = 2  return 1*5*4*3*2
n = 3  return 1*5*4*3*2
n = 4  return 1*5*4*3*2
n = 5  return 1*5*4*3*2
到此程序全部结束;
"""


# 2.斐波那契数列 用递归 1 1 2 3 5 8 13 ....
def feb(n):
	if n ==1 or n == 2:
		return 1
	# 当前值n = 上一个值(n-1) + 上上个值(n-2)
	return feb(n-1) + feb(n-2)

res = feb(5)
print(res)

"""
#代码解析:
n = 5 return feb(4) + feb(3) <=> 3 + 2 => 5

		feb(4)          feb(3)
	feb(3) + feb(2)  feb(2) + feb(1)
feb(2)+feb(1)

		feb(4)          feb(3)
	feb(3) + feb(2)  feb(2) + feb(1)
	1+1

		feb(4)          feb(3)
		2 + 1           1 + 1
		feb(4) = 3      feb(3) = 2
"""

math 数学模块

模块.方法()
import math

#ceil()  向上取整操作  *****
res = math.ceil(4.1)
print(res)

#floor() 向下取整操作  *****
res = math.floor(9.9)
print(res)

# pow() 计算一个数值的N次方(结果为浮点数) (对比内置pow)
res = math.pow(2,2)
print(res)

#sqrt() 开平方运算(结果为浮点数)
res = math.sqrt(81)
print(res)

#fabs() 计算一个数值的绝对值 (结果为浮点数) (对比内置abs)
res = math.fabs(-24)
print(res)

#modf() 将一个数值拆分为整数和小数两部分组成元组
res = math.modf(-10.9)
print(res)	#小数写在前

#copysign() 将参数的第二个数值的正负号拷贝给第一个 (返回一个小数)
res = math.copysign(-23,23)
print(res)

#fsum() 将一个容器数据中的数据进行求和运算 (结果浮点数) (对比内置num)
lst = [2,2,2,2]
res = math.fsum(lst)
print(res)

#圆周率常数 pi
res = math.pi
print(res)

随机模块 random

import random

#random()  获取随机0-1之间的小数(左闭右开) 0 <= x < 1
res = random.random()
print(res)

#randrange() 随机获取指定范围内的整数(包含开始值,不包含结束值,间隔值) 同range  *****

	#一个参数的用法
	res = random.randrange(2) # 0 , 1
	print(res)

	#两个参数的用法
	res = random.randrange(1,5) # 1,2,3,4
	print(res)

	#三个参数的用法
	res = random.randrange(1,11,2) # 1,3,5,7,9
	print(res)

#randint() 随机产生指定范围内的随机整数 (可以取到最大值)
res = random.randint(1,5)
print(res)

#uniform() 获取指定范围内的随机小数(左闭右开) 1<= x < 3 的小数
res = random.uniform(1,3)
print(res)

"""
"Get a random number in the range [a, b) or [a, b] depending on rounding."
return a + (b-a) * self.random()

a = 3 , b = 1
return a + (b-a) * 0~1
return 3 + (1-3) * 0~1
return 3 + -2 * (0~1)

最大值:3 + -2 * 0 = 3
最小值:3 + -2 * 1 = 1

1< x <=3
"""


#choice()  随机获取序列中的值(多选一)
lst = ["a","c","e","d"]
res = random.choice(lst)
print(res)


	#自定义choice函数
	def mychoice(lst):
		#随机获取0~3的下标
		num = random.randrange(len(lst))
		#通过下标来获取列表的值
		return lst[num]
	print(mychoice(lst))
	
	#lambda 表达式
	mychoice = lambda lst : lst[random.randrange(len(lst))]
	print(mychoice(lst))


#sample() 随机获取序列中的值(多选多) [返回列表]
res = random.sample(lst,3)
print(res)

#shuffle() 随机打乱序列中的值,(直接打乱原序列)
random.shuffle(lst)
print(lst)

随机验证码 4位,大小写字母数字

chr  给ascii码返回对应的字符

'''
A~Z
a~z
0~9
'''
#A = 65
#a = 97
print(chr(65))

def yanzheng():
	strvar = ""
	for i in range(4):
		#大写字母 A-Z 65-90
		B_word = chr(random.randrange(65,91))
		#小写字母 a-z 97-122
		b_word = chr(random.randrange(97,123))
		#数字 0-9
		num = str(random.randrange(10))
		#把可能的字符都放在列表里,一次抽一个
		lst = [B_word,b_word,num]
		strvar += random.choice(lst)
	return strvar
res = yanzheng()
print(res)

内置方法

#abs  绝对值函数
val = -11
res = abs(val)
print(res)

#round  四舍五入 (n.5  n为偶数则舍去 , 为奇数则进一)
奇进偶不进
val = 1.4
val1 = 2.6
val2 = 3.5
val3 = 3.49
res = round(val3)
print(res)

#sum  计算一个序列的和
lst = [1,2,3,4,5]
res = sum(lst)
print(res)

#max  获取一个序列里面的最大值
lst = [3,5,6,2,6,7,1,9]
res1 = max(lst)
res2 = min(lst)
print(res1,res2)

#sorted  找出最小值和最大值  也能排序
lst1 = sorted(lst)
max1 = lst1[-1]
min1 = lst1[0]
print(max1,min1)

#min  获取一个序列里面的最小值
	#sorted(Iterable,key=函数)  max 和 min 同sorted用法
	找出年龄最大的元组
	lst = [("xx",12),("cz",15),("gz",18),("dx",23)]

	def func(n):
		return n[-1] #返回的值是判断参考的依据
	res = max(lst,key=func)
	res = min(lst,key=func)
	print(res)


	dic = {"xx":1,"gz":-100,"cz":10}
	def func(n):
		print(n)
		return abs(dic[n])
	res = max(dic,key=func)
	print(res)


#pow  计算某个数值的x次方
	res = pow(2,5)
	print(res)
		
	res = pow(2,5,10)	#第三个参数是取余
	print(res)

#range 产生指定范围数据的可迭代对象
for i in range(1,11,2):
	print(i)
for j in range(10,0,-2):
	print(j)


#bin  将10进制数据转化为二进制
res = bin(2)	#0b10
print(res)

#oct  将10进制数据转化为八进制
res = oct(8)	#0o10
print(res)

#hex  将10进制数据转化为十六进制
res = hex(16)	#0x10
print(res)


#chr  将ASCII编码转换为字符
大小字母相差的ascii编码是32 , 小写字母 a = 97
res = chr(98)
print(res)

#ord  将字符转换成ASCII编码
res = ord("b")
print(res)

#谨慎使用eval 和 exec 尤其是在和用户交互数据的时候注意
#eval 将字符串当作python代码执行
strvar = ("print('print')")
print(strvar)
eval(strvar)

#exec  将字符串当作python代码执行(功能更强大)
strvar = "a=10"
strvar1 = """
for i in range(5):
	print(i)

"""
exec(strvar1)
print(a)


#repr  不转义字符输出字符串
strvar = "\nprint(111)"
print(repr(strvar))


#input  接受输入字符串
ssn = input("为什么不走?")
print(ssn)


#hesh  生成哈希值
两个相同的字符串 , 无论哈希多少次, 都会产生相同的唯一值

1. 让密码加密  hashlib
2. 文件的校验  比较文件内容

strvar1 = "asd"
strvar2 = "asd"
print(hash(strvar1))
print(hash(strvar2))

with open("ceshi1.txt",mode="r",encoding="utf-8")as fp:
	strvar = fp.read()
	res1 = (hash(strvar))
with open("ceshi2.txt",mode="r",encoding="utf-8")as fp:
	strvar2 = fp.read()
	res2 = (hash(strvar2))
print(res1,res2)

序列化模块 pickle

序列化 : 把不能够直接存储在文件中的数据变得可存储, 这个过程就是序列化
反序列化: 把文件中的数据内容拿出来, 恢复成原来的数据类型 , 这个过程就是反序列化
'''
php:
serialize
unserialize
'''

在文件中存储的数据, 要么是字符串 , 要么是字节流
python中, 所有的数据类型都可以通过dupms和loads进行序列化和反序列化


#错误案例  列表不能够直接塞到文件中
lst = [1,2,3]
with open("ceshi2.txt",mode="a+",encoding="utf-8")as fp:
	fp.write(lst)



### dumps 和 loads
import pickle

dumps 把任意对象序列化成一个bytes
	#序列化列表
	lst = [1,2,3]
	res = pickle.dumps(lst)
	print(res)

	#序列化函数
	def func():
		print("我是函数")
	res = pickle.dumps(func)
	print(res)

	#序列化迭代器
	it = iter(range(1,5))
	res = pickle.dumps(it)
	print(res)

loads 把任意bytes反序列化成原来的数据
	res1 = pickle.loads(res)
	for i in range(3):
		res2 = next(res1)
		print(res2)



### dump 和 load 
	#dump  把对象序列化后写入到file-like Object(即文件对象)
	dic = {"a":1,"b":2}
	with open("ceshi1.txt",mode="wb")as fp:
		#dump (要转换的数据,文件对象)
		pickle.dump(dic,fp)


	#load  把file-like Object(即文件对象)中的内容拿出来,反序列化成原来数据
	with open("ceshi1.txt",mode="rb")as fp:
		res = pickle.load(fp)
	print(res,type(res))


### 对比dumps 和 dump

dic = {"a":1,"b":2}
#通过dumps写入
strvarb = pickle.dumps(dic)
	#print(strvarb)
with open("ceshi1.txt",mode="wb")as fp:
	fp.write(strvarb)


#通过loads取出
with open("ceshi1.txt",mode="rb")as fp:
	res = fp.read()
	dic1 = pickle.loads(res)
print(dic1,type(dic1))

json

所有的编程语言都能够识别的数据格式叫做json  是字符串
能够通过json序列化成字符串的有如下类型: (int float bool str list tuple dict None)

pickle 序列化成字节流
json   序列化成字符串


#1.json 的用法
import json 

#dumps 和 loads 是一对 , 序列化成字符串
	dic = {"name":"王振","age":30,"classroom":"python30","family":["爸爸","妈妈","哥哥","姐姐"]}
		# ensure_ascii=False 不通过ascii来显示内容 
		# sort_keys=True 对字典的键来进行排序
	res = json.dumps(dic,ensure_ascii=False)
	print(res , type(res))


	#loads 反序列化成原来的数据
	dic1 = json.loads(res)
	print(dic1 , type(dic1))



#dump 和 load 是一对 , 针对于文件 , 把数据进行序列化操作
	dic = {"name":"王振","age":30,"classroom":"python30","family":["爸爸","妈妈","哥哥","姐姐"]}
	with open("ceshi1.txt",mode="w",encoding="utf-8")as fp:
		#dump (要转换的数据, 文件对象)
		json.dump(dic,fp,ensure_ascii=False)
	#通过load反序列化成原来的数据类型
	with open("deshi1.txt",mode="r",encoding="utf-8")as fp:
		dic1 = json.load(fp)
	print(dic1,type(dic))


#2.json 和 pickle 两个模块区别

	#json 
	json 可以连续dump , 不可以连续load 
	(load是一次性拿出所有数据进行反序列化, 容易出错)
	可以使用loads 来解决

	dic1 = {"a":1,"b":2}
	dic2 = {"c":3,"d":4}
	with open("ceshi1.txt",mode="w",encoding="utf-8")as fp:
		json.dump(dic1,fp)
		fp.write("\n")
		json.dump(dic2,fp)
		fp.write("\n")


	#load的弊端 , 一次性读取
	'''
	with open("ceshi1.txt",mode="r",encoding="utf-8")as fp:
		dic = json.load(fp)
	print(dic)
	'''

	#解决方法 , 使用loads , 一行一行进行反序列化
	with open("ceshi1.txt",mode="r",encoding="utf-8")as fp:
		#fp是一个迭代器
		for i in fp:
			dic = json.loads(i)
			print(dic)

pickle

import pickle

pickle 可以连续dump 可以连续load
dic1 = {"a":1,"b":2}
dic2 = {"c":3,"d":4}
with open("ceshi1.txt",mode="wb")as fp:
	pickle.dump(dic1,fp)
	pickle.dump(dic2,fp)
#方法一
with open("ceshi1.txt",mode="rb")as fp:
	dic = pickle.load(fp)
	print(dic)
	dic = pickle.load(fp)
	print(dic)


#方法二
'''
try ...  except ...  抑制报错  
如果try代码块里面有问题 
就执行except中的代码
'''

try :
	把有问题的代码放进来
except:
	如果出现异常执行这个分支的代码块



try:
with open("ceshi1.txt",mode="rb")as fp:
	while True:
		dic = pickle.load(fp)
		print(dic)
except:
	pass


#总结:
	json 和 pickle 两个模块的区别
	
	json序列化之后的数据类型是str , 所有编程语言都识别 , (数据交流)
	但是仅限于(int  float  bool ) (list tuple str  dict None)
	json 不能连续load  只能一次性拿出所有数据
	
	pickle 序列化之后的数据类型是bytes  (存储转换)
	所有数据类型都可以转化 , 但仅限于python之间的存储传输
	pickle可以连续load  多套数据放到同一个文件中

time

import time

#sleep()  程序睡眠等待
程序在当前行,阻塞3秒之后,代码往下执行
time.sleep(3)
print("zzz")

进度条效果

#定义进度条的样式

print("[%-50s]" % ("======>"))
print("[%-50s]" % ("===========>"))
print("[%-50s]" % ("================>"))

#让进度条动起来
strvar = ">>>"
for i in range(50):
	strvar += "#"
	time.sleep(0.1)
	print("\r[%-50s]" % (strvar),end="")


#根据文件大小,调整进度条的位置
def kongge(baifenbi):
	if baifenbi > 1:
		baifenbi = 1
	#打印出对应的#号效果
	strvar = int(50 * baifenbi) * "#"
	# %%  等于  打印出%号的效果
	print("\r[%-50s]  %d%%" % (strvar,int(100 * baifenbi)),end="")


#当前加载进度
jiazai = 0
# 假设文件总大小为10000
wenjian = 10000
while wenjian > jiazai:
	time.sleep(0.1)
	#每次加载1000
	jiazai += 1000
	#算出加载的百分比
	baifenbi = jiazai/wenjian
	kongge(baifenbi)

time 时间模块

import time

#time()  获取本地时间戳   *****
res = time.time()
print(res)	# 1589974905.6125166


#localtime  ->  mktime  ->  ctime

# localtime()  获取本地时间元组   (参数是时间戳 , 默认当前)
res = time.localtime()
print(res)	#time.struct_time(tm_year=2020, tm_mon=5, tm_mday=20, tm_hour=19, tm_min=43, tm_sec=38, tm_wday=2, tm_yday=141, tm_isdst=0)

res = time.localtime(1589974905.6125166)
print(res)


#mktime()   通过时间元组来获取时间戳  (参数是时间元组)
# 年 月 日 时 分 秒 0 0 0
ttp = (2015,8,31,10,10,10,0,0,0)
res = time.mktime(ttp)
print(res)	#1440987010.0


#ctime  获取本地时间字符串  (参数是时间戳,默认当前)
res = 1440987010.0
ttp = time.ctime(res)	#Mon Aug 31 10:10:10 2015
ttp = time.ctime()	#Wed May 20 19:49:57 2020
print(ttp)


#asctime()  通过时间元组获取时间字符串 ( 参数是时间元组)
	'''不能自动识别今天是周几'''
res = (2020,5,20,9,40,30,2,0,0)
ttp = time.asctime(res)
print(ttp)	# Wed May 20 09:40:30 2020


#sleep()  程序睡眠等待
time.sleep(3)
print("ohhhh")


'''
	strftime  元组 -> 字符串
	strptime  字符串 -> 元组


'''


#strftime()  格式化时间字符串 (要格式化的字符串,时间元组) 
'''linux系统下支持中文, windows 系统不支持中文'''
strvar = time.strftime("%H:%M:%S %Y-%m-%d") # 默认当前时间
print(strvar)	#19:59:19 2020-05-20

ttp = (2015,8,31,10,10,10,0,0,0)
strvar = time.strftime("%Y-%m-%d %H:%M:%S",ttp)	#指定时间元组
print(strvar)	#2015-08-31 10:10:10


#strptime()   将时间字符串通过指定格式提取时间元组中(时间字符串,格式化字符串)
strvar = "2020年5月20日20点02分30秒,我依然如此,像从前一样"
ttp = time.strptime(strvar,"%Y年%m月%d日%H点%M分%S秒,我依然如此,像从前一样")
print(ttp)	#time.struct_time(tm_year=2020, tm_mon=5, tm_mday=20, tm_hour=20, tm_min=2, tm_sec=30, tm_wday=2, tm_yday=141, tm_isdst=-1)


#perf_counter()  用于计算程序运行的时间 

	starttime = time.perf_counter()
	for i in range(100000000):
		pass
	endtime = time.perf_counter()
	print(strattime-endtime)	#2.8168545

os 模块, 对系统进行操作

import os

#system()  在python中执行系统命令

os.system("cmd")
os.system("calc")	#打开计算器
os.system("mspaint")#打开画图板
os.system("type nul>zzz.txt")	#创建一个文件
os.system("ipconfig")	#乱码

#popen()  执行系统命令返回对象, 通过read方法读出字符串
obj = os.popen("ipconfig")
print(obj)
	#windows默认编码为gbk  通过read方法可以直接转换为utf-8
print(obj.read())


#listdir()  获取指定文件夹中所有内容的名称列表
路径 : 相对路径 , 绝对路径 (完整路径)
	.  代表当前目录
	.. 代表上一级目录
	# 相对于当前
	res = os.listdir(".")
	print(res)	#['.idea', 'ceshi1.txt', 'ceshi2.txt', 'EV', 'Notepad++', 'PyCharm Community Edition 2019.3.2', 'python', 'shopping_data.json', 'Typora', 'z', 'z.py', 'zzz.txt', '历程', '软件']

	# 相对于上一级
	res = os.listdir("..")
	print(res)	#['$RECYCLE.BIN', '.390121816', 'Alive I can fly', 'au', 'BaiduNetdisk', 'BaiduNetdiskDownload', 'Bandizip', 'DTLSoft', 'FileZilla FTP Client', 'flashfxp', 'huorong', 'KGMusic', 'KuGou', 'Microsoft VS Code', 'Netease', 'PanDownload_v2.2.2', 'Program Files (x86)', 'qq', 'QQBrowser', 'SpeedPanX_185', 'steam', 'System Volume Information', 'The_Elder_Scrolls_V_SSE.v1.5.16.CHS.Green', 'WeChat', 'WeGameApps', '开班软件', '李大炮的云文档', '英雄时刻']

	#绝对路径
	res = os.listdir(r"D:\Alive I can fly")
	print(res)	#['.idea', 'ceshi1.txt', 'ceshi2.txt', 'EV', 'Notepad++', 'PyCharm Community Edition 2019.3.2', 'python', 'shopping_data.json', 'Typora', 'z', 'z.py', 'zzz.txt', '历程', '软件']


#environ  获取或修改环境变量
print(os.environ)
'''
environ({'ALLUSERSPROFILE': 'C:\\ProgramData', 'APPDATA': 'C:\\Users\\Dapao\\AppData\\Roaming', 'COMMONPROGRAMFILES': 'C:\\Program Files\\Common Files', 'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files', 'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files', 'COMPUTERNAME': 'MSI', 'COMSPEC': 'C:\\Windows\\system32\\cmd.exe', 'CONFIGSETROOT': 'C:\\Windows\\ConfigSetRoot', 'DRIVERDATA': 'C:\\Windows\\System32\\Drivers\\DriverData', 'FPS_BROWSER_APP_PROFILE_STRING': 'Internet Explorer', 'FPS_BROWSER_USER_PROFILE_STRING': 'Default', 'HOMEDRIVE': 'C:', 'HOMEPATH': '\\Users\\Dapao', 'IDEA_INITIAL_DIRECTORY': 'D:\\Alive I can fly\\PyCharm Community Edition 2019.3.2\\bin', 'LOCALAPPDATA': 'C:\\Users\\Dapao\\AppData\\Local', 'LOGONSERVER': '\\\\MSI', 'NUMBER_OF_PROCESSORS': '12', 'ONEDRIVE': 'C:\\Users\\Dapao\\OneDrive', 'OS': 'Windows_NT', 'PATH': 'C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Windows\\System32\\OpenSSH\\;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;C:\\Program Files\\NVIDIA Corporation\\NVIDIA NvDLISR;C:\\Program Files\\Intel\\WiFi\\bin\\;C:\\Program Files\\Common Files\\Intel\\WirelessCommon\\;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Windows\\System32\\OpenSSH\\;D:\\python\\;C:\\Users\\Dapao\\AppData\\Local\\Microsoft\\WindowsApps;D:\\Bandizip\\;D:\\Alive I can fly\\python;', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 158 Stepping 13, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '9e0d', 'PROGRAMDATA': 'C:\\ProgramData', 'PROGRAMFILES': 'C:\\Program Files', 'PROGRAMFILES(X86)': 'C:\\Program Files (x86)', 'PROGRAMW6432': 'C:\\Program Files', 'PSMODULEPATH': 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules', 'PUBLIC': 'C:\\Users\\Public', 'PYCHARM_HOSTED': '1', 'PYTHON': 'D:\\Alive I can fly\\python\\python.exe', 'PYTHONIOENCODING': 'UTF-8', 'PYTHONPATH': 'D:\\Alive I can fly\\z', 'PYTHONUNBUFFERED': '1', 'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:\\Windows', 'TEMP': 'C:\\Users\\Dapao\\AppData\\Local\\Temp', 'TMP': 'C:\\Users\\Dapao\\AppData\\Local\\Temp', 'USERDOMAIN': 'MSI', 'USERDOMAIN_ROAMINGPROFILE': 'MSI', 'USERNAME': 'Dapao', 'USERPROFILE': 'C:\\Users\\Dapao', 'WINDIR': 'C:\\Windows'})
PATH : 敲命令, 让系统通过路径找到对应系统文件, 进行执行
'''

print(os.environ["PATH"])
	# os.environ["PATH"] += D:\Alive I can fly;"
	# os.system("QQScLauncher")


# os 模块属性
	#name  获取系统表示  linux,mac -> posix    windows -> nt
	print(os.name)	# nt
	
	# sep  获取路径分割符号  linux,mac -> /    windows -> \
	print(os.sep)	#\
	
	# linesep  获取系统的换行符号  liunx,mac -> \n   windows -> \r\n 或\n 
	res = repr(os.linesep)#因为换行符号不显示,所以用repr来原型化输出
	print(res)	#'\r\n'

os 与 shutil

import os

#os.chdir(r"D:\Alive I can fly")
	#改变当前工作路径到指定路径

'''
os  创建和删除  文件和文件夹
shutil  复制和剪切  文件和文件夹
'''

#os 模块具有 新建/删除/
	
	# os.mknod  创建文件 (linux可以,windows有兼容问题)
	os.mknod("aaa.txt")	#报错了
	os.system("type nul>aaa.txt")#可以
	
	#os.remove  删除文件
	os.remove("aaa.txt")

	#os.mkdir  创建目录(文件夹)
	os.mkdir("aaa")	#创建出来总是文件夹

	#os.rmdir  删除目录(文件夹)
	os.rmdir("aaa")

	#os.rename  对文件,目录重命名
	os.rename("aaa","bbb")

	#os.makedirs  递归创建文件夹
	os.makedirs("aaa/b/c/d")

	#os.removedirs  递归删除文件夹(空文件夹)
	os.removedirs("bbb/b/c/d")


#shutil  模块  复制和剪切

import shutil
	#copy(src,dst)   复制文件权限和内容
	shutil.copy("zzz.txt","aaa.py")


	#copytree(src,dst)  拷贝文件夹里所有内容(递归拷贝)
	shutil.copytree("aaa","bbb")


	#rmtree(path)  删除当前文件夹及其中所有内容(递归删除)
	shutil.rmtree("aaa")


	#move(path1,path2)  移动文件或者文件夹
	shutil.move("aaa.py","..")

os.path 路径模块

import os

pathvar= r"‪D:\Alive I can fly\zzz.txt"

#basename()  返回文件名部分
res = os.path.basename(pathvar)
print(res)	#zzz.txt


#dirname()  返回路径部分
res = os.path.dirname(pathvar)
print(res)	#‪D:\Alive I can fly


#split()  将路径拆分成单独的文件部分和路径部分  组合成一个元组
print(os.path.split(pathvar))	#('\u202aD:\\Alive I can fly', 'zzz.txt')


#join()  将多个路径和文件组成新的路径  可以自动通过不同的系统加不同的斜杠
	#liunx / windows \
path1 = "D:"
path2 = "Alive I can fly"
path3 = "zzz.txt"
	#正常
	strvar = path1 + path2 + os.sep + path3
	print(strvar)	#D:Alive I can fly\zzz.txt


	#join
	strvar = os.path.join(path1,path2,path3)
	print(strvar)	#D:Alive I can fly\zzz.txt


#splitext()  将路劲分割为后缀和其他部分 
print(os.path.splitext(pathvar))	#('\u202aD:\\Alive I can fly\\zzz', '.txt')
print(pathvar.split(".")[-1])	#txt


#getsize()  获取文件的大小 (只能是文件)
res = os.path.getsize("zzz.txt")
print(res)


#is 系列
pathvar= r"‪D:\Alive I can fly\zzz.txt"
	#isdir()  检测路径是否是一个文件夹
	res = os.path.isdir(pathvar)
	print(res)	#False

	#isfile()  检测路径是否是一个文件
	res = os.path.isfile(pathvar)
	print(res)	#True


	#islink()  检测路径是否是一个链接
	res = os.path.islink(pathvar)
	print(res)	#False




#获取时间系列
	#getctime() [windows]文件的创建时间,[liunx]权限的改动时间(返回时间戳)
	res = os.path.getctime(pathvar)
	print(res)	#1589976850.1673756

	#getmtime() 获取文件最后一次修改时间(返回时间戳)
	res = os.path.getmtime(pathvar)
	print(res)	#1589976850.1673756

	#geatime() 获取文件最后一次访问时间(返回时间戳)
	res = os.path.getatime(pathvar)
	print(res)	#1589982558.4431171


	import time
	strvar = time.ctime(res)
	print(strvar)	#Wed May 20 21:49:18 2020


	#exists()  检测指定的路径是否存在 
	pathvar = r"D:\Alive I can fly\zzz.txt"
	res = os.path.exists(pathvar)
	print(res)	#True


	#isabs()  检测一个路径是否是绝对路径  
	#abspath()  将相对路径转化成绝对路径
	
	pathvar = "."
	res = os.path.isabs(".")	#False
	print(res)

	if not os.path.isabs("."):
		res = os.path.abspath(pathvar)
		print(res)	#D:\Alive I can fly

zipfile 后缀是zip

import zipfile

#压缩文件
	# 创建压缩包
	zf = zipfile.ZipFile("yasuo1.zip","w",zipfile.ZIP_DEFLATED)

	# 把文件写入到压缩包中
	#write(路径,别名)
	zf.write(r"D:\Alive I can fly\ceshi1.txt","ceshi1.txt")
	zf.write(r"D:\Alive I can fly\ceshi2.txt","ceshi2.txt")
	#可以允许临时创建一个文件夹tmp
	zf.write(r"D:\Alive I can fly\3.py","/tmp/3.py")


	#关闭压缩文件
	zf.close()


#解压文件
zf = zipfile.ZipFile("yasuo1.zip","r")
#./代表相对于当前路径
# zf.extractall("./yasuo1")	#解压到当前路径下的指定文件夹
# zf.extract(文件,文件夹)
zf.extract("ceshi1.txt","./ceshi1")
zf.close()


#追加文件
zf = zipfile.ZipFile("yasuo1.zip","a",zipfile.ZIP_DEFLATED)
zf.write(r"D:\Alive I can fly\4.py","4.py")
zf.close()
	#使用with语法进行优化 (可以省略掉close操作) 推荐
	with zipfile.ZipFile("yasuo1.zip","a",zipfile.ZIP_DEFLATED)as zf:
		zf.write(r"D:\Alive I can fly\5.py","/tmp/5.py")

#查看文件
with zipfilr.ZipFile("yasuo1.txt","r",zipfile.ZIP_DEFLATED)as zf:
	lst = zf.namelist()
print(lst)	#['ceshi1.txt', 'ceshi2.txt', 'tmp/3.py', 'tmp/4.py', 'tmp/5.py']

tarfilr .tar | .tar.gz | .tar.bz2

import tarfile
官方说法,.tar.bz2 的压缩算法  包是最小的

#压缩文件
	#创建tar压缩包	#10,240 字节
	tf = tarfile.open("yasuo2.tar","w",encoding="utf-8")
	#添加文件打包
	#add(路径,别名)
	tf.add(r"D:\Alive I can fly\ceshi1.txt","ceshi1.txt")
	tf.add(r"D:\Alive I can fly\ceshi2.txt","ceshi2.txt")
	tf.add(r"D:\Alive I can fly\3.py","/tmp/3.py")
	#关闭文件
	tf.close()


	# .tar.gz 的压缩包 	#217 字节
	tf = tarfile.open("yasuo2.tar.gz","w:gz",encoding="utf-8")
	tf.add(r"D:\Alive I can fly\ceshi1.txt","ceshi1.txt")
	tf.add(r"D:\Alive I can fly\ceshi2.txt","ceshi2.txt")
	tf.add(r"D:\Alive I can fly\3.py","/tmp/3.py")
	tf.close()

	#.tar.bz2 的压缩包  #217 字节 理论上  压缩出来的最小
	tf = tarfile.open("yasuo2.tar.bz2","w:bz2",encoding="utf-8")
	tf.add(r"D:\Alive I can fly\ceshi1.txt","ceshi1.txt")
	tf.add(r"D:\Alive I can fly\ceshi2.txt","ceshi2.txt")
	tf.add(r"D:\Alive I can fly\3.py","/tmp/3.py")
	tf.close()

	#zip压缩包  354 字节
	zf = zipfile.ZipFile("yasuo1.zip","w",zipfile.ZIP_DEFLATED)
	zf.write(r"D:\Alive I can fly\ceshi1.txt","ceshi1.txt")
	zf.write(r"D:\Alive I can fly\ceshi2.txt","ceshi2.txt")
	zf.write(r"D:\Alive I can fly\3.py","/tmp/3.py")
	zf.close()



#解压文件
	tf = tarfile.open("yasuo2.tar","r",encoding="utf-8")
	#extractall(路径)   解压所有文件到某个路径下
	# tf.extractall("yasuo2")
	# extract(文件,路径)   解压指定的某个文件到某个路径下
	tf.extract("ceshi1.txt", "ceshi1")
	tf.close()


#追加文件
	#只能对W模式下的打包进行追加,其他的模式不行
	with tarfile.open("yasuo2.tar","a",encoding="utf-8")as tf:
		tf.add(r"D:\Alive I can fly\4.py","4.py")


	#对于tar.gz 或者 tar.bz2 已经压缩过的包无法追加文件
	'''
	with tarfile.open("yasuo2","a",encoding="utf-8")as tf:
		tf.add(r"D:\Alive I can fly\4.py","4.py")
	'''


#查看压缩包
	with tarfile.open("yasuo2.tar","r",encoding="utf-8")as tf:
		lst = tf.getnames()
	print(lst)	#['ceshi1.txt', 'ceshi2.txt', 'tmp/3.py', '4.py', '4.py', '4.py', '4.py', '4.py', '4.py']

对tarfile 不能追加文件的bug进行优化

	# tarfile 的解决办法 , 文件或者文件夹都可以通过add放到压缩包中
	# 先解压原来的压缩包
	# 把要追加的内容放进去
	# 过滤数据,重新打包

	import os
	pathvar = os.getcwd()
	print(pathvar) # D:\Alive I can fly


	#压缩包的路径
	pathvar1 = os.path.join(pathvar,"yasuo2.tar.gz")#把路径拼接起来
	print(pathvar1)	#D:\Alive I can fly\yasuo2.tar.gz
	#解压文件夹的路径
	pathvar2 = os.path.join(pathvar,"yasuo2")
	print(pathvar2)	#D:\Alive I can fly\yasuo2

	#先解压压缩包
	with tarfile.open(pathvar1,"r",encoding="utf-8")as tf:
		tf.extractall(pathvar2)


	#把追加的内容放进来
	import shutil
	shutil.copy(r"D:\Alive I can fly\3.py",pathvar2)
	
	#过滤数据,重新打包
		#过滤掉ceshi2.txt这个文件
	lst = os.listdir(pathvar2)
	print(lst)	#['3.py', 'ceshi1.txt', 'ceshi2.txt', 'tmp']

	with tarfile.open(pathvar1,"w:bz2",encoding="utf-8")as tf:
		for i in lst:
			print(i)
			pathnew = os.path.join(pathvar2,i)
			print(pathnew)
			if i != "ceshi2.txt"
				tf.add(pathnew,i)

模块与包 [模块部分]

#import 导入
		导入一次,终身受益,不会重复导入
	
	
	import mymodule
	#直接打印了自建模块的print
	

	#1 模块.变量
		print(mymodule.a)
	#2 模块.函数
		mymodule.zzz()
	#3 模块.类
		print(mymodule.food().dami)


#导入任意路径下的模块
	默认只能导入当前文件所在的这个文件夹下所有模块
	通过sys.path 可以导入任意路径下的模块
	导入模块时 -> 会去找sys.path这个列表里面的路径,如果找到就导入,找不到就报错
	通过append可以在列表里追加路径,来实现导入的功能

	import sys
	print(sys.path)
	sys.path.append(D:\\Alive I can fly)
	'''
	# // 是为了防止转义, 代表符号 /
	['D:\\Alive I can fly',
	'D:\\Alive I can fly\\z', 
	'D:\\Alive I can fly\\python\\python36.zip',
	'D:\\Alive I can fly\\python\\DLLs',
	'D:\\Alive I can fly\\python\\lib',
	'D:\\Alive I can fly\\python',
	'C:\\Users\\Dapao\\AppData\\Roaming\\Python\\Python36\\site-packages',
	'D:\\Alive I can fly\\python\\lib\\site-packages']
	
	执行命令 , 找路径 , 执行对应的文件
	环境变量
	'''

	import mymodule2
	print(mymodule2.c)
	print(mymodule2.d)


	#起别名
	import mymodule2 as m2
	print(m2.c)
	print(m2.d)




#from ... import ... 从...导入...

	#导入单个
	from mymodule import a
	print(a)

	#导入多个
	from mymodule import a,b,zzz
	print(a)
	print(b)
	zzz()

	#导入所有  *  (代表所有)
	from mymodule import *
	zzz()


	#起别名
	from mymodule import a as aa , b as bb
	print(aa)
	print(bb)


	#指定*号的范围	使用__all__ = [] 来指定范围
	from mymodule import *
	print(a)
	print(b)
	zzz()	#没有指定就无法引用


#__name__
	返回模块名字的魔术属性 __name__
	如果当前文件是直接运行的 , 返回 __main__
	如果当前文件时间接导入的 , 返回当前文件名(模块名)
	import mymodule

模块与包 [包的部分]

#import 导入包
	#1.文件就是一个模块,文件夹就是一个包
		# 文件夹里面可以有很多的文件, 就相当于包里面有很多的模块
	#2.__init__.py 对包(文件夹)进行初始化的脚本文件
	#3.这个包下的其他模块可以通过初始化文件间接导入



	#导入包,通过init文件初始化,默认引入init文件中所有属性
	import package1
	print(package1.ceshi003)


	#引入包当中具体的一个模块
	方法一
		import package1.mypath
		package1.mypath.join()


		#起别名
		import package1.mypath as pm
		pm.join()

	方法二 (通过__init__间接导入,更加简洁)
		import package1
		package1.mypath.join()


#用 from ... import  从包导入成员(落脚点在模块或者成员)
	#1.包.模块.成员
	from package1 import ceshi002
	print(ceshi002)

	from package1 import mypath
	mypath.getsize()


	from package1.mypath import getsize
	getsize()

	#2.起别名
	from package1.mypath import ceshi004 as c4 , ceshi005 as c5
	print(c4)


#导入所有
from package1 import *
print(ceshi001)

单入口模式(相对路径导入)

import package2.pkg1.pkg1_module1 as pppm
# print(pppm.ceshi100)

#常用 : . 代表当前  .. 代表上一级
"""
# 1.当前文件如果含有相对路径,是不能够直接执行的!
# 2.通过导入到入口的启动文件中,在这个主文件中,能够识别出对应的相对路径
# 3.from .. import 落脚点在于引入的是模块或者模块中的成员
"""

ceshi100 = 100
ceshi101 = 101

# . 代表当前
from . import pkg1_module2
print(pkg1_module2.ceshi200)


from .pkg1_module2 import ceshi201
print(ceshi201)

# .. 代表上一级
from .. import pkg_module1
print(pkg_module1.ceshi400)


from ..pkg2 import pkg2_module1
print(pkg2_module1.ceshi300)


from ..pkg2.pkg2_module1 import ceshi301
print(ceshi301)
"""
.    当前路径
..   上一级路径
...  上一级的上一级
.... 上一级的上一级的上一级
.....   (这里的点是无限的)
from .......................................... import 模块
"""

正则表达式 匹配单个字符

import re
lst = re.findall(正则表达式,要匹配的字符串)
返回列表,按照正则表达式匹配到的内容都扔到列表里

#1.预定义字符集
	#\d 匹配数字
	lst = re.findall("\d","asdasdasd123szasd123")
	print(lst)	#['1', '2', '3', '1', '2', '3']

	#\D 匹配非数字
	lst = re.findall("\D","ASD123asd")
	print(lst)	#['A', 'S', 'D', 'a', 's', 'd']

	#\w 匹配字母或数字或下划线	(正则函数中,支持中文匹配)
	lst = re.findall("\w","asd123___)(*&*&^&")
	print(lst)	#['a', 's', 'd', '1', '2', '3', '_', '_', '_']

	#\W 匹配非字母数字下划线
	lst = re.findall("\W","asd123___)(*&*&^&")
	print(lst)	#[')', '(', '*', '&', '*', '&', '^', '&']

	#\s 匹配任意的空白符 \n \t \r " "
	lst = re.findall("\s","  		sad")
	print(lst)	#[' ', ' ', '\t', '\t']

	#\S 匹配任意的非空白符
	lst = re.findall("\S","  		sad")
	print(lst)	#['s', 'a', 'd']

	#\n 匹配换行符
	strvar = """
	ohhhhh
	"""
	lst = re.findall(r"\n",strvar)
	print(lst)	#['\n', '\n']

	#\t 匹配TAB缩进符
	strvar = """
	o  h	        			hhhh
	"""
	lst = re.findall(r"\t", strvar)
	print(lst)	#['\t', '\t', '\t', '\t']


#2.字符组  必须匹配中括号里列举的字符[]
	lst = re.findall("[abc]","asdzxcvbn")
	print(lst)	#['a', 'c', 'b']

	print(re.findall('a[abc]b','aab abb acb adb'))	
	#['aab', 'abb', 'acb']

	print(re.findall('a[0123456789]b','a1b a2b a3b acb ayb'))
		#['a1b', 'a2b', 'a3b']
		# -  是一个特殊的字符,代表的是一个范围 0-9 = 0123456789
		#'a[0123456789]b' = "a[0-9]b"

	print(re.findall('a[abcdefg]b','a1b a2b a3b acb ayb adb'))
		#['acb', 'adb']
		#'a[abcdefg]b' = "a[a-g]b"
		#如果要表达所有的小写字母 ,可以写成[a-z]

	print(re.findall('a[ABCDEFG]b','a1b a2b a3b  aAb aDb aYb'))
		#['aAb', 'aDb']
		#'a[ABCDEFG]b' = "a[A-G]b"
		#如果要表达所有的大写字母 , 可以写成[A-Z]

	print(re.findall('a[0-9a-zA-Z]b','a-b aab aAb aWb aqba1b'))
		#['aab', 'aAb', 'aWb', 'aqb', 'a1b']

	#不能写成[0-z] 因为其中含有数字大小写和特殊字符  比如@
	print(re.findall('a[0-z]b','a@b aab aAb aWb aqba1b')) 
		#['a@b', 'aab', 'aAb', 'aWb', 'aqb', 'a1b']

	print(re.findall('a[0-9][*#/]b','a1/b a2b a29b a56b a456b')) 
		#['a1/b']



	#在字符组中 , ^ 代表除了什么什么, 放到字符组的左边第一个位置
	print(re.findall('a[^-+*/]b',"a%b ccaa*bda&bd"))
		#['a%b', 'a&b']


	#如果想要匹配^或者 - ,就在原来字符前面加上\,让字符的含义失效
	lst = re.findall(r"a[\^\-]b","a^b  a-b")
	print(lst)	#['a^b', 'a-b']


	#匹配 \号
	lst = re.findall(r"a[\\]b",r"a\b  a-b  ")
	print(lst)	#['a\\b']
	#\b 代表转义字符  backspace  要在字符串前面加上r

正则表达式 , 多个字符的匹配

import re 
#量词练习
	#1. ? 匹配0个或1个
	print(re.findall("a?s","asaasssssaass"))
		#['as', 'as', 's', 's', 's', 's', 'as', 's']

	#2. + 匹配1个或多个
	print(re.findall("a+s","asaasssssaass"))
		#['as', 'aas', 'aas']

	#3. *匹配0个或多个
	print(re.findall("a*s","asaasssssaass"))
		#['as', 'aas', 's', 's', 's', 's', 'aas', 's']

	#4. {m,n} 匹配m个到n个  1 <= x <= 3 左闭右闭
	print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb'))
		#['aaab', 'ab', 'aab', 'ab', 'aab']
	print(re.findall('a{2}b','aaab ab aab abbb aaz aabb'))
		#前面修饰的a 必须是两个字符
		#['aab', 'aab', 'aab']
	print(re.findall('a{2,}b','aaab ab aab abbb aaz aabb'))
		#前面修饰的a 至少是两个字符
		#['aaab', 'aab', 'aab']

贪婪模式 与 非贪婪模式

贪婪模式 :   默认向更多次匹配 , 底层用的是回溯算法
非贪婪模式 : 默认向更少次匹配 , 用一个? 号来进行修饰, (修饰在量词的身后)

回溯算法 : 从左向右进行匹配,一直到最后 , 直接最后再也匹配不到,回头,寻找最后一个

 . 匹配任意字符, 除了换行符 \n

strvar = "刘能和刘老根和刘铁棍子777子888"
lst = re.findall("刘.",strvar)
print(lst)	#['刘能', '刘老', '刘铁']


#贪婪模式
lst = re.findall("刘.?",strvar)
print(lst)	#['刘能', '刘老', '刘铁']

lst = re.findall("刘.+",strvar)
print(lst)	#['刘能和刘老根和刘铁棍子777子888']

lst = re.findall("刘.*",strvar)
print(lst)	#['刘能和刘老根和刘铁棍子777子888']

lst = re.findall("刘.{0,11}",strvar)
print(lst)	#['刘能和刘老根和刘铁棍子7']

lst = re.findall("刘.*子",strvar)
print(lst)	#['刘能和刘老根和刘铁棍子777子']



#非贪婪模式
lst = re.findall("刘.??",strvar)
print(lst)	#['刘', '刘', '刘']

lst = re.findall("刘.+?",strvar)
print(lst)	#['刘能', '刘老', '刘铁']

lst = re.findall("刘.*?",strvar)
print(lst)	#['刘', '刘', '刘']

lst = re.findall("刘.{0.11}?",strvar)
print(lst)	#['刘', '刘', '刘']

lst = re.findall("刘.*?子",strvar)
print(lst)	#['刘能和刘老根和刘铁棍子']

边界符 \b ^ $

\b backspace 本身就是一个转义字符

边界符  卡单词 比如word
	卡住左边界 \bw
	卡住右边界 d\b


strvar = "word pwd scf"
lst = re.findall(r".*d\b",strvar)
print(lst)	#['word pwd']


lst = re.findall(r".*?d\b",strvar)
print(lst)	#['word', ' pwd']

lst = re.findall(r"\bw",strvar)
print(lst)	#['w']

lst = re.findall(r"\bw.*?",strvar)
print(lst)	#['w']

#正则表达式中写字符时, 要谨慎, 下面例子必须匹配到第一个空格时,才会结束
lst = re.findall(r"\bw.*? ",strvar)
print(lst)	#['word ']

lst = re.findall(r"\bw\S*",strvar)
print(lst)	#['word']


# ^ $
	^ 必须以..开头
	$ 必须以..结尾
	如果出现了 ^ .. $  , 那么要将这个字符串看成一个整体
	
	strvar = "大哥大嫂大爷"
	print(re.findall('大.',strvar))
	#['大哥', '大嫂', '大爷']
	
	print(re.findall('^大.',strvar))
	#['大哥']
	
	print(re.findall('大.$',strvar))
	#['大爷']
	
	print(re.findall('^大.$',strvar))
	#[]
	
	print(re.findall('^大.*?$',strvar))
	#['大哥大嫂大爷']
	
	print(re.findall('^大.*?大$',strvar))
	#[]
	
	print(re.findall('^大.*?爷$',strvar))
	#['大哥大嫂大爷']
	

	print(re.findall('^g.*? ' , 'giveme 1gfive gay'))
	#['giveme ']
	
	print(re.findall('five$' , 'aassfive'))
	#['five']
	
	print(re.findall('^giveme$' , 'giveme'))
	#['giveme']
	
	print(re.findall('^giveme$' , 'giveme giveme'))
	#[]
	
	print(re.findall('giveme' , 'giveme giveme'))
	#['giveme', 'giveme']
	
	print(re.findall("^g.*e",'giveme 1gfive gay'))
	#['giveme 1gfive']

正则表达式 匹配分组

import re 
#1. 分组练习 (用圆括号)  要所有的姓名
	
	print(re.findall('.*?_good','wusir_good alex_good secret男_good'))
	#['wusir_good', ' alex_good', ' secret男_good']


	#显示括号里面匹配到的内容
	print(re.findall('(.*?)_good','wusir_good alex_good secret男_good'))
	#['wusir', ' alex', ' secret男']

	#不显示括号里面的内容
	print(re.findall('(?:.*?)_good','wusir_good alex_good secret男_good'))
	#['wusir_good', ' alex_good', ' secret男_good']

| 代表 或 , a|b 匹配字符 a 或者 匹配字符b

#基本语法
strvar = "abcddd"
lst = re.findall("a|b",strvar)
print(lst)	#['a', 'b']

#要注意的问题
	匹配abc 或 abcd
	为了避免优先匹配前面的字符串, 导致字符串匹配不完整
	把较难匹配到的字符串写在前面, 容易匹配到的字符串放在后面
	
	strvar = "abc24234234ddabcd234234"
	# lst = re.findall(r"abc|abcd",strvar)
	# print(lst)	#['abc', 'abc']
	lst = re.findall(r"abcd|abc",strvar)
	print(lst)	#['abc', 'abcd']

练习

.  除了\n 能够匹配到任意字符
\  功效: 能让有意义的字符变得无意义,让无意义的字符变得有意义
\. 让点原来的特殊含义失效, 只是单纯的表达一个字符 点.

#匹配小数
strvar = "1.11  1.2  2. 11 22 33 .2  3.4444  asd.asd   44.55"
lst = re.findall(r"\d+\.\d+",strvar)
print(lst)	#['1.11', '1.2', '3.4444', '44.55']



#匹配小数和整数

整数(\d+)
小数(\d+\.\d+)

lst = re.findall(r"\d+\.\d+|\d+",strvar)
print(lst)	#['1.11', '1.2', '2', '11', '22', '33', '2', '3.4444', '44.55']



#用分组形式来做

findall 这个函数优先显示括号里面的内容
如果不想显示括号内容,使用?: 显示实际匹配到的内容
lst = re.findall(r"\d+(?:\.\d+)?",strvar)
print(lst)



#匹配135或171的手机号
strvar = "135asdfasdf1351111 13511110000aaa 171  234 1714444999 17100009999"
lst = re.findall(r"(135|171)\d{8}",strvar)
print(lst)	#['13511110000', '17100009999']

卡住开头和结尾 , 数字必须是11位
strvar = "13591199444"
lst = refindall(r"^(?:135|171)[0-9]{8}$",strvar)
print(lst)	#['13591199444']

search 函数

findall 把所有匹配到的字符串都搜出来,返回列表
		不能把分组内容和匹配内容都显示出来

search  只要搜索到一个结果就返回 , 返回对象
		可以把分组内容和匹配的内容同时显示出来

group : 对象.group()  直接获取匹配到的内容
groups: 对象.groups() 直接获取分组里面的内容

匹配www.baidu.com 或者 www.oldboy.com
strvar = "www.baidu.com www.oldboy.com"
lst = re.findall("(?:www)\.(?:baidu|oldboy)\.(?:com)", strvar)
print(lst)

obj = re.search("(www)\.(baidu|oldboy)\.(com)",strvar)
print(obj)	#<_sre.SRE_Match object; span=(0, 13), match='www.baidu.com'>
#获取的是匹配到的数据
print(obj.group())	#www.baidu.com

#获取的是分组里面的数据
print(obj.groups())	#('www', 'baidu', 'com')

	#获取第一个小括号里面的内容
	print(obj.group(1))	#www
	
	#获取第二个小括号里面的内容
	print(obj.group(2))	#baidu
	
	#获取第三个小括号里面的内容
	print(obj.group(3))	#com

案例 : "56-7/3" 匹配 56 或者 7/3

search函数 在匹配不到时, 返回的是None , 无法使用group

strvar = "5*6-7/3"
#匹配出 5*6
obj = re.search(r"\d+[*/]\d+",strvar)
print(obj)	#<_sre.SRE_Match object; span=(0, 3), match='5*6'>
str1 = obj.group()
print(str1)	#5*6


#按照*号分隔 算出乘积结果
n1,n2 = str1.split("*")
res1 = int(n1)*int(n2)
print(res1)	#30


#对字符串进行替换
str2 = strvar.replace(str1,str(res1))
print(str2)	#30-7/3


#匹配出7/3
obj = re.search(r"\d+[*/]\d+",str2)
print(obj)	#<_sre.SRE_Match object; span=(3, 6), match='7/3'>
str3 = obj.group()
print(str3)	#7/3

#按照除号分割 , 算出除法结果
n3,n4 = str3.split("/")
res2 = int(n3)/int(n4)
print(res2)	#2.3333333333333335


#对字符串进行替换
str4 = str2.replace(str3,str(res2))
print(str4)	#30-2.3333333333333335

#通过-号进行最后的分割,算出最后的结果
n5,n6 = str4.split("-")
res3 = float(n5)-float(n6)
print(res3)	#27.666666666666668

正则表达式 , 命名分组

import re 

strvar = "
明天就放假了,很开心
" #当不清楚字符串中含有什么内容时,用.*?进行取代 lst = re.findall(r"<(.*?)>(.*?)<(.*?)>",strvar) print(lst) #[('div', '明天就放假了,很开心', '/div')] #反向引用 #\1 代表反向引用 , 将第一个括号匹配到的字符串,在\1位置处再引用一次 lst = re.findall(r"<(.*?)(.*?)(/\1)>",strvar) print(lst) #[('div', '>明天就放假了,很开心<', '/div')] #\1 代表第一个括号 \2代表第二个括号 strvar = "a1b2cab" obj = re.search(r"(.*?)\d(.*?)\d(.*?)\1\2",strvar) print(obj) #<_sre.SRE_Match object; span=(0, 7), match='a1b2cab'> #返回匹配到的字符串 res = obj.group() print(res) #a1b2cab #返回匹配到的分组内容 res = obj.groups() print(res) #('a', 'b', 'c') #命名分组 命名分组 (给小组命名) (?P<组名>正则表达式) 给这个组起一个名字 (?p=组名) 引用之前组的名字 , 把该组名匹配到的内容放到当前位置 #方法一 strvar = "a1b2cabc" obj = re.search(r"(?P.*?)\d(?P.*?)\d(?P.*?)\1\2\3",strvar) print(obj.group()) #a1b2cabc #方法二 strvar = "a1b2cabc" obj = re.search(r"(?P.*?)\d(?P.*?)\d(?P.*?)(?P=tag1)(?P=tag2)(?P=tag3)",strvar) print(obj.group()) #a1b2cabc

正则函数

#search 通过正则匹配出第一个对象返回,通过group取出对象中的值
	strvar = "1-2 3*4"
	obj = re.search("\d+(.*?)\d+",strvar)
	#返回匹配到的内容(匹配到一个就返回)
	print(obj.group())	#1-2
	#把括号里面匹配到的内容扔到元组中返回
	res = obj.groups()
	print(res)	#('-',)


#match 验证用户输入内容
	search 只要在正则表达式前面加上 ^ 就和match一摸一样
	strvar = "z18235608990"
	strvar = "18235608990"
	obj = re.match("\d+",strvar)
	print(obj.group())
	
	obj = re.search("^\d+",strvar)
	print(obj.group())


#split 切割
	strvar = "aaa1bbb2ccc3"
	res = re.split("[123]",strvar)
	print(res)	#['aaa', 'bbb', 'ccc', '']

	res = re.split("\d",strvar)
	print(res)	#['aaa', 'bbb', 'ccc', '']



#sub 替换 (正则表达式,替换的字符串,原字符串,[可选替换次数])
	strvar = "aaa111bbb222ccc333"
	res = re.sub("[abc]", "[123]", strvar)
	print(res)	#[123][123][123]111[123][123][123]222[123][123][123]333
	

	res = re.sub("[abc]","[123]",strvar,1)
	print(res)	#[123]aa111bbb222ccc333


	#subn 替换与sub用法一样,区别在于返回值不同,返回的是元组
	res = re.subn("[abc]", "[123]", strvar)
	print(res)	#('[123][123][123]111[123][123][123]222[123][123][123]333', 9)

	res = re.subn("[abc]","[123]",strvar,1)
	print(res)	#('[123]aa111bbb222ccc333', 1)



#finditer 匹配字符串中相应内容 , 返回迭代器
	from collecthons import Iterator
	strvar = "a1b2c3d4"
	it = re.finditer(r"\d+",strvar)
	#判断是否是迭代器
	print(isinstance(it,Iterator))	#True
	#强转成列表获取数据
	print(list(it))
	#[<_sre.SRE_Match object; span=(1, 2), match='1'>,
	#<_sre.SRE_Match object; span=(3, 4), match='2'>,
	#<_sre.SRE_Match object; span=(5, 6), match='3'>,
	#<_sre.SRE_Match object; span=(7, 8), match='4'>]
	
	#遍历数据
	for i in it:
		print(i.group())
		#1
		#2
		#3
		#4


#compile 指定一个统一的匹配规则

	正常情况下,正则表达式执行一次,编译一次
	如果需要反复使用,会浪费系统资源,比如内存,cpu
	
	complie可以使正则编译一次,终身受益,无需反复编译
	
	strvar = "a1b2c3d4z5"
	pattern = re.complie("[a-z]")
	print(pattern)	#re.compile('[a-z]')

	obj = pattern.search(strvar)
	print(obj.group())	#a

	lst = pattern.findall(strvar)
	print(lst)	#['a', 'b', 'c', 'd', 'z']


#修饰符
	
	#re.I 使匹配对大小写不敏感
	strvar = "aBcD"
	pattern = re.compile("ABCD",flags=re.I)
	obj = pattern.search(strvar)
	print(obj)	#<_sre.SRE_Match object; span=(0, 4), match='aBcD'>
	print(obj.group())	#aBcD


	#re.M 使每一行都能够单独匹配(多行匹配) , 影响^ 和 $
	strvar = '''ASD
	123
	asd
	'''
	pattern = re.compile(r"^[0-9a-zA-Z]*$", flags=re.M)
	print(pattern.findall(strvar))	#['ASD', '123', 'asd', '']


	#re.S 使.匹配包括换行在内的所有字符
	strvar = '''ASD
	123
	asd
	'''
	pattern = re.compile("(.*?)\d+(.*?)", flags=re.S)
	obj = pattern.search(strvar)
	print(obj)	#<_sre.SRE_Match object; span=(0, 7), match='ASD\n123'>	
	print(obj.group())	#ASD
						#123

oop 面向对象程序开发

#类的定义
	class Car:
		pass
	
	class Car():
		pass
	
	class Car(object):
		pass



#类的实例化
	class Car():
		pass
	obj = Car()



#类的基本结构
	类中只有两种成员
	1.成员属性
	2.成员方法
	
	class Car():
		#成员属性 : 
		color = "原谅色的"
		#成员方法 : 
		def func():
			print("会变形")


#反例
	类中的代码可以直接执行,但是严禁使用,不要直接把代码裸露在类中
	应该把相应的逻辑放在成员方法当中处理
	class Car():
		print("zzz")
	
	#正确的方法
	class Car():
		def func():
			print("zzz")


#类的命名
	类的命名推荐使用大驼峰命名法
	dapao => DaPao

面向对象 oop 封装

#类中封装
	成员属性
	成员方法

#封装等级
	1.公有 : 公有成员既能够在类外调用,也可以在类内调用
	2.私有 : 私有成员不能够在类外调用,可以在类内调用

#调用语法
	对象.属性
	对象.方法

#类中的绑定方法 (方法在类的内部)
	1.绑定到对象 (对象调用方法时,系统自动把该对象当成参数进行传递)
	2.绑定到类   (对象或者类调用方法时,系统自动把该类当成参数进行传递)


class MyCar():
	#公有成员属性
	color = "黑色"
	#私有成员属性
	__logo = "特斯拉"
	
#公有成员方法
def show(self):
	print("公开的秘密")
#私有成员方法
def __mimi():
	print("没有人知道")


#类的实例化
obj = MyCar()

#对象的相关操作

#实例化的对象访问公有成员属性和方法
	#调用属性
	print(obj.color)	#黑色

	#调用方法
	对象调用方法时, 系统会自动把该对象当成参数传递到该方法中
	为了保证形参实参一一对应,在定义方法的时候,要加形参self,这个方法也叫绑定方法

	obj.show()	#公开的秘密


	#调用私有成员
	obj.__mimi()	#AttributeError: 'MyCar' object has no attribute '__mimi'




#实例化的对象动态添加公有成员属性和方法
	#添加成员属性
	obj.color = "白色"
	obj.ming = "zzz"
	#__dict__查看对象或者类当中的成员,返回一个字典
	print(obj.__dict__)	#{'color': '白色', 'ming': 'zzz'}
	print(obj.color)	#白色
	print(obj.ming)	#zzz
	obj.drive()	#公开的秘密

#添加成员方法

#动态添加无参方法
	def laogun():
		print("老滚")
	#对象.属性(自定义) = 方法
	obj.laogun = laogun
	obj.laogun()	#老滚


#动态添加有参方法
	
	#基础版
		def wushi(name):
			print("猎魔人{}".format(name))
		#对象.属性(自定义) = 方法
		obj.wushi = wushi
		obj.wushi("杰洛特")	#猎魔人杰洛特



	#升级版
		def fallout(obj,name):
			print("{}的{}捡垃圾不找儿子".format(obj.ming,name))
		#对象.属性(自定义) = 方法
			obj.fallout = fallout
			obj.fallout(obj,"老冰棍")	#zzz的老冰棍捡垃圾不找儿子



	#高级版(创建一个绑定方法,自动传递obj对象,) 在类外,让系统自动帮助传递obj这个对象参数
		import types
		
		def hlnt(self,name):
			print("你是{},你是{}".format(self.color,name))
		#通过MethodType 来创建一个绑定方法,自动传递obj对象
		#types.MethodType(函数,对象) 当调用方法时,自动把对象当成参数传递给该方法
		obj.hlnt = types.MethodType(hlnt,obj)
		obj.hlnt("空洞骑士")	#你是白色,你是空洞骑士



#动态添加lambda 匿名函数
obj.qirisha = lambda :print("血月降至")
obj.qirisha()	#血月降至
print(obj.__dict__)

类的相关操作

class MyGame():
	#公有成员属性
	num = 5
	#私有成员属性
	__name = "fallout4"
	
	#公有无参方法
	def like():
		print("辐射4")
	
	#私有无参方法
	def __mimi():
		print("7DaysToDie")


#实例化对象
obj = MyGame()
obj.like()	#error


#类的相关操作

	#定义的类访问公有成员属性和方法
		print(MyGame.num)	#5
		print(MyGame.__name)	#error
		MyGame.like()	#辐射4



	#定义的类动态添加公有成员属性和方法
		
		#添加公有成员属性
		MyGame.year = 10
		print(MyGame.__dict__)

		#添加公有成员方法
			
			
			
			#动态添加公有无参方法
			def flag():
				print("我不会再玩游戏")
			#类.成员(自定义名字) = 方法
			MyGame.flag = flag
			MyGame.flag()	#我不会再玩游戏



			#动态添加公有有参方法
			def noflag(qirisha):
				print("{}除外".format(qirisha))
			MyGame.noflag = noflag
			MyGame.noflag("七日杀")	#七日杀除外



			#动态添加lambda表达式
			MyGame.fushe = lambda haiyou : print("还有{}".format(haiyou))
			MyGame.fushe("辐射4")	#还有辐射4
			
			print(MyGame.__dict__)

类和对象之间的注意点

类中的成员只归属于当前这个类本身
对象可以调用其中的公有成员,但是没有修改和删除的权力,因为都归属于类,不是对象中的成员
类无法调用对象中的相关成员,但是对象可以调用类中的相关成员

#对象调用类中成员
调用对象中的成员时,先看看自己有没有该成员
如果有,那么就先调用自己的
如果没有,那么就调用类的
obj2 = MyGame()
print(obj2.year)	#10
obj2.year = 15
print(obj2.year)	#15
print(obj2.__dict__)	#{'year': 15}


#类调用对象中的成员
print(MyGame.year)	#10

类中的私有成员

class like():
	#公有成员属性
	aihao = "低级快乐"
	#私有成员属性
	__mimi = "game"
	
	#公有绑定方法
	def fushe(slef):
		print("辐射4")
	#公有无参方法
	def wushi():
		print("巫师3")
	
	#私有绑定方法
	def __zhenxiang(self):
		print("{}永远滴神".format(slef.__mimi))
	
	#私有无参方法
	def __zhenxiang2():
		print("{}真的舒服".format(like.__mimi))

	#用pub_info调用私有成员属性
	def pub_info(self):
		print(self.__mimi)
		self.__zhenxiang()

	def pub_info2():
		print(like.__mimi)
		like.__zhenxiang2()

obj = like()
obj.fushe()	#辐射4
like.wushi()	#巫师3
print(like.__dict__)



#私有成员的改名策略 [_类名__成员名] (不推荐)
print(obj._like__mimi)	#game
print(like._like__mimi)	#game
obj._like__zhenxiang()
like._like__zhenxiang2()

#利用类内的公有方法间接调用私有成员 (推荐)
obj.pub_info()
like.pub_info2()

删除相关成员

#实例化的对象删除公有成员属性和方法
	obj.aihao = "python"
	print(obj.__dict__)	#{'aihao': 'python'}
	
	#删除属性
		del obj.aihao
		print(obj.__dict__)	#{}

		#如果对象有该成员,先调用自己的,没有的话,调用类的,如果都没有,报错
		print(obj.aihao)	#低级快乐


	#删除方法
	obj.func = lambda : print("替罪羊")
	obj.func()	#替罪羊
	like.func()	#error
	del obj.func
	obj.func()	#error



#定义的类删除公有成员属性和方法
	#删除属性
		del like.aihao
		print(like.aihao)	#error
		obj.aihao	#当对象和类中都没有就会报错


	#删除方法
		del like.fushe
		obj.fushe()	#error


	#注意点
		obj.fushe = lambda : print("23333")
		del like.fushe	#没有意义
		del obj.fushe
		obj.fushe()

魔术方法

#__init__魔术方法 (构造方法)
	触发时机 : 实例化对象,初始化的时候触发
	功能 : 为对象添加成员
	参数 : 参数不固定,至少一个self参数
	返回值 : 无

	#基本语法
		class MyGame():
			def __init__(self):
				print(11)
				self.flag = "战争从未改变"
				print(22)
		#实例化对象 
		print(33)
		obj = MyGame()
		print(44)
		print(obj.flag)
		print(55)


	#带有多个参数的构造方法
		class MyGame():
			def __init__(self,name):
			#对象.成员属性(自定义) = 参数值
				self.name = name
		#实例化 (如果构造方法里面含有额外参数,在实例化时,需要传参)
		obj = MyGame("七日杀")
		print(obj.name)	#七日杀



	#类可以是1个,对象可以是多个,可以通过一个类实例化多个不同的对象
		每创建一个对象,都会单独占用一个空间,创建的越多,占用的空间就越大

		class MyGame():
			def __init__(self,name,year):
				self.name = name
				self.year = year
			
			def laogun(self):
				print("上古卷轴5")
			
			def fallout(self):
				print("辐射4")
			
			def __qirisha(self):
				print("七日杀")
			
			def pub_func(self):
				print("这个游戏叫{},我玩了{}年".format(self.name,self.year))
			#注意点
			def pub_func2(self,name,year):
				print("这个游戏叫{},我玩了{}年".format(name,year))



		#创建第一个对象
		lg = MyGame("上古卷轴","3")
		lg.laogun()	#上古卷轴5
		lg.pub_func()	#这个游戏叫上古卷轴,我玩了3年

		#创建第二个对象
		fs = MyGame("辐射4","2")
		fs.fallout()	#辐射4
		fs.pub_func()	#这个游戏叫辐射4,我玩了2年


		#注意点
		fs.pub_func2("空洞骑士","2")	#这个游戏叫空洞骑士,我玩了2年

继承 : 一个类除了自身所拥有的属性方法之外,还获取了另外一个类的成员属性和方法

一个类继承另外一个类,那么该类就是字类(衍生类),被继承的这个类叫做父类(基类,超类)

继承:
	单继承
	多继承

python所有的类都默认继承父类 object



#单继承
	class Human(object):
		eat = "生冷的"
		chuan = "树叶"
		
		def house(self):
			print("山洞")
		def __sex(self):
			print("公开")
	
	#子父继承之后,子类可以调用父类所有的公有成员
	class Man(Human):	#class Man(父类)
		pass

	obj = Man() # Man(构造方法的参数)
	print(obj.eat)	#生冷的


	#子父继承之后,子类不可以调用父类的私有成员
	class Woman(Human):
		def pub_info(self):
			self.__sex()
	obj = Woman()
	print(obj.house)	#山洞
	obj.__sex()	#error
	obj.pub_info()	#error
	

	#子父继承之后,子类可以重写父类的同名方法
	
	子父继承之后,
	如果子类里面有该成员属性方法,优先调用自己的
	如果没有该成员,name调用父类的公有成员
	如果都没有,直接报错
	class Children(Human):
		eat = "奶奶"
		def house(self):
			print("裹在羊皮里")
	
	obj = Children()
	print(obj.eat)	#奶奶
	obj.house()	#裹在羊皮里

多继承

#基本语法
	class School():
		live = "骄奢淫逸"
		def hobby(self):
			print("被水淹没不知所措")
	
	class Now():
		live = "真的在学习?"
		def shenghuo(self):
			print("发抛")

	class Dream(School,Now):
		pass

	#实例化对象
	obj = Dream()
	print(obj.live)	#骄奢淫逸
	obj.shenghuo()	#发抛




#super 用法
	#1.super本身是一个类, super()是一个对象, 用于调用父类的绑定方法
	#2.super() 只应用在绑定方法中, 默认自动传递self对象 (前提: super所在作用域存在self)
	#3.super用途: 解决复杂的多继承调用顺序
	
	
	class School():
		live = "骄奢淫逸"
		def hobby(self):
			print("被水淹没不知所措")
	
	class Now():
		live = "真的在学习?"
		def shenghuo():
			print("发抛")

	class Dream(School,Now):
		live = "你想要的你知道"

		#利用类来调用父类的成员
		def flag1(self):
			print(School.live)
			Now.shenghuo()	#用类调用不需要self
		
		#利用对象调用父类的属性和方法
		#self 在调用父类成员的时候,如果本类里有,先调用自己的,没有再调用父类的
		def flag2(self):
			self.hobby()
			print(self.live)
	
		#利用super调用父类的属性和方法
		#super()只调用父类相关的公有成员,不会调用自己本类中成员,父类也没有的话,直接报错
		#super()特指只调用父类,和self不同
		def flag3(self):
			print(super())
			print(super().live)
			super().shenghuo()	#error  但是super().hobby()可以
			#注意点 : super()调用方法时,必须是绑定方法, 默认传递该类的对象
		
	
	obj = Dream()
	obj.flag1()	#骄奢淫逸 \n 发抛
	obj.flag2()	#被水淹没不知所措 \n 你想要的你知道
	obj.flag3()	#, >  \n 骄奢淫逸 \n 被水淹没不知所措

菱形继承

class Quan():
	pass


class Jian():
	a = 4
	def ceshi(self):
		print("1")
		print(self.a)	#最后添加一个打印
		print("2")

class Bian1(Jian):
	a = 3
	def ceshi(self):
		print("3")
		super().ceshi()#第三次添加
		print("4")

class Bian2(Jian):
	a = 2
	def ceshi(self):
		print("5")
		super().ceshi()#第二次添加
		print("6")

class Xia(Bian1,Bian2):
	a = 1
	def ceshi(self):
		print("7")
		super().ceshi()#第一次添加
		print("8")

obj = Xia()
obj.ceshi()	# 什么都不加 7 8
obj.ceshi() # 第一次打印出 7 3 4 8
obj.ceshi() # 第二次没有变化
obj.ceshi() # 第三次打印出 7 3 5 1 2 6 4 8
obj.ceshi()	# 最后一次打印出 7 3 5 1 1 2 6 4 8
#super() 调用方法时,会携带着当前类的对象进行传递
#因此不管运行到哪个类中,都是a=1

mro 列表 : super用途的体现,解决复杂的多继承调用顺序

类.mro() 返回的是方法调用顺序的列表,针对于多继承下的同名方法,按照列表的顺序依次调用

lst = Xia.mro()
print(lst)
#[, , , , ][, , , , ]


#issubclass 判断是否存在子父关系,(语法使用与isinstance的使用一摸一样)
只要在一个继承链上即可(有血缘关系即可),应用范围在类的身上

	res = issubclass(Xia,Bian1)	#True
	res = issubclass(Xia,Bian2)	#True
	res = issubclass(Xia,Jian)	#True
	res = issubclass(Xia,Quan)	#False
	res = issubclass(Xia,(Jian,Bian1,Bian2,Quan))	#True 一真则真
	print(res)



#isinstance 判断类型
只要在一个继承链上即可,有血缘关系即可,是在判断对象和类之间的关系

	res = isinstance(obj,Xia)
	res = isinstance(obj,Bian1)
	res = isinstance(obj,Bian2)
	res = isinstance(obj,Jian)
	res = isinstance(obj,Quan)	#False
	print(res)

print(Xia.__dict__)
#{'__module__': '__main__', 'a': 1, 'ceshi': , '__doc__': None}

#in 判断在或者不在 , 在=>True  不在=>False
res = "ceshi" in Xia.__dict__
print(res)	#True

多态 : 不同的子类对象,调用相同的父类方法 , 产生了不同的执行结果

关键字 : 继承 改写


class LOL():
	def Q():
		pass
	def R():
		pass

class VN(LOL):
	def Q(self):
		print("[薇恩]发动闪避突袭")
	def R(self):
		print("[薇恩]开启终极时刻")

class PS(LOL):
	def Q(self):
		print("[潘森]投掷长矛")
	def R(self):
		print("[潘森]发动大荒星陨")

class ABM(LOL):
	def Q(self):
		print("我是[卢锡安],我来取你们的小命")
	def R(self):
		print("[卢锡安]发动圣枪洗礼")


#实例化三个英雄

vn = VN()
ps = PS()
abm = ABM()

#放入列表等待调用
lst = [vn,ps,abm]

#所有英雄放q
#所有英雄放R
#ps大招进场,其他人甩q
#不玩了


sign = True
while sign:
	num = input("碾碎他们! : ")
	for i in lst:
		if num == "1":
			i.Q()
		elif num == "2":
			i.R()
		elif num == "3":
			# 判断对象和类的关系
			if isinstance(i, PS):
				i.R()
			else:
				i.Q()
		elif num.upper() == "Q":
			print("/FF")
			sign = False
			break

		else:
			print("信息可用0/5")
			break

new 魔术方法

触发时机 : 实例化类生成对象的时候触发(触发时机在__init__之前)
功能 : 控制对象的创建过程
参数 : 至少一个cls接受当前的类,其他根据情况决定
返回值 : 通常返回对象或None


#基本语法
	class Myclass():
		a=1
	
	obj = Myclass()
	print(obj)	#<__main__.Myclass object at 0x00000189A1CCAC88>



	class Myclass1():
		def __new__(cls):
			print(cls)			# 是当前这个类
			#借助父类object = 类.方法(cls)
			#obj = object.__new__(cls)
			#return obj			#<__main__.Myclass1 object at 0x00000195D7D4AAC8>   返回了一个本类的对象
			#
			#返回其他类的对象 , 返回Myclass的对象
			#return obj		#<__main__.Myclass object at 0x000002710B56AD30>  返回的是上面Myclass的对象
			
			#不返回任何对象
			return None
	obj = Myclass1()
	print(obj)
	#print(obj.a)	#1  因为返回其他类对象,可以调用其属性和方法




#new方法的触发时机要快于init

	__new__ 用来创建对象
	__init__ 用来初始化对象(前提得有对象)
	先创建对象,再去初始化对象,所以new快于init

	class Myclass():
		def __init__(self):
			print(2)
		def __new__(cls):
			print(1)
			return object.__new__(cls)

	obj = Myclass()	# 1 2 说明new 快于 init



#new方法的参数要和init方法参数一一对应
	#一个参数
	class Myclass():
		def __new__(cls,name):
			return object.__new__(cls)
		
		def __init__(self,name):
			self.name = name
	
	obj = Myclass("大炮")
	print(obj.name)	#大炮


	#多个参数
	class Myclass():
		def __new__(cls,*args,**kwargs):
			return object.__new__(cls)
		
		def __init__(self,name,a,b,c,d):
			self.name = name

	obj = Myclass("大炮",1,2,3,4)
	print(obj.name)	#大炮



	#注意点
	如果返回的不是本类的对象,不会触发__init__构造方法
	class Myclass():
		a=1
	obj = Myclass()
	
	class Myclass1():
		def __new__(cls):
			return obj
		
		def __init__(self):
			print("111")
	obj1 = Myclass()

单态(例)模式 : 无论实例化多少次,都有且只有一个对象

目的意义:
为了节省内存空间,仅仅是为了调用类中的成员
不需要额外给该对象添加任何成员,这个场景,使用单态
比如: 操作数据库的增删改查这样的类,是不需要的

#基本语法
class Myclass():
	__obj = None
	def __new__(cls):
		if cls.__obj is None:
			cls.__obj = object.__new__(cls)
		return cls.__obj
'''
如果有这个对象就直接返回,如果没有就创建一个,保证只有一个
第一次实例化判断条件为真,说明没有该对象,
因此创建一个对象放入cls.__obj并返回
之后判断都不成立直接返回第一次创建的对象
<__main__.Myclass object at 0x000001F5DF58AE48>
<__main__.Myclass object at 0x000001F5DF58AE48>
<__main__.Myclass object at 0x000001F5DF58AE48>
<__main__.Myclass object at 0x000001F5DF58AE48>
'''

obj1 = Myclass()
print(obj1)
obj2 = Myclass()
print(obj2)
obj3 = Myclass()
print(obj3)
obj4 = Myclass()
print(obj4)



#单态模式 + 构造方法
class Myclass():
	__obj = None
	def __new__(cls,*args,**kwargs):
		if cls.__obj is None:
			cls.__obj = object.__new__(cls)
		return cls.__obj
	
	def __init__(self,name):
		self.name = name


obj1 = Myclass("大炮")
obj2 = Myclass("dapao")
print(obj1.name)
print(obj2.name)

'''
obj1 和 obj2 都是同时指向同一个对象,因为对象只创建了一个
对象.name  是获取后边dapao那个值,是同一个值打印了2次;
'''

连贯操作

通过.不停的调用下一个对象的操作就是连贯操作

#案例1
class A():
	a = 1
class B():
	def __init__(self,obj):
		self.b = obj
obj1 = A()
obj2 = B(obj1)
print(obj2.b.a)



#案例2
class A():
	a = 1
	def func1(self):
		print("zzz")
class B():
	def __init__(self,obj):
		self.b = obj
class C():
	def __init__(self,obj):
		self.c = obj
obj1 = A()
obj2 = B(obj1)
obj3 = C(obj2)
obj3.c.b.func1()
print(obj3.c.b.a)

小人射击

#面向对象核心思想 : 把对象作为程序的最小单元,让对象操作一切

#弹夹类 BulletBox
	#属性 : 子弹数量 bulletcount
	#方法 : 无

新建一个文件以定义弹夹类  BulletBox
class BulletBox():
	def __init__(self,bulletcount):
		self.bulletcount = bulletcount


#枪类 Gun
	#属性 : 弹夹(对象)
	#方法 : 射击 shoot

新建一个文件以定义枪类 Gun
class Gun():
def __init__(self,bulletbox):
	self.bulletbox = bulletbox

def shoot(self,shootcount):
	#通过self 调用自己的bulletbox属性 得到一个弹夹对象,再通过弹夹对象,得到子弹数量
	if self.bulletbox.bulletcount <= shootcount:
		print("弹药不足请填充")
	else:
		#开始射击  剩余子弹 = 总数量 - 射出的数量
		#	当前子弹减去要射出的子弹
		self.bulletbox.bulletcount -= shootcount
		print("哒" * shootcount , "还剩下%s颗子弹" % (self.bulletbox.bulletcount))



#人 Person
	#属性 : 枪(对象)
	#方法 : 射击,上弹

新建一个文件以定义人  Person
class Person():
	def __init__(self,gun):
		self.gun = gun

#射击
def fire(self,firecount):
	self.gun.shoot(firecount)


#上子弹
def load(self,num):
	self.gun.bulletbox.bulletcount += num
	#self.gun 调用枪对象
	#self.gun.bulletbox  调用弹夹对象
	#self.gun.bulletbox.bulletcount 调用子弹数量bulletcount属性


#将三个文件放入入口文件同级的文件夹中并引用
	from package.bulletbox import BulletBox
	from package.gun import Gun
	from package.person import Person

#创建一个弹夹
danjia = BulletBox(50)

#创建一根枪
qiang = Gun(danjia)


#创建一个人
human = Person(qiang)



#射击
if __name__ == "__main__" :

#开始
	 human.fire(1)

#上子弹
	human.load(2)

#再射击
	human.fire(3)

del 魔术方法(析构方法)

触发时机 : 当对象被内存回收的时候自动触发 (1. 页面执行完毕回收所有变量 2. 所有对象被del的时候) 
功能 : 对象使用完毕后资源回收
参数 : 一个self接受对象
返回值 : 无

class Myclass():
	a = "ohhhh"
	def __init__(self,name):
		self.name = name
	
	def __del__(self):
		print("析构方法")

#页面执行完毕回收所有变量
	obj = Myclass("大炮")
	print(obj.name)	#大炮 \n 析构方法

#所有对象被del的时候
	当一个值,没有任何变量指向或者引用,这个值才会被真正的释放
	obj1 = obj
	print(obj1 is obj)
	print("1")
	del obj
	del obj1	#当obj1被删除时,才真正没有任何资源
	print("2")
	


#模拟文件操作
#fp = open(文件,模式,编码)
#fp.read()
#fp.close()
import os
class Readfile():
	def __new__(cls,filename):
		#判断文件是否存在
		if os.path.exists(filename):
			return object.__new__(cls)
		else:
			return print("该文件不存在")

	def __init__(self,filename):
		#打开文件
		self.fp = open(filename,mode="r",encoding="utf-8")

	def Read(self):
		#读取文件
		neirong = self.fp.read()
		return neirong
	
	def __del__(self):
		self.fp.close()

obj = Readfile("zzz.txt")
print(obj)	#<__main__.Readfile object at 0x0000018EFEB9AF28>
print(obj.Read())

str 魔术方法

触发时机 : 使用print(对象)或者str(对象)的时候触发
功能 : 查看对象
参数 : 一个self接受当前对象
返回值: 必须返回字符串类型

class Myclass():
	a = "ohhhh"

	def __init__(self, b):
		self.b = b

	def __str__(self):
		return self.c()

	def c(self):
		return "属性{},__str__返回了方法c : {} ,c中打印了参数b".format(self.a,self.b)


obj = Myclass("zzz")
#触发方式一
print(obj)
#触发方式二 通过str(对象)
res = str(obj)
print(res)	#属性ohhhh,__str__返回了方法c : zzz ,c中打印了参数b

__repr__魔术方法

触发时机 : 使用repr(对象)的时候触发
功能 : 查看对象,与魔术方法__str__相似
参数 : 一个self接受当前对象
返回值 : 必须返回字符串类型


class Myclass():
	me = "我"
	def __init__(self,name):
		self.name = name
	
	def __repr__(self):
		return self.fangfa()
		
	def fangfa(self):
		return "{}叫{}".format(self.me,self.name)

obj = Myclass("大炮")
res = repr(obj)
print(res)	#我叫大炮

#在系统底层 , 如果定义了repr 将会默认赋值给str方法
# __str__ = __repr__

print(obj)	#我叫大炮
res = str(obj)
print(res)	#我叫大炮

call 魔术方法

触发时机 : 把对象当作函数调用的时候自动触发
功能 : 模拟函数化操作
参数 : 参数不固定,至少一个self参数
返回值 : 看需求

#基本用法
class Myclass():
	a = 1
	def __call__(self):
		print("call方法被触发,所以你看到了这句话")

obj = Myclass()
obj()	#call方法被触发,所以你看到了这句话

#模拟洗衣服的过程
class XYF():
	def __call__(self):
		self.step1()
		self.step2()
		self.step3()
		
	def __init__(self,one,two,three):
		self.one = one
		self.two = two
		self.three = three
		
	def step1(self):
		print("洗{}".format(self.one))

	def step2(self):
		print("洗{}".format(self.two))

	def step3(self):
		print("洗{}".format(self.three))

obj = XYF("裤衩","裤头","安全裤")
obj()	#洗裤衩 洗裤头 洗安全裤


#模拟内置方法 int
import math
class Myint():
	def delzero(self, num, sign=1):
		# 去掉左边多余的0
		strvar = num.lstrip("0")
		if strvar == "":
			return 0
		# 计算最终结果
		return eval(strvar) * sign

	def __call__(self, num):
		# 判断布尔类型
		if isinstance(num, bool):
			if num == True:
				return 1
			else:
				return 0

		# 判断是整型
		elif isinstance(num, int):
			return num

		# 判断是浮点型
		elif isinstance(num, float):
			'''
			if num >= 0 :
				return math.floor(num)
			else:
				return math.ceil(num)
			'''
			return math.floor(num) if num >= 0 else math.ceil(num)

		# 首字符是+或-  后面是纯数字字符串
		elif isinstance(num, str):
			if (num[0] == "+" or num[0] == "-") and num[1:].isdecimal():
				if num[0] == "+":
					sign = 1
				else:
					sign = -1
				return self.delzero(num[1:], sign)
			elif num.isdecimal():
				return self.delzero(num)
			else:
				print("请按照规矩来")


obj = Myint()
res = obj("-000666")
print(res)

bool

触发时机 : 使用bool(对象)的时候自动触发
功能 : 强转对象
参数 : 一个self接受当前对象
返回值 : 必须是布尔类型

类似的还有如下等等(了解):
__complex__(self)      被complex强转对象时调用
__int__(self)          被int强转对象时调用
__float__(self)        被float强转对象时调用


class Myclass():
	def __bool__(self):
		return True


obj = Myclass()
print(bool(obj))

add 魔术方法 (与之相关的__radd__ 反向加法)

触发时机 : 使用对象进行运算相加的时候自动触发
功能 : 对象运算
参数 : 二个对象参数
返回值 : 运算后的值

类似的还有如下等等(了解):
__sub__(self, other)           定义减法的行为:-
__mul__(self, other)           定义乘法的行为:
__truediv__(self, other)       定义真除法的行为:/

class Myadd():
	def __init__(self,num):
		self.num = num
	
	#对象在加号左侧时,自动触发
	def __add__(self,other):
		return self.num + other
	
	def __radd__(self,other):
		return self.num + other*3
obj = Myadd(5)
obj1 = Myadd(6)
#情况一 self接受obj other接受5 , 触发的是__add__方法
res = obj + 5
print(res)
#情况二 self接受obj  other 接受5 , 触发的是__radd__方法
res = 5 + obj
print(res)
#情况三 obj + obj1 先触发__add__ 再触发 __radd__
res = obj + obj1
print(res)

__len__魔术方法

触发时机 : 使用len(对象)的时候自动触发
功能 : 用于检测对象中或者类中成员的个数
参数 : 一个self接受当前对象
返回值 : 必须返回整型

类似的还有如下等等(了解):
__iter__(self)                 定义迭代容器中的元素的行为
__reversed__(self)             定义当被 reversed() 调用时的行为
__contains__(self, item)       定义当使用成员测试运算符(in 或 not in)时的行为


class Myclass():
	a = 1
	b = 2
	__c = 3

	def func1(self):
		pass

	def func2(self):
		pass

	def __func3(self):
		pass

	def __len__(self):
		# z = Myclass.__dict__
		# lst = []
		# for i in z:
		# 	if not (i.startswith("__") and i.endswith("__")):
		# 		lst.append(i)
		lst = [i for i in Myclass.__dict__ if not (i.startswith("__") and i.endswith("__"))]

		return len(lst)


obj = Myclass()
print(len(obj))

与类相关的魔术属性

#__dict__ 获取对象或类的内部成员结构
#__doc__  获取对象或类的内部文档
#__name__  获取类名函数名
#__class__ 获取当前对象所属的类
#__bases__ 获取一个类直接继承的所有父类,返回元组


class a():
	pass


class b():
	pass


class Fallout(a, b):
	'''zzzzzzz'''
	# 成员属性
	flag = "welcome to nukworld~"

	# 成员方法
	def __perk1(self):
		print("闪避突袭")

	def perk2(self):
		print("独行侠")

	def perk3(self):
		print("水女孩")

	def perk4(self, func):
		print("不明白")
		print(func.__name__, type(func.__name__))


obj = Fallout()

	
# __dict__ 获取对象或类的内部成员结构
print(obj.__dict__)  # 空的 因为它本身没有任何成员
print(Fallout.__dict__)

# __doc__  获取对象或类的内部文档
print(obj.__dict__)  # zzzzzzz
print(Fallout.__dict__)  # zzzzzzz

# __name__  获取类名函数名
def perk5(self):
	print("领导能力")
obj.perk4(perk5)
obj.perk4(Fallout)

#__class__ 获取当前对象所属的类
print(obj.__class__)	#


#__bases__ 获取一个类直接继承的所有父类,返回元组
print(Fallout.__bases__)	#(, )	

反射

概念 : 通过字符串去操作类对象 或者 模块当中的成员(属性方法)



class A():
	pass
class B():
	pass
class C(A,B):
	'''zzz'''
	
	a = "aaa"
	
	def zzz(self):
		print("aaaaa")
	def __zz(self):
		print("zzzzzzz")
obj = C()

#反射类对象中的成员
	
	#hasattr() 检测对象/类中是否有指定的成员
		#对象
		res = hasattr(obj,"a")
		print(res)	#True

		#类
		res = hasattr(C,"zzz")
		print(res)	#True
		res = hasattr(C,"__zz")
		print(res)	#False

	#getattr() 获取对象/类成员的值
		#对象
		func = getattr(obj,"zzz")
		func()	#aaaaa 通过对象反射出来的方法是绑定方法
		
		#类
		func = getattr(C,"zzz")
		func(1)	#aaaaa 通过类反射出来的是一个普通方法

		#当类对象中成员不存在时,可以设置默认值(第三个参数是默认参数)
		func = getattr(obj,"zzzzzz","该成员不存在")
		func()	#该成员不存在


		#综合案例
		strvar = input("请输入要调用的方法 : ")
		if hasattr(obj,strvar):
			func = getattr(obj,strvar)
			func()	#aaaaa



	#setattr() 设置对象/类成员的值
		#对象
		setattr(obj,"a","AAAAAAA")
		print(obj.a)	#AAAAAAA

		#类
		setattr(C,"bbb",lambda : print("bbbbbbb"))
		C.bbb()	#bbbbbbb
			通过这种方式添加的是一个无参普通方法,只能是类调用
	
	#delattr() 删除对象/类成员的值
		#对象
		delattr(obj,"a")
		print(obj.a)	#aaa
		
		#类
		delattr(C,"a")
		print(C.a)	#error



#反射模块中的成员
sys.modules 返回一个系统的字典,加载系统模块展现出来
import sys
print(sys.modules)
'''
{'builtins': ,
 'sys': ,
 '_frozen_importlib': ,
 '_imp': , 
 '_warnings': ,
 '_thread': , 
 '_weakref': ,
 '_frozen_importlib_external': , 
 '_io': ,
 'marshal': ,
 'nt': , 
 'winreg': , 
 'zipimport': , 
 'encodings': , 'codecs': , '_codecs': , 'encodings.aliases': , 'encodings.utf_8': , '_signal': , '__main__': , 'encodings.latin_1': , 'io': , 'abc': , '_weakrefset': , 'site': , 'os': , 'errno': , 'stat': , '_stat': , 'ntpath': , 'genericpath': , 'os.path': , '_collections_abc': , '_sitebuiltins': , 'sysconfig': , 'pickle': , 'types': , 'functools': , '_functools': , 'collections': , 'operator': , '_operator': , 'keyword': , 'heapq': , '_heapq': , 'itertools': , 'reprlib': , '_collections': , 'weakref': , 'collections.abc': , 'copyreg': , 'struct': , '_struct': , 're': , 'enum': , 'sre_compile': , '_sre': , 'sre_parse': , 'sre_constants': , '_locale': , '_compat_pickle': , '_pickle': , 'json': , 'json.decoder': , 'json.scanner': , '_json': , 'json.encoder': , 'time': , 'shutil': , 'fnmatch': , 'posixpath': , 'zlib': , 'bz2': , 'warnings': , '_compression': , 'threading': , 'traceback': , 'linecache': , 'tokenize': , 'token': , '_bz2': , 'lzma': , '_lzma': , 'zipfile': , 'importlib': , 'importlib._bootstrap': , 'importlib._bootstrap_external': , 'importlib.util': , 'importlib.abc': , 'importlib.machinery': , 'contextlib': , 'binascii': , 'tarfile': , 'copy': , 'math': }


'''

	#获取本模块的对象
	print(sys.modules["__main__"])	#
	selfmodules = sys.modules["__main__"]


	def func1():
		print("我是func1")
	def func2():
		print("我是func2")
	def func3():
		print("我是func3")


	#综合案例
	while True:
		strvar = input("请输入你要反射的方法 : ")
		if hasattr(selfmodules,strvar):
			func = getattr(selfmodules,strvar)
			func()
		elif strvar.upper() == "Q":
			break
		else:
			print("没有这个方法")

装饰器

装饰器 : 为原函数扩展新功能,用新功能去替代旧功能
作用 : 在不改变原有代码的基础上 , 实现功能上的扩展
符号 : @(语法糖)

#1.装饰器的基本用法
	def kuozhan(func):
		def newfunc():
			print("111")
			func()
			print("222")
		return newfunc
	
	def func():
		print("嘤嘤嘤")

	func = kuozhan(func)  #func = newfunc  > func() = newfunc()
	func()	#111 嘤嘤嘤 222



#2.@符号的使用
	@符号作用:
		可以自动把@符号下面的函数当成参数传递给装饰器
		把新函数进行返回,让新函数去替换旧函数,以实现功能的扩展
			# func = newfunc >> func() = newfunc()
	def kuozhan(func):
		def newfunc():
			print("333")
			func()
			print("444")
		return newfunc
	
	@kuozhan
	def func():
		print("嘤嘤嘤")

	func()	#333 嘤嘤嘤 444


#3.装饰器的嵌套
	def kuozhan1(func):
		def newfunc():
			print("111")
			func()
			print("222")
		return newfunc
	
	def kuozhan2(func):
		def newfunc():
			print("333")
			func()
			print("444")
		return newfunc
	
	@kuozhan2
	@kuozhan1
	def func():
		print("人人0")

	func()	#333 111 人人0 222 444


#4.用装饰器修饰带有参数的函数
	扩展的新功能和原函数的功能,在参数和返回值上,要保持一致性
	def kuozhan(func):
		def newfunc(my,you):
			print("111")
			func(my,you)
			print("222")
		return newfunc
	
	@kuozhan
	def func(my,you):
		print("{} and {}".format(my,you))

	func("i", "you")	#111 i and you 222


#5.用装饰器修饰带有参数返回值的函数
	def kuozhan(func):
		def newfunc(*args,**kwargs):#函数的定义处 , *号的打包操作
			print("111")
			lst = func(*args,**kwargs)	#函数的调用处, *号解包操作
			print("222")
			return lst
		return newfunc
	
	@kuozhan
	def func(*args, **kwargs):
		dic = {"a": "A", "b": "B", "c": "C"}
		'''
		lst = []
		strvar = ""
		for k,v in kwargs.items():
			if k in dic:
				strvar = dic[k] + "等于" + v
				lst.append(strvar)
		return lst
		'''
		return [dic[k] + "等于" + v for k,v in kwargs.items() if k in dic]
	res = func(a="1", b="2", c="3")
	print(res)	#111 222 ['A等于1', 'B等于2', 'C等于3']



#6.用类装饰器来拓展原函数
	class Kuozhan():
		
		def __call__(self,func):
			return self.kuozhan2(func)
			
			
		def kuozhan1(func):
			def newfunc():
				print("111")
				func()
				print("222")
			return newfunc
		
		def kuozhan2(self,func):
			def newfunc():
				print("333")
				func()
				print("444")
			return newfunc
		
		
	#方法一
	@Kuozhan.kuozhan1
	def func():
		print("彳亍")

	func()	#111 彳亍 222


	#方法二
	@Kuozhan()
	def func():
		print("彳亍")

	func()	#333 彳亍 444
	
	@Kuozhan()  => @obj<=>对象 => obj(func) <=> 把对象当成函数进行使用了,自动触发__call__魔术方法. 
	=>  把新函数newfunc 返回了  => @ 发动第二个技能,将新函数去替换旧函数, func = newfunc
	func()  <==>  newfunc()



#7.带有参数的函数装饰器
	
def other(num):
	def kuozhan(func):
		def newfunc1(self):
			print("aaa")
			res = func(self)
			print("bbb")
			return res
		
		def newfunc2(self):
			print("ccc")
			res = func(self)
			print("ddd")
			return res
		
		if num == 1:
			return newfunc1
		elif num == 2 :
			return newfunc2
		elif num == 3:
			#把方法变成属性
			return "444"
	return kuozhan

class Myclass():

	@other(1)	## outer(1) => kuozhan  ,   @kuozhan <=> kuozhan(func1) [@符号第一次发动技能] <=> func1 = newfunc1 [@符号第二次发动技能]

	def func1(self):
		print("111")
	@other(2)	# outer(2) => kuozhan  ,   @kuozhan <=> kuozhan(func2) [@符号第一次发动技能] <=> func2 = newfunc2 [@符号第二次发动技能]
	def func2(self):
		print("222")
	@other(3)
	def func3(self):
		print("333")

obj = Myclass()
obj.func1()
obj.func2()
#把方法变成属性
print(obj.func3)




#8.带有参数的类装饰器

如果参数是1,就为当前类添加成员属性和方法
如果参数是2,就把原方法run变成属性


class Kuozhan():
	A = "AAAAAAAA"
	
	def B(self):
		print("BBBBBBBBBB")
	
	def __init__(self,num):
		self.num = num
	
	def __call__(self,cls):
		if self.num == 1:
			return self.newfunc1(cls)
		elif self.num ==2:
			return self.newfunc2(cls)

	#参数为1
	def newfunc1(self,cls):
		def newfunc():
			#为当前cls这个类添加方法 和 属性
			cls.A = Kuozhan.A
			cls.B = Kuozhan.B
			return cls()	#对象
		return newfunc

	#参数为2
	def newfunc2(self,cls):
		def newfunc():
			if "go" in cls.__dict__:
				#调用类中的方法,拿到返回值
				res = cls.go()
				#把返回值重新赋值给go属性,后者覆盖前者,方法变成属性
				cls.go = res
				return cls()
		return newfunc

"""
# @obj  [@符号第一次发动技能] <=> obj(MyClass) 把对象当成函数使用了,触发__call__魔术方法
self.newfunc1(cls) <=> return newfunc 
=>  [@符号第二次发动技能]  将新函数替换旧函数 MyClass = newfunc  
obj = MyClass()  <=> newfunc() => cls() => obj对象
"""
#情况一
@Kuozhan(1)
class Myclass():
	def go():
		return "亢龙有悔"

obj = Myclass()
print(obj.A)	#AAAAAAAA
obj.B()	#BBBBBBBBBB


#情况二
@Kuozhan(2)
class Myclass():
	def go():
		return "亢龙有悔"
obj = Myclass()
print(obj.go)	#亢龙有悔


#obj = MyClass() 的解释:
	# 第一部分,定义一个类
	class Ceshi():
		c = 100
		
	obj = Ceshi()
	print(obj.c)

	# 第二部分,定义两个函数
	def func22():
		print(111)

	def func(cls):
		cls.aabbcc = 200
		obj = cls()
		return obj
		
	# 第三部分,把类当成参数传递给func,类在func函数中形成一个独立的副本
	obj = func(Ceshi)

	# 第四部分,把这个类做替换,变成函数,那么现在在全局空间的Ceshi已经变成了函数,不再是类
	Ceshi = func22

	# 第五部分,调用局部空间obj,还是可以得到原来类中的成员属性和方法;
	print(obj.c)
	print(obj.aabbcc)

面向对象中的方法

普通方法:  可以有参数,或者无参数,当成正常的函数调用
绑定方法:  (1) 绑定到对象(自动传递参数为对象) (2) 绑定到类(自动传递参数为类)
静态方法:  无论是对象还是类,都可以调用,不会默认传递任何参数


class ohh():
	a = "1"
	
	#普通方法
	def b():
		print("BBB")
		
	#绑定方法(对象)
	def c(self):
		print("CCC")

	#绑定方法(类)
	@classmethod
	def d(cls):
		print(cls)
		print("DDD")

	#静态方法
	@staticmethod
	def e(num):
		print("EEE")

obj = ohh()
#普通方法 (无参方法只能类调用)
	ohh.b()

#绑定方法(一般用对象调用)
	obj.c()	#推荐
	ohh.c(123)

#绑定方法(类)
#系统自己把类当成参数传递
	ohh.d()	#推荐
	obj.d()


#静态方法(不会默认传递任何参数,如果有参数,当成普通方法调用即可)
	obj.jump(1)
	ohh.jump(2)


#在类外,为对象添加成员方法,默认都是静态方法
	obj.func = lambda : print(1)
	obj.func()

property

property 可以把方法变成属性使用 
作用: 控制属性的获取 , 设置, 删除操作
变相的增加成员的安全性, 可以通过自定义逻辑对成员进行控制

自动触发 : 要求:是同一个名字
	获取 @property
	设置 @属性名.setter
	删除 @属性名.deleter


#方法一
	class Myclass():
		def __init__(self,name):
			self.name = name
		
		@property
		def username(self):
			return self.name

		@username.setter
		def username(self,a):
			print(123)
			val = "Zker"
			self.name = val
		
		@username.deleter
		def username(self):
			pass
			#del self.name

	obj = Myclass("DP")



	#获取属性 (自动触发获取方法 @property)
	print(obj.username)	#DP


	#设置属性 (自动触发设置方法) val形参自动接受设置的值
	obj.username = "zzz"
	print(obj.username)	#Zker


	#删除属性
	del obj.username





#方法二
class Myclass():
	def __init__(self,name):
		self.name = name
	
	#获取
	def get_username(self):
		return self.name
	
	#设置
	def set_username(self,val):
		self.name = val
	
	#删除(可拒绝)
	def del_username(self):
		del self.name

顺序必须按照  获取 -> 设置 -> 删除 的参数进行传递
username = property(get_username,set_username,del_username)

obj = Myclass("DP")

#获取
print(obj.username)	#DP

#设置
obj.username = "Zker"
print(obj.username)	#Zker
#删除
del obj.username
print(obj.username)	#error

异常处理

程序错误分为两种 : 语法错误 和 异常错误
语法错误 : 代码没有按照python规定语法去写,发明创造产生的错误
异常错误 : 在代码语法正确的前提下 , 程序报错就是异常

try ... except ... 基础语法 用于解决程序异常问题
raise 可以主动抛出异常 , 异常类可以自定义

#异常分类
IndexError                索引超出序列的范围
KeyError                  字典中查找一个不存在的关键字
NameError                 尝试访问一个不存在的变量
IndentationError          缩进错误
AttributeError            尝试访问未知的对象属性
StopIteration             迭代器没有更多的值




AssertionError			 断言语句(assert)失败
	assert断言 , 就是猜一猜后面的表达式是否正确
	如果猜对什么反应也没有,如果猜错就直接报错
	if 判定时选择执行或者不执行
	assert判定时选择报错或不报错
	
	assert 1>2
	assert 2>1
	
	if 1<2 :
		pass
	
	
	
EOFError                  用户输入文件末尾标志EOF(Ctrl+d)
FloatingPointError        浮点计算错误
GeneratorExit             generator.close()方法被调用的时候
ImportError               导入模块失败的时候
KeyboardInterrupt         用户输入中断键(Ctrl+c)
MemoryError               内存溢出(可通过删除对象释放内存)
NotImplementedError       尚未实现的方法
OSError                   操作系统产生的异常(例如打开一个不存在的文件)
OverflowError             数值运算超出最大限制
ReferenceError            弱引用(weak reference)试图访问一个已经被垃圾回收机制回收了的对象
RuntimeError              一般的运行时错误
SyntaxError               Python的语法错误
TabError                  Tab和空格混合使用
SystemError               Python编译器系统错误
SystemExit                Python编译器进程被关闭
TypeError                 不同类型间的无效操作
UnboundLocalError         访问一个未初始化的本地变量(NameError的子类)
UnicodeError              Unicode相关的错误(ValueError的子类)
UnicodeEncodeError        Unicode编码时的错误(UnicodeError的子类)
UnicodeDecodeError        Unicode解码时的错误(UnicodeError的子类)
UnicodeTranslateError     Unicode转换时的错误(UnicodeError的子类)
ValueError                传入无效的参数
ZeroDivisionError         除数为零

异常处理的基本语法

#基本语法
	try ... except ...
	把有问题的代码放到try这个代码块中
	如果出现了异常,直接执行except这个代码块
	作用 : 防止异常错误去终止程序


	try:
		a=1
		print(a)
		print(b)
	except:
		print("有异常错误")	#1 有异常错误





#带有分支条件的异常处理
	except + 异常错误类  特指在发生这类异常错误时, 要执行的分支
	try:
		#NameError
		a = 1
		print(a)
		print(b)
		
		#IndentationError
		if "1" == "1":
		print(1)
		
		#IndexError
		lst = [1,2,3]
		print(lst[3])
		
	except NameError:
		print("尝试访问一个不存在的变量")
	
	except IndentationError:
		print("缩进错误")
	
	except:
		print("有异常错误")




#处理迭代器的异常错误
	def mygen():
		yield 1
		yield 2
		return "ggggmeile"
	
	#初始化生成器函数 > 生成器
	gen = mygen()
	
	#通过try except 接受生成器函数中的返回值
	try:
		res = next(gen)
		res = next(gen)
		res = next(gen)
	except StopIteration as e:	#e 是自定义名字
		ptint("迭代器取值错误,越界")
		print(e)	#迭代器取值错误,越界  ggggmeile


	StopIteration是异常错误类
	StopIteration as e 给StopIteration这个类的对象起一个别名叫做e
	当打印对象时,会自动触发该魔术方法 , 自动接受return 的返回值






#异常处理的其他写法
	#1. try ... finally ... 不论代码是否报错 , 都必须要执行的代码放到finally中
		一报错会终止程序,后面的代码就不执行了,所有有些必须要走的代码放到finally中
		
		try:
			lst = [1,2,3]
			print(lst[3])
		finally:
			print(2)
			print(3)
			print("404found")
		print(111)	#这行代码不执行了,但是finally中的仍然执行


	#2. try ... except ...else ..
		如果try代码块中没有报错,就执行else这个分支,如果有报错,就不执行else
		
		try:
			print(1)	#正常执行结束
			
			
			print(a)	#出错了
			
			
		except:
			print("出错了")
		else:
			print("正常执行结束")




	#for / while ... else  如果遇到break异常终止了循环,不会执行else这个代码块(了解)
		for i in range(10):
			print(i)
			if i == 5:
				break	#没有break会打印else内容
		else:
			print("循环结束")

主动抛异常 raise

raise + 异常错误类 or 异常错误类对象

BaseException 所有异常类的父类(基类,超类) (子类为衍生类)
Exception 常规异常类的父类



#基本语法
	try:
		#主动抛出异常
		raise BaseException
	except BaseException:
		print("zzz")




#简写 (默认接受的都是BaseException)

	try:
		raise
	except:
		print("zzz")

自定义异常类 MyException (务必要继承父类 BaseException)

#(了解)系统底层获取行数和文件名的函数( 只有在程序异常时才能触发 ) 
	def return_errorinfo(n):
		import sys
		f = sys.exc_info()[2].tb_frame.f_back
		if n==1:		
			return str(f.f_lineno)      #返回当前行数
		elif n == 2:	
			return f.f_code.co_filename #返回文件名

#只有在抛出错误的时候,里面的行号和文件名才能获取到
def get_value(n):
	try:
		raise
	except:
		return return_errorinfo(n)



class MyException(BaseException):
	def __init__(self,num,msg,line,file):
		#错误号
		self.num = num
		#错误信息
		self.msg = msg
		#错误行数
		self.line = line
		#错误文件
		self.file = file


sex = "ladyboy"
try:
	if sex == "ladyboy":
		#raise + 异常错误类对象 => 主动抛异常
		raise MyException(404,"found",get_value(1),get_value(2))



#给MyException的类对象起别名叫做e
except MyException as e:
	#对象.属性
	print(e.num)	#404
	print(e.msg)	#found
	print(e.line)	#38
	print(e.file)	#D:/Alive I can fly/z.py

ATM小练习

day25

你可能感兴趣的:(python)