《Python基础语言 二 》— Echo版

二、Python

8. Python入门仪式

写Python程序方式1
 可以自定义python文件, 文件的后缀名是.py
 在控制台上可以通过python解释器 向计算机解释python程序
写Python程序方式2
	在控制台上 借助指令python进入到python环境中 在环境中书写程序
写Python程序方式3
	借助编辑器[Python提供的编辑器idle 或者 使用Pycharm]
向Python世界say Hello

简单而言 借助python程序输出hello world

print
	输出的时候 不同的数据 书写格式是不一样的 对应的数据类型是不一样的
		具有相同特征的鬼节为一个类型的数据

	简单的数据类型
		整型数据int --- 数据全部都是整数
		浮点型数据float --- 数据全部都是小数
		布尔类型数据bool --- True/False
		字符串类型数据str ---
			如果数据是单个或者多个字符拼在一起的 就是字符串类型
			标识是引号 不区分单双引号
			注意:要输出多个字符或者单个字符 需要使用引号包含 而不能直接使用符号
				"hello world" 正确的
				hello world 错误的
print的使用
	help帮助功能 可以查看使用的功能的方式

	 print(values, sep=' ', end='\n', file=sys.stdout, flush=False)

values:
	表示输出的数据 - 可以输出多个数据 每个数据之间使用逗号分开即可 [注意写程序所有点符号都是在英文状态下的]
		>>> print(10)
     10
     >>> print(10, 3.14)
     10 3.14
     >>> print(10,3.14,True,"hello world")
     10 3.14 True hello world
	   >>>	
sep 
	默认值是空格符号
	设置的是当输出多个数据时 每个数据之间的分隔符
	可以进行自定义
	>>> print("h","e","l","l","o")
   h e l l o
   >>> print("h","e","l","l","o",sep="")
   hello
   >>>
end
	\表示的是转义符  用于转义\后面的符号
		\n --- 把n换成了换行的意思
	默认值是换行
	作用: 执行多条输出语句时[写了多个print] 每个print输出的内容是以换行结尾的
	如果一行有多个语句[单独的一个功能], 语句之间使用分号隔开
file ----> 表示的是 默认将内容输出到控制台
	更改:将输出的内容存于到指定文件里
		前提需要打开一个文件 打开模式设置写入w的状态
			打开模式:
				r --- 读取文件 read
				w --- 写入文件 write  >
				a --- 写入文件 append >>
flush----> 输出的内容是否及时刷新	

9. 编程语言的描述

程序员需要与计算机进行交互, 进而完成对应的功能

能完成交互前提是 程序员需要使用计算机识别的语言来沟通

计算机中的数据是二进制格式的

人们制定了一种规范去和计算机进行交互, 这个规则对应的语法就是编程语言

学习编程语言 其实学习的就是语法规则

语法: 制定好的固定格式 使用这个语法直接嵌套就可以了

10. Python发展史

Python底层是通过C语言来完成 1991年正式发布的 研发者是一个荷兰人 “硅叔” 1989年

1999年 支持了网站开发 爬虫开发

2000年出现了python2.0版本

2004年出现了python2.4版本 — Django出现了

2008年出现了Python2.6

2.x中的输出的格式: print "hello world"

3.x中的输出格式: print("hello world")

2008年底的时候出现了python3.0 — 与2.x的版本完全不兼容

2010年的时候出现了2.7的版本 — 向3.0的过度

2020年不再对2.x的版本进行维护 学习的是3.x的版本

现在不要使用3.7 第二阶段Django 使用的版本1.x的版本 长久版 不兼容3.7

11. 注释

用自己的语言 来描述代码的功能使用 便于自己后期的理解

因为现在接触的代码全部都是英文的

注释的格式:

​ 单行注释 — 只能注释掉一行内容

​ 格式: #注释内容

​ 多行注释 — 三对引号[引号不区分单双]

​ 格式: ''' 注释内容 '''

建议对自己的代码多加注释

12. 变量

变量的概念:

​ 某个内容的值是变化的

小学知识 一元一次方程

​ 题目:

​ 车a在马路上以80km/h的形式速度匀速形式 问多少小时后 行驶1000km??

​ 解: 设x小时后行驶1000km

​ 80 * x = 1000

​ x = 1000/80 = 12.5

设置的x就是一个变量 根据不同的题意 x对应的内容是不同的

变量对应的数据是变化 如果想获取这个数据 不能准确的获取 但是可以通过x获得对应的值

​ 车b在马路上行驶 100km/h a行驶1000km后 b开始出发 问b多长时间追上a

​ 设y小时后 b追上a

​ 80 * x + 80 * y = 100 * y

​ 80 * 12.5 + 80 * y = 100 * y

​ 20 * y = 1000

​ y = 50

变量的作用:

存储运算过程中一些变化的数据的结果的,便于后面的其他情况的使用

在程序中对变量的解释:

​ 内存:

把他比作成高楼大厦, 分布着很多小的房间[比作成字节],数据占用的是字节,如果有多个字节,可以理解成将这个多个小房间打通称为一个地址,高楼大厦中每个房间都有字节标号[地址]

在内存中查找某个数据, 该数据对应的地址查找比较方便快捷的

​ 比如:外卖人员给你送外卖, 北京市当做内存 外卖人员通过地址定位到送货位置的

​ 变量的解释:

变量是来存放数据的,数据是在内存中开辟对应的字节数来存放的,这个数据就有一个对应的地址,把这个地址给设置给对应的接收者, 通过接收者接受到地址获取其对应的数据,这个接受者会有一个名字, 这个名字称之为变量名

这个变量名是程序员自己定义的, 程序中程序员自己定义的名字需要遵守一些规范, 这个规范称之为标识符

规范:

标识符的组成: 数字 字母  下划线
组合的时候注意事项:
	1. 自定义的名字不能以数字开头
	2. 自定义的名字不能使用Python中占用的名字[关键字] 和 备用的名字
			----> 只要python使用了 咱们就不能再使用  如果使用会将python中提供的原有意义给覆盖掉, 如果再想使用原有意义就使用不了了
	3.尽量做到见名思意
现在接触到的自定义名字有哪些??
	1.自定义python文件名
		规范:英文字母全部是小写的, 每个单词之间使用下划线隔开
			first_demo
	2.自定义变量名
		规范:英文字母全部是小写的, 每个单词之间使用下划线隔开
			max_value
	3.自定义项目的名字
		规范: 单词的每一个英文字母大写  遵守的是大驼峰
			FirstProject
在Python中声明变量的时候的注意事项:
	1. 在使用该变量之前必须先进行声明 并赋予初始值 [定义出来]
	2. 变量声明的格式:
		a.声明一个变量:
			x = 10
			或者
			x:数据类型
			x = 10
			例如:
			7变量的声明
              #1. 声明立即进行初始化
              x = 10
              print("x")
              print(x)
              '''
              在使用一个符号的时候 加引号和不加引号的区别:
                  加上引号 这个符号表示的是一个字符串类型的数据
                  不加引号 这个符号表示的是一个变量名  要使用的是他对应的数据
              '''


              #2. 声明先不赋予初始值 再使用之前赋予
              y:int
              y = 10
              print(y)
           b.声明多个变量
          		i.多个变量的值是相同的
            		x = y = z = 10
              	ii. 多个 变量的值是不同的
                	x, y, z = 10, 11, 12                      

13. 数据类型的初见

不同的特征的数据 对应者不同的数据类型

系统提供的数据类型:

  • 针对于数值的数据类型 : 整型 浮点型 复数型[很少用]

  • 布尔类型 : 用于标记状态的 成立或者不成立 只有两个值 True和False

  • 字符串类型 : 容器, 存放的多个字符,使用引号包含单个或者多个字符的

  • 列表类型 : 容器 可以存放多个变量的数据

  • 元组类型 : 容器, 也可以存放多个变量

  • 字典类型 : 容器 存放的是具有映射关系的数据 一对一的 键值对

  • 集合类型 : 容器 具有排重的作用 —> 里面的数据不能重复的

13.1 数值类型
整型
	类型名字 int
	这种类型的数据 全部都是整数

	python2.x int这个类型 数据占用的字节数是4B
			  long 长整型  占用的字节数是8B
	python3.x中去掉了long  只保留了int  int占用的字节数与原本的long一致的 8B

浮点型
	float
	这种类型的数据全部是小数

复数型[很少使用]
	complex
	复数有实部和虚部之分  数据格式是  实部+虚部j
13.2 布尔类型
bool

什么情况下使用该类型的数据?
	用于标记某种状态的时候 这种状态只有两种情况

bool的值只有两个 True / False
13.3 字符串类型
str
是一个字符序列 --- 包含字符的一个容器
使用引号来包含单个或者多个字符
字符串的内容一旦确定是不允许更改的  字符串中每个字符也有自己的编号 可以通过编号获取该位置对应的字符

获取格式:
	接受字符串的变量名[索引]
13.4 列表类型[使用比较多]
list
容器, 可以存放多个变量的值, 表示是使用中括号[]来表示的, 也就是在中括号中存放多个数据, 每个数据之间使用逗号隔开. 有序的序列[存放顺序和显示顺序是一致的]
存放在列表中的数据都有自己的编号 这个编号是从0开始的 编号还称之为索引 下标 脚标
可以通过编号来查找数据或者这个这个位置的数据
------------------------------------------------------------------------------
a.可以添加数据
	接受列表的变量名.append(数据)  #在最后添加的
b.在指定位置插入
	接受列表的变量名.insert(索引位置, 数据)
c.移除元素
	1.删除指定数据
		接受列表的变量名.remove(数据)
			删除是第一次出现的数据
	2.删除末尾元素
		接受列表的变量名.pop()
	3.删除指定位置的元素
		接受列表的变量名.pop(索引)
d.获取容器的长度
	len(接受容器的变量名)
#Python是一个动态语言 - 变量的类型是根据赋予的值来决定的
a = 10
#查看变量对应的类型的方式
#1. type(变量名)
print(type(a))

#2. isinstance(变量名, 类型名字) 查看该变量是否是指定类型
print(isinstance(a, int)) #True
print(isinstance(a, float)) #False

a = 10.2
print(type(a))

#字符串类型
a = "hello"
print(type(a))
#根据索引获取指定位置的字符
ch = a[0]
print(ch)

'''
a[0] = "m"
TypeError: 'str' object does not support item assignment
字符串内容一旦确定 不允许后期发生修改
'''
#a[0] = "m"
#print(a)


#列表
l1 = [12, 3.14, True, "hello"]
print(l1)

value = l1[1]
print(value)

l1[1] = 3.1415926
print(l1)

l1.append(99)
print(l1)

#获取长度
length = len(l1)
print(length)

#在指定位置插入
l1.insert(0, "头儿")
print(l1)
#末尾追加
l1.append(12)
print(l1)

#删除
l1.remove(12) #删除第一次出现的元素
print(l1)
#删除末尾元素
l1.pop()
print(l1)
#删除指定位置
l1.pop(2)
print(l1)
13.5 元组类型
tuple
每设置一个数据 都在内存中有其独立的地址
获取数据对应的地址  id(变量)
容器,用于存放多个变量的数据,长度一旦确定是不允许发生变化的,而且元组中元素的数据地址不允许发生变化
在元组中添加的元素也有对应的编号,可以通过编号获取元素的值

元组声明的时候   使用小括号()来包含元素的
注意:
 ()具有提高优先级的意义
 如果声明元组时 元素只有1个 需要在该元素的后面添加逗号分隔   告诉Python解释器这个小括号是元组数据的代表   而非是提高优先级的意义。如果不加这个逗号的话  解释器会将其解释成提高 

**注意:**Python这门语言对于格式对其很讲究 平级的语句不允许出现缩进的情况 左边必须是平齐的

m = 32
print(id(m))

m = 12
print(id(m))

tuple0 = (23, 56, 78, True)
print(type(tuple0))
print(tuple0)

value = tuple0[0]
print(value)

'''
: 'tuple' object does not support item assignment
'''
#元组中数据的地址不能发生改变  不能被再次赋值
# tuple0[1] = 77
# print(tuple0)
# 注释的快捷键 ctrl + /   解开注释 再使用ctrl + /

#如果只有一个元素的时候 必须在该元素后添加逗号 才会将该数据解释成元组
#否则 小阔号就是一个提高优先级的含义 会将小括号中的数据赋值给变量名
tuple1 = (10,)
print(tuple1)
print(type(tuple1))
13.6 集合类型
set
容器  没有索引一说   主要作用用于排重(排除重复)
无序的---添加顺序和最终的顺序可能不一致 但是数据位置一旦确定 不管再怎么运行  位置都不会发生变化

set(容器)------>集合类型
#集合
list1=[77, 28, 31, 52, 44, 28, 77, 66, 28]
set0 = set(list1)
print(set0)
>>>{66, 44, 77, 52, 28, 31}
13.7 字典类型[使用比较多]**
dict
存放的是具有映射关系的键值对  键值对的格式:key:valus 是使用{}来包含多个键值对的,每个键值对之间使用逗号隔开
{key:valus,key1:valus1,key2:valus2}

字典没有索引一说,是通过键查找值得,要求:键不允许重复 而且一般键的地址是不允许发生变化的  键使用的是不可变得数据类型(常用的就是整型,字符串类型)

通过键来查找值得方式:
	接受字典的变量名[键名]
		这种方式如果键不存在  会报错 会报错keyError 程序会终止 

或者

	接受字典的变量名.get(键名)
 	如果键不存在  不会报错  返回一盒个特殊值None

在字典中新增键值对
		接受字典的变量名[键名]=值
     	如果键名已经存在   将新值覆盖旧值
     	不存在会当做一个新的键值对添加
移除键值对
	方式1:
		接受字典的变量名.pop(键名)
	方式2:
 	del 接受字典的变量名[键名]
#字典
dict0 = {"英语":88, "数学":99}
print(dict0)

#没有索引一说
#KeyError: 0  键错误 --  表示的字典中没有0这个键
# item = dict0[0]
# print(item)

#通过键来查找值的方式
# value = dict0["英语1"]
# print(value)

value = dict0.get("英语1")
print(value)

print(len(dict0))


print(dict0)
dict0["语文"] = 65
print(dict0)

dict0["英语"] = 65
print(dict0)

# dict0.pop("数学")
# print(dict0)

# del dict0["数学"]
# print(dict0)

14. 输入功能

输出功能:
	print(数据) -- 结果显示在控制台上
输入功能:
	结果 = input(提示语:提示用户输入什么数据)
	结果接受的就是用户输入的数据

	注意 python2.x和python3.x的区别
	在python2.x的版本中 输入什么格式的数据  结果就是该数据对应的类型
	在Python3.x的版本中 不管输入的是什么格式的数据 结果都是字符串类型的

15. 不同的类型之间的转换

1.将数据转化为整型
	一般使用会将字符串  /  小数转化为整型
	转化的方式  int(数据)

	注意:转换字符串
		字符串可以以+或者-开头
		其余的必须是整数数字格式的  不允许包含其他数字内容 如果包含的话就会转换失败    报错
#类型转换

x = 3.14
print(x)

res = int(x)
print(res)

s = "+99."
res = int(s)
print(res)
print(type(res))
2.转化为浮点型
	将数值 / 字符串进行转换
	float(数据)
	注意:
		字符串 可以包含正确的正负符号
		可以包含一个小数点.  
		必须满足的小数/整数的数据格式 否则的话将会转换失败 报错
res = float(3)
print(res)

res = float("9..9")
print(res)
3.转化为bool类型
	值只有True / False

	数值类型:0即为True
	字符串类型: 非空字符序列即为True  空字符序列:只有一个引号 引号中没有任何内容""
	其他类型:None即为True

	bool(数据)
4.将数据转化为字符串类型
	str(数据)
5.解析字符串
	eval(字符串)
		可以将字符串中式子提取进行对应的运算
		也可以提取字符串中对应的数据 结果类型为字符串中数据的类型
		eval的使用
		解析字符串 扒掉外层字符串的衣服 剩下的是什么 就是什么
	"a" -----> 字符串数据
	a -----> 起的变量名 如果使用它的话是使用该变量对应的数据的

	eval("a") =====> a  #注意 如果前面没有声明过a这个变量 使用的话报错/
 code="12+34"
res=eval(code)#拔掉字符串这层衣服
print(res)#输出为int型46

con="10"
res=eval(con)
print(res)#输出 int型10

con1="[12,34,56]"
res=eval(con1)
print(res)#输出list型[12,34,56]

con2="(12,34,56)"
res=eval(con2)
print(res)#输出tuple型(12,34,56)

6. 编码
	将生活中常用的数据与计算机数据关联
	关联的中间介质是十进制数据
	生活中的数据 <-----> 十进制 <------>二进制
获取生活中某个字符对应的十进制数据  ord(单个符号)
	"a" ====> 97
	"A" ====> 65
	"0" =====> 48====> 
根据十进制数据获取其对应生活中的字符  chr(十进制数据)
	#要求十进制数据的范围:
		0-0x110000 ====> 十进制范围 [0, 1114112)

7.进制之间的转换
	将数据转化为16进制
		hex(数据)
	转化为二进制
		bin(数据)
	转化为八进制
		oct(数据)

16. 运算符

16.1 算术运算符
基本算术运算符:

	+
		在数值类型中将两个数进行求和
		在字符串类型中 将两个字符串进行拼接 生成一个新的字符串
-------------------------------------------------------------------------------		
	-
		数值中 求差
-------------------------------------------------------------------------------           *
		在数值类型中 求积
		在字符串类型中 将字符串原有内容重复n遍 生成一个新的字符串
-------------------------------------------------------------------------------       
	/
		数值中做商 保留小数
-------------------------------------------------------------------------------       
	//
		数值中做商  结果只保留整数
-------------------------------------------------------------------------------
	%   
		取模 做商之后取的是余数
		一个数a能被另一个数b整除 === 做商之后没有多余的数剩下 
		 a % b == 0
-------------------------------------------------------------------------------       
	**
		幂数
		 x ** y ===> x的y次方
-------------------------------------------------------------------------------     
复合赋值运算符
	=
	+=
		a += b =====> a = a + b
	-=
		a-=b ====> a = a - b
	*=
		a *= b ====> a = a * b
	/=
	 	a /= b ====> a = a / b
	//=
		a //= b ====> a = a // b
	%=
		a %= b ====> a = a % b
	**=
		a **= b ====> a = a **b 
a = 10
b = 20
'''
等号左边的变量 是等待被赋值的
等号右边的变量 是取变量的值的 这个时候相当于使用变量 如果之前没有声明并赋予初始值 就会报错
'''
res = a + b
print(res)

s1 = "abc"
s2 = "-def"
res = s1 + s2
print(res, s1, s2, sep="     ")

res = a * b
print(res)

res = s1 * 2
print(res, s1, sep="        ")

x = 11
y = 2
print(x / y)
print(x // y)
print(x % y)

print(x ** y)

m = 10
n = 5

m **= n
print(m)
16.2 关系运算符
经过关系运算符运算之后 最终的结果是bool类型的

> 大于
< 小于
>= 大于等于
<= 小于等于
== 是否相等
!= 是否不相等

在数值中比较数值的大小 或者是否相等
在字符串中 比较方式
	从第一个字符开始两者一一去对应比较的  本质上比较的是该字符对应的十进制数据
	其中某个字符比较出来大小 比较结束 
a = 10
b = 20
print(a > b)
print(a < b)
print(a >= b)
print(a <= b)
print(a == b)
print(a != b)
print("------------------------------")
s1 = "abcd"
s2 = "ab"
print(s1 > s2)
print(s1 < s2)
print(s1 >= s2)
print(s1 <= s2)
print(s1 == s2)
print(s1 != s2)

16.3 逻辑运算符
运算符两边绑定的数据是bool类型的  运算之后的结果也是bool类型的
逻辑与(and)
	规则: 一假则全假 ===> and符号两边有一方为假False  结果就是False
逻辑或(or)
	规则: 一真则全真 ====> or符号两边有一方为True 结果就是True
逻辑非(not)
	规则: 真变假 假变真 ===> not后面的结果是True 最终结果为False
						 not后面的结果是False 最终结果为True

优先等级: not > and > or
短路原则:
	逻辑与and的短路原则:
		根据一假则全假出现的
		如果and左边的表达式不成立False 右边表达式不会被执行  如果后面有or的表达式 会直接执行or后面的内容

	逻辑或or的短路原则:	
		如果or左边的表达式成立True 右边表达式不会被执行 

	 根据这个规则出现一个语法:  三元运算符  值1和值2遵守的bool转换原则  这个三元运算符有弊端
		 	变量名 = 条件表达式 and1 or2
		 	条件表达式成立 执行值1
		 	否则执行 值2
		 演示求两个数的最大值

	以后使用三元运算符:
		变量名 =1 if 条件表达式 else2	
x = 0
y = -1

res = x > y and x or y
print(res)

res = x if x > y else y
print(res)
16.4 成员运算符
针对于容器而言的
判断指定元素是否在指定的容器中
in    在的话为True

判断指定元素是否不在指定的容器中
not in  不在为True
s = "abcdef"
list0 = ["a", "b", "c", "d"]

res = "ba" not in s  #不仅判断是否有这个字符 还判断顺序是否正确
print(res)

res = "a" in list0
print(res)
16.5 身份运算符
验证变量的地址是否一致

is -- 地址一致结果为True
is not --- 地址不一致结果为True


id(数据) 获取数据的地址
16.6 位运算符

位运算符

针对于二进制数据的运算
二进制数据运算时是以补码的形态运算的
规则:1视作True  0视作False
二进制数通过运算符运算的时候 符号位也要参与运算的

以八位为例

按位与(&)
	两个二进制数 上下一一对应参与运算
	运算准则: 一假则全假

	5&-7
		5的补码: 0000 0101
		-7的原码: 1000 0111
		-7的反码: 1111 1000
		-7的补码: 1111 1001
		  &		 0000 0101
		  ------------------
		  		 0000 0001 -----> 1
按位或(|)
	两个二进制数 上下一一对应参与运算
	运算准则:一真则全真

	5 | (-7)
		0000 0101
	|	1111 1001
	----------------
		1111 1101 [补码] ----> -1求反码: 1111 1100 ----> 取反求原码: 1000 0011 [-3]
按位异或(^)
	两个二进制数 上下一一对应参与运算
	运算准则: 相同为假 不同为真

	5 ^ -7
		0000 0101
	^	1111 1001
	--------------
	     1111 1100[补码] ---> -1求反码:  1111 1011 ----> 取反求原码: 1000 0100 [-4]

	小知识点:
		一个数与相同的数异或两次 结果是其本身 ----> 简单的小小的加密
			密码: 123456 ----> 对应与一个数异或: 765489
			用户输入123456 ---->验证的时候 异或一个对应的数据 与 存放的数据进行验证匹配
		交换两个变量的值
			a = 10
			b = 20
			 ====> a = 20  b = 10
按位取反(~)
	01  10

		~(-7)
			1111 1001
		~
     -----------------
     	 0000 0110 ----> 6
按位左移(<<)
	将二进制数向左移动指定的位数 右边会空出 空出补0

		1 << 3 ===> 1左移30000 0001

		结论:
			原有的数据 * 2 ^ 移动的位数

按位右移(>>)
	将二进制数向右移动指定的位数 左边会空出 正数补0   负数补1

		32 >> 2 ====> 8

		结论: 原有的数据 // 2 ^ 移动的位数
res= 5 & (-7)
print(res)

res= 5 | (-7)
print(res)

res= 5 ^ (-7)
print(res)

res = -4 ^ -7  # 5 ^ -7 ^ -7
print(res)


a, b = 10, 20
# a, b = b, a
# print(a, b)

#因为当为a重新赋值的时候 a原来的值没有变量名接受了 所以这个数据就无法获取了  消失了
#先把a原来的值 使用另外一个变量名接受
# c = a
# a = b
# b = c
# print(a, b)


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


res = ~-7
print(res)

res = 1 << 3
print(res)

res = 32 >> 2
print(res)
16.7 转义符
\ --- 具有转移的含义
可以使用其后面的字符失去原本意义  生成一个新的含义
\n -- 换行
\t --- 制表符 tab
\r --- 回车

windows中表示换行的是 \r\n
如果以后写代码的时候 \n没有达到换行的效果 使用\r\n

17. 知识点–判断语句

三种:
	if单语句:
		if 条件表达式:
			[缩进tab]执行语句 --- 为什么要缩进?  执行语句是在满足if判断条件的情况下执行的
	if-else
		if 条件表达式:
			执行语句1
		else:
			执行语句2
		如果条件表达式成立 执行语句1  否则执行语句2

'''
键盘录入一个字符  如果是小写英文字母 将其转化为大写英文字母
否则 输入字符原本样子
'''
ch = input("请输入一个字符:")

#方式1
# if 'a' <= ch <= "z":
#     print(chr(ord(ch) - 32))
# else:
#     print(ch)
#
# print("over")


#方式2:
data = ord(ch)
if 97 <= data <= 122:
 print(chr(data-32))
else:
 print(ch)		

17. 位运算符补充

位运算符	
交换两个变量的值:[重点]
	第一种方式: Python独有的:
		a , b = 10, 20
		a, b = b, a  #等号左边的变量 是等待被赋值的  右边的变量是取原来对应的数据的
	第二种方式: 借助第三方变量 [JavaScript]  一般情况下应用于非Python的两个变量的交换
		c = a
		a = b
		b = c
	第三种方式: 使用异或的 一个数与相同的数异或两次 结果是其本身 [了解]
		先将两个数进行异或
		a = a ^ b
		b = a ^ b # b = a ^ b ^ b = a
		a = a ^ b # a = a ^ b ^ a = b

18. 模块与range功能的使用

模块 -----> 一个py文件就是一个模块 可以把模块当做一个工具箱使用

​ 模块之间是可以互相访问的 访问的前提需要导入要使用的模块

​ 自己定义的模块之间的访问

​ 使用系统提供的模块 random 随机模块

​ range — 可以生成一个整数序列的功能

一个python文件就是一个模块 把他当做一个工具箱

不同的python文件是可以相互访问的 访问的前提需要导入使用模块

导入模块的格式:

import 模块名

​ 使用模块中的内容的话 模块名.内容名

from 模块名 import 内容名字 ====> 在指定模块中导入指定内容

​ 使用内容的话 直接使用内容名

​ 这种导入 只能使用该模块下你导入的内容名

from 模块名 import * =====> 导入指定模块中所有的内容

可以直接使用该模块下的所有被__all__这个列表包含的内容,如果模块中没有设置__all__这个字段, 默认是使用所有

原生模块 random的使用
	random这个是随机模块 --- 可以在指定的内容中产生随机数据
	import random

#1. 在指定的容器中随机选择一个元素
res = random.choice("abcdefghtyui")
print(res)

res = random.choice((12, 34, 65, 71))
print(res)

#2. 在指定的整数范围内随机选择一个整数
#在指定的闭合区间中 随机的选择一个整数  [0, 1000]
value = random.randint(0, 1000)
print(value)

#3. 在指定的整数范围内随机选择一个整数  前闭后开的区间  [start, end)
value = random.randrange(1, 100, 2)
# ====>
value = random.choice(range(1, 100, 2))


#4.在指定的序列中选择指定个数的随机的功能
res = random.sample("1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM", 5)
print(res) #使用列表容器存放产生的多个随机元素

range的使用
	产生整数序列
		help(功能)
help(range)
'''
range(stop) -> range object
 传入一个结束值  区间的开始值是0
 生成的这个区间序列 [0, stop)
range(start, stop[, step]) -> range object
 需要传入起始值 传入结束值  step表示的是步长 默认是1
 如果传入step 会按照指定步长递增 或者 递减

 生成的区间 [start, stop)
'''

reslut = range(10)
print(reslut)
#将指定序列转化为列表  list(序列) ==> 将序列中的每一个元素存放于列表中
res_list = list(reslut)
print(res_list)


reslut = range(1, 10) #生成一个步长为1的序列  序列的起始值是1
res_list = list(reslut)
print(res_list)


reslut = range(1, 10, 2) #生成一个步长为1的序列  序列的起始值是1
res_list = list(reslut)
print(res_list)

#从10 -1 这种递减  10 9 8 7 6 5 4 3 2 1
reslut = range(10, 0, -2) #生成一个步长为1的序列  序列的起始值是1
res_list = list(reslut)
print(res_list)
#设置外界使用模块内容的权限
__all__ = ["name", "add", "div"]

name = "工具箱"

#设置一个功能  函数的封装  计算两个数的和
'''
一个: 是否有位置项参与功能的运算
 有多少个 在函数名的小括号中写多少个变量名
2. 问一下 这个功能是否需要将结果返回给使用者
    在函数中需要有return 一个返回 将结果返回给使用者
    如果没有 return可以省略 或者 return None ===> 使用者获得的结果是None
函数格式:
    def 功能名字(接受未知项的变量名):
        功能的实现
        return 功能运算结果
'''
def add(a, b):
    total = a + b
    return total

def div(a, b):
    return a / b



  #第一种导入方式
# import tool
#
# res = tool.name
# print(res)
#
# res = tool.add(12, 16)
# print(res)

#第二种导入方式
# from tool import name, add
#
# res = name
# print(res)
#
# #如果没有导入其他模块的内容  在当前模块中查找
# res = add(12, 34)


#第三种导入方式
from tool import *

res = name
print(res)

res = add(12, 45)
print(res)

res = div(12, 3)
print(res)

练习:
	1.使用range生成以下序列
		-1 ~ -10	
		range(-1, -11, -1)
	2.生成1-1000的序列  在该序列中随机选择3个数据
		import random
		res_list = random.sample( range(1, 1001) , 3)

19. 流程控制语句

19.1 顺序语句

什么叫做语句??

​ 在语法上自成体系的一个单位, 可能是一个词, 也可以能是通过逻辑关联的多个词

​ a:int

​ a = 10

在一般的编程语言中 语句结束的标志是分号(😉

在Python中语句结束的时候也可以以分号结尾 允许不写[建议不写]

​ 什么情况下来写?? ----- 如果在一行中书写多条语句, 这个分号就不能省略了

建议 最好是一条语句占用一行

顺序语句的意思: 表示的是代码的执行顺序 是从上往下走的

print("hello")

print("h");
print("b")
19.2 分支语句

分许需求的时候出现了不同的情况 — 出现了分支

出现了不同的情况 – 有可能会出现 —> 如果出现了 —> if

分支语句是if语句

if单语句 ---- 是一个整体
	if 条件表达式:
		[缩进tab]执行语句
	执行的流程:
 	判断条件表达式是否成立  成立的话  执行语句 if语句整体执行完毕 结束  向下执行与if平级的语句
 	不成立的话  if语句直接执行完毕 向下执行与if平级的语句
 案例:
 	键盘录入一个整数 判断这个数是不是偶数
 	偶数的概念: 能被2整除 ---> 余数为0   num % 2 == 0 
if-else语句
	if 条件表达式:
		执行语句1
	else:
		执行语句2
	执行流程解读:
		先判断条件表达式是否成立  如果成立的话 执行语句1 if-else整体结束
		否则 执行语句2  if-else语句结束

	案例:用户输入一个年份 验证这个年份是否是闰年
		闰年的条件判断:
			1.能被4整除 但是不能被100整除 year % 4 == 0 and year % 100 != 0
			2.能被400整除  year % 400 == 0
			12之间的关系 是满足其一即可  or
year = int(input("请输入一个年份:"))

if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
 print(year, "是闰年")
else:
 print(year, "不是闰年")


print("验证完毕")

import random			


	练习:1-100中随机生成两个数
			前者>后者  计算两个数的差
			否则计算两个数的和
import random

num1 = random.randint(1, 100)
num2 = random.randint(1, 100)
print(num1, num2)
if num1 > num2:
 c = num1 - num2
 print(c)
else:
 b = num1 + num2
 print(b)
print("结束") 



res = random.sample(range(1, 101), 2)
a, b = res
print(type(res))
if a > b:
 print(a-b)
else:
 print(a + b)

x = random.choice(range(1, 101))
y = random.choice(range(1, 101))

if x > y:
 print(x - y)
else:
 print(x + y)

x = random.randrange(1, 101)
y = random.randrange(1, 101)
if x > y:
 print(x - y)
else:
 print(x + y)
if-elif-else语句  elif ===> else if的简写
	注意: 只有 if如果的后面才会有条件表达式的判断 else是没有条件判断的 只有一个:跟随其后

	if 条件表达式1:
		执行语句1
	elif 条件表达式2:
		执行语句2
	....
	elif 条件表达式n:
		执行语句n
	else:
		上述列出的所有条件表达式都不满足 才会执行else

	这多个if并联的是一条语句 满足其中一个条件 整体结束

	案例:
		猜字游戏 猜一次
		系统随机生成一个50-300的整数 sys_num
		用户输入一个50-300的整数  user_num
		两个 比较大小
			如果 用户 大于 系统
				提示用户猜大了
			否则如果 用户 < 系统
				提示用户猜小了
			否则
				提示用户中奖了
import random

sys_num = random.randint(50, 300)
print(sys_num)
user_num = int(input("请输入一个50-300的整数:"))

#进行判定
if user_num > sys_num:
 print("猜大了")
elif user_num < sys_num:
 print("猜小了")
else:
 print("中奖了")

print("游戏结束")			



	练习:
		1.用户输入一个季节 根据季节输出对应的描述
			春 ---- 万物复苏
			夏 ---- 烈日炎炎
			秋 ---- 硕果累累
			冬 ----- 白雪皑皑

season = input("请输入一个季节:")
if season == "春":
 print("万物复苏")
elif season == "夏":
 print("烈日炎炎")
elif season == "秋":
 print("硕果累累")
elif season == "冬":
 print("白雪皑皑")
else:
 print("输入正确的季节")            

		2.成绩等级划分
			录入学生成绩 输出对应的等级
				>= 90	A
				>= 80	B
				>= 70	C
				>= 60	D
				其他	  E
grade=int(input("请输入学生的成绩:"))
if grade>=90:
 print("A")
elif grade>=80:
 print("B")
elif grade>=70:
 print("C")
elif grade>=60:
 print("D")
else:
 print("E")
print("请继续努力")               

		3.用户输入字符
			如果是小写英文字母 --- 输出其对应的大写字母
			如果是大写英文字母 ---- 输出其对应的小写字母
			其他 输出字符本身
ch = input('请输入一个字符:')
res1 = ord(ch) #获得字符对应的十进制数据
if 65 <= res1 <= 90:
 print(chr(res1 + 32))
elif 97 <= res1 <= 122:
 print(chr(res1 - 32))
else:
 print(ch)            

   或者
ch=input("请输入一个字符:")
if "a"<=ch<="z":
 res=ord(ch)
 print(chr(res-32))
elif "A"<=ch<="Z":
 res1=ord(ch)
 print(chr(res1+32))
else:
 print(ch)            
19.3 语句嵌套 - 符合所有的流程控制语句

分析逻辑的时候 在满足某种需求的情况下 又出现了逻辑判定

月份:
	1 3 5 7 8 10 12 ----> 31

	想要判定的话:
		需要列出所有的满足31天的月份 查看你输入的月份是否在其中  在其中就是31天
		month in [1, 3, 5, 7, 8, 10, 12]
				31
		month in [4, 6, 9, 11]
				30
		month == 2
			需要判定年份 -- 是闰年(29)还是平年(28)
	借助的成员运算符  将需要的数据存于容器中 判断指定数据是否在容器中
	语句嵌套
'''
语句嵌套
'''
month = int(input("请输入月份:"))
year = int(input("请输入年份:"))

if month in [1, 3, 5, 7, 8, 10, 12]:
 print(month, "有31天")
elif month in [4, 6, 9, 11]:
 print(month, "有30天")
elif month == 2:
 if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
     print(year, "年的", month,"月有29天")
 else:
     print(year, "年的", month, "月有28天")

20. 循环语句

循环: 重复做某件事情

没有终止的重复做某件事情, 这种循环称之为死循环

20.1 while循环机制
格式:
	while 条件表达式:
		重复的功能
	执行流程:
		判断条件表达式是否成立, 如果不成立 循环语句直接结束 执行与while平级的语句
		如果成立 执行重复的功能 ---> 再去判断条件表达式是否成立
	如何达到死循环:
		条件表达式一直成立的

写while循环的时候 明确条件:
	1. 明确循环条件是什么
	2. 重复做的事情是什么
案例:
	以数数为例
	数1-10
		循环条件: 数据 <= 10
		重复做的事情:
			输出数据
			对数据进行+1
'''
要求:
    只数1-10之间能被3整除的数
    需要获取1-10之间的所有数
    循环条件:
    	从1数到10  <= 10
    重复做的事情
    	进行判断 是否能被3整除 --> 输出
    	对数据进行+1
'''
练习:
	1.1-10的累加和
		加 -- 累加
		和 --- 需要用一个变量接收
		声明一个变量
			sum1 = 0 #在循环内声明还是在循环外声明
		num = 1
		sum1 = 0 #需要在外面声明
		while num <= 10:
			#sum1 = 0 #如果是在这里面 每次循环都会将累计的和清零 
			sum1 += num
			num += 1
	2.1-10之间偶数的累加和
	a = 1
sum1 = 0
sum2 = 0
while a <= 10:
    sum1 += a
    if a % 2 == 0:
        sum2 += a
    a += 1
print("1-10之间的累加和是", sum1)
print("1-10之间的偶数的累加和是", sum2)
猜字游戏:
	系统随机生成 50-300之间的一个数
	用户去猜

	循环的条件:
		用户猜的 != 系统生成
	重复的操作:
		用户就得猜 用户输入
		比较大小
			对应提示
import random
#系统随机生成
sys_num = random.randint(50, 300)
print(sys_num)

#在判断条件中使用user_num  给其赋值的位置却在使用之后 这种会出现错误  需要在使用之前先把该变量声明出来
#再使用之前 需要赋予初始值 初始值 需要满足 user_num不会与sys_num相等
user_num = None

#重复的操作
while user_num != sys_num:
    #用户去猜
    user_num = int(input("请输入50-300的数据:"))
    if user_num > sys_num:
        print("猜大了")
    elif user_num < sys_num:
        print("猜小了")
    else:
        print("中奖了")

print("game over")

'''
格式化小键盘:
    选中 -- tab -- 集体缩进
    shit + tab ----> 反缩进
'''

while True:
    #用户去猜
    user_num = int(input("请输入50-300的数据:"))
    if user_num > sys_num:
        print("猜大了")
    elif user_num < sys_num:
        print("猜小了")
    else:
        print("中奖了")
        #循环就可以结束了
        break

print("game over")			
20.2 For循环机制
用于遍历序列的  容器的

格式:
	for 变量名 in 容器:
		操作
	for循环的遍历机制:
		遍历的时候有一个遍历指针 指针的起始位置 在第一个元素的上方, 进行遍历的时候 先判断是否有下一个元素 如果有 指针向下移动一位 获取该位置的元素 赋予给变量  如果判断是否有下一位的时候结果是False, 遍历结束

使用forin完成数数

#遍历字符串
for ch in "abcdef":
print(ch)


for i in range(1, 11):
print(i)

print("-------------")
#打印1-10之间的偶数
for j in range(1, 11):
if j % 2 == 0:
  print(j)
print("-----------------")
#使用continue演示: 如果是奇数就跳过打印
for m in range(1, 11):
if m % 2 != 0:
  break
  #print("a")
print(m)
"""
日历是以1900年1月1日00:00:00为基础的 那天的星期一是已知的
万年历
a:先输入提示语句,并接受用户输入的年、月
b:根据用户输入的年,先判断是否是闰年。
c:根据用户输入的月来判断月的天数。
d:用循环计算用户输入的年份距1900年1月1日的总天数。
e:用循环计算用户输入的月份距输入年份的1月1日共有多少天。
f:相加D与E的天数,得到总天数。
g:用总天数来计算输入月的第一天的星期数。
h:根据G的值,格式化输出这个月的日历!
换行的时候的规则:
(空格数 + 日期号) % 7 == 0

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

"""

'''
1.验证指定年是否是闰年
'''
def is_leap(year):
if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
  return True
else:
  return False

'''
2.获得指定月的天数
'''
def get_days(month, year):
if month in [1,3, 5, 7, 8, 10, 12]:
  return 31
elif month in [4, 6, 9, 11]:
  return 30
else:
  return 29 if is_leap(year) else 28

'''
3. 获得指定年到1900年经历了多少天
'''
def get_year_days(year):
 year_days = 0
 for y in range(1900, year):
     year_days += 366 if is_leap(y) else 365
 return year_days

'''
4.获得指定到到当前年1月经历了多少天
'''
def get_month_days(month, year):
 month_days = 0
 for m in range(1, month):
     month_days += get_days(month, year)
 return month_days

#键盘录入年 和 月
year = int(input("请输入年份:"))
month = int(input("请输入月份:"))

#获得这个月的天数
days = get_days(month, year)
print(days)

#获取总天数
total_days = get_year_days(year) + get_month_days(month, year) + 1 #这个1是进入指定月份的第一天
#获取这个月的第一天对应的星期数
week = total_days % 7  #星期几
print(week)

print("星期日\t星期一\t星期二\t星期三\t星期四\t星期五\t星期六")
#真正的日期前面有空白站位
#打印空白
for s in range(week):
 print("\t\t", end="")

#打印真正的日期
for d in range(1, days + 1):
 print(d, end="\t\t")
 if  (week + d) % 7 == 0:
     print()  
20.3 关键字的使用
break
	只对循环语句起作用
	作用是结束其当前所在的循环语句 
	就近原则: 只结束离他最近的循环语句
continue
	只对循环语句起作用
	作用: 结束当前次循环  继续下一次
	在遍历的时候遇到continue 会中断该次的遍历 回到循环条件判断的位置 如果判断成立 执行下一次循环
注意:
	breakcontinue后面 不要添加与其平级的任何语句 因为这些语句永远不会被执行

# isrunning = True
# while isrunning:
#     while True:
#         if True:
#             isrunning = False
#             break
当嵌套了两个while循环语句的时候,break只能结束离他最近的while语句,外面的语句没有办法终止
20.4 while循环跟for循环详解
while循环 --  使用场景在明确循环条件的情况下
while循环
	break
	continue
		都是作用于就近的循环

while 条件表达式:
	重复的操作

另外一个格式:
	while 条件表达式:
		重复的操作
	else:
		当且仅当 while的条件表达式不成立的时候 才会执行else,如果是break导致的while强行结束不会执行到else语句
--------------------------------------------------------------------------------	
#数数 1-10
num = 1
#数到5之就不数了
while num <= 10:
print(num)
 num += 1
 if num > 5:
     break
else:
print("条件不成立了")
print("数完了")		
for循环 ----> 使用场景 遍历序列

for 变量名 in 序列:
	重复的操作

另外一种格式:
	for 变量名 in 序列:
		重复的操作
	else:
		当且仅当 序列中元素全部遍历结束的时候 才会执行else
	案例:
		判断一个数是不是质数(素数)
			质数的概述: 只能被1和本身n整除 
			整除的判定的时候:
				如果这个数被 2 ~ n/2之间的数整除 ----> 这个数不是质数
			for i in range(2, (n)//2+1):
				if n % i == 0:
					#代表这个数不是质数
					break #当只要在这个中 被整除1次 就已经不满足条件了 其他的数据没有必要再去验证
			else:
				#这个数是质数

			特殊的数据 6
				[2, 3]
			特殊的数据 9  
				[2, 3, 4]
			特殊的数据 11  
				[2, 3, 4, 5]
			分析:
				当从头到尾遍历完成  if条件都不成立 --- 这个数才是质数
			#先不考虑 特殊数据是1 --- 什么都不是



n = int(input("请输入一个整数:"))

if n <= 1:
pass  #空白站位符  在缩进的语句中不知道该做些什么操作  但是缩进语句又不能不写内容  用pass来站位就行
else:
for i in range(2, n // 2 + 1): #如果是2的情况下 [2, 2) [2, 3) [2, 4)
     if n % i == 0:
         print(i)
         print(n, "不是质数")
         break
 else:
     print(n,"是质数")	
注意:
	循环的话导致程序在循环的位置 一直执行 知道循环结束 程序才会继续向下进行

	循环嵌套这里的建议:
		嵌套的层数最好不要超过3层, 如果循环次数过多, 占用内存, 如果内存占用过多 程序会卡死 甚至崩溃

21. 函数

21.1 什么叫做函数

在程序中独立存在一段代码, 一个功能. 又称之为方法

函数的作用:

​ 将常用的代码 封装成功能, 使用该代码的时候直接调用功能, 便于简化代码, 减少代码的重复率

函数的分类:

​ 系统提供的内置函数

​ 例如: 输出功能print 输入功能input

​ 自定义函数

​ 根据需求自定定义的一个功能

案例:求圆的面积
	公式: π *r ** 2  π默认取的是3.14

需求:
	求半径为5的面积
	s = 3.1415926 * 5 ** 2

	求半径为10的面积
	s = 3.1415926 * 10 ** 2

	求半径为20的面积
	s = 3.1415926 * 20 ** 2

	需求: 精确圆周率 将圆周率改为3.1415926

单独封装成功能 - 求指定半径的圆的面积
def area(r):
	s = 3.14 * r ** 2
	return s

area(5)
area(10)
21.2 自定义函数的格式
def 函数名(设置的接收参与功能未知项的变量名):
	函数功能
	return 功能运行的结果

解释:
	def ---- 自定义函数的一个关键字
	函数名 ---- 自定义功能起的名字  需要遵守标识符规范
			命名规则:英文字母都是小写 每个单词之间使用下划线隔开
				例如: get_max_value

	()小括号中的变量名: -----> 形式参数 ----> 简称形参
		作用: 是用于接受参与功能运算的数据
		有多少个未知的数据参与功能运算 ,就得声明几个形参, 每个形参之间使用逗号分开
		如果没有未知项参与运算 小括号也不能省略 必须存在的
			例如: 求圆的面积
				def area(r):
						pass
				求两个数的和
				def add(a, b):
					pass
		实际参数 -----> 简称实参
			使用者调用功能时  向功能运算中传递的数据  是给形参赋值的

	return ----> 结束函数 并将结果返回给使用者
		如果自定义的功能没有结果返回  return语句可以省略 或者 写为 return None [这两种写法都是向调用者返回一个空值None]
最好做到两个明确:
	1. 明确这个功能是否有未知项参与运算  有几个??
			----> 完成形参的设置
	2. 明确这个功能是否需要将结果返回给使用者
			-----> 是否需要书写return
return 和 print的区别:
	return只能应用于函数中  作用是结束函数  把结果返回给使用功能的地方
	print 输出语句 可以应用于任何位置 把你想要输出的结果输出到控制台
1. 判断两个数是否相等
未知项: 两个
需要把结果返回 ----> 最好返回的是bool类型

def is_equal(a, b):
 # if a == b:
 #     return True
 # else:
 #     return False
 #return True if a == b else False
 return a == b

2.比较两个数的大小
	前者>后者  返回1
	前者<后者	返回-1
	否则返回	0

	def compare(a, b):
 if a > b:
     return 1
 elif a < b:
     return -1
 else:
     return 0

3. 封装一个功能: 打印九九乘法表
	调用功能 -- 控制台上出现九九乘法表

def print_nine_table():
 for r in range(1, 10):
     for c in range(1, r + 1):
         print(c, "*", r, "=", c*r, end="\t")
     print()

4. 封装一个函数: 打印指定行数的乘法表
	3 ---> 1 ~ 3
	4---> 1~4

def print_table(line):
 for r in range(1, line + 1):
     for c in range(1, r + 1):
         print(c, "*", r, "=", c * r, end="\t")
     print()

5. 封装一个函数 验证制定年是否是闰年

def is_leap(year):
 if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
     return True
 else:
     return False

6.封装一个函数 获取指定月的天数

def get_days(year, month):
 if month in [1, 3, 5, 7, 8, 10, 12]:
     return 31
 elif month == 2:
     return 29 if is_leap(year) else 28
 else:
     return 30
使用功能:
	函数名(实际参数)
		如果功能有结果的返回 可以使用一个变量接受结果
		注意: 声明函数时有多少个形参 就得传递多少个实参 而且两者是一一对应的

22. 变量的分类

变量的分类: 全局变量 和 局部变量

全局变量:在非函数中声明的变量  都是全局变量
	全局变量的特点: 只要声明出来  在声明之后的任何位置都可以使用


局部变量:
	在函数中声明的变量[包含形参和在函数体中声明的变量]
	特点:
		作用范围仅限于在函数体中  出了函数体没有任何意义

	在函数中声明一个变量  如果这个变量与全局变量重名  作用范围采用就近原则

	如果想让函数中声明的变量  使用就是全局变量的哪个作用范围 需要在函数中对该变量进行一个修饰 告知解释器这个变量的范围为全局变量的范围
		修饰符号 global
		在使用之前进行修饰
		global 变量名

23. 方法的执行流程

内存结构:
	内存结构中划分了不同的区域
		栈区  堆区  方法区  本地方法区 寄存器(什么数据存于寄存器中是由CPU决定的)
-----------------------------------------------------------------------------------	
	方法区(与程序共存亡的):
		属于共享区域
		有划分了3个部分:
			常量池:
				存放的数值类型数据 和 字符串类型的数据
				存放的特点:
					将常量池中的数据赋值给变量, 先在常量池中查找是否有该数据, 如果有的话 会直接将该数据的地址赋值给变量, 如果没有先在常量池中开辟空间存放数据, 再将对应的地址赋予给变量
			静态池:
				存放这全局变量
				和自定义类型中类变量
			方法池
				声明的方法 都存放与方法池中
-----------------------------------------------------------------------------------	
	栈区:
		存放正在执行的方法和局部变量, 将方法池中的方法拷贝一份存放于栈中 进而去执行
		栈的特点:
			先进后出
			方法执行完成 会立即被销毁  空间立即释放出来
-----------------------------------------------------------------------------------	
	堆区:
		存放的是非(数值类型和字符串类型)的数据
		特点: 每生成一个新的数据 都有自己独特的地址  即使数据外表看起来一样
		释放内存的时机:
			当数据没有变量名指向的时候 会被标记上垃圾的标识, 有Python垃圾回收机制将其回收

24. 默认参数

在调用函数时 给某个形参赋值时 值通常情况下是固定的 但是也有特殊的情况 这种情况下就可以将对应的形参赋予一个常用的默认值, 再调用函数时 如果需要的是这个默认值 就可以不用给该形参赋值, 如果是其他特殊值可以给该形参再重新赋值

例如:
	输出功能中 多个打印的数据之间的分隔符 默认是空格
			打印结束之后 的结束符 默认是换行
例子:
	求x的y次方
		常用的情况下是求x的平方

'''
默认参数
'''
'''
例子:
	求x的y次方
		常用的情况下是求x的平方
'''
def power(x, y=2):
 return x ** y


res = power(2, 2)
print(res)


res = power(3)
print(res)


res = power(4, 3)
print(res)

25. 递归算法

#在功能内部直接使用功能本身
算法:
	前辈们已经总结好的解决某种问题或者逻辑思路的一种方式
递归算法:
	在函数体中调用函数本身 这种情况就是递归算法

斐波拉契数列
	假设初始第一个月的时候有一对兔子, 从第三个月开始这对兔子每个月生一对小兔子, 小兔子从出生的撕单个月开始 每个月生一对小小兔子,8个月后兔子总共有多少对

	已知项:
		F(1) = 1
		F(2) = 1
		F(n) = F(n-1) + F(n-2) n>=3

注意事项:
	1.递归必须得有出口 - 功能的已知项
		否则会造成栈溢出RecursionError: maximum recursion depth exceeded
	2. 递归的层次不能太深 [调用的时候 一层一层的压栈 -- 就有有可能出现栈溢出]




递归来完成练习:
	1.求出1-指定数之间的累加和  指定数是必须>1
        F(1) ----> 1
        F(2) -----> 2 + 1 = 2 + F(1)
        F(3) -----> 3 + 2 + 1 = 3 + F(2)
        F(n) = n + F(n-1)
    2.求出指定数的阶乘
        5! = 5 * 4 * 3 * 2 * 1
        F(1) = 1
        F(2) = 2 * 1 = 2 * F(1)

          映射:
                F ----> 函数名
                (n) ----> 形参
                =号后面的内容 就是return的结果

 '''
F(n) = F(n-1) + F(n-2)  n>=3
F(1) = 1
F(2) = 1

'''

def F(n): # n = 3
    if n in (1, 2):
        return 1
    else:
        return F(n-1) + F(n-2)


res = F(3)
print(res)


def get_sum(num):
    if num == 1:
        return 1
    else:
        return num + get_sum(num-1) # 3 + get_sum(2) # 3 + 2 + get_num(1)

res = get_sum(3)
print(res)

def mul(num):
    if num == 1:
        return 1
    else:
        return num * mul(num - 1)

res = mul(5)
print(res)               

26. 可变参数*args

#传递给函数的实际参数个数是可变的---args

声明的函数的时候:
	明确有几个未知项参与运算  有几个声明几个  -- 形参的个数
	函数调用的时候 有几个形参  传递对应的实参
但是有些情况下 参与功能运算的未知项的个数不能确定 这个时候就可以把形参设置成可变参数
可变参数声明格式:
	在形参变量名前添加*

def 函数名(*变量名):
	函数功能
	return 结果

案例:
	计算n个数的和
	def get_sum(*nums):
   #nums需要是一个容器 才可以接受多个数据
   #<class 'tuple'>
   print(type(nums))
   print(nums)
   #求和
   total = 0
   #遍历元组
   for n in nums:
       total += n
   return total
 #经常使用的状态
 res = get_sum(121, 13, 56, 78)
 print(res)
调用函数时
	函数名(实际参数1, 实际参数2, ... 实际参数n)
		每个实际参数之间使用逗号隔开

	可变参数经典案例:
		print(*values, sep=" ", end="\t")
在可变参数中使用的是一个元组类型的容器 存放使用者传递过来的多个数据
练习:
	1.求n个数的累乘
def get_mul(*nums):
 #声明一个变量 接受累乘的结果
 result = 1
 #遍历nums容器中的每一个数据 将其与result累乘
 for i in nums:
     result *= i
 return result


res = get_mul(2, 45, 9)
print(res)    


	2.声明一个功能 可以接受任意个数据  获得这些数据中的偶数
		容器存放需要获取的数据
def get_even_num(*values):
 #因为偶数可能有多个 都需要获取出来 所以需要一个容器来存放这个偶数
 odd_list = []
 for num in values:
     if num % 2 == 0:
         odd_list.append(num)
 return odd_list		

27. 关键字参数**kwargs

使用者调用函数时 实参的个数要与形参的个数一致 并且两者是一一对应的

#获得指定月的天数
	def get_days(month, year):
		if month in [1, 3, 5, 7, 8, 10, 12]:
			pass


	#调用函数的时候
	get_days(3, 1960)

如果形参个数较多, 顺序记得不太清除 可以使用关键字形式传递实参
调用函数的时候:
	函数名(形参名=实参数据, 形参名2 = 实参数据)


针对于函数声明的:
	可以借助于注册账户的时候 有必填项和选填项
	必填项的字段 非常明确的 --- 声明在函数中 形参字段 明确的
	选填项用户可以传 也可以不传 字段的有无就不明确了  但是如果有的话 服务器端就得保存下来
	字段声明或者不声明就不明确了 -- 声明成关键字参数
		web网站 --- 服务器端
			--- 服务于用户的  存储用户的数据 给用户发送对应的数据等

		客户端和服务器端交互的时候  服务器接收客户端数据就通过函数调用来接收了

	讲一个形参设置为关键字参数的方式:
		在变量名前面加**
	def 函数名(**kwargus):
		pass
		#函数中 kwargus是字典类型的    


	接收用户数据时  用户传递数据的格式:
		函数名(key=value, key1=value1)
def get_days(month, year):
if month in [1, 3, 5, 7, 8, 10, 12]:
  return 31
elif month in [4, 6, 9, 11]:
  return 30
elif month == 2:
  if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
      return 29
  else:
      return 28
else:
  print("请输入正确的月份")
  return 0
res = get_days(year=1997, month=3)
print(res)


这里年和月调换了位置,采用了关键字参数year=199,month=3来实现位置的调换

28. 偏函数

因为一些函数是具有默认值的 这些默认值是在通常使用的情况下允许的
但是有些情景下常用的是另外一种值, 这个默认值在使用的时候就需要给每次进行赋值
可以借助自己的方法或者系统提供的机制 生成一个新的函数 采用的是新的默认值  这种函数就叫做偏函数

例如:
	print(sep=" ") #空格是默认使用场景下的

	现在需要分割符 是*号
	print(sep="*")
修改方式有两种:
	1.自定义一个方法
		在这个方法调用原本函数本身 修改函数的默认值
	2.使用系统提供的一种机制
		需要导入模块functools 有一个功能可以重新设置函数的默认值 并生成一个新的对应的函数
		import functools
		cus_p=functools.partial(print,sep="*")(函数可以当作值被赋予给其他变量)
		调用时可以直接使用:cup_s(10,20)

函数可以当做值赋予给其他变量
#
b = print
b("a", "b")

#如果带小括号的话,就是讲print的值赋予给   b
b=print()

这种情况下 b就有了与print一样的功能 可以向print一样去打印
赋值的时候注意:
	函数当做值来赋予的时候 赋予的是函数名 不要加小括号 加上小括号是调用函数 是把函数的运行结果赋予给了变量

29. 匿名函数

常用于一些系统提供的方法中的为指定接收函数的形参赋值的
可以简化一些简单的函数

如果这个函数 功能中只有一个表达式 并且这个表达式的结果就是函数的运行结果 就可以把这个函数简化成匿名函数

def  函数名(形参):
	return 结果

匿名函数的格式:
	lambda 形式参数1, 形式参数2,..形式参数n : 表达式结果

例如:
	求两个数的和:

	def add(a, b):
		return a + b

	====> lambda a, b: a + b

匿名函数如果没有变量值来接受该函数 他只会被执行1次 便在内存中消失了

匿名函数的执行:
	res = (lambda a, b: a + b)(实际参数1, 实际参数2)
def add(a, b):
 return a + b

res = add(12, 34)
print(res)

#匿名函数
res = (lambda a, b: a + b)(34, 56)
print(res)


'''
函数可以当做值被付给其他变量
'''
f = lambda a, b: a == b

res = f(15, 14)
print(res)

30. 闭包

函数嵌套
在一个函数中声明另外一个函数  这种函数嵌套的格式 称之为闭包

def 外部函数(形参):
	def 内部函数(形参):
		pass

在内部函数中可以使用外部函数的变量, 但是如果在内部函数中声明了一个与外部函数同名的变量, 内部函数的变量的作用范围采用就近原则 仅作用于内部函数  与外部函数的变量只是重名了而已

在内部函数中想要修改外部函数的变量的值  需要在内部函数中对该变量进行修饰 nonlocal非本地变量修饰 只有这样才可以将内部与外部函数同名的变量关联起来
''''
需求 在外部函数outer1的外部调用 内部函数 inner1
直接调用完成 不了 -- 间接调用
间接调用:
 将外部函数的返回值设置为内部函数
'''
def outer1():
 print("这是外部函数")
 def inner1():
     print("内部函数")
 return inner1

res = outer1()
print(res)
#想运行inner1就是运行res
res()
'''
闭包
'''
def outer():
 num = 100
 print("这是外部函数")
 def inner():
     nonlocal num
     num = 200
     print("这是内部函数")
     print(num, "内部函数的num")
 inner()
 print(num, "外部函数的num")


outer()


'''
inner的使用范围是什么??
在outer的外部可不可以调用inner

inner的使用范围仅限于在outer内部
函数拥有自己独立的作用域 -- 这个作用域与外界互不干扰
在函数内部声明的内容 只能在函数内部使用
'''

''''
需求 在外部函数outer1的外部调用 内部函数 inner1
直接调用完成 不了 -- 间接调用
间接调用:
 将外部函数的返回值设置为内部函数
'''
def outer1():
 print("这是外部函数")
 def inner1():
     print("内部函数")
 return inner1

res = outer1()
print(res)
#想运行inner1就是运行res
res()

31. 装饰器

装饰器:
	在不修改原有功能/类的基础上 为他们增加额外的新的信息

不加装饰器:
	获取的功能的本身操作
加上装饰器之后:
	不仅有本身的操作  还有新的信息展示


例如:
	家中的吊灯:
		发光的本质 ---- 灯泡本身
	为了好看 会给他添加修饰 -- 但是这些修饰只是在发光的本质上增加的额外的内容


反应的程序中:
	修饰的内容 --- 使用特殊的闭包[将内部函数当做外部函数的返回值]来体现的

	装饰器的闭包的写法:
		def 外部函数(外部函数的形参):
			def 内部函数(内部函数的形参):
				一系列操作
			return 内部函数

		讲解:
			外部函数的形参接受的是 被修饰的函数
		为原有功能添加装饰器的语法: 语法糖 @语法

		@外部函数名
		def 原有功能():
			pass
装饰器时可以为所有功能添加装饰的


添加装饰器的时候闭包的完整格式:
	def 外部函数名(接受被装饰的函数的变量名):
		def 内部函数名(*values, **kwargs):
			添加的装饰部分
			 result = 真正功能执行(*vlaues, **kwargs)
			 return rerult
		return 内部函数名


	给一个功能添加装饰的时候
	@外部函数名 --- 有这个装饰的时候 调用被修饰的函数名执行方法 结果中既包含原有功能的实现 又有被装饰的内容出现
			如果没有这个装饰 调用被修饰的函数名执行方法 执行的原有功能的本身

	知识点:
		为一个功能添加装饰器后 该装饰器的外部函数只会被执行1次 执行时机是@语法糖的时候
			--- 学习自定义类的时候 ---设计模式:单例类 --- 用到了这个知识点


	练习:
		借助装饰器 是一个功能只会被执行1次  第一次执行有对应的结果出现 之后的每一次运行 获取的都是第一次的结果

		def add(a, b):
			return a + b

		res = add(12, 12) ===> 24

		res = add(12, 34) ===> 24

def single_run(func):
 #借助的是外部函数只会被执行1次
 result = None  #这一执行完1次之后 不会再有被重置的可能了
 def inner(*values, **kwargs):
     nonlocal result
     if result == None:
         result = func(*values, **kwargs)
     return result
 return inner

@single_run
def add(a, b):
 return a + b

res = add(12, 34)
print(res)

res = add(13, 34)
print(res)

res = add(15, 34)
print(res)

装饰器:
	本质上就是一个函数, 可以让其他函数在不需要更改任何代码的情况下增加额外的功能
装饰器的返回值:
	是一个函数
装饰器在书写的时候 是一个函数嵌套的格式
	#简单的装饰器的书写
	def out(func):
		def inner():
			func()
		return inner

想将装饰器中额外的功能给指定函数添加
在指定函数声明的上方 @out

当你@的时候  装饰器的外部函数执行了 
保持一个为原有功能添加额外功能之后 原有函数名不变
#这个代码是解释器执行的 原有函数名 = out(原有功能名字)
程序员只需要@即可 上面的代码会自动完成

调用函数的时候 怎么调用 --- 就像没有添加装饰器格式调用即可

@out
def add(a, b):
	return a + b

res = add(11, 22) #有无装饰器  调用的始终是原有函数名
def single_run(func):
 #借助的是外部函数只会被执行1次
 result = None  #这一执行完1次之后 不会再有被重置的可能了
 def inner(*values, **kwargs):
     nonlocal result
     if result == None:
         result = func(*values, **kwargs)
     return result
 return inner

@single_run
def add(a, b):
 return a + b

res = add(12, 34)
print(res)

res = add(13, 34)
print(res)

#功能: 打印九九乘法表

# def print_table():
#     import time
#     start = time.time()
#     for r in range(1, 10):
#         for c in range(1, r + 1):
#             print(c, "*", r , "=", c * r , end="\t")
#         print()
#     stop = time.time()
#     print("执行时间:", stop - start)

def print_table():
 for r in range(1, 10):
     for c in range(1, r + 1):
         print(c, "*", r , "=", c * r , end="\t")
     print()

# print_table()


'''
看一下这个功能执行需要多长时间
需要一个模块
 time
     time() --- 获取当前时间的时间戳
不修改原有功能
 ----> 可以单独写一个方法----> 计算指定功能运行时间的
 ----> 有一个未知项 ---> 待计算时间的功能
'''
def get_time(func):
 import time
 start = time.time()
 func()
 stop = time.time()
 print("执行时间", stop - start)


#查看执行时间
get_time(print_table)

print_table()

'''
要求 执行函数本身 print_table既能实现原有的功能 又能计算执行时间
---- 装饰器
'''

练习

1.封装一个功能 可以接受任意个参数 获取传入数据中的所有奇数


def get_odd_nums(*values):
 #values中可以存放多个数据 --- values对应的类型 是一个容器
 print(type(values)) #tuple
 print(values)
 #获取所有的奇数 -- 需要一个容器来接受存放 -- 容器随着遍历vlaues长度是可变的
 odd_list = []
 #遍历
 for v in values:
     print(v)
     if v % 2 != 0:
         odd_list.append(v)

 #遍历完成 所有的奇数都找到了
 return odd_list


res = get_odd_nums(13, 56, 78, 10, 19)
print(res)

2.列表中的数据为
	list0 = ["hello", "nice", "family", "you"]
	根据字符串长度 获取列表中长度最大的字符串


list0 = ["hello", "nice", "family", "you"]
max_str = max(list0, key=len)
print(max_str)
'''
key -- 设置按照指定的标准 取比较序列中/多个数据中元素的大小

key这个函数返回的是一个比较的标准  按照这个标准 
比较序列中/多个数据中元素的大小 返回的对应序列中/多个数据中的最值
一般情况key默认是None  比较的标准是数据的原本大小

key接受的一个函数 --- 这个函数必须有返回值
将序列中/多个数据依次传入到函数中 根据函数返回值 作为一个比较的标准 取对元素进行比较 按照该标准获得对应的最值
'''

max_value = max(13, 45, 71, 28, -89)
print(max_value)

max_value = max(13, 45, 71, 28, -89, key=abs)
print(max_value)



3.设计一个装饰器 装饰器的功能是 可以计算出一个功能的执行时间



def get_time(func): #func ---> 接受被装饰的函数的
 def inner(*values, **kwargs):
     import time
     start = time.time()
     result = func(*values, **kwargs) #在额外增加的功能中嵌套着原有功能的实现
     stop = time.time()
     print("执行时间:", stop - start)
     return result
 return inner
'''
执行了装饰器的外部函数  add = get_time(func = add)  #保持的是原有函数的函数名不变  调用函数的时候一
直使用原有的函数名进行调用

没有添加装饰器 --- 调用的函数功能本身
添加了装饰器 -- 调用了装饰器中的内部函数
'''
@get_time
def add(a, b):
 return a + b

res = add(12, 45)
print(res)

'''
没有添加装饰器
执行的就是函数的本身
添加了装饰器 -- 已经把函数本身传入到装饰器中了
add = get_time(func = add)
 添加了装饰器 不仅要执行函数本身的功能 还要执行装饰的内容
装饰的内容在装饰器的内部函数中封装者 ----. 所以需要去执行内部函数

 如何执行内部函数:
     执行外部函数的时候 将内部函数返回出来了  装饰器保持着原有的功能的函数名不变的本质 所以接受
     内部函数的时候 使用与原有功能同名的变量名来接受的
         add = get_time(add)
         这个时候 add被重新赋值了 等价于内部函数

         所以添加上装饰器之后 再使用原有函数名来调用函数的话 其实调用的是内部函数
'''

32. 数据类型详解

数值类型

字符串数据类型

列表数据类型

​ 有一些算法需要掌握:

​ 排序算法

​ 查找算法

32.1 数值类型

数值类型中:

​ 整型int 浮点型float 复数型complex

系统提供的操作数据的方式
------------------------------------------------------------------------------------
1. 比较两个数的大小
	python2.x中 cmp(x, y)
		x > y 返回的是1
		x < y 返回的是-1
		x == y返回的是0
	python3.x舍弃了上述方法:
		提供了另外一种方式: 在这种方式中将True视作1False视作0
			(x > y) - (x < y)

#1. 比较两个数的大小
a, b = 17, 24
res = (a > b) - (a < b)
print(res)
------------------------------------------------------------------------------------ 
2.求绝对值
	abs(数据)

#2.求绝对值
res = abs(res)
print(res)
------------------------------------------------------------------------------------
3.四舍五入
	round(number[, digit])
		number 要进行四舍五入的数据
		digit 表示进行四舍五入之后 保留小数的个数
			digit默认是0

res = round(3.54)
print(res)

res = round(3.547, 2)
print(res)  
------------------------------------------------------------------------------------ 
4.求指定数的幂数
	pow(x, y)
		x ** y

#指定数的幂数
res = pow(2, 4)
print(res)    
------------------------------------------------------------------------------------
5. 求序列中或者多个数据值中的最值
	max(序列/多个数据, key=函数) 求最大值
	min(序列/多个数据, key=函数) 求最小值
		key接受的是一个函数, 将序列或者多个数据依次作用于函数 根据函数的返回结果进行比较获取序列/多个数据中的最值
		key可以不传值 默认为None  这种情况下是根据数据的真正大小比较的

#求最值
max_value = max(23, 71, -15, -89)
print(max_value)


#根据数据的绝对值的结果 获得对应的最值
'''
将多个数据中的每个数据都在abs中运行 根据获得结果中的最值 找到在原有的数据中对应的数据

或者 以绝对值的形式比较数据的大小 获取对应的原有数据的最值

[23 71  15  89]
'''
max_value = max(23, 71, -15, -89, key=abs)
print(max_value)

max_value = max([34, 56, 71, 25])
print(max_value)

'''
如何获得序列中的最值???
 1.按照元素大小取比较  直接获取的最值元素
 2.根据脚标对应的元素进行比较  获得最值对应的脚标 根据这个脚标获得元素
'''
------------------------------------------------------------------------------------
模块math --- 是针对于数学的函数功能
	三角函数
import math

#1. 向上求整  >= 指定数据 离指定数据最接近的整数
res = math.ceil(18.1)
print(res)

#2. 向下求整 <= 指定数据 离指定数据最接近的整数
res = math.floor(18.9)
print(res)

#
res = math.log2(16)
print(res)

#开平方
res = math.sqrt(9)
print(res)

#圆周率
print(math.pi)

res = round(math.pi, 3)
print(res)
print(type(res))
32.2 字符串数据类型
字符串对应的类型名字: str
字符串是存放的一系列字符的容器, 在字符串中存放的字符都有自己的编号 这个编号是从0开始的

注意: 字符串的内容是不允许发生变化的, 如果发生变化是新生成了另外一个字符串 与原来的字符串无关

常用方法

s = "good good study"
--------------------------------------------------------------------------------
#1.获得字符串的长度
length = len(s)
print(length)
--------------------------------------------------------------------------------
#2.在字符串中每个字符都有自己对应的索引
'''
索引有两种表示方式
    1. 从0开始的  到len(s)-1  [0, len(s)-1]
    2. 从-len(s)  到 -1       [-len(s), -1]
'''
#获取第一个字符:
ch = s[0]
print(ch)

ch = s[-length]
print(ch)
#注意索引范围 防止索引越界
# ch = s[length]  #IndexError: string index out of range
# print(ch)

#字符串的内容一旦确定不能再发生改变
# s[0] = "G" #TypeError: 'str' object does not support item assignment  字符串的元素不允许被再次赋值
# print(s)
--------------------------------------------------------------------------------
#3.切片 ---- 提取子串
'''
[start:stop[:step]]
start 和 stop控制的是索引 索引是按照指定数据递增的
start  stop step数据都可以省略  但是:不允许省略  与步长绑定的冒号可以省略  

步长省略 默认值为1

start数据省略 默认是从头开始读取
stop省略  默认是到尾结束

如果设置stop ----> 提取的范围: [start, stop)


'''
sub_s = s[:]
print(sub_s)

#设置步长  步长前面的:必须存在
sub_s = s[::2]
print(sub_s)

#可以设置步长为负数  start 和 stop不赋值 可以生成字符串反转
sub_s = s[::-1]  #===> s[-1:-len(s)-1:-1]
print(sub_s)

sub_s = s[-1:-len(s)-1:-1]  #[::-1]是这个式子的简写
print(sub_s)

sub_s = s[:5]
print(sub_s)

sub_s = s[5:]
print(sub_s)
--------------------------------------------------------------------------------
#4.获得字符串中指定字符出现的次数
'''
指定字符串
    字符串接受者.指定的功能
'''
s = "kkkabcdkkkk"
#从头到尾找连续的字符 如果字符之前找过 不会再列入重找
num = s.count("kk")
print(num)

#从某个位置{表示的是索引}开始查看某个字符串出现的次数
num = s.count("kk", 5)
print(num)

#指定区间范围 在区间范围内查找指定符出现的次数
# [start, stop)
num = s.count("kk", 5, 9)
print(num)
--------------------------------------------------------------------------------
s = "nice to meeto you too"
#5.查找指定字符第一次出现的位置
# 如果找的是多个连续字符第一次出现的位置 返回的是连续字符中第一个字符对应索引位置
#index --- 找到返回索引位置 找不到报错
# index = s.index("top")  #ValueError: substring not found
# print(index)
#find --- 常用  找到返回对应的索引位置 找不到返回-1
index = s.find("to")
print(index)

#指定起始位置开始查找
index = s.find("to", 6)
print(index)

#指定范围查找
index = s.find("to", 6, 19)
print(index)

#指定字符最后一次出现的位置
index = s.rfind("to")
print(index)

#指定范围去查找
index = s.rfind("to",0, 18)
print(index)


s = "nice to meeto you too"
'''
从第一次出现的t 开始 提取之后的子串 [包含t]
'''

sub_s = s[s.find("t"):]
print(sub_s)
--------------------------------------------------------------------------------
s = "nice to meeto you too"
#6.字符串切割 -- 以指定的切割符为切点 将字符串分成对应的子串 --- 返回结果是列表类型的
'''
字符串.split(["指定切割符"])
不设置切割符 默认是以所有的空白字符序列[print打印的时候显示出来的是空白]为切割符
 "  "  "\n"  "\r"  "\t"
 在结果中产生的空字符序列会被移除
   '''
   sub_list = s.split(" ")
print(sub_list)

sub_list = s.split("o")
print(sub_list)
'''
nice to meeto you too
第一个 ====> nice t,   meeto you too
第二个 ====>  meet,  you too
第三个 ====>  y, u too
第四个 ====> u t, o
第五个 ====> "", ""
'''

s = "\n你好\n我好\n大家好\n"
res = s.split() #["","你好","我好", "大家好", ""]
print(res)
--------------------------------------------------------------------------------
#7.字符串格式化
#7.1. 想保持字符串原样输出 ====> 多行注释 就是一个字符串
s = '''
nice to meeto you too
第一个 ====> nice t,   meeto you too
第二个 ====>  meet,  you too
第三个 ====>  y, u too
第四个 ====> u t, o
第五个 ====> "", ""
'''
print(s)

#7.2.包含特殊字符 --- 转义符
'''
\ --转义符
可以将其后面的字符更改意义
例如
 \n
 \t
 有一些情况下 需要保持n或者t的本意
        \\n ----> 设置一个文件路径
        文件路径的分隔符 \
    借助于r 在字符串前面添加r修饰符 可以保持\的本意
   '''
   path = "C:\\Documents\\讲课内容\BJPython1901\day06\\notes"
   print(path)

path = r"C:\Documents\讲课内容\BJPython1901\day06\notes"
print(path)

#7.3输出的字符串 的内容中 需要包含引号
'''
你好 ---> 'hello'

方式1. 如果输出的引号是单引号  最外层使用双引号包含
 方式2:  使用\进行转义
'''
s = "你好 ----> \"hello\""
print(s)

#7.4format
'''
键盘录入姓名和年龄
--- 输出的格式是 我的姓名是xxx, 年龄是xx
'''
name = input("请输入姓名:")
age = int(input("请输入年龄:"))
# print("我的姓名是",name,", 年龄是",age, sep="")
'''
format格式化的方式
先把想要的字符串格式写出来 在未知项的地方使用{}占位, 在format中为大括号的位置赋值
'''

s = "我的姓名是{}, 年龄是{}".format(name, age)
print(s)

#格式化的数据来源于容器
info_list = ["小沐1",18]
s = "我的姓名是{}, 年龄是{}".format(*info_list)
print(s)


'''
赋值的是关键字参数
关键字参数 接受的就是一个字典的格式
需要在站位的时候 {字典中对应的键}
'''
s = "我的姓名是{name}, 年龄是{age}".format(name="小明", age=18)
print(s)

info_dict = {"name":"小强", "age":19}
s = "我的姓名是{name}, 年龄是{age}".format(**info_dict)
print(s)

'''
站位借助于索引
{索引值}
'''
s = "我的姓名是{0}, 年龄是{1}, 时间是{1}".format("小红", 10)
   print(s)

'''
字符串显示的时候 有些数据需要格式化
小数保留多少位显示
  需要使用小数的占位符
     :f
        :.nf
            n的话表示的是保留的位数

    想让数据以二进制格式显示
        :b
    八进制
        :o
    十六进制
        :x
    数值大的情况下 按照千位分割显示
        :,
   '''
   s = "我的成绩是{:.2f}".format(67.875)
   print(s)

s = "二进制显示{:b}".format(10)
print(s)

s = "八进制显示{:o}".format(10)
print(s)

s = "十六进制显示{:x}".format(10)
print(s)

s = "数据千位分割显示{:,}".format(123456789)
print(s)
--------------------------------------------------------------------------------
#8.在字符串中可以使用运算符
'''
如何判断哪些类型可以使用指定的运算符??
取查看对应的类型中是否有 这些方法的实现:
     __add__ =====> +
     __sub__ =====> -
     __mul__=====> *
        __truediv__ ====> /
        __floordiv__ ====> //
        __mod__ ====> %
        __eq__ ====> ==
        __ne__ ====> !=
        __ge__ ====> >=
        __gt__======> >
        __le__ =====> <=
        __lt__ =====> <   
   '''
   '''
   在字符串中可以操作的运算符
       + ====> 必须是两个字符串类型数据相加 结果生成一个新的字符串 字符串的内容是两个字符串的拼接
    * ====> 一个字符串乘以的整型数值 结果生成一个新的字符串 字符串的内容是原有内容重复n次
 % ====> 格式化字符串的一种方式
     也有一些占位符
         %d ----> 整数
         %f -----> 小数
                %.nf
            %s -----> 表示其它类型的数据
    in

      针对于字符串内容比较大小  
    >=
    >
    <=
    <
    ==
    !=
   '''

   s1 = "abc"
   s2 = "opq"
new_s = s1 + s2
print(new_s, s1, s2)

new_s = s1 * 3
print(new_s)

#%格式化
'''
与format是类似
先将要进行格式化的字符串声明完成 使用对应的占位符进行占位 在 % 后 为这些占位符赋值
'''

s = "我的姓名是%s" % "小强"
   print(s)

s = "我的姓名是%s, 年龄是%d 成绩是%.2f" % ("小强", 17, 78.567)
print(s)
--------------------------------------------------------------------------------
#9.去除掉字符串两端的指定内容
s = "abc你好abcabc"
new_s = s.strip("abc")
print(new_s)
'''
strip([去除的指定的字符串])
如果没有赋值 去除的是两端的空白字符串
'''

s = "     good  good  \n"
new_s = s.strip()
print(new_s)
#只去除左端
new_s = s.lstrip()
print(new_s)

#只去除右端
new_s = s.rstrip()
print(new_s)
--------------------------------------------------------------------------------
s = r"c:\documents\notes\1.听写.MP4"
#10.关于判断的方式
#10.1 判断字符串是否以指定内容开头 ====> 从左到右查看子串的内容是否与原串前面的内容是对应的?
res = s.startswith(r"c:\documents\notes\1.听写.MP4")
print(res)

#10.2 判断字符串是否以指定内容结尾 ====> 从右到左查看子串的内容是否与原串前面的内容是对应的?
res = s.endswith(r"1.听写.MP4")
print(res)

s = "10a"
#10.3 判断字符串内容是否是纯数字
res = s.isdigit()
print(res)

s = "10*"
#10.4 判断字符串中的内容是否是纯字母
res = s.isalpha()
print(res)


#10.5 判断字符串中的内容是否是数字或字母
res = s.isalnum()
print(res)
--------------------------------------------------------------------------------
s = "Hello nice to meet you"
#11.转换的方法
#11.1 将字符串中的小写字母转化为大写字母
new_s = s.upper()
print(new_s)

#11.2 将大写字母转话为小写字母
new_s = s.lower()
print(new_s)

#11.3 大写转小写 小写转大写  其他符号保持不变
new_s = s.swapcase()
print(new_s)

s = "hello nIce"
#11.4  将字符串中第一个字符转化为大写  其他转化为小写
new_s = s.capitalize()
print(new_s)

#11.5 将字符串中每个单词的首字母大写 其他小写
# 单词: 在字符串中使用空格隔开的子串
new_s = s.title()
print(new_s)

#11.6 编码和解码
'''
生活中的数据 
计算集中的数据: 字节数据
编码 ----> 将生活中的数据转化为计算机中的数据
解码 ----> 将计算机中的数据解析成生活中的数据
'''
s = "你好"
encode_data = s.encode(encoding="utf-8")
print(encode_data) #b'\xe4\xbd\xa0\xe5\xa5\xbd'  使用十六进制表示的
'''
utf-8下1个汉字占3个字节
1个字节是8位二进制数
字符对应的十进制数据 最小的为0
这8位二进制数 可以对应着多少十进制数  2^8 = 256
 0000 0000 ----> 0
 0111 1111 ----> 2^8-1
 1 2 4 8 16 32 64 128 256

 256个十进制数 ---> [0, 255] ---> 十六进制[0x00, 0xff]
'''

   s = "你好啊"
   encode_data = s.encode(encoding="gbk")
   print(encode_data)

#解码--- 解码方式要与编码方式一致  否则会出现解码错误
decode_str = encode_data.decode(encoding="gbk")
print(decode_str)
--------------------------------------------------------------------------------
#12. 替换字符串
s = "cat and dog"
new_s = s.replace("a", "A")
print(new_s)

s = "cat and dog"
#指定替换的个数
new_s = s.replace("a", "A", 1)
print(new_s)
--------------------------------------------------------------------------------
#13.以指定拼接符 拼接指定序列中的数据
'''
"拼接符".join(序列)
'''
str_list = ["h", "e", "l", "l", "o"]  #===> hello
res = "*".join(str_list)
print(res)

str0 = "hello"
res = "-".join(str0)
print(res)
--------------------------------------------------------------------------------
'''
字符串模块 string
'''
import string

#1. 所有的空白符号
res = string.whitespace
print(res)

print("\f") #向上的箭头

#2. 所有小写字母
lower_str = string.ascii_lowercase
#3. 所有的大写字母
upper_str = string.ascii_uppercase
#4. 所有英文字母
all_case = string.ascii_letters
#5.所有数字字符
num_str = string.digits
print(lower_str, upper_str, all_case, num_str)
--------------------------------------------------------------------------------
#随机数的时候  在字母和数字中随意获取指定个数的字符
import random
ch_list = random.sample(string.digits + string.ascii_letters, 5)
print(ch_list)
#把列表中的数据拼接成一个字符串串 --- 验证码
res = "".join(ch_list)
print(res)
#自己获取字符串的长度
#len("abc")

def cus_len(itearable):
 #声明一个计数器
 num = 0
#遍历序列
 '''
 遍历的时候 需要在序列中获取数据的 如果需要这些数据 那就得设置一个变量接受这些数据
     for 变量名 in 序列:
        pass
 如果不需要 可以使用下划线 在变量名处站位
        for _ in 序列:
            pass
    '''
    for _ in itearable:
        num += 1
    return num

   res = cus_len("abcdefg")
   print(res)

   #统计某个字符出现的次数 --- 只统计单个字符
   def cus_count_single_ch(src_str, key_ch):
    '''
    统计指定单个字符在字符串中出现的次数
:param src_str: 指定的字符串
 :param key_ch: 要查找的指定字符
 :return: 指定字符出现的次数
'''
 #计数器
 count = 0
    #遍历字符串
    for ch in src_str:
        if ch == key_ch:
            count += 1
    return count

   res = cus_count_single_ch("hello nice look beauty", "e")
   print(res)

   '''
   统计某个子串在字符串中出现的次数
   特别简单的方法 --- 借助切割 以子串为切割点
   '''
def cus_count(src_str, sub_str):
 sub_list = src_str.split(sub_str)
 print(sub_list)
return len(sub_list) - 1

res = cus_count("good look nood", "oo")
print(res)

'''
   逻辑思维复杂的:
    自己去数
   数的话 分为两种情况:
以待找的子串长度  从原串提取出来子串

 提取的子串 == 待找的子串
    次数 += 1

 查找范围更新 ---> 起始位置+待找子串的长度

  提取的子串 != 待找的子串
        起始位置 += 1
   '''
   def cus_count_1(src_str, key_str):
    #计数器
    count = 0
    # 查找的起始范围
    start = 0
    #查找:
    while True:
     sub_str = src_str[start:start + len(key_str)]
     if sub_str == key_str:
            #计数器 +1
            count += 1
            #查找起始发生变化
            start += len(key_str)
        else:
            start += 1

        #查找的起始值发生变化
        if start >= len(src_str):
            break #如果查找起始范围到原串的最大位置 不用再找了
    return count

   res = cus_count_1("good look nood", "oo")
   print(res)

   '''
   方案3: 借助find
   find("子串", 起始值)
   从起始值开始 查找第一次出现的子串索引
如果有的话 返回子串中第一个字符的索引位置  如果没有返回-1
'''
def cus_count_2(src_str, key_str):
#计数器
 count = 0
 #设置起始值
 start = 0
 #循环查找
 while True:
     index = src_str.find(key_str, start)

        if index == -1:
            break
        else:
            count += 1
            #更改start的起始位置
            start = (index + len(key_str))

return count

   res = cus_count_2("good look nood", "oo")
   print(res)
   '''
   start = 0
   index = s.find("oo", start)
index = 1
    count += 1
start = index + len(key_str)

index = 6
 count += 1
 start = index + len(key_str)
'''

   '''
   find
查找第一次出现的子串的位置  有的话返回第一个字符的位置 没有的话返回-1
'''
   #查找某个字符第一次出现的位置
   def find_single(src_str, key_ch):
 #因为要获取的字符的位置 所以遍历的时候是按照索引遍历的
for i in range(len(src_str)):
     if src_str[i] == key_ch:
         return i
    return -1

res = find_single("hello nice", "m")
print(res)

   #查找某个字符串第一次出现的位置  找到的话返回的第一个字符的索引 否则返回-1
   '''
   从头开始提取待找子串长度的子串
    提取出来的子串 == 待找的子串
    返回start
 提取出来的子串 != 待找的子串
     start += 1
'''
def cus_find(src_str, key_str):
 #起始值
 start = 0
    #进行查找
    while True:
        #按照待找子串的长度提取子串
        sub_str = src_str[start:start + len(key_str)]
     if sub_str == key_str:
         return start
        else:
            start += 1

        #从起始位置 + 待查找的子串的长度 已经查过了原串的大小了
        if start + len(key_str) > len(src_str):
            break
    return -1

   res = cus_find("hemllo nicem", "emm")  #start = 10  [10: 13)
   print(res)

   #将字符串中大写字母转化为小写字母:
   def cus_lower(src_str):
    #字符串内容发生变化 起始是新生成了一个字符串
    new_str = ""
#遍历字符串
 for ch in src_str:
     if "A" <= ch <= "Z":
        #将其转化为小写
         lower_ch = chr(ord(ch) + 32)
         new_str += lower_ch
        else:
            new_str += ch
    return new_str

   res = cus_lower("HeLLo")
   print(res)
32.3 列表数据类型的使用
列表是一个容器 可以存放多个数据, 每个数据都会有自己的编号 这个编号是从0开始的

列表是一个有序的容器 === 存放顺序和显示顺序是一致的

列表的标识是 []

列表对应的类型名字list

常用方法:

#1. 列表的声明方式
#方式1  使用系统提供的方法
'''
list()
list(序列) -- 将其他序列转化为列表
'''
list0 = list() # 生成了一个空列表 ===> []
print(list0)

#生成一个列表 列表里面的元素指定序列中的元素
list0 = list("abcd")
print(list0)

list0 = list((12, 34, 56))
print(list0)

#将字典中的键存放于列表中
dict0 = {"name":"小明", "age":18}
list0 = list(dict0)
print(list0)

#获得字典中所有的键
keys = dict0.keys()
print(keys)

#获取字典中所有的值
values = dict0.values()
print(values)

#获得字典中所有的键值对
items = dict0.items()
print(items)

#将字典中的值全部存放于列表中
list0 = list(dict0.values())
print(list0)

#将字典中的键值对全部存放于列表中
list0 = list(dict0.items())
print(list0)

#将集合中的数据存放于列表中
list0 = list({12, 34, 56})
print(list0)


#方式2 使用字面量形式直接赋值 使用中括号的形式直接赋值[] 最常用的方式
list1 = []
print(list1)
list1 = [12, 45, 67]
print(list1)

#2. 可以通过元素索引操作列表中的数据
'''
索引有两种表现形式
 [0, len(list0)-1]
 [-len(list0), -1]
注意索引范围
'''
#获取列表中的元素
#value = list1[len(list1)] #IndexError: list index out of range
value = list1[0]
print(value)

#更改列表中的元素
list1[1] = 88
print(list1)

#3列表中使用的运算符
'''
+  两个列表相加 生成一个新的列表 列表中的元素为两个列表拼接在一起的结果
in
*  乘以的一个正整数  生成一个新的列表 列表中的元素为原列表的n倍
>=
<=
>
<
==
!=
与字符串比较类型
    将两个列表中的元素一一进行对比
'''
l1 = [12, 34]
l2 = [55, 27, 12]
new_list = l1 + l2
print(new_list, l1, l2)

new_list = l1 * 3
print(new_list, l1)

l1 = [12, 34]
l2 = [12, 34, 56]
res = l1 >= l2
print(res)

l1 = [12, 34]
l2 = [12, 34]
res = l1 == l2
print(res)

#4.切片 --- 原则等同于字符串的切片原则 --- 提取子列表
'''
[start:stop[:step]]
:step可以省略  默认为1
start 和 stop表示的是索引  不设置值的话默认是从头到尾
设置值的话不包含stop本身
'''
l1 = [12, 56, 71, 23, 54, 38]
sub_list = l1[:]
print(sub_list)

sub_list = l1[:2]
print(sub_list)

sub_list = l1[2:]
print(sub_list)

sub_list = l1[2:5]
print(sub_list)

sub_list = l1[::-1]
print(sub_list)

#5.列表提供了一个反转的方法
l1.reverse()  #这个反转功能没有返回值 修改的是原列表
print(l1)

#6.列表中添加元素的操作 -- 操作的都是列表本身 没有返回其他数据
#在末尾追加
l1.append(19)
print(l1)

#2. 在指定位置插入
l1.insert(0, 29)
print(l1)

#3. 将其他序列中的元素追加到列表的末尾  合并列表
l1.extend("abc")
print(l1)
l1.extend([14, 12])
print(l1)


#7.移除的方法
#移除指定元素: 第一次出现的元素
l1.remove(12)
print(l1)

#移除末尾的元素
l1.pop()
print(l1)

#移除指定位置的元素
l1.pop(1)
print(l1)

#8.获得列表中指定元素出现的个数
l1 = [12, 34, 56, 12, 71, 12]
res = l1.count(12)
print(res)

#9. 获得指定元素第一次出现的位置 不常用  找不到会报错
# index = l1.index(122)
# print(index)

#10. 对列表中的元素进行排序
l1 = [12, 34, 71, 29, 56, 44]
# l1.sort() # 按照数据的大小 升序排序
# print(l1)

#按照数据大小降序排序
# l1.sort(reverse=True)
# print(l1)

l1 = ["hello", "nice", "family"]
#以字符串长度为标准 对列表进行排序
l1.sort(key=len, reverse=True)
print(l1)
'''
key 接受的是一个函数
    默认是None -- 以数据原有大小为标准进行排序
    如果不为None 将列表中的数据作用函数 以函数的返回结果为标准 对列表元素进行排序
reverse
    默认是False -- 表示升序排序
    True --- 降序排序
'''


def cus_sort(src_list):
    for out in range(1, len(src_list)):
        for inner in range(out, 0, -1):
            if src_list[inner] < src_list[inner-1]:
                src_list[inner], src_list[inner-1] = src_list[inner-1],src_list[inner]


list0 = [56, 27, 31, 44, 29]
cus_sort(list0)
print(list0)
'''
排序影响本身的本质:
    给对应的变量传递数据时  赋予的是数据的地址
    list0 与 src_list地址是一致的

    通过src_list 把地址中对应的数据修改了
    list0 通过地址来获取的数据的话 就是发生过修改的
'''

list0 = [56, 27, 31, 44, 29]
list1 = list0

list1[0] = 88

print(list0[0])

def cus_sort_1(src_list, reverse=False):
    #reverse == False  升序  否则为降序
    for out in range(1, len(src_list)):
        for inner in range(out, 0, -1):
            if reverse == False:
                if src_list[inner] < src_list[inner - 1]:
                    src_list[inner], src_list[inner - 1] = src_list[inner - 1], src_list[inner]
            else:
                if src_list[inner] > src_list[inner - 1]:
                    src_list[inner], src_list[inner - 1] = src_list[inner - 1], src_list[inner]

list2 = [29, 41, 38, 55, 42]
cus_sort_1(list2, reverse=True)
print(list2)

查找列表中的元素
list0 = [34, 71, 29, 30, 46, 77]

key_ele = int(input("请输入要查找的元素:"))

#设置一个标记
flag = False #默认没有找到

#遍历列表
for ele in list0:
    if ele == key_ele:
        print("找到了该元素")
        flag = True
        #break
# else:
#     print("没有该元素")

if flag == False:
    print("没有找到该元素")



#把顺序查找的方式封装成函数 找到返回数据对应的索引 找不到返回-1
'''
未知项:
    两个未知项
        1.进行查找的序列
        2.要查找的元素

'''
def search_ele(src_list, key_ele):
    for i in range(len(src_list)):
        if src_list[i] == key_ele:
            return i

    return -1

res = search_ele([23, 19, 28, 17, 22, 55, 19], 19)
print(res)

'''
获得指定元素在列表中的所有位置
如果这个元素在列表中 返回所有的位置
没有的话返回-1
'''
def search_all_ele(src_list, key):
    #需要一个容器 存放所有的索引
    index_list = []
    for i in range(0, len(src_list)):
        if src_list[i] == key:
            index_list.append(i)

    # if len(index_list) == 0:
    #     return -1
    # else:
    #     return index_list
    return -1 if len(index_list) == 0 else index_list


res = search_all_ele([23, 19, 28, 17, 22, 55, 19], 29)
print(res)

听写

使用系统提供的方法:

s = "nice to meet you you are very beautiful"
1. 获得字符串的长度
	res = len(s)
2. 从字符串中的第一个"o" 开始提取子串
	index = s.find("o")
	sub_s = s[index:]
3. 对字符串以空格为分割符 进行分割
	str_list = s.split(" ")
4. 将分割后的数据使用"--"为拼接符拼接在一起
	res = "--".join(str_list)
5. 对分割后的数据进行排序 以字符串长度为排序标准  进行降序排序
	str_list.sort(key=len, reverse=True)
6. 将s字符串进行反转
	res = s[::-1]  #[-1:-len(s)-1:-1]
7. 将s字符串的首字母大写 其他字母为小写
	res = s.capitalize()
8. 将s字符串中每个单词的首字母大写
	res = s.title()
9. 对s字符串以"gbk"形式进行编码 和 解码
	编码: 将生活中的数据编译成计算机识别的数据[字节数据]
	解码: 将计算机识别的数据[字节数据]转义成生活中的数据

	encode_data = s.encode(encoding="gbk")
	decode_str = encode_data.decode(encoding="gbk")
10.判断字符串的内容是否是纯字母
	res = s.isalpha()
11. 判断字符串的内容是否是纯数字
	res = s.isdigit()

	s.isalnum() # 是否是字母或数字
问题
1.break的使用
	break 作用于循环语句 跳出当前所在的循环

	#设置一个功能: 可以接受任意参数 获得这些数据中的奇数
	def get_odd(*values): #values = (12, 13, 17, 28, 15)
		odd_list = []
		for v in values: #v = 12
			if v % 2 == 0:
				#break
				continue
			else:
				odd_list.append(v)
		return odd_list

	get_odd(12, 13, 17, 28, 15)

3.遍历序列
	list0 = ["nice", "beauty", "family"]
	max_value = list0[0]

	for i in list0:
		if len(i) > len(max_value):
			max_value = i
	print(max_value)

	#索引
	for i in range(0, len(list0)):
		if len(list0[i]) > len(max_value):
			max_value = list0[i]
	print(max_value)

	#遍历序列的时候
		如果后面跟随的是序列  前面的变量接受的是序列中的元素值  可不是索引
		后面跟随的是range(0, len(list0)) 这个时候才获取的是索引

作业:
'''
 3.字符串第一个字符大写 其他小写
 4.字符串中每个单词的首字母大写 其余小写
 5.去除掉字符串两端的指定内容
        思路:从前向后按照内容长度提取子串 与指定内容比较 记录起始位置 一直到不相等位置
             提取后面的内容与子串内容比较 记录索引 一致到不相等位置
             根据前后索引 利用切片提取子串
'''
#字符串第一个字符大写 其他小写
def cus_capitalize(src_str):
    #声明一个变量 记录改变之后的字符串
    new_str = ""
    if len(src_str) != 0:
        #判断第一个字符:
        if "a" <= src_str[0] <= "z":
            new_str += chr(ord(src_str[0]) - 32)
        else:
            new_str += src_str[0]
        #遍历第一个之后的
        for i in range(1, len(src_str)):
            if "A" <= src_str[i] <= "Z":
                new_str += chr(ord(src_str[i]) + 32)
            else:
                new_str += src_str[i]
    return new_str

res = cus_capitalize("abC")
print(res)

def cus_title(src_str):
    new_str = ""
    #对字符串进行切割
    str_list = src_str.split(" ") #列表中存放的一个个的字符串
    print(str_list)
    #遍历列表
    # for i in range(0, len(str_list)):
    #     if i == len(str_list) -1:
    #         new_str += cus_capitalize(str_list[i])
    #     else:
    #         new_str += cus_capitalize(str_list[i]) + " "

    #设置一个新的列表 存放转换之后的字符串
    new_str_list = []
    for ele in str_list:
        new_ele = cus_capitalize(ele)
        new_str_list.append(new_ele)
    new_str = " ".join(new_str_list)

    return new_str

res = cus_title("hello nice")
print(res)


'''
 5.去除掉字符串两端的指定内容
        思路:从前向后按照内容长度提取子串 与指定内容比较 记录起始位置 一直到不相等位置
             提取后面的内容与子串内容比较 记录索引 一致到不相等位置
             根据前后索引 利用切片提取子串

 abcabc1234567abc
'''
def cus_strip(src_str, del_str):
    '''
    去除字符串两端的指定内容
    :param src_str:  原生的字符串
    :param del_str:  要删除的指定内容
    :return:  返回的是去取指定内容之后的字符串
    '''

    #起始索引
    start = 0
    #结束索引
    end = len(src_str)

    #从前向后看
    while True:
        sub_str = src_str[start:start + len(del_str)]
        if sub_str == del_str:
            start += len(del_str)
        else:
            break

    #从后向前看
    while True:
        end_sub_str = src_str[end - len(del_str):end]
        if end_sub_str == del_str:
            end -= len(del_str)
        else:
            break
    return src_str[start:end]

res = cus_strip("abcab123456abcabc", "abc")
print(res)


s = "abcabc1234556abcabc"
res = s.startswith("abc")
print(res)
#指定起始位置  查看从该位置开始是否以指定内容开头
res = s.startswith("abc",4)
print(res)

res = s.endswith("abc")
print(res)
#指定起始位置和结束位置  查看从该位置开始是否以指定内容结尾
res = s.endswith("abc",0, 15)
print(res)

def cus_strip_1(src, del_str):
    #起始位置
    start = 0
    #设置一下结束位置
    end = len(src)

    #从前向后看
    while True:
        start_res = src.startswith(del_str, start)
        if start_res == True:
            start += len(del_str)
        else:
            break

    #从后向前看
    while True:
        end_res = src.endswith(del_str, 0, end)
        if end_res == True:
            end -= len(del_str)
        else:
            break

    return src[start:end]

res = cus_strip_1("abcab123456abcabc", "abc")
print(res)


# list0 = [“nice”, “你好”, “今天天气真好”, “beautiful”, “family", 15, 67, 31]
# 1.提取列表中的所有字符串存放于新的列表中 str_list
list0 = ["a", "b", "c", 10, 12, "d"]
str_list = []
# for ele in list0:
#     if type(ele) == str:
#         str_list.append(ele)
# print(str_list)

for ele in list0:
    #推荐使用的 判断数据是否是指定类型
    if isinstance(ele, str):
        str_list.append(ele)
print(str_list)

# list0 = [“nice”, “你好”, “今天天气真好”, “beautiful”, “family", 15, 67, 31]
# 1.提取列表中的所有字符串存放于新的列表中 str_list
list0 = ["a", "b", "c", 10, 12, "d"]
str_list = []
# for ele in list0:
#     if type(ele) == str:
#         str_list.append(ele)
# print(str_list)

for ele in list0:
    #推荐使用的 判断数据是否是指定类型
    if isinstance(ele, str):
        str_list.append(ele)
print(str_list)
32.4 列表中的知识
关于排序的算法
以升序为例:---> 大
冒泡排序:
	规则:
		遍历列表中的数据[循环]:
			从索引为0的位置开始 前后两个元素之间两两进行比较
				如果前者 > 后者:
					两者交换位置
			第一次遍历完成 --- 获得最值

		一直遍历到排好序为止


获取列表的最值:

list0 = [34, 71, 29, 18, 44]

#获得最小值
#1. 声明一个变量 接受比较之后的最小值 假设第一个元素是最小的
min_value = list0[0]
#遍历列表
for ele in list0:
 if ele < min_value:
     min_value = ele
print(min_value)


#2.设置最小值对应的索引 假设最小值对应的索引是0
min_index = 0
#根据索引去遍历
for i in range(1, len(list0)):
 if list0[i] < list0[min_index]:
     min_index = i
print(list0[min_index])




l0 = [56, 27, 31, 44, 29]

#外层控制的是遍历的次数  len(l0) - 1
for out in range(1, len(l0)):
 for inner in range(0, len(l0)-out):
     if l0[inner] > l0[inner + 1]:
         l0[inner], l0[inner + 1] = l0[inner + 1], l0[inner]

print(l0)		

升序排序:---> 大
选择排序:每次遍历找最值: 降序的话找最大值 升序的话找最小值
	规则:
		遍历列表
			第一次遍历:
				假设脚标为0的位置的元素是最小的
				将这个位置的元素与之后的每一个元素进行比较
					脚标为0的位置的元素 > 后面的元素:
						两者交换数据 ----> 脚标为0的位置存放的最小值
			第二次遍历:
				假设脚标为1的位置的元素是最小的
				将这个位置的元素与之后的每一个元素进行比较
					脚标为1的位置的元素 > 后面的元素:
						两者交换数据 ----> 脚标为1的位置存放的最小值
			...

			直到排好序为止
两种方式:
#方式1: 直接找最小值元素
list0 = [56, 27, 31, 44, 29]

for out in range(0, len(list0)-1):
 for inner in range(out + 1, len(list0)):
     if list0[out] > list0[inner]:
         list0[out], list0[inner] = list0[inner], list0[out]

print(list0)

#方式2: 找最小值对应的脚标
#根据索引获取最值
for out in range(0, len(list0)-1):
 #假设固定脚标对应的元素是最小的
 min_index = out
 for inner in range(out + 1, len(list0)):
     if list0[inner] < list0[min_index]:
         min_index = inner
 #这个时候找到的是最小值对应的脚标  最小值对应的元素应该放于固定的位置上
 #交换固定脚标与最小值对应的脚标两个位置的数据
 list0[out], list0[min_index] = list0[min_index], list0[out]
print(list0)
升序:----> 大
插入排序:-- 与冒泡是反向走的
	遍历的列表:
		第一次遍历的时候 从脚标为1的元素开始 与前面的元素两两进行比较
		第二次遍历的时候 从脚标为2的元素开始 与前面的元素两两进行比较
		....
		排好序为止
	插入排序 ---- 会达到部分有序的情况
list0 = [56, 27, 31, 44, 29]

for out in range(1, len(list0)):
 for inner in range(out, 0, -1):
     if list0[inner] < list0[inner-1]:
         list0[inner], list0[inner-1] = list0[inner-1], list0[inner]
     else:
         break

print(list0)

列表中提供了排序的方式:

list0 = [56, 27, 31, 44, 29]
list0.sort()#升序
list0.sort(reverse = True) #降序  影响的是列表本身 没有生成新的列表
import operator  
一. 按字典值排序(默认为升序)  
x = {1:2, 3:4, 4:3, 2:1, 0:0}   
1. sorted_x = sorted(x.iteritems(), key=operator.itemgetter(1))  
print sorted_x  
#[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]  
#如果要降序排序,可以指定reverse=True  
2. sorted_x = sorted(x.iteritems(), key=operator.itemgetter(1), reverse=True)  
print sorted_x  
#[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]  . 或者直接使用list的reverse方法将sorted_x顺序反转  
#sorted_x.reverse()  . 更为常用的方法是,lambda表达式  
3. sorted_x = sorted(x.iteritems(), key=lambda x : x[1])  
print sorted_x  
#[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]  
4. sorted_x = sorted(x.iteritems(), key=lambda x : x[1], reverse=True)  
print sorted_x  
#[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]  . 包含字典dict的列表list的排序方法与dict的排序类似,如下:  
  x = [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]  
sorted_x = sorted(x, key=operator.itemgetter('name'))  
print sorted_x  
#[{'age': 10, 'name': 'Bart'}, {'age': 39, 'name': 'Homer'}]  
sorted_x = sorted(x, key=operator.itemgetter('name'), reverse=True)  
print sorted_x  
#[{'age': 39, 'name': 'Homer'}, {'age': 10, 'name': 'Bart'}]  
sorted_x = sorted(x, key=lambda x : x['name'])  
  print sorted_x  
#[{'age': 10, 'name': 'Bart'}, {'age': 39, 'name': 'Homer'}]  
5. sorted_x = sorted(x, key=lambda x : x['name'], reverse=True)  
print sorted_x  
#[{'age': 39, 'name': 'Homer'}, {'age': 10, 'name': 'Bart'}] 
关于查找
顺序查找:
	规则:
		遍历列表 获取列表中的元素 与待查找的数据进行对比 进而进行查找行为
list0 = [34, 71, 29, 30, 46, 77]

key_ele = int(input("请输入要查找的元素:"))

#设置一个标记
flag = False #默认没有找到

#遍历列表
for ele in list0:
 if ele == key_ele:
     print("找到了该元素")
     flag = True
     #break
# else:
#     print("没有该元素")

if flag == False:
 print("没有找到该元素")



#把顺序查找的方式封装成函数 找到返回数据对应的索引 找不到返回-1
'''
未知项:
 两个未知项
     1.进行查找的序列
     2.要查找的元素

'''
def search_ele(src_list, key_ele):
 for i in range(len(src_list)):
     if src_list[i] == key_ele:
         return i

 return -1

res = search_ele([23, 19, 28, 17, 22, 55, 19], 19)
print(res)

'''
获得指定元素在列表中的所有位置
如果这个元素在列表中 返回所有的位置
没有的话返回-1
'''
def search_all_ele(src_list, key):
 #需要一个容器 存放所有的索引
 index_list = []
 for i in range(0, len(src_list)):
     if src_list[i] == key:
         index_list.append(i)

 # if len(index_list) == 0:
 #     return -1
 # else:
 #     return index_list
 return -1 if len(index_list) == 0 else index_list


res = search_all_ele([23, 19, 28, 17, 22, 55, 19], 29)
print(res)
二分法查找:
	查找算法
	查找前提: 列表必须是有序[升序或者降序]的状态的
	以升序为例:---> 大

	规则:
		利用索引设置一个查找区间[min, max] ===> [0, len(list0)-1]
		获取区间中的中间索引位置 mid = (min + max) // 2

		将中间索引位置对应的元素 与 待查找的元素进行比较
			list0[mid] == key_ele ----> 找到了
			list0[mid] > key_ele:
				更新查找范围:更新结束索引 max = mid - 1
			list0[mid]  < key_ele:
				更新查找范围:更新开始索引 min = mid + 1

			范围更新好了 --- 出现了新的查找范围
				更新该范围下的中间索引 mid = (min + max) // 2

	什么情况下找不到?????
 	从查找范围来看   max < min
 		[min, max] --- 区间不合理的情况下 找不到的情况

#只对排好序的列表进行查找 --- 以升序为例
def half_search(src_list, key):
 #设置查找初始区间
 min_index = 0
 max_index = len(src_list) - 1
 #获得初始区间对应的中间索引
 mid_index = (min_index + max_index) // 2

 #循环查找: 要查找的元素 与 中间索引对应的元素不相等
 while key != src_list[mid_index]:
     if key > src_list[mid_index]:
         #更新查找区间  取后面查找
         min_index = mid_index + 1
     elif key < src_list[mid_index]:
         #更新区间 去前面找
         max_index = mid_index - 1

     #上面的两种情况 都更新了区间范围 需要判断区间的合理性
     #[0, 1]
     if max_index >= min_index:
         #区间是合法的  获取该区间下的中间索引
         mid_index = (min_index + max_index) // 2
     else:
         #区间不合法了  结束查找
         return -1

 #出了循环 代表数据已经找到了 返回对应的位置
 return mid_index

res = half_search([34, 51, 66, 72, 83], 183)
print(res)
二维列表
什么叫做二维列表:
	列表中的元素的类型依然是列表类型的

1.如何获得二维列表中 一维列表的元素
	接受二维列表的变量名[索引][索引]
	#列表中的元素的数据类型依然是列表

   #声明方式
   two_list = [[15, 78],[24, 56]]
   print(two_list)

   #或者
   list0 = [12, 34, 56]
   list1 = [77, 22]
   two_list = [list0, list1]
   print(two_list)

   #获取内层列表中的元素
   res = two_list[0]
   print(res) #res也是一个列表

   value = res[0]
   print(value)

   #上述的两个式子可以合并
   value = two_list[0][0]
   print(value)
2.对二维列表进行遍历
for ele in two_list:
 print(ele) #接受是二维列表中的内层列表
 for e in ele: #想获取内层列表的数据 需要对内层列表进行遍历
     print(e)
32.5 元组数据类型
元组也是容器 可以存放多个数据 每个数据都有自己的编号 编号是从0开始的
与列表的区别:
	1. 列表长度是可变的 元组时不可变的
	2. 列表中元素对应的地址是可变的, 元组中元素对应的地址是不可变的
	3. 列表的标识是[], 元组的标识是()
	4. 只有一个元素时, 列表中可以在中括号中直接包含元素数据
		在元组中必须得在该数据的后面添加逗号 否则解释器会将小括号解释为提高优先级的含义
常用方法:
#1. 声明方式
#1.1 使用方法进行声明
'''
tuple() -- 生成的是一个空元祖
tuple(序列) -- 将指定序列转化为元组
    将序列中每一个元素存放于元组中
'''
tuple0 = tuple() # ===> ()
print(tuple0)

tuple0 = tuple("abc")
print(tuple0)

tuple0 = tuple([12, 34])
print(tuple0)

tuple0 = tuple({"a":97, "b":98})
print(tuple0)

tuple0 = tuple({"a":97, "b":98}.values())
print(tuple0)

tuple0 = tuple({"a":97, "b":98}.items())
print(tuple0)

tuple0 = tuple({12, 34, 56, 77})
print(tuple0)

#1.2 字面量形式的声明
tuple1 = ()
print(tuple1)

#注意只有一个元素的时候 要在元素的后面添加逗号
tuple1 = (10)
print(tuple1)
print(type(tuple1)) #int

tuple1 = (10,)
print(tuple1)
print(type(tuple1)) #tuple


tuple1 = (34, 56, 71, 28, ["a", "b"])
#2.可以通过索引获取元组中的数据
'''
索引有两种表示方式:
    [0, len(tuple1)-1]
    [-len(tuple1), -1]
'''
value = tuple1[0]
print(value)

#3.元组中元素对应的地址是不可变的  但是允许地址中对应的内容发生变化
#tuple1[4] = None #    tuple1[4] = None
#TypeError: 'tuple' object does not support item assignment

tuple1[4][0] = "M"
print(tuple1)


tuple1 = (13, 45, 71, 28)
#4.切片 --- 提取子元组
'''
[start:stop:step]
start 和 stop表示索引 可以省略 省略的话 默认是从头到尾  但是两者之间的冒号不允许省略

step 表示是步长 默认是1  步长如果省略的话 前面的冒号可以省略
如果修改了步长 冒号必须有
'''
sub_t = tuple1[:]
print(sub_t)

sub_t = tuple1[:2]
print(sub_t)

sub_t = tuple1[1:]
print(sub_t)

sub_t = tuple1[::-1]
print(sub_t)


#5. 在元组中能够使用的运算符
'''
+: 合并两个元组 将合并的结果存放于一个新的元组中
in: 成员的判断
* : 乘以的是一个正整数  将圆元组中的数据重复n倍 存放于一个新的元组中

跟列表/字符串比较是一致的
两者以相同索引位置的元素一一进行比较
>=
<=
>
<
==
!=
'''
tuple1 = (12, 34)
tuple2 = (55, 66)
new_tuple = tuple1 + tuple2
print(new_tuple, tuple1, tuple2)

new_tuple = tuple1 * 5
print(new_tuple)


#6. 常用方法的使用:
#6.1 获取指定元素出现的个数
num = new_tuple.count(12)
print(num)

#6.2 获取某个元素第一次出现的位置 不常用
index = new_tuple.index(12)
print(index)
32.6 字典的使用
字典中存放的数据是成对出现的, 存放的是具有映射关系的数据. 
注意: 字典是没有编号一说, 字典是根据键查找数据的
字典:
	字典的键不允许重复
字典的类型的名字: dict
字典的标识是 {}
字典的使用场景:
		如果想显示的数据是成对出现的 ----> 必须使用字典
键值对的格式:
	key:value

常用的方式:

#1.字典的声明方式
#1.1 使用方法声明
#生成空的字典
dict0 = dict() #===> {}
print(dict0)

#将序列转化为字典 序列的要求: 该序列必须是二维序列 内层序列中必须有两个元素
# [[12, 34],[34, 56]]
two_list = [[12, 34],[34, 56]]
for item in two_list:
 k, v = item
 print(item)
 print(k, v)
for k, v in two_list:
 print(k, v)

dict0 = dict(two_list)
print(dict0)

new_dict = {}
for k, v in two_list:
 print(k, v)
 new_dict[k] = v
print(new_dict)

#可以接受关键字参数
dict0 = dict(one=1, two=2)
print(dict0)

#变量的数据可以来源于容器
# a, b = 12, 34
# a, b = [12, 34]

#1.2使用字面量形式 - 直接使用{}来完成字典的声明
dict1 = {} #空的字典
print(dict1)
dict1 = {"a":97, "b":98, "d":100, "c":99}
print(dict1)
-----------------------------------------------------------------------------------
#2.字典是根据键来查找值的
#查找方式: 变量名[键]  #这种方式有一个弊端 如果键不存在 会报错keyerror  不建议使用这种方式获取值
value = dict1["b"]
print(value)

# value = dict1["B"]
# print(value)

#通过这种方式添加键值对 或者 为某个键修改值
#如果键不存在 会添加一个新的键值对 如果存在 会新值覆盖旧值
#格式: 变量名[键] = 值
dict1["a"] = 90
print(dict1)

dict1["e"] = 101
print(dict1)

#建议使用下列方法根据键获取值
#如果键不存在返回None
#变量名.get(键)
value = dict1.get("B")
print(value)
-----------------------------------------------------------------------------------
#合并字典 -- 会将后面的字典的内容合并到前者
dict2 = {"z":122, "y":121, "a":97}
dict1.update(dict2)
print(dict1)
-----------------------------------------------------------------------------------
#3.删除键值对
#变量名.pop(键)
dict1.pop("b")
print(dict1)

#或者 借助del ==delete关键字
del dict1["c"]
print(dict1)

#del可以删除任意变量
a = 10
print(a)

del a  #直接将对应的变量在内存中删除
#print(a)

list0 = [12, 34, 56]
del list0[0]
print(list0)
-----------------------------------------------------------------------------------
#删除最后一个键值对
dict1.popitem()
print(dict1)
-----------------------------------------------------------------------------------
#获取字典中所有的键
keys = dict1.keys()
print(keys)
-----------------------------------------------------------------------------------
#获得字典中所有的值
values = dict1.values()
print(values)
-----------------------------------------------------------------------------------
#获得所有的键值对
items = dict1.items()
print(items)
-----------------------------------------------------------------------------------
#字典的遍历
#直接遍历字典 获取的是字典中的键
for ele in dict1:
print(ele)
-----------------------------------------------------------------------------------
for ele in dict1.keys():
print(ele)

#遍历所有的值
for v in dict1.values():
print(v)

#获取键值对 -- 只能遍历items
for item in dict1.items():
print(item)
k, v = item
 print("{}:{}".format(k, v))

for k, v in dict1.items():
print("{}:{}".format(k, v))
-----------------------------------------------------------------------------------
#清空字典
dict1.clear()
print(dict1)
-----------------------------------------------------------------------------------
#清空列表
[12, 34].clear()
-----------------------------------------------------------------------------------
案例:
	统计字符串中每个字符出现的次数
	思路: 需要一个字典的容器存放最终显示的数据  键:值  字符当做键 次数是值
		遍历字符串 获取每一个字符
			字符第一次出现 次数是1
			之后再出现 在原来的基础上+1
			问题: 如何判断时候是第一次出现???????
				判断字典中是否有对应的字符为键 ---> 键是否被字典包含 ---> 键是否是字典的成员 in
s = "hellohighgoodnicelike"
#1.声明一个字典
count_dict = {}
#2.遍历字符串
for ch in s:
#判断这个字符串是否已经在字典中作为键
if ch not in count_dict:
  count_dict[ch] = 1
 else:
     count_dict[ch] += 1
print(count_dict)

#获得出现次数最高的字符
#1. 需要获得value中的最大值
max_count = max(count_dict.values())
print(max_count)

#2. 声明一个容器 存放满足最大值的键
key_list = []
#3.遍历字典的键值对
for k, v in count_dict.items():
if v == max_count:
  key_list.append(k)
print(key_list)
练习:
	字符串word = "good good study day day up"

	a. 获取上述字符串中每个单词出现的次数
	b. 获得长度最长的单词
word = "good good study day day up"
word_list = word.split(" ")
print(word_list)
word_dict = {}
for w in word_list:
if w not in word_dict:
  word_dict[w] = 1
else:
     word_dict[w] += 1
print(word_dict)

#根据长度获得列表中的最值
max_len = max(word_list, key=len)
print(max_len)
32.7 集合的使用
集合也是一个容器, 容器内的数据是不会重复, 无序的[存放顺序与显示顺序不一致]
集合也没有索引一说
集合的作用: 去重 将重复的数据只保留1个
		===> 去重之后数据的顺序可能与原来不一致
集合的类型名字为set


help(set)=====>查看set的方法

常用方法:

#1. 声明方式
#1.1使用方法
set0 = set() #生成的是一个空集合  空集合的表示方式只有一种:  set()
print(set0)
#将其他序列转化为集合
set0 = set("abcdefa")
print(set0)

set0 = set((14, 51,27))
print(set0)

set0 = set([99, 27, 38, 27])
print(set0)

data = {} #====> 表示的是空的字典

#1.2 字面量
set1 = {12, 34, 56,71}
print(set1)

#2. 运算符
'''
&
 求两个集合的交集 并把数据存放于一个新的集合中
|
 求两个集合的并集 并把数据存放于一个新的集合中
^
 求两个集合的非交集 并把数据存放于一个新的集合中
-
 在前者集合中去除掉与后者交集的部分
>=
>
<=
<
==
!=
'''
set1 = {12, 34, 56}
set2 = {34, 28, 19}

new_set = set1 & set2
print(new_set, set1, set2)

new_set = set1 | set2
print(new_set, set1, set2)

new_set = set1 ^ set2
print(new_set, set1, set2)

new_set = set1 - set2
print(new_set, set1, set2)


set1 = {23, 18, 19, 28, 71}
#3.在集合中添加元素
set1.add(99)
print(set1)

#4.在集合中移除元素
#4.1 清空
# set1.clear()
# print(set1)

#4.2 移除元素 如果该元素存在 移除 不存在没有任何影响
set1.discard(189)
print(set1)

#4.3 remove ---> 如果不存在会报错
# set1.remove(189)
# print(set1)

#4.4 pop 移除的任意的一个 会把删除的元素返回  如果是一个空集合  会报错
value = set1.pop()
print(set1, value)

value = set1.pop()
print(set1, value)


set1 = {12, 34, 56}
set2 = {34, 56, 71}
#5.其他方法的使用
#求的是交集
#生成了一个新的集合 存放交集
new_set = set1.intersection(set2)
print(new_set, set1, set2)

#求的是交集 没有生成新的集合 而是直接影响了前者
# set1.intersection_update(set2)
# print(set1, set2)

#求并集
new_set = set1.union(set2)
print(new_set, set1, set2)

# set1.update(set2)
# print( set1, set2)

#求非交集^
new_set = set1.symmetric_difference(set2)
print(new_set, set1, set2)

# set1.symmetric_difference_update(set2)
# print(set1, set2)


#在前者中去除掉与后者的交集  -
new_set = set1.difference(set2)
print(new_set, set1, set2)
#
# set1.difference_update(set2)
# print(set1, set2)

#判断的方式
#1. 判断两个集合是否没有交集
res = set1.isdisjoint(set2)
print(res)

#2. 判断前者是否是是后者的子集
res = set1.issubset(set2)
print(res)

#3. 判断后者是否是前者的子集
res = set1.issuperset(set2)
print(res)
32.8 集合和字典无序的本质
本质:
	源于底层的数据结构

集合的底层数据结构是哈希表
哈希表的组成是由数组和链表组成的

数组的使用:
	数组是一个定长的 但是允许数据发生改变的容器
	也是有索引定位数据
链表:
	由节点组成的 分为单向链表和双向链表
	单向链表:
		节点是由两部分组成的:存储的数据 + 下一个节点的地址
	双向链表:
		节点由三部分组成: 上一个节点的地址 + 存储的数据 + 下一个节点的地址
哈希表: 数组和链表组成的

在哈希表中存放数据:
	将数据经过哈希函数运算, 生成一个与数组中对应的索引, 根据这个索引定位到数组中的位置, 在该位置处创建一个链表节点,包含要存放的数据

	再次放数据的时候, 将该数据经过哈希函数的运算 生成在数组中对应的索引 根据这个索引定位到数组中的位置, 如果这个位置有数据, 新值覆盖旧值的情况, 如果没有数据, 就在此处生成一个链表节点 存放数据

哈希表的数据结构与数组这种数据结构的优缺点:
	字典/集合 与 列表的优缺点:
		从内存角度分析
     	字典/集合比列表属于浪费内存
     		因为列表存放数据 从索引0开始依次存放数据
     		但是字典/集合 是根据函数计算出来的索引 可能会造成索引跳跃站位的情况 导致某些索引位置处没有数据 但是却占用者内存

     从查找效率的角度分析[真对于大量数据]
     	列表的查询效率要比字典/集合慢
     		因为列表查询数据的话 需要从头到尾遍历 进行比较判断 如果数据靠后的话 查找会很不便
     		字典是根据键查寻对应的数据 直接将键经过函数运算出来索引 直接定位到指定索引对应的数据

33. 列表生成式和字典生成式*******

列表生成式/字典生成式 可以理解成对列表或者字典筛选的简化方式 可以快速的生成列表和字典
列表生成式的格式:
	列表的标识是[]
	[要存入列表中的数据 数据的来源 [对数据的筛选]]
		====> [对数据的筛选] 可能有 可能没有 看需求

案例:
	生成一个存放1-100的数据的列表
#生成一个存放1-100的数据的列表
list0 = []
for i in range(1, 101):
 list0.append(i)
print(list0)

# list0 = [1, 2, 3, 4..10]
# list0 = list(range(1, 101))
# print(list0)

#列表生成式 -- 数据根据for循环来的
list0 = [i for i in range(1, 101)]
print(list0)


str_list = ["hello", "nice", "10", "20", "good"]
new_list = []
for ele in str_list:
 if ele.isalpha():
     new_list.append(ele)
print(new_list)

new_list = [ele for ele in str_list if ele.isalpha()]
print(new_list)

#列表生成式
'''
1. 生成1-10之间的偶数
2. list0 = [12, 34, 56, True, "nice", "like", 3.14]
    提取整数类型的数据存放于列表中
3. list0 = ["    ", "  good_study\n", "\n\t", "    \n", "    \t", "\tnice"]
    提取列表中的非空白字符序列
    字符串的strip 什么都不传 去除的字符串两端的空白序列

    字符串的split
    split如果什么都不传 默认以空白字符序列来进行分割 分割之后结果中的空字符串会被移除
'''
#1.
new_list = [ele for ele in range(1, 11) if ele % 2 == 0]
print(new_list)

#2.
list0 = [12, 34, 56, True, "nice", "like", 3.14]
new_list = [ele for ele in list0 if type(ele) == int]
print(new_list)

new_list = [ele for ele in list0 if isinstance(ele, int) and not isinstance(ele, bool)]
print(new_list)

#3.
list0 = ["    ", "  good_study\n", "\n\t", "    \n", "    \t", "\tnice"]
new_list = [ele for ele in list0 if ele.strip() != ""]
new_list = [ele for ele in list0 if len(ele.strip()) != 0]
new_list = [ele for ele in list0 if ele.split() != []]
new_list = [ele for ele in list0 if len(ele.split()) != 0]
print(new_list)

print("      ".strip(), "v", sep="")

print("   ".split())
字典生成式:
字典的标识是{}
字典生成式格式
	{键值对 键值对来源 [对键值对的筛选]}
		[对键值对的筛选] --- 可有可无 按照需求设定
案例:
	count_dict = {"a":7, "h":3, "m":9, "k":2}
	---> 提取字典中次数大于5的键值对 存放于新的字典中
'''
count_dict = {"a":7, "h":3, "m":9, "k":2}
	---> 提取字典中次数大于5的键值对 存放于新的字典中
'''

count_dict = {"a":7, "h":3, "m":9, "k":2}
new_dict = {}
for k, v in count_dict.items():
    if v >= 5:
        new_dict[k] = v
print(new_dict)

#字典生成式
new_dict = {k:v for k, v in count_dict.items() if v >= 5}
print(new_dict)

'''
1.
    字典:
        score_dict = {"政治":77, "英语":57, "语文":82, "历史":62}
        提取成绩大于等于60的成绩存放于新的字典中
2. word = "hello nice to meet you nice to meet you too"
    获得每个单词出现的次数 存放于字典中
    将单词长度大于3的键值对 存放于新的字典中
'''
#1.
score_dict = {"政治":77, "英语":57, "语文":82, "历史":62}
new_dict = {k:v for k,v in score_dict.items() if v >= 60}
print(new_dict)

#2.
word = "hello nice to meet you nice to meet you too"
list1 = word.split()
word_dict = {}
for i in list1:
    if i not in word_dict:
        word_dict[i] = 1
    else:
        word_dict[i] += 1
print(word_dict)

new_dict = {k:v for k, v in word_dict.items()  if len(k) > 3}
print(new_dict)

34. 深浅拷贝

地址对应的内容不可以发生变化的数据 是没有拷贝一说的 即使使用拷贝方式 生成的结果使用还是原来的地址
	例如数值类型 字符串类型
拷贝需要导入模块 copy
copy.copy(数据) ##浅拷贝: 生成一个新的地址 来存放最外层数据的内容  内层数据对应的地址还是使用的原来的

copy.deepcopy(数据) ##深拷贝: 数据一致 但是内外对应的地址不一样
#地址对应的内容不可以发生变化的数据 是没有拷贝一说的 即使使用拷贝方式 生成的结果使用还是原来的地址
	#例如数值类型 字符串类型
import copy

# a = 10
# print("原数据地址:",id(a))
# #进行浅拷贝
# b = copy.copy(a)
# print("浅拷贝数据对应的地址:",id(b))
# #进行深拷贝
# c = copy.deepcopy(a)
# print("深拷贝数据对应的地址:",id(c))
'''
原数据地址: 1916038448
浅拷贝数据对应的地址: 1916038448
深拷贝数据对应的地址: 1916038448
'''

# a = "hello"
# print("原数据地址:",id(a))
# #进行浅拷贝
# b = copy.copy(a)
# print("浅拷贝数据对应的地址:",id(b))
# #进行深拷贝
# c = copy.deepcopy(a)
# print("深拷贝数据对应的地址:",id(c))
'''
原数据地址: 2687755858192
浅拷贝数据对应的地址: 2687755858192
深拷贝数据对应的地址: 2687755858192
'''
####元素地址对应内容可变的数据 进行深浅拷贝
'''
地址对应的内容数据是可以发生变化的  可以进行深浅拷贝
例如列表中的数据是可以发生变化的

如果内层数据对应的地址是不能发生变化的  深浅拷贝的结果对于内层数据而言是一致的
'''

# list0 = ["a", "b", "c"]
# print("原数据的地址:", id(list0))
# print("内层数据的地址:", id(list0[0]))
# #进行浅拷贝
# list1 = copy.copy(list0)
# print(list1)
# print("浅拷贝生成的地址:", id(list1))
# print("浅拷贝内层数据的地址:", id(list1[0]))
#
# #进行深拷贝
# list2 = copy.deepcopy(list0)
# print(list2)
# print("深拷贝生成的地址:", id(list2))
# print("深拷贝内层数据的地址:", id(list2[0]))

# list0 = ["a", "b", "c"]
# list1 = ["hello", 12, list0]
# print("原数据对应的地址:", id(list1))
# print("内层数据地址对应的内容可以发生变化的数据的地址:", id(list1[2]))
#
# #浅拷贝
# list2 = copy.copy(list1)
# print("浅拷贝外层数据对应的地址:", id(list2))
# print("浅拷贝内层数据地址对应的内容可以发生变化的数据的地址:", id(list2[2]))
#
# #深拷贝
# list3 = copy.deepcopy(list1)
# print("深拷贝外层数据对应的地址:", id(list3))
# print("深拷贝内层数据地址对应的内容可以发生变化的数据的地址:", id(list3[2]))
特殊的数据类型: 元组
元组的特殊性:  元组中元素对应的地址是不可变的
#特殊的数据是元组
'''
元组中元素的地址是不允许发生变化的
'''
# tuple0 = (12, 34)
# tuple0[1] = 88 #TypeError: 'tuple' object does not support item assignment

tuple0 = (12, 34, ["a", "b"])
#tuple0[2] = [55, 66] #TypeError: 'tuple' object does not support item assignment
tuple0[2][0] = "A"  #元组中元素的地址没有发生变化 但是该地址对应的内容发生变化 这个是可以的
print(tuple0)
#####元组的拷贝:

'''
拷贝中的元组
如果元组中元素地址对应的内容是不可变的  元组没有深浅拷贝一说  使用的都是原数据的地址

如果元组中元素地址对应的内容是可变的  只有深拷贝一说
'''
# tuple1 = (12, "hello")
# print("原数据的地址:", id(tuple1))
#
# #浅拷贝
# tuple2 = copy.copy(tuple1)
# print("浅拷贝的地址:", id(tuple2))
#
# #深拷贝
# tuple3 = copy.deepcopy(tuple1)
# print("浅拷贝的地址:", id(tuple3))

tuple1 = (12, "hello", [34, 21])
print("原数据的地址:", id(tuple1))
print("内层地址对应内容可变数据的地址:", id(tuple1[2]))
#浅拷贝
tuple2 = copy.copy(tuple1)
print("浅拷贝的地址:", id(tuple2))
print("浅拷贝内层地址对应内容可变数据的地址:", id(tuple2[2]))

#深拷贝
tuple3 = copy.deepcopy(tuple1)
print("浅拷贝的地址:", id(tuple3))
print("深拷贝内层地址对应内容可变数据的地址:", id(tuple3[2]))
总结:
	1. 没有拷贝一说的
			数值类型
			字符串类型
			元组中元素的地址对应的内容是不可变的时候
	2.没有浅拷贝 只有深拷贝一说
			元组中元素的地址对应的内容是可变的时候
	3. 具有深浅拷贝的
		列表
		字典
		集合
		以及之后自定以的数据类型
		浅拷贝:
			将数据拷贝一份 生成一个新的外层数据的地址 存放拷贝出来的数据
		深拷贝:
			将数据拷贝一份  内外数据对应的地址都生成一份新的存放拷贝出来的数据

35. 生成器

生成器的类型 generator
针对于列表生成式的弊端产生的

列表生成式快速的生成一批 数据, 这批数据会立即存放于内存中, 但是使用的使用前面一部分的数据, 对于后面的数据而言数据过度占用内存, 可以使用生成器去生成数据
生成器也可以生成一批数据, 这批数据不会立即存放于内存中 当取出来使用的时候才会在内存中存放对应的数据
生成器中数据一旦取出 生成器中就不存在该数据了 再取的话取的是数据的下一个

在生成器中取数据的方式是通过next(生成器)获取数据 这种方式如果生成器中没有数据了 再取的会报错

设计生成器的方式:
	1. 将列表生成式的[] 改为()
		(数据 数据的来源 [对数据的筛选])
	2. 将函数的定义中 return改为yield
		def 函数名():
			数据来源
				yield 数据 #返回数据
ge = (ele for ele in range(1, 11) if ele % 2 == 0)
print(ge)

#生成器中存放这数据 --  也是一个容器
# for i in ge:
#     print(i)

#通常情况下在生成器中获取数据的方式
value = next(ge)
print(value)

value = next(ge)
print(value)

value = next(ge)
print(value)

value = next(ge)
print(value)

value = next(ge)
print(value)
print("---------------------")
# value = next(ge)
# print(value) #StopIteration
def get_value():
    for i in range(1, 11):
        if i % 2 == 0:
            yield i #把数据在生成器中去除  当使用next()方式获取数据的时候 才会调用生成器的内部
            print("{}数据已经取出".format(i)) #当下一次next的时候 才会来指定者行代码

ge1 = get_value()
print(ge1)

value = next(ge1)
print(value)

value = next(ge1)
print(value)

36. 迭代器

只是序列的另外一种遍历方式
遍历的话 for in遍历就可以了

另外一种遍历方式是通过next(序列)来从序列中一个一个的获取数据
能使用next方法迭代数据的只有迭代器类型的才可以
	迭代器类型存放于collections下
		Iterable --- 验证指定的数据是否是可进行遍历的
		Iterator -- 迭代器类型
from collections import Iterable, Iterator

print(isinstance(10, Iterable))

print(isinstance("10", Iterable))

print(isinstance(("10",), Iterable))

print(isinstance(["10"], Iterable))

#可不可以通过迭代器进行遍历
print(isinstance(["10"], Iterator))
print(isinstance("10", Iterator))

print(isinstance(("10",), Iterator)) #False  不是迭代器类型 就不可以使用next进行遍历

#如何让数据可以使用迭代器进行遍历呢??
#将指定序列转化为迭代器类型
it = iter("10")

value = next(it)
print(value)

'''
如果想使用
 迭代器对字符串 元组 列表 字典 集合进行遍历 需要将其转化为迭代器类型
 it = iter(数据)
 it就是指定数据对应的迭代器类型 就可以使用next进行遍历
'''

37. 包和程序入口的设定

:

			相当于计算机中的文件夹

			常识: 在同一个目录下 不允许存在同名的两个文件

			作用:

				1.对python文件进行分类管理

				2.对python文件提供多级命名空间

				m	a.py

				n	a.py
创建包:
	选中创建包的位置 右键---> new ---> python package ----> 起一个包名
		包名的命名规范:
			符合标识符规范
			英文单词是小写的 单词之间使用下划线隔开
	计算中目录的分割是使用\来进行分割的
	在程序中包之间的分割是用.来进行分割的

	创建出来的是一个包的话
		包会自带一个__init__.py的文件 --- 标记这个目录时程序中的包 而非一个普通的文件夹

	创建出来包之后 包和包之间的python文件是可以互相访问的 普通文件夹下python文件不可以互相访问
		访问方式就是倒模块方式
			有了包之后倒模块的方式要发生变化:
				import 一级包名.二级包名...n级包名.模块名
					使用模块下的内容:
						一级包名.二级包名...n级包名.模块名.内容的名字
				from 一级包名.二级包名...n级包名.模块名 import 具体的内容名字, 内容名字1

				from  一级包名.二级包名...n级包名.模块名 import *
					*默认是导入该模块下所有内容
					但是如果模块下有__all__列表的生成  只能导入该列表下指定的内容
		起别名 as
		 	import 一级包名.二级包名...n级包名.模块名 as 别名
		 	使用模块内容时候 使用别名进行调用 而且只能使用别名调用

# import pack1.sub_pack.tool

#as 就是起别名
import pack1.sub_pack.tool as pst
#
# res = pack1.sub_pack.tool.add(12, 34)
# print(res)

res = pst.add(12, 34)
print(res)		 	


		同一个包下面的两个python文件互相访问
			导入模块的时候 可以直接使用模块名导入 如果提示错误 这个错误可以忽略
			如果看不了这个错误 导入包名.模块名
程序入口的设定:
	在程序中标记出来 起始指定文件 --- 告知其他人程序入口是哪个文件

	如何标记:
		在起始文件中加入判断语
			if __name__ == "__main__":
				程序入口中的内容

		其实每个py文件中都有一个 __name__ 这个字段
		如果起始文件 这个字段的值为 "__main__"
		其他py文件 __name__ 的值为对应的py文件名
模块导入:
	第一次进行模块导入时 解释器会针对于这个模块生成一个对应的缓存文件.pyc文件
	之后再导入的时候直接使用.pyc文件中的数据

模块时天然的单例
	单个实例
	只要我导入一次 之后不管再怎么进行导入 使用都是原来生成的那一个内容

38. 浅拷贝

对于列表和字典的数据类型中提供了浅拷贝的方式
	列表数据.copy() ===> copy.copy(列表数据)
	字典数据.copy() ====> copy.copy(字典数据)

39. 高阶函数

39.1 map函数
help(map)
'''
|  map(func, *iterables) --> map object
 第一个参数 接受的是一个函数
     函数的作用是对应序列中的中据进行指定操作的转化
     函数类似于排序是key接受的函数
         函数有一个参数  函数的返回值是 按照需求对参数转化的结果
             注意:
                 参数默认接受的数据就是序列中的每一个元素了
 第二个参数:
     序列
'''

str0 = "abcdefg"
#将字符串中的每个字符转化为大写字母
map_obj = map(lambda ele: ele.upper(), str0)
print(map_obj)
#相当于把序列中的内容取出了 取出了容器中就不存在了
# for ch in map_obj:
#     print(ch)

new_str = "".join(map_obj)
print(new_str)
#字符串的结果 是拼接出来的  能不能使用str(数据)进行转换 ===> 不可以

a = 10
print(a)
print(str(a), type(str(a)))



# list0 = ["10", "20", "30", "40"]
# map_obj = map(int, list0)
# new_list = list(map_obj)
# print(new_list)

print(str(map_obj), type(str(map_obj)))

'''
str(变量名) ---> 将变量名对应的数据转化为字符串类型
a = 10
print(a)
print(str(a), type(str(a)))
str(a) ---> a对应的10转化为字符串

print(str(map_obj), type(str(map_obj)))
map_obj --> 变量名
str(map_obj) ----> map_obj对应的数据转化 为字符串
map_obj对应的值:<map object at 0x0000022B61219208>
str(map_obj) ===> "<map object at 0x0000022B61219208>"
'''

# list1 = [12, 34]
# res = str(list1)
# print(res) #"[12, 34]"

'''
练习:
    1. list0 = [2, 4, 6, 8, 10]
        ---> 将列表中的每一个数据 求平方 存于新的列表中
    2. list0 = ["12", "hello", "nice", "34"]
        ----> 将列表中的数据 进行转化 
            列表中的字符串只有两种格式: 纯字母 和 纯数字
            如果字符串内容为纯字母 保留原字符串
            否则字符串内容为纯数字 转化为整型
    map(函数, 序列)
'''
#1.
list0 = [2, 4, 6, 8, 10]
new_list = list(map(lambda x:x**2, list0))
print(new_list)

#2.
list0 = ["12", "hello", "nice", "34"]

def x(s):
    if s.isalpha():
        return s
    else:
        return int(s)

new_list = list(map(x, list0))
print(new_list)


#map的另外一种使用方式
'''
map接受序列的时候 可以接受多个序列
接受多个序列一般进行的操作 是按照设置的格式对多个序列中的内容进行重组
对序列进行重组
    函数的设置的形参:
        有几个序列 设置几个形参  
            形参接受元素的顺序 与 设置序列的顺序是一致的
            形参接受的数据 -- 默认接受的就是对应序列中的每一个元素
'''
i1 = range(1, 11)
i2 = "abcdefghij"
#操作:i1中的1-i2中的a
def new_ite(a, b):
    return (b, a)
map_obj = map(new_ite,i1, i2)
# for item in map_obj:
#     print(item)

# list0 = list(map_obj)
# print(list0)


dict0 = dict(map_obj)
print(dict0)
39.2 zip函数
zip函数的使用类似于map的第二种使用方式
	将多个序列中的数据进行重组
help(zip)
'''
zip(iter1 [,iter2 [...]]) --> zip object

参数就是序列
 ----> 将指定序列中的数据 根据对应的位置依次取出 重组成新的序列
 组合的时候 最后新的序列的个数 由序列元素少的决定的
'''
tuple0 = (12, 34, 56)
list0 = [15, 23, 71, 89]
zip_obj = zip(tuple0, list0)
print(zip_obj)

# for item in zip_obj:
#     print(item)

dict0 = dict(zip_obj)
print(dict0)

#将字典的键和值颠倒
dict0 = {"a":97, "b":98, "c":99}
new_dict = {v:k for k, v in dict0.items()}
print(new_dict)

new_dict = dict( zip(dict0.values(), dict0.keys()))
print(new_dict)
39.3 filter函数
对序列进行筛选的
接受一个函数
	函数有一个形参: 默认接受的就是序列中的每一个元素
		函数的返回值是bool类型的
			True 表示保留该数据
			False 表示去除该数据
help(filter)
'''
filter(function, iterable) ---> filter
 第一个参数是函数
     函数有一个形参 --- 默认已经接受的是序列中的每一个元素
     函数有返回值 bool类型的
         True为保留
         False 为去除
 第二个参数
     要进行筛选的序列
'''
s = "abcdefg123456*!@#"
#去除掉字符串中的非字母和非数字的字符 ===> 只保留字母或数字
new_str = ""
for ch in s:
 if ch.isdigit() or ch.isalpha():
     new_str += ch
print(new_str)

filter_obj = filter(lambda ch : ch.isalpha() or ch.isdigit(), s)
print(filter_obj)
# for i in filter_obj:
#     print(i)

new_str = "".join(filter_obj)
print(new_str)


''''
1. list0 = ["   ", "good", "\nlike", "\t\r", "book\t"]
    保留列表中非空白字符序列
2. dict0 = {"政治":78, "历史":32, "数学":99}
    保留字典中成绩>=60的键值对
'''
#1.
list0 = ["   ", "good", "\nlike", "\t\r", "book\t"]
new_list = list(filter(lambda ele: ele.strip() != "", list0))
print(new_list)

#2.
dict0 = {"政治":78, "历史":32, "数学":99}
new_dict = {k:v for k, v in dict0.items() if v >= 60}
print(new_dict)

for item in dict0.items():
    print(item) # 在dict.items()序列中 每一个元素是一个小元组  元组中有两个数据 第一个是键 第二个是值

#[(),(),()]
new_dict = dict(filter(lambda item:item[1]>=60, dict0.items()))
print(new_dict)
39.4 reduce函数
需要先导入模块functools
	from functools import reduce
函数的功能是进行按照要求进行累计的效果

两个参数:
	函数 --- 需要接受两个形参
		第一次接受的是 序列中的前两个数据 根据功能计算出结果
		第二次之后:
			将结果和序列中下一个元素传入函数中 取计算结果
	序列:
		要进行累计的序列
from functools import reduce

help(reduce)
'''
reduce(function, sequence) -> value
'''
s = "123456"
# ====> 对字符串的数值进行累加

def add(x, y):
 return int(x) + int(y)

res = reduce(add, s)
print(res)
39.5 sorted函数
函数是对序列进行排序的
	sorted(指定进行排序的列表, key=进行排序是数据的标准,reverse=升序/降序)
	这个排序方式 会新生成一个列表 对原来的列表没有影响
列表类型中自带的排序方式:
	要排序的列表.sort(key, reverse) ====> 影响的是原列表
list0 = ["hello", "like", "milk", "good"]

#用原生的列表中的方法进行数据大小的升序排序
# list0.sort()
# print(list0)

#降序
# list0.sort(reverse=True)
# print(list0)

#修改排序是数据比较的标准
# list0.sort(key=len)
# print(list0)

#sorted
new_list = sorted(list0, key=len)
print(list0) #不会影响原列表
print(new_list)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值