python_basics

一:python是一门编程语言

​ 什么是编程语言?什么语言?为什么要有编程语言?
​ 编程语言的本质就是一门语言
​ 语言就是一种事物与另外一种事物沟通的表达方式/工具

	人--------------人类的语言------------>奴隶
	人--------------编程语言------------->计算机


什么编程?为什么要编程?
	编程就是人把自己想计算机做的事,也就是自己的思维逻辑,用编程语言表达出来
	编程的目的就是让计算机按照人类的思维逻辑去工作,从而解放人力
二:计算机基础
1.什么是计算机
	计算机俗称“电脑”,包含人对计算机的终极期望,能够真的像人脑一样去工作
2、为何要有计算机
	为了执行人类的程序,从而把人类解放出来

	大前提:计算机所有的组成都是模仿人的某一功能或器官

3、计算机的组成
	控制器:
		作用:是计算机的指挥系统,负责控制计算机所有其他组件如何工作的
		类比:控制器=》人类的大脑

	运算器:
		作用:运算包括数学运算与逻辑运算
		类比:运算=》人类的大脑

		控制器+运算器=》cpu===》人类的大脑

	存储器/IO设备
		作用:是计算机的记忆功能,负责数据的存取
		分类:
			内存(基于电工作):存取数据都快,断电数据丢失,只能临时存取数据
			外存(硬盘,基于磁工作):存取速度都慢,断电数据也不丢,可以永久保存数据

		类比:
			内存===》人类的大脑的记忆功能
			外存===》人的笔记本

	输入设备input
		如键盘、鼠标
	输出设备output
		如显示器、打印机


4、一个程序的运行与三大核心硬件的关系
	人--------------编程语言------------->计算机
			程序如下:
			  1、去包子店                 
			  2、付钱
			  3、把包子送回来

	总结:
		程序最先是存放于硬盘之上
		程序的运行一定事先把程序的代码加载到内存
		然后cpu从内存中读取指令执行
三:操作系统
1、引入
	用户/应用程序(暴风影音、腾讯qq、快播、哇嘎)
	操作系统:控制程序(windows、linux)
	计算机硬件
2、操作系统概念
	操作系统是一个协调、管理、控制计算机硬件资源与应用软件资源的一个控制程序
	作用:
		1、控制计算机硬件的基本运行 
		2、把使用硬件的复杂操作封装成简单的功能,给上层的应用程序使用

		例如:文件就是操作系统提供给应用程序/用户操作硬盘的一种功能


3、程序的区分
	计算机硬件是死的,计算机硬件的运行都受软件控制,所以说,软件相当于计算机的灵魂
	具体来说软件分为两种:
		1、应用软件:应用程序相关逻辑
		2、系统软件:控制底层硬件的


4、计算机系统三层结构
	应用程序
	操作系统
	计算机硬件


5、平台
	计算机硬件+操作系统=》平台

	软件的跨平台性指的是:一款软件可以任意平台上运行,是衡量软件质量高低的一个非常重要的指标

人---------编程语言--------》计算机

           去包子店
           付款
           把包子送回来

1、计算机硬件
	(运算器,控制器)=》CPU
		负责运行人类程序的硬件是cpu
	
	存储器
		内存:存取速度都快,基于电工作的,断电数据就丢失,不能永久保存数据=========》人脑的记忆功能
		外存(磁盘):存取速度都慢,基于磁工作的,断电数据不丢失,可以永久保存数据===》人的笔记本
	输入设备
		键盘
	输出设备
		显示器


2、看图总结:https://images2018.cnblogs.com/blog/1036857/201803/1036857-20180314171523158-1421724255.png

	2.1、cpu存取的数据和指令都来自于内存
	2.2、内存称之为主存
		主存储器内的数据则是从输入单元所传输进来!而CPU处理完毕的数据也必须先写回主存储器中,最后数据才从主存储器传输到输出单元。

3、三大核心硬件
	程序最先是存放于硬盘中的
	程序的运行一定是先把程序的代码由硬盘加载到内存
	然后cpu从内存中取出指令运行


4、什么是操作系统?为啥要有操作系统?
	4.1、操作系统是一个协调、管理、控制计算机硬件资源与应用软件资源的控制程序
	它位于计算机硬件与应用软件之间,起承上启下的作用

	4.2 操作的系统意义
		I:控制计算机硬件的基本运行
		II:将硬件操作的复杂细节封装成简单的接口来提供给应用程序或用户使用


5、计算机体系的三层结构
	应用程序、用户
	操作系统
	计算机硬件

6、平台与跨平台
	平台具体指的是应用程序的运行平台,或者说用户的使用平台
	平台=操作系统+计算机硬件
计算机基础知识想详解
1、cpu详解
			cpu的分类与指令集
			x86-64(*****)
				cpu具有向下兼容性
					64的cpu既能运行32位的程序也能运行64位的程序
		内核态与用户态(*****)
			代表cpu的两种工作状态
				1、内核态:运行的程序是操作系统,可以操作计算机硬件
				2、用户态:运行的程序是应用程序,不能操作计算机硬件

			内核态与用户态的转换
				应用程序的运行必然涉及到计算机硬件的操作,那就必须有用户态切换到
				内核态下才能实现,所以计算机工作时在频繁发生内核态与用户态的转换
		多线程与多核芯片
			2核4线程:
				2核代表有两个cpu,4线程指的是每个cpu都有两个线程=》假4核

			4核8线程
				4核代表有4个cpu,8线程指的是每个cpu都有两个线程=》假8核


	2、存储器
		RAM:内存
		ROM:“只读内存”
			存放计算机厂商写死计算机上的一段核心程序=》BIOS
		CMOS:存取速度慢,断电数据丢失,耗电量极低

		硬盘:
			机械硬盘:磁盘
				磁道:一圈数据,对应着一串二进制(1bit代表一个二进制位)
					8bit比特位=1Bytes字节
					1024Bytes=1KB
					1024KB=1MB
					1024MB=1GB
					1024GB=1TB
					1024TB=1PB

					200G=200*1000*1000B

				扇区:
					一个扇区通过为512Bytes
					站在硬盘的解读,一次性读写数据的最小单为为扇区

					操作系统一次性读写的单位是一个block块=》8扇区的大小=4096Bytes


				柱面

			固态硬盘
		IO延迟(*****)
			7200转/min
			120转/s
			1/120转/s=转一圈需要花费8ms

			平均寻道时间:机械手臂转到数据所在磁道需要花费的时间,受限于物理工艺水平,目前机械硬盘可以达到的是5ms

			平均延迟时间:转半圈需要花费4ms,受限于硬盘的转速

			IO延迟=平均寻道时间+平均延迟时间

			优化程序运行效率的一个核心法则:能从内存取数据,就不要从硬盘取


		虚拟内存

		IO设备=设备的控制+设备本身

	3、总线

	4、操作系统的启动流程(*****)

		BIOS介绍:

			BIOS:Basic Input Output System
			BIOS被写入ROM设备


		裸机:
			cpu
			ROM:充当内存,存放BIOS系统
			CMOS:充当硬盘


		操作系统的启动流程(*****)
			1.计算机加电

			2.BIOS开始运行,检测硬件:cpu、内存、硬盘等

			3.BIOS读取CMOS存储器中的参数,选择启动设备

			4.从启动设备上读取第一个扇区的内容(MBR主引导记录512字节,前446为引导信息,后64为分区信息,最后两个为标志位)

			5.根据分区信息读入bootloader启动装载模块,启动操作系统

			6.然后操作系统询问BIOS,以获得配置信息。对于每种设备,系统会检查其设备驱动程序是否存在,如果没有,系统则会要求用户按照设备驱动程序。一旦有了全部的设备驱动程序,操作系统就将它们调入内核



		BIOS
			1、存有win10系统的光盘、u盘、移动硬盘:无密码
			2、本地硬盘上的win7系统:密码

		应用程序的启动流程(*****)
			1、双击exe快捷方式--》exe文件的绝对路径,就是在告诉操作系统
				说:我有一个应用程序要执行,应用程序的文件路径是(exe文件的绝对路径)

			2、操作系统会根据文件路径找到exe程序在硬盘的位置,控制其代码从硬盘加载到内存

			3、然后控制cpu从内存中读取刚刚读入内存的应用程序的代码执行,应用程序完成启动
python入门(全为重点)

​ 1、编程语言介绍
​ 分类:
​ 机器语言
​ 汇编语言
​ 高级语言(编译型、解释型号)

	总结:
		#1、执行效率:机器语言>汇编语言>高级语言(编译型>解释型)

		#2、开发效率:机器语言<汇编语言<高级语言(编译型<解释型)

		#3、跨平台性:解释型具有极强的跨平台型



2、python介绍
	python语言:指的是pyton的语法风格
	python解释器:专门用来识别python这门语言的语法并解释执行的

3、解释器多版本共存
	设置环境变量
		windows
			win10:参考视频
			win7:C:\python27;C:\python27\scripts;C:\a\b;D:\a\b;E:\a\b

		linux:
			vim /etc/profile
				PATH=$PATH:/usr/local/python38:/usr/local/python38
				export PATH

		mac:
			同linux

4、运行python程序的两种方式
	1、交互式
		即时得到程序的运行结果,多用于调试
	2、脚本的方式
		把程序写到文件里(约定俗称文件名后缀为.py),然后用python解释器解释执行其中的内容

		python3.8 python程序文件的路径


5、一个python应用程序的运行的三个步骤(******)
	python3.8 C:\a\b\c.py  执行python程序经历三个步骤
		1、先启动python3.8解释器,此时相当于启动了一个文本编辑器
		2、解释器会发送系统调用,把c.py的内容从硬盘读入内存,此时c.py中的内容
			全部为普通字符,没有任何语法意义
		3、解释器开始解释执行刚刚读入内存的c.py的代码,开始识别python语法

	对比文本编辑器读取C:\a\b\c.py文件内容也经历了三个步骤
		1、先启动文本编辑器
		2、文本编辑器会发送系统调用,把c.py的内容从硬盘读入内存
		3、文本编辑会将刚刚读入内存的内容控制输出到屏幕上,让用户看到结果


	总结:
		二者在前两个阶段做的事情完全一致
		唯一不同的就是第三个阶段对读入内存的python代码的处理方式不同
6、注释
	1、注释是对关键代码的解释说明
		单行注释:#
            # 这是一行xxx的代码
            print("hello")  # 这是一行xxx的代码

		多行注释:''''''  """"""
            """
            笔记
            """
	2、被注释的代码不会被执行
7、IDE集成开发环境pycharm
	mac平台pycharm使用参考视频讲解
	windows平台pycharm使用参考博客https://zhuanlan.zhihu.com/p/108676916
		windows平台下相关配置
			选择pycharm对话框左上角File,然后点击settings,接下来的配置同mac平台
01 变量
'''
一、什么是变量?

变量就是可以变化的量,量指的是事物的状态,比如人的年龄、性别,游戏角色的等级、金钱等等

二、为什么要有变量?
为了让计算机能够像人一样去记忆事物的某种状态,并且状态是可以发生变化的
详细地说:
程序执行的本质就是一系列状态的变化,变是程序执行的直接体现,所以我们需要有一种机制能够反映或者说是保存下来程

三、如何用变量
'''
# 1、变量基本使用
# 原则:先定义,后引用
# name = ''  # 定义-》存
# print(name)  # 引用-》取

# age = 18
# print(age)

# 2、内存管理:垃圾回收机制
# 垃圾:当一个变量值被绑定的变量名的个数为0时,该变量值无法被访问到,称之为垃圾
# 引用计数增加
x = 10  # 10的引用计数为1
y = x  # 10的引用计数为2
z = x  # 10的引用计数为3

# 引用计数减少
del x  # 解除变量名x与值10的绑定关系,10的引用计数变为2
# print(y)
del y  # 10的引用计数变为1
# print(z)
z = 12345  # # 10的引用计数变为0
# print(z)

# 3、变量有三大组成部分
# I:变量名=》是指向等号右侧值的内存地址的,用来访问等号右侧的值
# II:赋值符号:将变量值的内存地址绑定给变量名
# III:变量值:代表记录的事物的状态

# 4、变量名的命名的规则
# 原则:变量名的命名应该见名知意
# 4.1. 变量名只能是 字母、数字或下划线的任意组合
# 4.2. 变量名的第一个字符不能是数字
# 4.3. 关键字不能声明为变量名,常用关键字如下
# ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from','global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
# age=18
# print='Harry'

# ps:不要用拼音,不要用中文,在见名知意的前提下尽可能短
# mingzi='Harry'
# 名字='Harry'
# print(名字)

# 5、变量名的命名风格
# 5.1 纯小写加下划线的方式(在python中,关于变量名的命名推荐使用这种方式)
age_of_alex = 73
# print(age_of_alex)
# 5.2 驼峰体
AgeOfAlex = 73
# print(AgeOfAlex)

# 6、变量值三个重要的特征
# name='Harry'
# id:反映的是变量值的内存地址,内存地址不同id则不同
# print(id(name))
# type:不同类型的值用来表示记录不同的状态
# print(type(name))
# value:值本身
# print(name)

# 6.2 is与==
# is:比较左右两个值身份id是否相等
# ==:比较左右两个值他们的值是否相等
'''
id不同的情况下,值有可能相同,即两块不同的内存空间里可以存相同的值
id相同的情况下,值一定相同,x is y成立,x == y也必然成立
>>> 
>>> x='info:Harry:18'
>>> y='info:Harry:18'
>>> print(x,y)
info:Harry:18 info:Harry:18
>>> print(id(x),id(y))
4565819264 4566192176
>>> 
>>> 
>>> 
>>> x == y
True
>>> x is y
False
'''

# 了解:小整数池[-5,256]
# 从python解释器启动那一刻开始,就会在内存中事先申请
# 好一系列内存空间存放好常用的整数
'''
>>> m=10
>>> n=10
>>> id(m)
4562619328
>>> id(n)
4562619328
>>> 
>>> res=4+6
>>> res
10
>>> id(res)
4562619328
'''

'''
>>> x=-5
>>> y=-5
>>> x is y
True
>>> x=-6
>>> y=-6
>>> x is y
False
'''

'''
>>> x='aaa'
>>> y='aaa'
>>> 
>>> 
>>> id(x)
4566200880
>>> id(y)
4566200880
'''

'''
x=-6
y=-6
print(id(x))
print(id(y))
print(x is y)
'''

# 7、常量:不变的量
# 注意:python语法中没有常量的概念,但是在程序的开发过程中会涉及到常量的概念
AGE_OF_ALEX = 73  # 小写字母全为大写代表常量,这只是一种约定、规范
AGE_OF_ALEX = 74
print(AGE_OF_ALEX)
02 基本数据类型
# 1、数字类型
# 1.1 整型int
# 作用:记录年龄、身份证号、个数等等
# 定义:
age = 18
# print(type(age))

# 浮点型float
# 作用:记录薪资、身高、体重
# 定义
salary = 3.3
height = 1.87
weight = 70.3
# print(type(height))

# 数字类型的其他使用
# level = 1
# level=level + 1
# print(level)
# print(10 *3)

# print(10 + 3.3) # int与float之间可以相加
# age = 19
# print(age > 18)


# 2、字符串类型str
# 作用:记录描述性质的状态,名字、一段话
# 定义:用引号('',"",''' ''',""" """,)包含的一串字符
info = '''
天下只有两种人。比如一串葡萄到手,一种人挑最好的先吃,
另一种人把最好的留到最后吃。
照例第一种人应该乐观,因为他每吃一颗都是吃剩的葡萄里最好的;
第二种人应该悲观,因为他每吃一颗都是吃剩的葡萄里最坏的。
不过事实却适得其反,缘故是第二种人还有希望,第一种人只有回忆。
'''
# print(type(info))
# name="Harry"
# print(name)

# x=18
# print(type(x))
# x='18' # 由数字组成的字符串,是字符串类型,不是int类型
# print(type(x))

# 'name'='Harry' # 语法错误,等号左边是变量名,变量名的命名不能有引号

# xxx # 代表访问变量名字
'xxx'  # 代表的是值

# x=10
# y=x

# 其他使用:
# 字符串的嵌套,注意:外层用单引号,内存应该用双引号,反之亦然
# print("my name is 'Harry'")
# print('my name is \'Harry\'')

# 字符串之间可以相加,但仅限于str与str之间进行,
# 代表字符串的拼接,了解即可,不推荐使用,因为str之间的
# 相加效率极低
# print('my name is '+'Harry')
# print('='*20)
# print('hello world')
# print('='*20)


# 3、列表:索引对应值,索引从0开始,0代表第一个
# 作用:按位置记录多个值(同一个人的多个爱好、同一个班级的所有学校姓名、同一个人12个月的薪资),并且可以按照索引取指定位置的值

# 定义:在[]内用逗号分隔开多个任意类型的值,一个值称之为一个元素
#  0   1    2        3          4
l = [10, 3.1, 'aaa', ['bbb', 'ccc'], 'ddd']
# print(l)
# print(l[1])
# print(l[2])
# print(l[3][1])

# print(l[4])
# print(l[-1])

# hobbies='read music play'
# print(hobbies)
# hobbies = ['read', 'music', 'play']
# print(hobbies[1])

# 其他的用途:
# students_info=[
#     ['tony',18,['jack',]],
#     ['jason',18,['play','sleep']]
# ]
# 取出第一个学生的第一个爱好
# print(students_info[0][2][0])


# 4、
# 索引反映的是顺序、位置,对值没有描述性的功能
#      0      1   2     3
info=['egon',18,'male',19]
# print(type(info))
# print(info[0])
# print(info[1])
# print(info[2])

# 字典类型:key对应值,其中key通常为字符串类型,所以key对值可以有描述性的功能
# 作用:用来存多个值,每个值都有唯一一个key与其对应,key对值有描述性功能
# 定义:在{}内用逗号分开各多个key:value
# d={'a':1,'b':2}
# print(type(d))
# print(d['a'])

# info={
#     "name":'egon',
#     "age":18,
#     "gender":'male',
#     "salary":19
# }
# print(info["salary"])

# 其他用途:
# students_info=[
#     第1个信息,
#     第2个信息,
#     第3个信息,
# ]

students_info=[
    {"name":'egon1','age1':19,'gender':'male'},
    {"name":'egon2','age1':19,'gender':'male'},
    {"name":'egon3','age1':19,'gender':'male'},
]

print(students_info[1]['gender'])


# 5 布尔bool
# 6.1 作用
# 用来记录真假这两种状态
#
# 6.2 定义
# is_ok = True
# is_ok = False
# print(type(is_ok))

# x=1
# y=0

# students=[
#     {'name':'egon','gender':'male'},
#     {'name':'alex','gender':'female'},
# ]

# students=[
#     {'name':'egon','gender':True},
#     {'name':'alex','gender':False},
# ]

students=[
    {'name':'egon','gender':1},
    {'name':'alex','gender':0},
]

# 6.3 其他使用
# 通常用来当作判断的条件,我们将在if判断中用到它



# 总结:如何选择合适的类型来记录状态
# 1、选取的类型是否可以明确标识事物的状态
# 2、存不是目的,存的目的是为了日后取出来用,并且方便的用
# 3、把自己想象成一台计算机,如果我是计算机,
#    我会如何以何种形式把事物的状态记到脑子里
#    然后再去python中找相应的数据类型来让计算机像自己一样去记下事物的状态
03 垃圾回收机制
# 垃圾回收机制详解(了解)

# 1、引用计数
# x = 10  # 直接引用
# print(id(x))
# y = x
# z = x
#
# l = ['a', 'b', x]  # 间接引用
# print(id(l[2]))  
#
# d = {'mmm': x}  # 间接引用
#
# print(id(d['mmm']))


# x=10
# l=['a','b',x] # l=['a'的内存地址,'b'的内存地址,10的内存地址]
#
# x=123
# print(l[2])
#
#
# x=10
# x=[10,]
#
# l=['a','b',10]


# 2、标记清除:用来解决循环引用带来的内存泄露问题
# 循环引用=>导致内存泄露
l1=[111,]
l2=[222,]

l1.append(l2) # l1=[值111的内存地址,l2列表的内存地址]
l2.append(l1) # l2=[值222的内存地址,l1列表的内存地址]

# print(id(l1[1]))
# print(id(l2))

# print(id(l2[1]))
# print(id(l1))

# print(l2)
# print(l1[1])

del l1
del l2

# 3、分代回收:用来降低引用计数的扫描频率,提升垃圾回收的效率
04 与用户交互
# 1、接收用户的输入
# 在Python3:input会将用户输入的所有内容都存成字符串类型
# username = input("请输入您的账号:")  # "Harry"
# print(username, type(username))

# age = input("请输入的你的年龄: ")  # age="18"
# print(age, type(age))
# age=int(age) # int只能将纯数字的字符串转成整型
# print(age > 16)

# int("12345")
# int("1234.5")
# int("1234abc5")


# 在python2中:
# raw_input():用法与python3的input一模一样
# input(): 要求用户必须输入一个明确的数据类型,输入的是什么类型,就存成什么类型
# >>> age=input(">>>>>>>>>>>>>>>>>>>>>: ")
# >>>>>>>>>>>>>>>>>>>>>: 18
# >>> age,type(age)
# (18, <type 'int'>)
# >>>
# >>> x=input(">>>>>>>>>>>>>>>>>>>>>: ")
# >>>>>>>>>>>>>>>>>>>>>: 1.3
# >>> x,type(x)
# (1.3, <type 'float'>)
# >>>
# >>> x=input(">>>>>>>>>>>>>>>>>>>>>: ")
# >>>>>>>>>>>>>>>>>>>>>: [1,2,3]
# >>> x,type(x)
# ([1, 2, 3], <type 'list'>)
# >>>


# 2。字符串的格式化输出
# 2.1 %
# 值按照位置与%s一一对应,少一个不行,多一个也不行
# res="my name is %s my age is %s" %('egon',"18")
# res="my name is %s my age is %s" %("18",'egon')
# res="my name is %s" %"egon"
# print(res)

# 以字典的形式传值,打破位置的限制
# res="我的名字是 %(name)s 我的年龄是 %(age)s" %{"age":"18","name":'egon'}
# print(res)

# %s可以接收任意类型
# print('my age is %s' %18)
# print('my age is %s' %[1,23])
# print('my age is %s' %{'a':333})
# print('my age is %d' %18) # %d只能接收int
# print('my age is %d' %"18")

# 2.2 str.format:兼容性好
# 按照位置传值
# res='我的名字是 {} 我的年龄是 {}'.format('egon',18)
# print(res)

# res='我的名字是 {0}{0}{0} 我的年龄是 {1}{1}'.format('egon',18)
# print(res)

# 打破位置的限制,按照key=value传值
# res="我的名字是 {name} 我的年龄是 {age}".format(age=18,name='egon')
# print(res)

# 了解知识
"""
2.4 填充与格式化
# 先取到值,然后在冒号后设定填充格式:[填充字符][对齐方式][宽度]
# *<10:左对齐,总共10个字符,不够的用*号填充
print('{0:*<10}'.format('开始执行')) # 开始执行******

# *>10:右对齐,总共10个字符,不够的用*号填充
print('{0:*>10}'.format('开始执行')) # ******开始执行

# *^10:居中显示,总共10个字符,不够的用*号填充
print('{0:*^10}'.format('开始执行')) # ***开始执行***
2.5 精度与进制

print('{salary:.3f}'.format(salary=1232132.12351))  #精确到小数点后3位,四舍五入,结果为:1232132.124
print('{0:b}'.format(123))  # 转成二进制,结果为:1111011
print('{0:o}'.format(9))  # 转成八进制,结果为:11
print('{0:x}'.format(15))  # 转成十六进制,结果为:f
print('{0:,}'.format(99812939393931))  # 千分位格式化,结果为:99,812,939,393,931

"""

# 2.3 f:python3.5以后才推出
x = input('your name: ')
y = input('your age: ')
res = f'我的名字是{x} 我的年龄是{y}'
print(res)
05 运算符
# 1、算数运算符
# print(10 + 3.1)
# print(10 + 3)
# print(10 / 3)  # 结果带小数
# print(10 // 3)  # 只保留整数部分
# print(10 % 3) # 取模、取余数
# print(10 ** 3) # 取模、取余数

# 2、比较运算符: >、>=、<、<=、==、!=
# print(10 > 3)
# print(10 == 10)
#
# print(10 >= 10)
# print(10 >= 3)

# name=input('your name: ')
# print(name == 'egon')


# 3、赋值运算符
# 3.1 =:变量的赋值
# 3.2 增量赋值:
# age = 18
# # age += 1  # age=age + 1
# # print(age)
#
# age*=3
# age/=3
# age%=3
# age**=3 # age=age**3

# 3.3 链式赋值
# x=10
# y=x
# z=y
# z = y = x = 10 # 链式赋值
# print(x, y, z)
# print(id(x), id(y), id(z))

# 3.4 交叉赋值
m=10
n=20
# print(m,n)
# 交换值
# temp=m
# m=n
# n=temp
# print(m,n)

# m,n=n,m # 交叉赋值
# print(m,n)

# 3.5 解压赋值
salaries=[111,222,333,444,555]
# 把五个月的工资取出来分别赋值给不同的变量名
# mon0=salaries[0]
# mon1=salaries[1]
# mon2=salaries[2]
# mon3=salaries[3]
# mon4=salaries[4]

# 解压赋值
# mon0,mon1,mon2,mon3,mon4=salaries
# print(mon0)
# print(mon1)
# print(mon2)
# print(mon3)
# print(mon4)

# mon0,mon1,mon2,mon3=salaries # 对应的变量名少一个不行
# mon0,mon1,mon2,mon3,mon4,mon5=salaries # 对应的变量名多一个也不行

# 引入*,可以帮助我们取两头的值,无法取中间的值
# 取前三个值
# x,y,z,*_=salaries=[111,222,333,444,555] # *会将没有对应关系的值存成列表然后赋值给紧跟其后的那个变量名,此处为_
# print(x,y,z)
# print(_)

# 取后三个值
# *_,x,y,z=salaries=[111,222,333,444,555]
# print(x,y,z)

# x,*_,y,z=salaries=[111,222,333,444,555]
# print(x,y,z)

# salaries=[111,222,333,444,555]
# _,*middle,_=salaries
# print(middle)

# 解压字典默认解压出来的是字典的key
x,y,z=dic={'a':1,'b':2,'c':3}
print(x,y,z)
06 可变不可变类型
# 1、可变不可变类型

# 可变类型:值改变,id不变,证明改的是原值,证明原值是可以被改变的
# 不可变类型:值改变,id也变了,证明是产生新的值,压根没有改变原值,证明原值是不可以被修改的

# 2、验证
# 2.1 int是不可变类型
# x=10
# print(id(x))
# x=11 # 产生新值
# print(id(x))

# 2.2 float是不可变类型
# x=3.1
# print(id(x))
# x=3.2
# print(id(x))

# 2.3 str是不可变类型
# x="abc"
# print(id(x))
# x='gggg'
# print(id(x))

# 小结:int、float、str都被设计成了不可分割的整体,不能够被改变


# 2.4 list是可变类型
# l=['aaa','bbb','ccc']
# print(id(l))
# l[0]='AAA'
# print(l)
# print(id(l))

# 2.5 dict
# dic={'k1':111,'k2':222}
# print(id(dic))
# dic['k1']=3333333333
# # print(dic)
# print(id(dic))


#2.6 bool不可变


# 关于字典补充:
# 定义:{}内用逗号分隔开多key:value,
#           其中value可以是任意类型
#           但是key必须是不可变类型

# dic={
#     'k1':111,
#     'k2':3.1,
#     'k3':[333,],
#     'k4':{'name':'egon'}
# }
#
# dic={
#     2222:111,
#     3.3:3.1,
#     'k3':[333,],
#     'k4':{'name':'egon'}
# }
# print(dic[3.3])

# dic={[1,2,3]:33333333}
# dic={{'a':1}:33333333}
07 条件
# 2、什么是条件?什么可以当做条件?为何要要用条件?
# 第一大类:显式布尔值
# 2.1 条件可以是:比较运算符
# age = 18
# print(age > 16)  # 条件判断之后会得到一个布尔值

# 2.1 条件可以是:True、False
# is_beautiful=True
# print(is_beautiful)


# 第二大类:隐式布尔值,所有的值都可以当成条件去用
# 其中0、None、空(空字符串、空列表、空字典)=》代表的布尔值为False,其余都为真
08 逻辑运算符
# 一:not、and、or的基本使用
# not:就是把紧跟其后的那个条件结果取反
# ps:not与紧跟其后的那个条件是一个不可分割的整体
# print(not 16 > 13)
# print(not True)
# print(not False)
# print(not 10)
# print(not 0)
# print(not None)
# print(not '')

# and:逻辑与,and用来链接左右两个条件,两个条件同时为True,最终结果才为真
# print(True and 10 > 3)

# print(True and 10 > 3 and 10 and 0) # 条件全为真,最终结果才为True
# print( 10 > 3 and 10 and 0 and 1 > 3 and 4 == 4 and 3 != 3)  # 偷懒原则

# or:逻辑或,or用来链接左右两个条件,两个条件但凡有一个为True,最终结果就为True,
#            两个条件都为False的情况下,最终结果才为False
# print(3 > 2 or 0)
# print(3 > 4 or False or 3 != 2 or 3 > 2 or True) # 偷懒原则

# 二:优先级not>and>or
# ps:
# 如果单独就只是一串and链接,或者说单独就只是一串or链接,按照从左到右的顺讯依次运算即可(偷懒原则)
# 如果是混用,则需要考虑优先级了

# res=3>4 and not 4>3 or 1==3 and 'x' == 'x' or 3 >3
# print(res)
#
# #       False                 False              False
# res=(3>4 and (not 4>3)) or (1==3 and 'x' == 'x') or 3 >3
# print(res)



res=3>4 and ((not 4>3) or 1==3) and ('x' == 'x' or 3 >3)
print(res)
09 成员运算与身份运算
# 1、成员运算符
# print("Harry" in "hello Harry") # 判断一个字符串是否存在于一个大字符串中
# print("H" in "hello Harry") # 判断一个字符串是否存在于一个大字符串中

# print(111 in [111,222,33]) # 判断元素是否存在于列表

# 判断key是否存在于字典
# print(111 in {"k1":111,'k2':222})
# print("k1" in {"k1":111,'k2':222})

# not in
# print("Harry" not in "hello Harry") # 推荐使用
# print(not "Harry" in "hello Harry") # 逻辑同上,但语义不明确,不推荐

# 2、身份运算符
# is # 判断的是id是否相等
09 流程控制之if判断
# print(1)
# print(2)
# print(3)
# if 条件:
#     代码1
#     代码2
#     代码3
# print(4)
# print(5)
'''
语法1:
if 条件:
    代码1
    代码2
    代码3

'''
# age = 60
# is_beautiful = True
# star = '水平座'
#
# if age > 16 and age < 20 and is_beautiful and star == '水平座':
#     print('我喜欢,我们在一起吧。。。')
#
# print('其他代码.............')


'''
语法2:
if 条件:
    代码1
    代码2
    代码3
else:
    代码1
    代码2
    代码3
'''

# age = 60
# is_beautiful = True
# star = '水平座'
#
# if age > 16 and age < 20 and is_beautiful and star == '水平座':
#     print('我喜欢,我们在一起吧。。。')
# else:
#     print('阿姨好,我逗你玩呢,深藏功与名')
#
# print('其他代码.............')


'''
语法3:
if 条件1:
    代码1
    代码2
    代码3
elif 条件2:
    代码1
    代码2
    代码3
elif 条件2:
    代码1
    代码2
    代码3
'''
# score=73
# if score >= 90:
#     print('优秀')
# elif score >= 80 and score < 90:
#     print('良好')
# elif score >= 70 and score < 80:
#     print('普通')

# 改进
# score = input('请输入您的成绩:') # score="18"
# score=int(score)
#
# if score >= 90:
#     print('优秀')
# elif score >= 80:
#     print('良好')
# elif score >= 70:
#     print('普通')


'''
语法3:
if 条件1:
    代码1
    代码2
    代码3
elif 条件2:
    代码1
    代码2
    代码3
elif 条件2:
    代码1
    代码2
    代码3
...
else:
    代码1
    代码2
    代码3
'''
# score = input('请输入您的成绩:') # score="18"
# score=int(score)
#
# if score >= 90:
#     print('优秀')
# elif score >= 80:
#     print('良好')
# elif score >= 70:
#     print('普通')
# else:
#     print('很差,小垃圾')
#
# print('=====>')


'''
if嵌套if
'''
age = 17
is_beautiful = True
star = '水平座'

if 16 < age < 20 and is_beautiful and star == '水平座':
    print('开始表白。。。。。')
    is_successful = True
    if is_successful:
        print('两个从此过上没羞没臊的生活。。。')
else:
    print('阿姨好,我逗你玩呢,深藏功与名')

print('其他代码.............')
稳固知新代码
# l=[111,222,333]
# l2=l # 把l的内存地址给l2
#
#
# l[0]='balabla'
# print(l)
#
# print(l2)
#
# l2[1]=4444444444444
# print(l2)
# print(l)
#
#
# del l2

# 格式化输出
# print('my name is %s age is %s' %('egon',18))
# print('成功的概率 %s%% ' % (97,))

# """
# name:{}
# age:{}
# sex:{}
# """.format('egon',18,'male')

# """
# name:{x}
# age:{y}
# sex:{z}
# """.format(z='male',x='egon',y=18)

# format新增(了解):
# print('{x}=============='.format(x='开始执行')) # 开始执行******
# print('{x:=<10}'.format(x='开始执行')) # 开始执行******
# print('{x:=>10}'.format(x='开始执行')) # 开始执行******
# print('{x:=^10}'.format(x='开始执行')) # 开始执行******

# 四舍五入
# print('{salary:.3f}'.format(salary=1232132.12351))  #精确到小数点后3位,四舍五入,结果为:1232132.124


# x='egon'
# y=18
# res=f'name:{x} age {y}'
# print(res)

#
# x='egon'
# y=18
# res=f'name:{{{x}}} age {y}'
# print(res)

# 了解f的新用法:{}内的字符串可以被当做表达式运行
# res=f'{10+3}'
# print(res)

# f'{print("aaaa")}'
01 深浅copy
list1=[
    'egon',
    'lxx',
    [1,2]
]

# 1、二者分隔不开,list改list2也跟着该,因为指向的就是同一个地址
# list2=list1 # 这不叫copy
# list1[0]='EGON'
# print(list2)

# 2、需求:
# 1、拷贝一下原列表产生一个新的列表
# 2、想让两个列表完全独立开,并且针对的是改操作的独立而不是读操作


# 3、如何copy列表
# 3.1 浅copy:是把原列表第一层的内存地址不加区分完全copy一份给新列表
list1=[
    'egon',
    'lxx',
    [1,2]
]

list3=list1.copy()
# print(list3)
# print(id(list1))
# print(id(list3))

# print(id(list1[0]),id(list1[1]),id(list1[2]))
# print(id(list3[0]),id(list3[1]),id(list3[2]))

# 实验1:对于不可变类型的赋值,都是产生了新值,让原列表的索引指向新的
# 内存地址,并不会影响新列表
list1[0]='EGON'
list1[1]='LXX'
# list1[2]=123

# 实验2:但对于可变类型,我们可以改变可变类型中包含的值,但内存地址不变
# 即原列表的索引指向仍然指向原来的内存地址,于是新列表也跟着一起受
# 影响,如下
# list1[2][0]=111
# list1[2][1]=222
# print(list1)
# print(list3)

# 综合实验1和实验2可以得出,要想copy得到的新列表与原列表的改操作完全独立开
# 必须有一种可以区分开可变类型与不可变类型的copy机制,这就是深copy

# 3.2 深copy
import copy
list1=[
    'egon',
    'lxx',
    [1,2]
]

list3=copy.deepcopy(list1)
# print(id(list1))
# print(id(list3))
# print(list3)

#          不可变        不可变        可变
# print(id(list1[0]),id(list1[1]),id(list1[2]))
# print(id(list3[0]),id(list3[1]),id(list3[2]))
'''
4497919088 4498367856 4498449216
4497919088 4498367856 4498595328
'''
# print(list3)
# print(id(list1[2][0]),id(list1[2][1]))
# print(id(list3[2][0]),id(list3[2][1]))

list1[0]='EGON'
list1[1]='LXX'

list1[2][0]=111
list1[2][1]=222
# print(list1)

print(list3)
02 流程控制之while循环
# 1、循环的语法与基本使用
'''
print(1)
while 条件:
     代码1
     代码2
     代码3
print(3)
'''

# count=0
# while count < 5: # 5 < 5
#     print(count) # 0,1,2,3,4
#     count+=1 # 5
#
# print('顶级代码----->')


# 2、死循环与效率问题
# count=0
# while count < 5: # 5 < 5
#     print(count) # 0,1,2,3,4

# while True:
#     name=input('your name >>>> ')
#     print(name)

# 纯计算无io的死讯会导致致命的效率问题
# while True:
#     1+1

# while 1:
#     print('xxxx')

# 3、循环的应用
username = 'egon'
password = '123'

# 两个问题:
# 1、重复代码
# 2、输对了应该不用再重复
# while True:
#     inp_name=input('请输入您的账号:')
#     inp_pwd=input('请输入您的密码:')
#
#     if inp_name  == username and inp_pwd == password:
#         print('登录成功')
#     else:
#         print('账号名或密码错误')


# 4、退出循环的两种方式
# 方式一:将条件改为False,等到下次循环判断条件时才会生效
# tag=True
# while tag:
#     inp_name=input('请输入您的账号:')
#     inp_pwd=input('请输入您的密码:')
#
#     if inp_name  == username and inp_pwd == password:
#         print('登录成功')
#         tag = False # 之后的代码还会运行,下次循环判断条件时才生效
#     else:
#         print('账号名或密码错误')
#
#     # print('====end====')

# 方式二:break,只要运行到break就会立刻终止本层循环
# while True:
#     inp_name=input('请输入您的账号:')
#     inp_pwd=input('请输入您的密码:')
#
#     if inp_name  == username and inp_pwd == password:
#         print('登录成功')
#         break # 立刻终止本层循环
#     else:
#         print('账号名或密码错误')
#
#     # print('====end====')


# 7、while循环嵌套与结束
'''
tag=True
while tag:
    while tag:
        while tag:
            tag=False
    

# 每一层都必须配一个break
while True:
    while True:
        while True:
            break
        break
    break
'''
## break的方式
# while True:
#     inp_name=input('请输入您的账号:')
#     inp_pwd=input('请输入您的密码:')
#
#     if inp_name  == username and inp_pwd == password:
#         print('登录成功')
#         while True:
#             cmd=input("输入命令>: ")
#             if cmd == 'q':
#                 break
#             print('命令{x}正在运行'.format(x=cmd))
#         break # 立刻终止本层循环
#     else:
#         print('账号名或密码错误')
#
#     # print('====end====')

# # 改变条件的方式
# tag=True
# while tag:
#     inp_name=input('请输入您的账号:')
#     inp_pwd=input('请输入您的密码:')
#
#     if inp_name  == username and inp_pwd == password:
#         print('登录成功')
#         while tag:
#             cmd=input("输入命令>: ")
#             if cmd == 'q':
#                 tag=False
#             else:
#                 print('命令{x}正在运行'.format(x=cmd))
#     else:
#         print('账号名或密码错误')


# 8、while +continue:结束本次循环,直接进入下一次
# 强调:在continue之后添加同级代码毫无意义,因为永远无法运行
# count=0
# while count < 6:
#     if count == 4:
#         count+=1
#         continue
#         # count+=1 # 错误
#     print(count)
#     count+=1

# 9、while +else:针对break
# count=0
# while count < 6:
#     if count == 4:
#         count+=1
#         continue
#     print(count)
#     count+=1
# else:
#     print('else包含的代码会在while循环结束后,并且while循环是在没有被break打断的情况下正常结束的,才不会运行')

# count=0
# while count < 6:
#     if count == 4:
#         break
#     print(count)
#     count+=1
# else:
#     print('======>')


# 应用案列:
# 版本1:
# count=0
# tag=True
# while tag:
#     if count == 3:
#         print('输错三次退出')
#         break
#     inp_name=input('请输入您的账号:')
#     inp_pwd=input('请输入您的密码:')
#
#     if inp_name  == username and inp_pwd == password:
#         print('登录成功')
#         while tag:
#             cmd=input("输入命令>: ")
#             if cmd == 'q':
#                 tag=False
#             else:
#                 print('命令{x}正在运行'.format(x=cmd))
#     else:
#         print('账号名或密码错误')
#         count+=1

# 版本2:优化
count=0
while count < 3:
    inp_name=input('请输入您的账号:')
    inp_pwd=input('请输入您的密码:')

    if inp_name  == username and inp_pwd == password:
        print('登录成功')
        while True:
            cmd=input("输入命令>: ")
            if cmd == 'q': # 整个程序结束,退出所有while循环
                break
            else:
                print('命令{x}正在运行'.format(x=cmd))
        break
    else:
        print('账号名或密码错误')
        count+=1
else:
    print('输错3次,退出')
01 流程控制之for循环
'''
1、什么是for循环
    循环就是重复做某件事,for循环是python提供第二种循环机制

2、为何要有for循环
    理论上for循环能做的事情,while循环都可以做
    之所以要有for循环,是因为for循环在循环取值(遍历取值)比while循环更简洁

3、如何用for循环
语法:
for 变量名 in 可迭代对象:# 可迭代对象可以是:列表、字典、字符串、元组、集合
    代码1
    代码2
    代码3
    ...
'''
# 一:for基本使用之循环取值
# 案例1:列表循环取值
# 简单版
# l = ['alex_dsb', 'lxx_dsb', 'egon_nb']
# for x in l:  # x='lxx_dsb'
#     print(x)

# 复杂版:
# l = ['alex_dsb', 'lxx_dsb', 'egon_nb']
# i=0
# while i < 3:
#     print(l[i])
#     i+=1


# 案例2:字典循环取值
# 简单版
# dic={'k1':111,'k2':2222,'k3':333}
# for k in dic:
#     print(k,dic[k])

# 复杂版:while循环可以遍历字典,太麻烦了

# 案例3:字符串循环取值
# 简单版
# msg="you can you up,no can no bb"
# for x in msg:
#     print(x)

# 复杂版:while循环可以遍历字典,太麻烦了


# 二:总结for循环与while循环的异同
# 1、相同之处:都是循环,for循环可以干的事,while循环也可以干
# 2、不同之处:
#           while循环称之为条件循环,循环次数取决于条件何时变为假
#           for循环称之为"取值循环",循环次数取决in后包含的值的个数
# for x in [1,2,3]:
#     print('===>')
#     print('8888')


# 三:for循环控制循环次数:range()
# in后直接放一个数据类型来控制循环次数有局限性:
#                 当循环次数过多时,数据类型包含值的格式需要伴随着增加
# for x in 'a c':
#     inp_name=input('please input your name:   ')
#     inp_pwd=input('please input your password:   ')
#

# range功能介绍
'''
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> 
>>> range(1,9) # 1...8
[1, 2, 3, 4, 5, 6, 7, 8]
>>> 
>>> range(1,9,1) # 1 2 3 4 5 6 7 8 
[1, 2, 3, 4, 5, 6, 7, 8]
>>> range(1,9,2) # 1 3 5 7 
[1, 3, 5, 7]
'''
# for i in range(30):
#     print('===>')


# for+break: 同while循环一样
# for+else:同while循环一样
# username='egon'
# password='123'
# for i in range(3):
#     inp_name = input('请输入您的账号:')
#     inp_pwd = input('请输入您的密码:')
#
#     if inp_name == username and inp_pwd == password:
#         print('登录成功')
#         break
# else:
#     print('输错账号密码次数过多')


# 四:range补充知识(了解)
# 1、for搭配range,可以按照索引取值,但是麻烦,所以不推荐
# l=['aaa','bbb','ccc'] # len(l)
# for i in range(len(l)):
#     print(i,l[i])
#
# for x in l:
#     print(l)
# 2、range()在python3里得到的是一只"会下蛋的老母鸡"


# 五:for+continue
# for i in range(6):  # 0 1 2 3 4 5
#     if i == 4:
#         continue
#     print(i)

# 六:for循环嵌套:外层循环循环一次,内层循环需要完整的循环完毕
# for i in range(3):
#     print('外层循环-->', i)
#     for j in range(5):
#         print('内层-->', j)

# 补充:终止for循环只有break一种方案

# print('hello %s' % 'egon')
# 1、print之逗号的使用
# print('hello','world','egon')
# 2、换行符
# print('hello\n')
# print('world')
# 3、print值end参数的使用
# print('hello\n',end='')
# print('word')
print('hello',end='*')
print('world',end='*')
02 数字类型
# 一:int类型
# 1、作用:
# 2、定义:
# age = 10 # age=int(10)

# 名字(参数)
# print('hello','world')

# x=int(10)
# name=input('xxx')
# res=print('xxx') # 没有产品
# print(res)

# 2、类型转换
# 2.1 纯数字的字符串转成int
# res=int('100111')
# print(res,type(res))

# 2.2(了解)
# 2.2.1 十进制转成其他进制
# 10进制 -> 二进制
# 11 - > 1011
# 1011-> 8+2+1
# print(bin(11)) # 0b1011

# 10进制 -> 八进制
# print(oct(11)) # 0o13

# 10进制 -> 十六进制
# print(hex(11)) # 0xb
# print(hex(123)) # 0xb

# 2.2.2 其他制转成其十进制
# 二进制->10进制
# print(int('0b1011',2)) # 11

# 二进制->8进制
# print(int('0o13',8)) # 11

# 二进制->16进制
# print(int('0xb',16)) # 11

# 3、使用

# 二:float类型
# 1、作用
# 2、定义
# salary=3.1 # salary=float(3.1)

# 3、类型转换
# res=float("3.1")
# print(res,type(res))

# 4、使用
# int与float没有需要掌握的内置方法
# 他们的使用就是数学运算+比较运算
03 字符串类型
# 1、作用
# 2、定义
# msg='hello' # msg=str('msg')
# print(type(msg))

# 3、类型转换
# str可以把任意其他类型都转成字符串
# res=str({'a':1})
# print(res,type(res))

# 4、使用:内置方法
# 4.1 优先掌握
# 4.1.1、按索引取值(正向取+反向取) :只能取
msg='hello world'
# 正向取
# print(msg[0])
# print(msg[5])
# 反向取
# print(msg[-1])

# 只能取
# msg[0]='H'


# 4.1.2、切片:索引的拓展应用,从一个大字符串中拷贝出一个子字符串
msg='hello world'
# 顾头不顾尾
# res=msg[0:5] #x
# print(res)
# print(msg)

# 步长
# res=msg[0:5:2] # 0 2 4
# print(res) # hlo

# 反向步长(了解)
# res=msg[5:0:-1]
# print(res) #" olle"

msg='hello world'
# res=msg[:] # res=msg[0:11]
# print(res)

# res=msg[::-1] # 把字符串倒过来
# print(res)

# 4.1.3、长度len
# msg='hello world'
# print(len(msg))

# 4.1.4、成员运算in和not in
# 判断一个子字符串是否存在于一个大字符串中
# print("alex" in "alex is sb")
# print("alex" not in "alex is sb")
# print(not "alex" in "alex is sb") # 不推荐使用

# 4.1.5、移除字符串左右两侧的符号strip
# 默认去掉的空格
# msg='      egon      '
# res=msg.strip()
# print(msg) # 不会改变原值
# print(res) # 是产生了新值

# 默认去掉的空格
# msg='****egon****'
# print(msg.strip('*'))

# 了解:strip只取两边,不去中间
# msg='****e*****gon****'
# print(msg.strip('*'))

# msg='**/*=-**egon**-=()**'
# print(msg.strip('*/-=()'))

# 应用
# inp_user=input('your name>>: ').strip() # inp_user=" egon"
# inp_pwd=input('your password>>: ').strip()
# if inp_user == 'egon' and inp_pwd == '123':
#     print('登录成功')
# else:
#     print('账号密码错误')


# 4.1.6、切分split:把一个字符串按照某种分隔符进行切分,得到一个列表
# # 默认分隔符是空格
# info='egon 18 male'
# res=info.split()
# print(res)

# # 指定分隔符
# info='egon:18:male'
# res=info.split(':')
# print(res)

# 指定分隔次数(了解)
# info='egon:18:male'
# res=info.split(':',1)
# print(res)

# 4.1.7、循环
# info='egon:18:male'
# for x in info:
#     print(x)


# 4.2 需要掌握
#4.2.1、strip,lstrip,rstrip
# msg='***egon****'
# print(msg.strip('*'))
# print(msg.lstrip('*'))
# print(msg.rstrip('*'))

#4.2.2、lower,upper
# msg='AbbbCCCC'
# print(msg.lower())
# print(msg.upper())

#4.2.3、startswith,endswith
# print("alex is sb".startswith("alex"))
# print("alex is sb".endswith('sb'))

#4.2.4、format

#4.2.5、split,rsplit:将字符串切成列表
# info="egon:18:male"
# print(info.split(':',1)) # ["egon","18:male"]
# print(info.rsplit(':',1)) # ["egon:18","male"]

#4.2.6、join: 把列表拼接成字符串
# l=['egon', '18', 'male']
# res=l[0]+":"+l[1]+":"+l[2]
# res=":".join(l) # 按照某个分隔符号,把元素全为字符串的列表拼接成一个大字符串
# print(res)

# l=[1,"2",'aaa']
# ":".join(l)

#4.2.7、replace
# msg="you can you up no can no bb"
# print(msg.replace("you","YOU",))
# print(msg.replace("you","YOU",1))

#4.2.8、isdigit
# 判断字符串是否由纯数字组成
# print('123'.isdigit())
# print('12.3'.isdigit())

# age=input('请输入你的年龄:').strip()
# if age.isdigit():
#     age=int(age) # int("abbab")
#     if age > 18:
#         print('猜大了')
#     elif age < 18:
#         print('猜小了')
#     else:
#         print('才最了')
# else:
#     print('必须输入数字,傻子')

# 4.3了解
#4.3.1、find,rfind,index,rindex,count
msg='hello egon hahaha'
# 找到返回起始索引
# print(msg.find('e')) # 返回要查找的字符串在大字符串中的起始索引
# print(msg.find('egon'))
# print(msg.index('e'))
# print(msg.index('egon'))
# 找不到
# print(msg.find('xxx')) # 返回-1,代表找不到
# print(msg.index('xxx')) # 抛出异常

# msg='hello egon hahaha egon、 egon'
# print(msg.count('egon'))

#4.3.2、center,ljust,rjust,zfill
# print('egon'.center(50,'*'))
# print('egon'.ljust(50,'*'))
# print('egon'.rjust(50,'*'))
# print('egon'.zfill(10))

#4.3.3、expandtabs
# msg='hello\tworld'
# print(msg.expandtabs(2)) # 设置制表符代表的空格数为2

#4.3.4、captalize,swapcase,title
# print("hello world egon".capitalize())
# print("Hello WorLd EGon".swapcase())
# print("hello world egon".title())

#4.3.5、is数字系列
#4.3.6、is其他
# print('abc'.islower())
# print('ABC'.isupper())
# print('Hello World'.istitle())
# print('123123aadsf'.isalnum()) # 字符串由字母或数字组成结果为True
# print('ad'.isalpha()) # 字符串由由字母组成结果为True
# print('     '.isspace()) # 字符串由空格组成结果为True
# print('print'.isidentifier())
# print('age_of_egon'.isidentifier())
# print('1age_of_egon'.isidentifier())


num1=b'4' #bytes
num2=u'4' #unicode,python3中无需加u就是unicode
num3='四' #中文数字
num4='Ⅳ' #罗马数字

# isdigit只能识别:num1、num2
# print(num1.isdigit()) # True
# print(num2.isdigit()) # True
# print(num3.isdigit()) # False
# print(num4.isdigit()) # False



# isnumberic可以识别:num2、num3、num4
# print(num2.isnumeric()) # True
# print(num3.isnumeric()) # True
# print(num4.isnumeric()) # True

# isdecimal只能识别:num2
print(num2.isdecimal()) # True
print(num3.isdecimal()) # False
print(num4.isdecimal()) # False
01 列表类型
# 1、作用:按位置存放多个值
# 2、定义
# l=[1,1.2,'a'] # l=list([1,1.2,'a'])
# print(type(l))

# 3、类型转换: 但凡能够被for循环遍历的类型都可以当做参数传给list()转成列表
# res=list('hello')
# print(res)
#
# res=list({'k1':111,'k2':222,'k3':3333})
# print(res)


# 4、内置方法
# 优先掌握的操作:
# 1、按索引存取值(正向存取+反向存取):即可以取也可以改
# l=[111,'egon','hello']
# 正向取
# print(l[0])
# 反向取
# print(l[-1])
# 可以取也可以改:索引存在则修改对应的值
# l[0]=222
# print(l)

# 无论是取值操作还是赋值操作:索引不存在则报错
# l[3]=333


# 2、切片(顾头不顾尾,步长)
l = [111, 'egon', 'hello', 'a', 'b', 'c', 'd', [1, 2, 3]]
# print(l[0:3])
# print(l[0:5:2]) # 0 2 4

# print(l[0:len(l)])
# print(l[:])
# new_l=l[:] # 切片等同于拷贝行为,而且相当于浅copy
# print(id(l))
# print(id(new_l))

# l[-1][0]=1111111
# print(l)
# print(new_l)

# print(l[::-1])

# msg1='hello:egon:<>:18[]==123'
# msg2=msg1[:]
# print(msg1,id(msg1))
# print(msg2,id(msg2))
# 3、长度
# print(len([1, 2, 3]))
# 4、成员运算in和not in
# print('aaa' in ['aaa', 1, 2])
# print(1 in ['aaa', 1, 2])
# 5、往列表中添加值
# 5.1 追加
# l=[111,'egon','hello']
# l.append(3333)
# l.append(4444)
# print(l)

# 5.2、插入值
# l=[111,'egon','hello']
# l.insert(0,'alex')
# print(l)

# 5.3、extend添加值
# new_l=[1,2,3]
# l=[111,'egon','hello']
# l.append(new_l)
# print(l)

# 代码实现
# for item in new_l:
#     l.append(item)
# print(l)

# extend实现了上述代码
# l.extend(new_l)
# l.extend('abc')
# print(l)


# 7、删除
# 方式一:通用的删除方法,只是单纯的删除、没有返回值
# l = [111, 'egon', 'hello']
# del l[1]
# x =del l[1] # 抛出异常,不支持赋值语法
# print(l)

# 方式二:l.pop()根据索引删除,会返回删除的值
# l = [111, 'egon', 'hello']
# l.pop() # 不指定索引默认删除最后一个
# l.pop()
# print(l)

# res=l.pop(1)
# print(l)

# print(res)

# 方式三:l.remove()根据元素删除,返回None
# l = [111, 'egon', [1,2,3],'hello']
# l.remove([1,2,3])
# print(l)
# res=l.remove('egon')
# print(res) # None


# 8、循环
# l=[1,'aaa','bbb']
# for x in l:
#     l.pop(1)
#     print(x)

# 需要掌握操作
l = [1, 'aaa', 'bbb','aaa','aaa']
# 1、l.count()
# print(l.count('aaa'))

# 2、l.index()
# print(l.index('aaa'))
# print(l.index('aaaaaaaaa')) # 找不到报错

# 3、l.clear()
# l.clear()
# print(l)

# 4、l.reverse():不是排序,就是将列表倒过来
# l = [1, 'egon','alex','lxx']
# l.reverse()
# print(l)

# 5、l.sort(): 列表内元素必须是同种类型才可以排序
# l=[11,-3,9,2,3.1]
# l.sort() # 默认从小到大排,称之为升序
# l.sort(reverse=True) # 从大到小排,设置为降序
# print(l)

# l=[11,'a',12]
# l.sort()

# l=['c','e','a']
# l.sort()
# print(l)

# 了解:字符串可以比大小,按照对应的位置的字符依次pk
# 字符串的大小是按照ASCI码表的先后顺序加以区别,表中排在后面的字符大于前面的
# print('a'>'b')
# print('abz'>'abcdefg')

# 了解:列表也可以比大小,原理同字符串一样,但是对应位置的元素必须是同种类型
# l1=[1,'abc','zaa']
# l2=[1,'abc','zb']
#
# print(l1 < l2)


# 补充
# 1、队列:FIFO,先进先出
# l=[]
# # 入队操作
# l.append('first')
# l.append('second')
# l.append('third')
#
# print(l)
# # 出队操作
# print(l.pop(0))
# print(l.pop(0))
# print(l.pop(0))

# 2、堆栈:LIFO,后进先出
l=[]
# 入栈操作
l.append('first')
l.append('second')
l.append('third')

print(l)
# 出队操作
print(l.pop())
print(l.pop())
print(l.pop())
02 元组
# 元组就是"一个不可变的列表"
#1、作用:按照索引/位置存放多个值,只用于读不用于改

#2、定义:()内用逗号分隔开多个任意类型的元素
# t=(1,1.3,'aa') # t=tuple((1,1.3,'aa'))
# print(t,type(t))


# x=(10) # 单独一个括号代表包含的意思
# print(x,type(x))

# t=(10,) # 如果元组中只有一个元素,必须加逗号
# print(t,type(t))

# t=(1,1.3,'aa') # t=(0->值1的内存地址,1->值1.3的内存地址,2->值'aaa'的内存地址,)
# t[0]=11111

# t=(1,[11,22]) # t=(0->值1的内存地址,1->值[1,2]的内存地址,)
# print(id(t[0]),id(t[1]))
# # t[0]=111111111 # 不能改
# # t[1]=222222222 # 不能改
#
# t[1][0]=11111111111111111
# # print(t)
# print(id(t[0]),id(t[1]))


#3、类型转换
# print(tuple('hello'))
# print(tuple([1,2,3]))
# print(tuple({'a1':111,'a2':333}))

#4、内置方法
#优先掌握的操作:
#1、按索引取值(正向取+反向取):只能取
# t=('aa','bbb','cc')
# print(t[0])
# print(t[-1])

#2、切片(顾头不顾尾,步长)
# t=('aa','bbb','cc','dd','eee')
# print(t[0:3])
# print(t[::-1])

#3、长度
# t=('aa','bbb','cc','dd','eee')
# print(len(t))
#4、成员运算in和not in
# print('aa' in t)

#5、循环
# for x in t:
#     print(x)

#6、
t=(2,3,111,111,111,111)
# print(t.index(111))
# print(t.index(1111111111))

print(t.count(111))
03 字典类型
#1、作用

#2、定义:{}内用逗号分隔开多个key:value,其中value可以使任意类型,但是
#                                   key必须是不可变类型,且不能重复
# 造字典的方式一:
# d={'k1':111,(1,2,3):222} # d=dict(...)
# print(d['k1'])
# print(d[(1,2,3)])
# print(type(d))

# d={} # 默认定义出来的是空字典
# print(d,type(d))

# 造字典的方式二:
# d=dict(x=1,y=2,z=3)
# print(d,type(d))


#3、数据类型转换
# info=[
#     ['name','egon'],
#     ('age',18),
#     ['gender','male']
# ]
# # d={}
# # for k,v in info: # k,v=['name','egon'],
# #     d[k]=v
# # print(d)
#
# 造字典的方式三:
# res=dict(info) # 一行代码搞定上述for循环的工作
# print(res)


# 造字典的方式四:快速初始化一个字典
# keys=['name','age','gender']
# # d={}
# # for k in keys:
# #     d[k]=None
# # print(d)
# d={}.fromkeys(keys,None) # 一行代码搞定上述for循环的工作
# print(d)

#4、内置方法
#优先掌握的操作:
#1、按key存取值:可存可取
# d={'k1':111}
# 针对赋值操作:key存在,则修改
# d['k1']=222
# 针对赋值操作:key不存在,则创建新值
# d['k2']=3333
# print(d)

#2、长度len
# d={'k1':111,'k2':2222,'k1':3333,'k1':4444}
# print(d)
# print(len(d))


#3、成员运算in和not in:根据key
# d={'k1':111,'k2':2222}
# print('k1' in d)
# print(111 in d)

#4、删除
d={'k1':111,'k2':2222}
# 4.1 通用删除
# del d['k1']
# print(d)

# 4.2 pop删除:根据key删除元素,返回删除key对应的那个value值
# res=d.pop('k2')
# print(d)
# print(res)

# 4.3 popitem删除:随机删除,返回元组(删除的key,删除的value)
# res=d.popitem()
# print(d)
# print(res)

#5、键keys(),值values(),键值对items()  =>在python3中得到的是老母鸡
d={'k1':111,'k2':2222}
'''
在python2中
>>> d={'k1':111,'k2':2222}
>>> 
>>> d.keys()#6、循环
['k2', 'k1']
>>> d.values()
[2222, 111]
>>> d.items()
[('k2', 2222), ('k1', 111)]
>>> dict(d.items())
{'k2': 2222, 'k1': 111}
>>>
'''  

#6、for循环
# for k in d.keys():
#     print(k)
#
# for k in d:
#     print(k)

# for v in d.values():
#     print(v)

# for k,v in d.items():
#     print(k,v)


# print(list(d.keys()))
# print(list(d.values()))
# print(list(d.items()))


#需要掌握的内置方法
d={'k1':111}
#1、d.clear()

#2、d.update()
# d.update({'k2':222,'k3':333,'k1':111111111111111})
# print(d)

#3、d.get() :根据key取值,容错性好
# print(d['k2'])  # key不存在则报错

# print(d.get('k1')) # 111
# print(d.get('k2')) # key不存在不报错,返回None

#4、d.setdefault()
# info={}
# if 'name' in info:
#     ... # 等同于pass
# else:
#     info['name']='egon'
# print(info)

# 4.1 如果key有则不添加,返回字典中key对应的值
info={'name':'egon'}
res=info.setdefault('name','egon')
# print(info)

print(res)

# 4.2 如果key没有则添加,返回字典中key对应的值
info={}
res=info.setdefault('name','egon')
# print(info)
print(res)
01 集合
# 1、作用
# 1.1 关系运算
# friends1 = ["zero","kevin","jason","egon"]
# friends2 = ["Jy","ricky","jason","egon"]
#
# l=[]
# for x in friends1:
#     if x in friends2:
#         l.append(x)
# print(l)


# 1.2、去重


# 2、定义: 在{}内用逗号分隔开多个元素,多个元素满足以下三个条件
#            1. 集合内元素必须为不可变类型
#            2. 集合内元素无序
#            3. 集合内元素没有重复

# s={1,2} # s=set({1,2})

# s={1,[1,2]} # 集合内元素必须为不可变类型
# s={1,'a','z','b',4,7} # 集合内元素无序
# s={1,1,1,1,1,1,'a','b'} # 集合内元素没有重复
# print(s)

# 了解
# s={} # 默认是空字典
# print(type(s))
# 定义空集合
# s=set()
# print(s,type(s))

# 3、类型转换
# set({1,2,3})
# res=set('hellolllll')
# print(res)

# print(set([1,1,1,1,1,1]))
# print(set([1,1,1,1,1,1,[11,222]]) # 报错

# print(set({'k1':1,'k2':2}))

# 4、内置方法
# =========================关系运算符=========================
friends1 = {"zero","kevin","jason","egon"}
friends2 = {"Jy","ricky","jason","egon"}

# 4.1 取交集:两者共同的好友
# res=friends1 & friends2
# print(res)
# print(friends1.intersection(friends2))
# 4.2 取并集/合集:两者所有的好友
# print(friends1 | friends2)
# print(friends1.union(friends2))

# 4.3 取差集:取friends1独有的好友
# print(friends1 - friends2)
# print(friends1.difference(friends2))

# 取friends2独有的好友
# print(friends2 - friends1)
# print(friends2.difference(friends1))

# 4.4 对称差集: 求两个用户独有的好友们(即去掉共有的好友)
# print(friends1 ^ friends2)
# print(friends1.symmetric_difference(friends2))

# 4.5 父子集:包含的关系
# s1={1,2,3}
# s2={1,2,4}
# 不存在包含关系,下面比较均为False
# print(s1 > s2)
# print(s1 < s2)

# s1={1,2,3}
# s2={1,2}
# print(s1 > s2) # 当s1大于或等于s2时,才能说是s1是s2他爹
# print(s1.issuperset(s2))
# print(s2.issubset(s1)) # s2 < s2  =>True

# s1={1,2,3}
# s2={1,2,3}
# print(s1 == s2) # s1与s2互为父子
# print(s1.issuperset(s2))
# print(s2.issuperset(s1))


# =========================去重=========================
# 1、只能针对不可变类型去重
# print(set([1,1,1,1,2]))

# 2、无法保证原来的顺序
# l=[1,'a','b','z',1,1,1,2]
# l=list(set(l))
# print(l)


l=[
    {'name':'lili','age':18,'sex':'male'},
    {'name':'jack','age':73,'sex':'male'},
    {'name':'tom','age':20,'sex':'female'},
    {'name':'lili','age':18,'sex':'male'},
    {'name':'lili','age':18,'sex':'male'},
]
new_l=[]
for dic in l:
    if dic not in new_l:
        new_l.append(dic)

# print(new_l)

# 其他操作
'''
# 1.长度
>>> s={'a','b','c'}
>>> len(s)
3

# 2.成员运算
>>> 'c' in s
True

# 3.循环
>>> for item in s:
...     print(item)
... 
c
a
b
'''

# 其他内置方法
s={1,2,3}
# 需要掌握的内置方法1:discard
# s.discard(4) # 删除元素不存在do nothing
# print(s)
# s.remove(4) # 删除元素不存在则报错


# 需要掌握的内置方法2:update
# s.update({1,3,5})
# print(s)

# 需要掌握的内置方法3:pop
# res=s.pop()
# print(res)

# 需要掌握的内置方法4:add
# s.add(4)
# print(s)



# 其余方法全为了解
res=s.isdisjoint({3,4,5,6}) # 两个集合完全独立、没有共同部分,返回True
print(res)

# 了解
# s.difference_update({3,4,5}) # s=s.difference({3,4,5})
# print(s)
02 字符编码
分析过程

x="上"

                    内存
上-------翻译-----》0101010
上《----翻译《-----0101010

字符编码表就是一张字符与数字对应关系的表


a-00
b-01
c-10
d-11

ASCII表:
    1、只支持英文字符串
    2、采用8位二进制数对应一个英文字符串

GBK表:
    1、支持英文字符、中文字符
    2、
    采用8位(8bit=1Bytes)二进制数对应一个英文字符串
    采用16位(16bit=2Bytes)二进制数对应一个中文字符串


unicode(内存中统一使用unicode):
    1、
        兼容万国字符
        与万国字符都有对应关系
    2、
    采用16位(16bit=2Bytes)二进制数对应一个中文字符串
    个别生僻会采用4Bytes、8Bytes


    unicode表:
                          内存
        人类的字符---------unicode格式的数字----------
                             |                     |
                             |                     |
                             |
                            硬盘                    |
                             |
                             |                     |
                             |                     |
                        GBK格式的二进制       Shift-JIS格式的二进制

        老的字符编码都可以转换成unicode,但是不能通过unicode互转



utf-8:
    英文->1Bytes
    汉字->3Bytes



结论:
    1、内存固定使用unicode,我们可以改变的是存入硬盘采用格式
        英文+汉字-》unicode-》gbk
        英文+日文-》unicode-》shift-jis
        万国字符》-unicode-》utf-8

    2、文本文件存取乱码问题
        存乱了:解决方法是,编码格式应该设置成支持文件内字符串的格式
        取乱了:解决方法是,文件是以什么编码格式存如硬盘的,就应该以什么编码格式读入内存



    3、python解释器默认读文件的编码
        python3默认:utf-8
        python2默认:ASCII

        指定文件头修改默认的编码:
        在py文件的首行写:
            #coding:gbk

     4、保证运行python程序前两个阶段不乱码的核心法则:
        指定文件头
        # coding:文件当初存入硬盘时所采用的编码格式


     5、
        python3的str类型默认直接存成unicode格式,无论如何都不会乱码
        保证python2的str类型不乱码
            x=u'上'


    6、了解
        python2解释器有两种字符串类型:str、unicode
            # str类型
            x='上' # 字符串值会按照文件头指定的编码格式存入变量值的内存空间
            # unicode类型
            x=u'上' # 强制存成unicode
03 编码解码
# coding:utf-8

x='上'

res=x.encode('gbk') # unicode--->gbk
# print(res,type(res))

print(res.decode('gbk'))
01 文件与文件模式介绍
1、什么是文件
    文件是操作系统提供给用户/应用程序操作硬盘的一种虚拟的概念/接口

    用户/应用程序(open())
    操作系统(文件)
    计算机硬件(硬盘)

2、为何要用文件
    用户/应用程序可以通过文件将数据永久保存的硬盘中
    即操作文件就是操作硬盘

    用户/应用程序直接操作的是文件,对文件进行的所有的操作,都是
    在向操作系统发送系统调用,然后再由操作将其转换成具体的硬盘操作

3、如何用文件:open()
        控制文件读写内容的模式:t和b
            强调:t和b不能单独使用,必须跟r/w/a连用

            t文本(默认的模式)
                1、读写都以str(unicode)为单位的
                2、文本文件
                3、必须指定encoding='utf-8'

            b二进制/bytes

        控制文件读写操作的模式
            r只读模式
            w只写模式
            a只追加写模式
            +:r+、w+、a+


02 文件操作基本
# 1、打开文件
# windows路径分隔符问题
# open('C:\a.txt\nb\c\d.txt')
# 解决方案一:推荐
# open(r'C:\a.txt\nb\c\d.txt')
# 解决方案二:
# open('C:/a.txt/nb/c/d.txt')


f=open(r'aaa/a.txt',mode='rt') # f的值是一种变量,占用的是应用程序的内存空间
# print(f)
# x=int(10)

# 2、操作文件:读/写文件,应用程序对文件的读写请求都是在向操作系统发送
# 系统调用,然后由操作系统控制硬盘把输入读入内存、或者写入硬盘
res=f.read()
print(type(res))
# print(res)
# 3、关闭文件
f.close() # 回收操作系统资源
# print(f)
# f.read() # 变量f存在,但是不能再读了

# del f     # 回收应用程序资源
03 with上下文管理
# 文件对象又称为文件句柄

# with open('a.txt',mode='rt') as f1: # f1=open('a.txt',mode='rt')
#     res=f1.read()
#     print(res)


with open('a.txt',mode='rt') as f1,\
        open('b.txt',mode='rt') as f2:
    res1=f1.read()
    res2=f2.read()
    print(res1)
    print(res2)

    # f1.close()
    # f2.close()
04 指定字符编码
'''
强调:t和b不能单独使用,必须跟r/w/a连用

t文本(默认的模式)
1、读写都以str(unicode)为单位的
2、文本文件
3、必须指定encoding='utf-8'

'''
# 没有指定encoding参数操作系统会使用自己默认的编码
# linux系统默认utf-8
# windows系统默认gbk
with open('c.txt',mode='rt',encoding='utf-8') as f:
    res=f.read() # t模式会将f.read()读出的结果解码成unicode
    print(res,type(res))



# 内存:utf-8格式的二进制-----解码-----》unicode
# 硬盘(c.txt内容:utf-8格式的二进制)
05 文件操作模式详解
# 以t模式为基础进行内存操作

# 1、r(默认的操作模式):只读模式,当文件不存在时报错,当文件存在时文件指针跳到开始位置
# with open('c.txt',mode='rt',encoding='utf-8') as f:
#     print('第一次读'.center(50,'*'))
#     res=f.read() # 把所有内容从硬盘读入内存
#     print(res)
#
# # with open('c.txt', mode='rt', encoding='utf-8') as f:
#     print('第二次读'.center(50,'*'))
#     res1=f.read()
#     print(res1)


# ===============案例==================
# inp_username=input('your name>>: ').strip()
# inp_password=input('your password>>: ').strip()
#
# # 验证
# with open('user.txt',mode='rt',encoding='utf-8') as f:
#     for line in f:
#         # print(line,end='') # egon:123\n
#         username,password=line.strip().split(':')
#         if inp_username == username and inp_password == password:
#             print('login successfull')
#             break
#     else:
#         print('账号或密码错误')


# 应用程序====》文件
# 应用程序====》数据库管理软件=====》文件

# 2、w:只写模式,当文件不存在时会创建空文件,当文件存在会清空文件,指针位于开始位置
# with open('d.txt',mode='wt',encoding='utf-8') as f:
    # f.read() # 报错,不可读
    # f.write('擦勒\n')

# 强调1:
# 在以w模式打开文件没有关闭的情况下,连续写入,新的内容总是跟在旧的之后
# with open('d.txt',mode='wt',encoding='utf-8') as f:
#     f.write('擦勒1\n')
#     f.write('擦勒2\n')
#     f.write('擦勒3\n')

# 强调2:
# 如果重新以w模式打开文件,则会清空文件内容
# with open('d.txt',mode='wt',encoding='utf-8') as f:
#     f.write('擦勒1\n')
# with open('d.txt',mode='wt',encoding='utf-8') as f:
#     f.write('擦勒2\n')
# with open('d.txt',mode='wt',encoding='utf-8') as f:
#     f.write('擦勒3\n')

# 案例:w模式用来创建全新的文件
# 文件文件的copy工具

# src_file=input('源文件路径>>: ').strip()
# dst_file=input('源文件路径>>: ').strip()
# with open(r'{}'.format(src_file),mode='rt',encoding='utf-8') as f1,\
#     open(r'{}'.format(dst_file),mode='wt',encoding='utf-8') as f2:
#     res=f1.read()
#     f2.write(res)


# 3、a:只追加写,在文件不存在时会创建空文档,在文件存在时文件指针会直接调到末尾
# with open('e.txt',mode='at',encoding='utf-8') as f:
#     # f.read() # 报错,不能读
#     f.write('擦嘞1\n')
#     f.write('擦嘞2\n')
#     f.write('擦嘞3\n')

# 强调 w 模式与 a 模式的异同:
# 1 相同点:在打开的文件不关闭的情况下,连续的写入,新写的内容总会跟在前写的内容之后
# 2 不同点:以 a 模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾,新写的内容永远写在最后


# 案例:a模式用来在原有的文件内存的基础之上写入新的内容,比如记录日志、注册
# 注册功能
# name=input('your name>>: ')
# pwd=input('your name>>: ')
# with open('db.txt',mode='at',encoding='utf-8') as f:
#     f.write('{}:{}\n'.format(name,pwd))


# 了解:+不能单独使用,必须配合r、w、a
# with open('g.txt',mode='rt+',encoding='utf-8') as f:
#     # print(f.read())
#     f.write('中国')

# with open('g.txt',mode='w+t',encoding='utf-8') as f:
#     f.write('111\n')
#     f.write('222\n')
#     f.write('333\n')
#     print('====>',f.read())

#
# with open('g.txt',mode='a+t',encoding='utf-8') as f:
#     print(f.read())
#
#     f.write('444\n')
#     f.write('5555\n')
#     print(f.read())
01 x模式

x模式(控制文件操作的模式)-》了解
    x, 只写模式【不可读;不存在则创建,存在则报错】
"""
# with open('a.txt',mode='x',encoding='utf-8') as f:
#     pass

# with open('c.txt',mode='x',encoding='utf-8') as f:
#     f.read()

with open('d.txt', mode='x', encoding='utf-8') as f:
    f.write('哈哈哈\n')
02 b模式

控制文件读写内容的模式
t:
    1、读写都是以字符串(unicode)为单位
    2、只能针对文本文件
    3、必须指定字符编码,即必须指定encoding参数
b:binary模式
    1、读写都是以bytes为单位
    2、可以针对所有文件
    3、一定不能指定字符编码,即一定不能指定encoding参数

总结:
1、在操作纯文本文件方面t模式帮我们省去了编码与解码的环节,b模式则需要手动编码与解码,所以此时t模式更为方便
2、针对非文本文件(如图片、视频、音频等)只能使用b模式
"""

# 错误演示:t模式只能读文本文件
# with open(r'爱nmlgb的爱情.mp4',mode='rt') as f:
#     f.read() # 硬盘的二进制读入内存-》t模式会将读入内存的内容进行decode解码操作


#
# with open(r'test.jpg',mode='rb',encoding='utf-8') as f:
#     res=f.read() # 硬盘的二进制读入内存—>b模式下,不做任何转换,直接读入内存
#     print(res) # bytes类型—》当成二进制
#     print(type(res))

# with open(r'd.txt',mode='rb') as f:
#     res=f.read() # utf-8的二进制
#     print(res,type(res))
#
#     print(res.decode('utf-8'))

# with open(r'd.txt',mode='rt',encoding='utf-8') as f:
#     res=f.read() # utf-8的二进制->unicode
#     print(res)


# with open(r'e.txt',mode='wb') as f:
#     f.write('你好hello'.encode('gbk'))

# with open(r'f.txt',mode='wb') as f:
#     f.write('你好hello'.encode('utf-8'))
#     f.write('哈哈哈'.encode('gbk'))


# 文件拷贝工具
src_file=input('源文件路径>>: ').strip()
dst_file=input('源文件路径>>: ').strip()
with open(r'{}'.format(src_file),mode='rb') as f1,\
    open(r'{}'.format(dst_file),mode='wb') as f2:
    # res=f1.read() # 内存占用过大
    # f2.write(res)

    for line in f1:
        f2.write(line)




# 循环读取文件
# 方式一:自己控制每次读取的数据的数据量
# with open(r'test.jpg',mode='rb') as f:
#     while True:
#         res=f.read(1024) # 1024
#         if len(res) == 0:
#             break
#         print(len(res))


# 方式二:以行为单位读,当一行内容过长时会导致一次性读入内容的数据量过大
# with open(r'g.txt',mode='rt',encoding='utf-8') as f:
#     for line in f:
#         print(len(line),line)

# with open(r'g.txt',mode='rb') as f:
#     for line in f:
#         print(line)

# with open(r'test.jpg',mode='rb') as f:
#     for line in f:
#         print(line)
03 文件的操作的其他方法
# 一:读相关操作
# 1、readline:一次读一行
# with open(r'g.txt',mode='rt',encoding='utf-8') as f:
#     # res1=f.readline()
#     # res2=f.readline()
#     # print(res2)
#
#     while True:
#         line=f.readline()
#         if len(line) == 0:
#             break
#         print(line)

# 2、readlines:
# with open(r'g.txt',mode='rt',encoding='utf-8') as f:
#     res=f.readlines()
#     print(res)

# 强调:
# f.read()与f.readlines()都是将内容一次性读入内存,如果内容过大会导致内存溢出,若还想将内容全读入内存,


# 二:写相关操作
# f.writelines():
# with open('h.txt',mode='wt',encoding='utf-8') as f:
#     # f.write('1111\n222\n3333\n')
#
#     # l=['11111\n','2222','3333',4444]
#     l=['11111\n','2222','3333']
#     # for line in l:
#     #     f.write(line)
#     f.writelines(l)


# with open('h.txt', mode='wb') as f:
#     # l = [
#     #     '1111aaa1\n'.encode('utf-8'),
#     #     '222bb2'.encode('utf-8'),
#     #     '33eee33'.encode('utf-8')
#     # ]
#
#     # 补充1:如果是纯英文字符,可以直接加前缀b得到bytes类型
#     # l = [
#     #     b'1111aaa1\n',
#     #     b'222bb2',
#     #     b'33eee33'
#     # ]
#
#     # 补充2:'上'.encode('utf-8') 等同于bytes('上',encoding='utf-8')
#     l = [
#         bytes('上啊',encoding='utf-8'),
#         bytes('冲呀',encoding='utf-8'),
#         bytes('小垃圾们',encoding='utf-8'),
#     ]
#     f.writelines(l)


# 3、flush:
# with open('h.txt', mode='wt',encoding='utf-8') as f:
#     f.write('哈')
#     # f.flush()


# 4、了解
with open('h.txt', mode='wt', encoding='utf-8') as f:
    print(f.readable())
    print(f.writable())
    print(f.encoding)
    print(f.name)

print(f.closed)
04 文件的高级操作:控制文件指针的移动

# 指针移动的单位都是以bytes/字节为单位
# 只有一种情况特殊:
#       t模式下的read(n),n代表的是字符个数

# with open('aaa.txt',mode='rt',encoding='utf-8') as f:
#     res=f.read(4)
#     print(res)

# f.seek(n,模式):n指的是移动的字节个数
# 模式:
# 模式0:参照物是文件开头位置
# f.seek(9,0)
# f.seek(3,0) # 3

# 模式1:参照物是当前指针所在位置
# f.seek(9,1)
# f.seek(3,1) # 12

# 模式2:参照物是文件末尾位置,应该倒着移动
# f.seek(-9,2) # 3
# f.seek(-3,2) # 9

# 强调:只有0模式可以在t下使用,1、2必须在b模式下用

# f.tell() # 获取文件指针当前位置

# 示范
# with open('aaa.txt',mode='rb') as f:
#     f.seek(9,0)
#     f.seek(3,0) # 3
#     # print(f.tell())
#     f.seek(4,0)
#     res=f.read()
#     print(res.decode('utf-8'))



# with open('aaa.txt',mode='rb') as f:
#     f.seek(9,1)
#     f.seek(3,1) # 12
#     print(f.tell())


# with open('aaa.txt',mode='rb') as f:
#     f.seek(-9,2)
#     # print(f.tell())
#     f.seek(-3,2)
#     # print(f.tell())
#     print(f.read().decode('utf-8'))
01 f.seek的应用
import time

with open('access.log', mode='rb') as f:
    # 1、将指针跳到文件末尾
    # f.read() # 错误
    f.seek(0,2)

    while True:
        line=f.readline()
        if len(line) == 0:
            time.sleep(0.3)
        else:
            print(line.decode('utf-8'),end='')
02 文件修改的两种方式

# with open('a.txt',mode='r+t',encoding='utf-8') as f:
#     f.seek(9,0)
#     f.write('<男妇女主任>')


# 文件修改的两种方式
# 方式一:文本编辑采用的就是这种方式
# 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存
# with open('c.txt',mode='rt',encoding='utf-8') as f:
#     res=f.read()
#     data=res.replace('alex','dsb')
#     print(data)
#
# with open('c.txt',mode='wt',encoding='utf-8') as f1:
#     f1.write(data)


# 方式二:
import os
# 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份数据存了两份
with open('c.txt', mode='rt', encoding='utf-8') as f, \
        open('.c.txt.swap', mode='wt', encoding='utf-8') as f1:
    for line in f:
        f1.write(line.replace('alex', 'dsb'))

os.remove('c.txt')
os.rename('.c.txt.swap', 'c.txt')




f = open('a.txt')
res = f.read()
print(res)
函数
03 函数基本使用
1、什么是函数
    函数就相当于具备某一功能的工具
    函数的使用必须遵循一个原则:
        先定义
        后调用
2、为何要用函数
    1、组织结构不清晰,可读性差
    2、代码冗余
    3、可维护性、扩展性差

3、如何用函数
        先定义
            三种定义方式
        后调用
            三种调用方式

        返回值
            三种返回值的形式

"""
# 一、先定义
# 定义的语法
'''
def 函数名(参数1,参数2,...):
    """文档描述"""
    函数体
    return 值
'''


# 形式一:无参函数
# def func():
#     # x
#     # print(
#     print('哈哈哈')
#     print('哈哈哈')
#     print('哈哈哈')

# 定义函数发生的事情
# 1、申请内存空间保存函数体代码
# 2、将上述内存地址绑定函数名
# 3、定义函数不会执行函数体代码,但是会检测函数体语法

# 调用函数发生的事情
# 1、通过函数名找到函数的内存地址
# 2、然后加口号就是在触发函数体代码的执行
# print(func)
# func()

# 示范1
# def bar(): # bar=函数的内存地址
#     print('from bar')
#
# def foo():
#     # print(bar)
#     bar()
#     print('from foo')
#
# foo()

# 示范2
# def foo():
#     # print(bar)
#     bar()
#     print('from foo')
#
# def bar():  # bar=函数的内存地址
#     print('from bar')
#
# foo()

# 示范3
# def foo():
#     # print(bar)
#     bar()
#     print('from foo')
#
# foo()
#
# def bar():  # bar=函数的内存地址
#     print('from bar')

# 形式二:有参函数
# def func(x,y): # x=1  y=2
#     print(x,y)
# func(1,2)

# 形式三:空函数,函数体代码为pass
def func(x, y):
    pass


# 三种定义方式各用在何处
# 1、无参函数的应用场景
# def interactive():
#     name=input('username>>: ')
#     age=input('age>>: ')
#     gender=input('gender>>: ')
#     msg='名字:{} 年龄:{} 性别'.format(name,age,gender)
#     print(msg)
#
# interactive()
# interactive()
# interactive()
# interactive()

# 2、有参函数的应用场景
# def add(x,y): # 参数-》原材料
#     # x=20
#     # y=30
#     res=x + y
#     # print(res)
#     return res # 返回值-》产品
#
# # add(10,2)
# res=add(20,30)
# print(res)

# 3、空函数的应用场景
# def auth_user():
#     """user authentication function"""
#     pass
#
# def download_file():
#     """download file function"""
#     pass
#
# def upload_file():
#     """upload file function"""
#     pass
#
# def ls():
#     """list contents function"""
#     pass
#
# def cd():
#     """change directory"""
#     pass


# 二、调用函数
# 1、语句的形式:只加括号调用函数
# interactive()
# add(1,2)

# 2、表达式形式:
# def add(x,y): # 参数-》原材料
#     res=x + y
#     return res # 返回值-》产品
# 赋值表达式
# res=add(1,2)
# print(res)
# 数学表达式
# res=add(1,2)*10
# print(res)

# 3、函数调用可以当做参数
# res=add(add(1,2),10)
# print(res)

# 三、函数返回值
# return是函数结束的标志,即函数体代码一旦运行到return会立刻
# 终止函数的运行,并且会将return后的值当做本次运行的结果返回:
# 1、返回None:函数体内没有return
#             return
#             return None
#
# 2、返回一个值:return 值
# def func():
#     return 10
#
# res=func()
# print(res)

# 3、返回多个值:用逗号分隔开多个值,会被return返回成元组
def func():
    return 10, 'aa', [1, 2]

res = func()
print(res, type(res))

01 函数参数的使用

"""
@作者: egon老湿
@微信:18611453110
@专栏: https://zhuanlan.zhihu.com/c_1189883314197168128
"""


# 一 形参与实参介绍
# 形参:在定义函数阶段定义的参数称之为形式参数,简称形参,相当于变量名
def func(x, y):  # x=1,y=2
    print(x, y)


# 实参:在调用函数阶段传入的值称之为实际参数,简称实参,相当于变量值
# func(1,2)

# 形参与实参的关系:
# 1、在调用阶段,实参(变量值)会绑定给形参(变量名)
# 2、这种绑定关系只能在函数体内使用
# 3、实参与形参的绑定关系在函数调用时生效,函数调用结束后解除绑定关系

# 实参是传入的值,但值可以是以下形式
# 形式一:
# func(1,2)

# 形式二:
# a=1
# b=2
# func(a,b)

# 形式三:
# func(int('1'),2)
# func(func1(1,2,),func2(2,3),333)


# 二 形参与实参的具体使用
# 2.1 位置参数:按照从左到右的顺序依次定义的参数称之为位置参数
# 位置形参:在函数定义阶段,按照从左到右的顺序直接定义的"变量名"
#        特点:必须被传值,多一个不行少一个也不行
# def func(x,y):
#     print(x,y)
# func(1,2,3)
# func(1,)

# 位置实参:在函数调用阶段, 按照从左到有的顺序依次传入的值
#        特点:按照顺序与形参一一对应

# func(1,2)
# func(2,1)

# 2.2 关键字参数
# 关键字实参:在函数调用阶段,按照key=value的形式传入的值
#       特点:指名道姓给某个形参传值,可以完全不参照顺序
# def func(x,y):
#     print(x,y)

# func(y=2,x=1)
# func(1,2)

# 混合使用,强调
# 1、位置实参必须放在关键字实参前
# func(1,y=2)
# func(y=2,1)

# 2、不能能为同一个形参重复传值
# func(1,y=2,x=3)
# func(1,2,x=3,y=4)


# 2.3 默认参数
# 默认形参:在定义函数阶段,就已经被赋值的形参,称之为默认参数
#       特点:在定义阶段就已经被赋值,意味着在调用阶段可以不用为其赋值
# def func(x,y=3):
#     print(x,y)
#
# # func(x=1)
# func(x=1,y=44444)


# def register(name,age,gender='男'):
#     print(name,age,gender)
#
# register('三炮',18)
# register('二炮',19)
# register('大炮',19)
# register('没炮',19,'女')


# 位置形参与默认形参混用,强调:
# 1、位置形参必须在默认形参的左边
# def func(y=2,x):
#     pass

# 2、默认参数的值是在函数定义阶段被赋值的,准确地说被赋予的是值的内存地址
# 示范1:
# m=2
# def func(x,y=m): # y=>2的内存地址
#     print(x,y
# m=3333333333333333333
# func(1)

# 示范2:
# m = [111111, ]
#
# def func(x, y=m): # y=>[111111, ]的内存地址
#     print(x, y)
#
# m.append(3333333)
# func(1)

# 3、虽然默认值可以被指定为任意数据类型,但是不推荐使用可变类型
# 函数最理想的状态:函数的调用只跟函数本身有关系,不外界代码的影响
# m = [111111, ]
#
# def func(x, y=m):
#     print(x, y)
#
# m.append(3333333)
# m.append(444444)
# m.append(5555)
#
#
# func(1)
# func(2)
# func(3)


# def func(x,y,z,l=None):
#     if l is None:
#         l=[]
#     l.append(x)
#     l.append(y)
#     l.append(z)
#     print(l)

# func(1,2,3)
# func(4,5,6)

# new_l=[111,222]
# func(1,2,3,new_l)


# 2.4 可变长度的参数(*与**的用法)
# 可变长度指的是在调用函数时,传入的值(实参)的个数不固定
# 而实参是用来为形参赋值的,所以对应着,针对溢出的实参必须有对应的形参来接收

# 2.4.1 可变长度的位置参数
# I:*形参名:用来接收溢出的位置实参,溢出的位置实参会被*保存成元组的格式然后赋值紧跟其后的形参名
#           *后跟的可以是任意名字,但是约定俗成应该是args

# def func(x,y,*z): # z =(3,4,5,6)
#     print(x,y,z)

# func(1,2,3,4,5,6)

# def my_sum(*args):
#     res=0
#     for item in args:
#         res+=item
#     return res
#
# res=my_sum(1,2,3,4,)
# print(res)

# II: *可以用在实参中,实参中带*,先*后的值打散成位置实参
# def func(x,y,z):
#     print(x,y,z)
#
# # func(*[11,22,33]) # func(11,22,33)
# # func(*[11,22]) # func(11,22)
#
# l=[11,22,33]
# func(*l)

# III: 形参与实参中都带*
# def func(x,y,*args): # args=(3,4,5,6)
#     print(x,y,args)

# func(1,2,[3,4,5,6])
# func(1,2,*[3,4,5,6]) # func(1,2,3,4,5,6)
# func(*'hello') # func('h','e','l','l','o')


# 2.4.2 可变长度的关键字参数
# I:**形参名:用来接收溢出的关键字实参,**会将溢出的关键字实参保存成字典格式,然后赋值给紧跟其后的形参名
#           **后跟的可以是任意名字,但是约定俗成应该是kwargs
# def func(x,y,**kwargs):
#     print(x,y,kwargs)
#
# func(1,y=2,a=1,b=2,c=3)

# II: **可以用在实参中(**后跟的只能是字典),实参中带**,先**后的值打散成关键字实参
# def func(x,y,z):
#     print(x,y,z)

# func(*{'x':1,'y':2,'z':3}) # func('x','y','z')
# func(**{'x':1,'y':2,'z':3}) # func(x=1,y=2,z=3)

# 错误
# func(**{'x':1,'y':2,}) # func(x=1,y=2)
# func(**{'x':1,'a':2,'z':3}) # func(x=1,a=2,z=3)


# III: 形参与实参中都带**
# def func(x,y,**kwargs):
#     print(x,y,kwargs)

# func(y=222,x=111,a=333,b=444)
# func(**{'y':222,'x':111,'a':333,'b':4444})




# 混用*与**:*args必须在**kwargs之前
# def func(x,*args,**kwargs):
#     print(args)
#     print(kwargs)
#
# func(1,2,3,4,5,6,7,8,x=1,y=2,z=3)


def index(x,y,z):
    print('index=>>> ',x,y,z)

def wrapper(*args,**kwargs): #args=(1,) kwargs={'z':3,'y':2}
    index(*args,**kwargs)
    # index(*(1,),**{'z':3,'y':2})
    # index(1,z=3,y=2)

wrapper(1,z=3,y=2) # 为wrapper传递的参数是给index用的
# 原格式---》汇总-----》打回原形



# 2.5 命名关键字参数(了解)
# 2.6 组合使用(了解)
01 函数参数补充

# 1. 命名关键字参数(了解)
#  命名关键字参数:在定义函数时,*后定义的参数,如下所示,称之为命名关键字参数
# 特点:
# 1、命名关键字实参必须按照key=value的形式为其传值
# def func(x,y,*,a,b): # 其中,a和b称之为命名关键字参数
#     print(x,y)
#     print(a,b)
#
# # func(1,2,b=222,a=111)

# 示例
# def func(x,y,*,a=11111,b):
#     print(x,y)
#     print(a,b)
#
# func(1,2,b=22222)

# 2. 组合使用(了解)
# 形参混用的顺序:位置新参,默认形参,*args,命名关键字形参,**kwargs
# def func(x,y=111,*args,z,**kwargs):
#     print(x)
#     print(y)
#     print(args)
#     print(z)
#     print(kwargs)
#


# 实参混用的顺序:
def func(x,y,z,a,b,c):
    print(x)
    print(y)
    print(z)
    print(a)
    print(b)
    print(c)

# func(111,y=222,*[333,444],**{'b':555,'c':666})
# func(111,y=222,333,444,b=555,c=666)

# func(111,*[333,444],a=222,**{'b':555,'c':666})
# func(111,333,444,a=222,b=555,c=66)

# func(111,*[333,444],**{'b':555,'c':666},a=222,)
func(111,3333,4444,b=555,c=666,a=222)


# func(1)
# func(x=1)
# func(1,x=1)
# func(*'hello')
# func(**{})
# func(*'hell',**{})
02 名称空间与作用域

# 一:名称空间namespacs:存放名字的地方,是对栈区的划分
# 有了名称空间之后,就可以在栈区中存放相同的名字,详细的,名称空间
# 分为三种
# 1.1 内置名称空间
# 存放的名字:存放的python解释器内置的名字
'''
>>> print
<built-in function print>
>>> input
<built-in function input>
'''
# 存活周期:python解释器启动则产生,python解释器关闭则销毁


# 1.2 全局名称空间
# 存放的名字:只要不是函数内定义、也不是内置的,剩下的都是全局名称空间的名字
# 存活周期:python文件执行则产生,python文件运行完毕后销毁

# import os
#
# x=10
# if 13 > 3:
#     y=20
#     if 3 == 3:
#         z=30
#
# # func=函数的内存地址
# def func():
#     a=111
#     b=222

# class Foo:
#     pass



# 1.3 局部名称空间
# 存放的名字:在调用函数时,运行函数体代码过程中产生的函数内的名字
# 存活周期:在调用函数时存活,函数调用完毕后则销毁
# def func(a,b):
#     pass
#
# func(10,1)
# func(11,12)
# func(13,14)
# func(15,16)


# 1.4 名称空间的加载顺序
# 内置名称空间>全局名称空间>局部名称空间

# 1.5 销毁顺序
# 局部名称空间>全局名空间>内置名称空间

# 1.6 名字的查找优先级:当前所在的位置向上一层一层查找
# 内置名称空间
# 全局名称空间
# 局部名称空间

# 如果当前在局部名称空间:
# 局部名称空间—>全局名称空间->内置名称空间
# # input=333
#
# def func():
#     # input=444
#     print(input)
#
# func()


# 如果当前在全局名称空间
# 全局名称空间->内置名称空间
# input=333
# def func():
#     input=444
# func()
# print(input)


# 示范1:
# def func():
#     print(x)
# x=111
#
# func()

# 示范2:名称空间的"嵌套"关系是以函数定义阶段为准,与调用位置无关
# x=1
# def func():
#    print(x)
#
#
# def foo():
#     x=222
#     func()
#
# foo()

# 示范3:函数嵌套定义
# input=111
# def f1():
#     def f2():
#         # input=333
#         print(input)
#     input=222
#
#     f2()
#
#
# f1()


# 示范4:
# x=111
# def func():
#     print(x) #
#     x=222
#
# func()


# 二:作用域-》作用范围
# 全局作用域:内置名称空间、全局名称空间
# 1、全局存活
# 2、全局有效:被所有函数共享

# x=111
#
# def foo():
#     print(x,id(x))
#
# def bar():
#     print(x,id(x))
#
# foo()
# bar()

# print(x,id(x))

# 局部作用域: 局部名称空间的名字
# 1、临时存活
# 2、局部有效:函数内有效

# def foo(x):
#     def f1():
#         def f2():
#             print(x)



# LEGB
# # builtin
# # global
# def f1():
#     # enclosing
#     def f2():
#         # enclosing
#         def f3():
#             # local
#             pass
03 global与nonlocal
# 示范1:
# x=111
#
# def func():
#     x=222
#
# func()
# print(x)

# 示范2:如果再局部想要修改全局的名字对应的值(不可变类型),需要用global
# x=111
#
# def func():
#     global x # 声明x这个名字是全局的名字,不要再造新的名字了
#     x=222
#
# func()
# print(x)


# 示范3:
# l=[111,222]
# def func():
#     l.append(333)
#
# func()
# print(l)


# nonlocal(了解): 修改函数外层函数包含的名字对应的值(不可变类型)
# x=0
# def f1():
#     x=11
#     def f2():
#         nonlocal x
#         x=22
#     f2()
#     print('f1内的x:',x)
#
# f1()



def f1():
    x=[]
    def f2():
        x.append(1111)
    f2()
    print('f1内的x:',x)

f1()
01 函数对象
# 精髓:可以把函数当成变量去用
# func=内存地址
def func():
    print('from func')


# 1、可以赋值
# f=func
# print(f,func)
# f()

# 2、可以当做函数当做参数传给另外一个函数
# def foo(x): # x = func的内存地址
#     # print(x)
#     x()
#
# foo(func) # foo(func的内存地址)

# 3、可以当做函数当做另外一个函数的返回值
# def foo(x): # x=func的内存地址
#     return x # return func的内存地址
#
# res=foo(func) # foo(func的内存地址)
# print(res) # res=func的内存地址
#
# res()

# 4、可以当做容器类型的一个元素
# l=[func,]
# # print(l)
# l[0]()

# dic={'k1':func}
# print(dic)
# dic['k1']()

# 函数对象应用示范:
# def login():
#     print('登录功能')
#
#
# def transfer():
#     print('转账功能')
#
#
# def check_banlance():
#     print('查询余额')
#
# def withdraw():
#     print('提现')
#
#
# def register():
#     print('注册')
#
# func_dic={
#     '1':login,
#     '2':transfer,
#     '3':check_banlance,
#     '4':withdraw,
#     '5':register
# }
#
# # func_dic['1']()
#
#
# while True:
#     print("""
#     0 退出
#     1 登录
#     2 转账
#     3 查询余额
#     4 提现
#     5 注册
#     """)
#     choice = input('请输入命令编号:').strip()
#     if not choice.isdigit():
#         print('必须输入编号,傻叉')
#         continue
#
#     if choice == '0':
#         break
#
#
#     if choice in func_dic:
#         func_dic[choice]()
#     else:
#         print('输入的指令不存在')
#
#     # if choice == '1':
#     #     login()
#     # elif choice == '2':
#     #     transfer()
#     # elif choice == '3':
#     #     check_banlance()
#     # elif choice == '4':
#     #     withdraw()
#     # else:
#     #     print('输入的指令不存在')


# 修正
def login():
    print('登录功能')


def transfer():
    print('转账功能')


def check_banlance():
    print('查询余额')


def withdraw():
    print('提现')


def register():
    print('注册')


func_dic = {
    '0': ['退出', None],
    '1': ['登录', login],
    '2': ['转账', transfer],
    '3': ['查询余额', check_banlance],
    '4': ['提现', withdraw],
    '5': ['注册', register]
}
# func_dic['1']()


while True:
    for k in func_dic:
        print(k, func_dic[k][0])

    choice = input('请输入命令编号:').strip()
    if not choice.isdigit():
        print('必须输入编号,傻叉')
        continue

    if choice == '0':
        break

    # choice='1'
    if choice in func_dic:
        func_dic[choice][1]()
    else:
        print('输入的指令不存在')
02 函数嵌套
# 函数嵌套
# 1、函数的嵌套调用:在调用一个函数的过程中又调用其他函数
# def max2(x,y):
#     if x > y:
#         return x
#     else:
#         return y
#
#
# def max4(a,b,c,d):
#     # 第一步:比较a,b得到res1
#     res1=max2(a,b)
#     # 第二步:比较res1,c得到res2
#     res2=max2(res1,c)
#     # 第三步:比较res2,d得到res3
#     res3=max2(res2,d)
#     return res3
#
# res=max4(1,2,3,4)
# print(res)


# 2、函数的嵌套定义:在函数内定义其他函数
# def f1():
#     def f2():
#         pass


# 圆形
# 求圆形的求周长:2*pi*radius
def circle(radius,action=0):
    from math import pi

    def perimiter(radius):
        return 2*pi*radius

    # 求圆形的求面积:pi*(radius**2)
    def area(radius):
        return pi*(radius**2)

    if action == 0:
        return 2*pi*radius

    elif action == 1:
        return area(radius)

circle(33,action=0)
03 闭包函数
# 一:大前提:
# 闭包函数=名称空间与作用域+函数嵌套+函数对象
#        核心点:名字的查找关系是以函数定义阶段为准

# 二:什么是闭包函数
# "闭"函数指的该函数是内嵌函数
# "包"函数指的该函数包含对外层函数作用域名字的引用(不是对全局作用域)

# 闭包函数:名称空间与作用域的应用+函数嵌套
# def f1():
#     x = 33333333333333333333
#     def f2():
#         print(x)
#     f2()
#
#
# x=11111
# def bar():
#     x=444444
#     f1()
#
# def foo():
#     x=2222
#     bar()
#
# foo()



# 闭包函数:函数对象
# def f1():
#     x = 33333333333333333333
#     def f2():
#         print('函数f2:',x)
#     return f2
#
# f=f1()
# # print(f)
#
# # x=4444
# # f()
# def foo():
#     x=5555
#     f()
#
# foo()


# 三:为何要有闭包函数=》闭包函数的应用
# 两种为函数体传参的方式
# 方式一:直接把函数体需要的参数定义成形参
# def f2(x):
#     print(x)
#
# f2(1)
# f2(2)
# f2(3)

# 方式二:
# def f1(x): # x=3
#     x=3
#     def f2():
#         print(x)
#     return f2
#
# x=f1(3)
# print(x)
#
# x()



import requests

# 传参的方案一:
# def get(url):
#     response=requests.get(url)
#     print(len(response.text))
#
# get('https://www.baidu.com')
# get('https://www.cnblogs.com/linhaifeng')
# get('https://zhuanlan.zhihu.com/p/109056932')


# 传参的方案二:
def outter(url):
    # url='https://www.baidu.com'
    def get():
        response=requests.get(url)
        print(len(response.text))
    return get

baidu=outter('https://www.baidu.com')
baidu()

cnblogs=outter('https://www.cnblogs.com/linhaifeng')
cnblogs()

zhihu=outter('https://zhuanlan.zhihu.com/p/109056932')
zhihu()
01 无参装饰器
# 一:储备知识
#1、 *args, **kwargs
# def index(x,y):
#     print(x,y)
#
#
# def wrapper(*args,**kwargs):
#     index(*args,**kwargs) #
#                           # index(y=222,x=111)
# wrapper(y=222,x=111)


# 2、名称空间与作用域:名称空间的的"嵌套"关系是在函数定义阶段,即检测语法的时候确定的

# 3、函数对象:
#    可以把函数当做参数传入
#    可以把函数当做返回值返回
# def index():
#     return 123
#
# def foo(func):
#     return func
#
# foo(index)

# 4、函数的嵌套定义:
# def outter(func):
#     def wrapper():
#         pass
#     return wrapper


# 闭包函数
# def outter():
#     x=111
#     def wrapper():
#         x
#     return wrapper
#
# f=outter()



# 传参的方式一:通过参数的形式为函数体传值


# def wrapper(x):
#     print(1)
#     print(2)
#     print(3)
#     x
#
# wrapper(1)
# wrapper(2)
# wrapper(3)
# 传参的方式二:通过闭包的方式为函数体传值
# def outter(x):
#     # x=1
#     def wrapper():
#         print(1)
#         print(2)
#         print(3)
#         x
#     return wrapper # return outter内的wrapper那个函数的内地址
#
# # f1=outter(1)
# # f2=outter(2)
# # f3=outter(3)
#
#
# wrapper=outter(1)
#


#二 装饰器
"""
1、什么是装饰器
    器指的是工具,可以定义成成函数
    装饰指的是为其他事物添加额外的东西点缀
    
    合到一起的解释:
        装饰器指的定义一个函数,该函数是用来为其他函数添加额外的功能
        
    
2、为何要用装饰器
    开放封闭原则
        开放:指的是对拓展功能是开放的
        封闭:指的是对修改源代码是封闭的
        
    装饰器就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能
3、如何用
"""
# 需求:在不修改index函数的源代码以及调用方式的前提下为其添加统计运行时间的功能
# def index(x,y):
#     time.sleep(3)
#     print('index %s %s' %(x,y))
#
# index(111,222)
# # index(y=111,x=222)
# # index(111,y=222)

# 解决方案一:失败
# 问题:没有修改被装饰对象的调用方式,但是修改了其源代码
# import time
#
# def index(x,y):
#     start=time.time()
#     time.sleep(3)
#     print('index %s %s' %(x,y))
#     stop = time.time()
#     print(stop - start)
#
# index(111,222)


# 解决方案二:失败
# 问题:没有修改被装饰对象的调用方式,也没有修改了其源代码,并且加上了新功能
#      但是代码冗余
# import time
#
# def index(x,y):
#     time.sleep(3)
#     print('index %s %s' %(x,y))
#
# start=time.time()
# index(111,222)
# stop=time.time()
# print(stop - start)
#
#
#
# start=time.time()
# index(111,222)
# stop=time.time()
# print(stop - start)
#
#
# start=time.time()
# index(111,222)
# stop=time.time()
# print(stop - start)


# 解决方案三:失败
# 问题:解决了方案二代码冗余问题,但带来一个新问题即函数的调用方式改变了
# import time
#
# def index(x,y):
#     time.sleep(3)
#     print('index %s %s' %(x,y))
#
# def wrapper():
#     start=time.time()
#     index(111,222)
#     stop=time.time()
#     print(stop - start)
#
# wrapper()

# 方案三的优化一:将index的参数写活了
# import time
#
# def index(x,y,z):
#     time.sleep(3)
#     print('index %s %s %s' %(x,y,z))
#
# def wrapper(*args,**kwargs):
#     start=time.time()
#     index(*args,**kwargs) # index(3333,z=5555,y=44444)
#     stop=time.time()
#     print(stop - start)
#
# # wrapper(3333,4444,5555)
# # wrapper(3333,z=5555,y=44444)


# 方案三的优化二:在优化一的基础上把被装饰对象写活了,原来只能装饰index
# import time
#
# def index(x,y,z):
#     time.sleep(3)
#     print('index %s %s %s' %(x,y,z))
#
# def home(name):
#     time.sleep(2)
#     print('welcome %s to home page' %name)
#
#
# def outter(func):
#     # func = index的内存地址
#     def wrapper(*args,**kwargs):
#         start=time.time()
#         func(*args,**kwargs) # index的内存地址()
#         stop=time.time()
#         print(stop - start)
#     return wrapper
#
# index=outter(index) # index=wrapper的内存地址
# home=outter(home) # home=wrapper的内存地址
#
#
# home('egon')
# # home(name='egon')

# 方案三的优化三:将wrapper做的跟被装饰对象一模一样,以假乱真
# import time
#
# def index(x,y,z):
#     time.sleep(3)
#     print('index %s %s %s' %(x,y,z))
#
# def home(name):
#     time.sleep(2)
#     print('welcome %s to home page' %name)
#
# def outter(func):
#     def wrapper(*args,**kwargs):
#         start=time.time()
#         res=func(*args,**kwargs)
#         stop=time.time()
#         print(stop - start)
#         return res
#
#
#
#     return wrapper
# # 偷梁换柱:home这个名字指向的wrapper函数的内存地址
# home=outter(home)
#
#
# res=home('egon') # res=wrapper('egon')
# print('返回值--》',res)

# 大方向:如何在方案三的基础上不改变函数的调用方式




# 语法糖:让你开心的语法
import time

# 装饰器
# def timmer(func):
#     def wrapper(*args,**kwargs):
#         start=time.time()
#         res=func(*args,**kwargs)
#         stop=time.time()
#         print(stop - start)
#         return res
#
#
#
#     return wrapper
#
#
# # 在被装饰对象正上方的单独一行写@装饰器名字
# # @timmer # index=timmer(index)
# def index(x,y,z):
#     time.sleep(3)
#     print('index %s %s %s' %(x,y,z))
#
# # @timmer # home=timmer(ome)
# def home(name):
#     time.sleep(2)
#     print('welcome %s to home page' %name)
#
#
# index(x=1,y=2,z=3)
# home('egon')



# 思考题(选做),叠加多个装饰器,加载顺序与运行顺序
# @deco1 # index=deco1(deco2.wrapper的内存地址)
# @deco2 # deco2.wrapper的内存地址=deco2(deco3.wrapper的内存地址)
# @deco3 # deco3.wrapper的内存地址=deco3(index)
# def index():
#     pass



# 总结无参装饰器模板
# def outter(func):
#     def wrapper(*args,**kwargs):
#         # 1、调用原函数
#         # 2、为其增加新功能
#         res=func(*args,**kwargs)
#         return res
#     return wrapper








def auth(func):
    def wrapper(*args,**kwargs):
        # 1、调用原函数
        # 2、为其增加新功能
        name=input('your name>>: ').strip()
        pwd=input('your password>>: ').strip()
        if name == 'egon' and pwd == '123':
            res=func(*args,**kwargs)
            return res
        else:
            print('账号密码错误')
    return wrapper



@auth
def index():
    print('from index')

index()

01 二分法

# 算法:是高效解决问题的办法
# 算法之二分法

# 需求:有一个按照从小到大顺序排列的数字列表
#      需要从该数字列表中找到我们想要的那个一个数字
#      如何做更高效???


nums=[-3,4,7,10,13,21,43,77,89]
find_num=10

nums=[-3,4,13,10,-2,7,89]
nums.sort()
print(nums)

# 方案一:整体遍历效率太低
# for num in nums:
#     if num == find_num:
#         print('find it')
#         break

# 方案二:二分法
# def binary_search(find_num,列表):
#     mid_val=找列表中间的值
#     if find_num > mid_val:
#         # 接下来的查找应该是在列表的右半部分
#         列表=列表切片右半部分
#         binary_search(find_num,列表)
#     elif find_num < mid_val:
#         # 接下来的查找应该是在列表的左半部分
#         列表=列表切片左半部分
#         binary_search(find_num,列表)
#     else:
#         print('find it')

# nums=[-3,4,7,10,13,21,43,77,89]
# find_num=8
# def binary_search(find_num,l):
#     print(l)
#     if len(l) == 0:
#         print('找的值不存在')
#         return
#     mid_index=len(l) // 2
#
#     if find_num > l[mid_index]:
#         # 接下来的查找应该是在列表的右半部分
#         l=l[mid_index+1:]
#         binary_search(find_num,l)
#     elif find_num < l[mid_index]:
#         # 接下来的查找应该是在列表的左半部分
#         l=l[:mid_index]
#         binary_search(find_num,l)
#     else:
#         print('find it')
#
# binary_search(find_num,nums)

02 面向过程编程思想

# 编程思想/范式

# 面向过程的编程思想:
#      核心是"过程"二字,过程即流程,指的是做事的步骤:先什么、再什么、后干什么
#      基于该思想编写程序就好比在设计一条流水线

# 优点:复杂的问题流程化、进而简单化
# 缺点:扩展性非常差

# 面向过程的编程思想应用场景解析:
# 1、不是所有的软件都需要频繁更迭:比如编写脚本
# 2、即便是一个软件需要频繁更迭,也不并不代表这个软件所有的组成部分都需要一起更迭

03 匿名函数

# 1、def用于定义有名函数
# func=函数的内存地址
# def func(x,y):
#     return x+y

# print(func)
# 2、lamdab用于定义匿名函数
# print(lambda x,y:x+y)


# 3、调用匿名函数
# 方式一:
# res=(lambda x,y:x+y)(1,2)
# print(res)

# 方式二:
# func=lambda x,y:x+y
# res=func(1,2)
# print(res)

#4、匿名用于临时调用一次的场景:更多的是将匿名与其他函数配合使用

04 匿名函数的应用

salaries={
    'siry':3000,
    'tom':7000,
    'lili':10000,
    'jack':2000
}
# 需求1:找出薪资最高的那个人=》lili
# res=max([3,200,11,300,399])
# print(res)

# res=max(salaries)
# print(res)


salaries={
    'siry':3000,
    'tom':7000,
    'lili':10000,
    'jack':2000
}
# 迭代出的内容    比较的值
# 'siry'         3000
# 'tom'          7000
# 'lili'         10000
# 'jack'         2000

# def func(k):
#     return salaries[k]

# ========================max的应用
# res=max(salaries,key=func) # 返回值=func('siry')
# print(res)

# res=max(salaries,key=lambda k:salaries[k])
# print(res)

# ========================min的应用
# res=min(salaries,key=lambda k:salaries[k])
# print(res)


# ========================sorted排序
# salaries={
#     'siry':3000,
#     'tom':7000,
#     'lili':10000,
#     'jack':2000
# }
res=sorted(salaries,key=lambda k:salaries[k],reverse=True)
# print(res)

# ========================map的应用(了解)
# l=['alex','lxx','wxx','薛贤妻']
# new_l=(name+'_dsb' for name in l)
# print(new_l)

# res=map(lambda name:name+'_dsb',l)
# print(res) # 生成器
# ========================filter的应用(了解)
# l=['alex_sb','lxx_sb','wxx','薛贤妻']
# res=(name for name in l if name.endswith('sb'))
# print(res)

# res=filter(lambda name:name.endswith('sb'),l)
# print(res)

# ========================reduce的应用(了解)
from functools import reduce
res=reduce(lambda x,y:x+y,[1,2,3],10) # 16
print(res)

res=reduce(lambda x,y:x+y,['a','b','c']) # 'a','b'
print(res)

05 模块


'''
1、什么是模块?
    模块就是一系列功能的集合体,分为三大类
        I:内置的模块
        II:第三方的模块
        III:自定义的模块
            一个python文件本身就一个模块,文件名m.py,模块名叫m

            ps:模块有四种形式
              1 使用python编写的.py文件

              2 已被编译为共享库或DLL的C或C++扩展
            
              3 把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
            
              4 使用C编写并链接到python解释器的内置模块
                        
2、为何有用模块
    I:内置与第三的模块拿来就用,无需定义,这种拿来主义,可以极大地提升自己的开发效率
    II:自定义的模块
        可以将程序的各部分功能提取出来放到一模块中为大家共享使用
        好处是减少了代码冗余,程序组织结构更加清晰
        

3、如何用模块
'''

y=333
z=444
import foo
# 1、首次导入模块会发生3件事
# 1、执行foo.py
# 2、产生foo.py的名称空间,将foo.py运行过程中产生的名字都丢到foo的名称空间中
# 3、在当前文件中产生的有一个名字foo,该名字指向2中产生的名称空间

# 之后的导入,都是直接引用首次导入产生的foo.py名称空间,不会重复执行代码
# import foo
# import foo
# import foo
# import foo


# 2、引用:
# print(foo.x)
# print(foo.get)
# print(foo.change)
# 强调1:模块名.名字,是指名道姓地问某一个模块要名字对应的值,不会与当前名称空间中的名字发生冲突
# x=1111111111111
# print(x)
# print(foo.x)

# 强调2:无论是查看还是修改操作的都是模块本身,与调用位置无关
# import foo
#
# x=3333333333
# # foo.get()
#
# foo.change()
# print(x)
#
# print(foo.x)
# foo.get()




# 3、可以以逗号为分隔符在一行导入多个模块
# 建议如下所示导入多个模块
# import time
# import foo
# import m

# 不建议在一行同时导入多个模块
import time,foo,m


# 4、导入模块的规范
#I. python内置模块
#II. 第三方模块
#III. 程序员自定义模块

# import time
# import sys
#
# import 第三方1
# import 第三方2
#
# import 自定义模块1
# import 自定义模块2
# import 自定义模块3


# 5、import 。。。 as 。。。
# import foo as f # f=foo
# f.get()


# import abcdefgadfadfas
# #
# # abcdefgadfadfas.f1
# # abcdefgadfadfas.f2
# # abcdefgadfadfas.f3


# import abcdefgadfadfas as mmm
#
# mmm.f1
# mmm.f2
# mmm.f3


#6、模块是第一类对象
import foo

#7、自定义模块的命名应该采用纯小写+下划线的风格


#8、可以在函数内导入模块
def func():
    import foo

01 一个py文件有几种用途

# 一个python文件有两种用途
# 1、被当成程序运行
# 2、被当做模块导入

# 二者的区别是什么?

02 from...import导入模块

# impot导入模块在使用时必须加前缀"模块."
# 优点:肯定不会与当前名称空间中的名字冲突
# 缺点:加前缀显得麻烦

# from ... import ...导入也发生了三件事
# 1、产一个模块的名称空间
# 2、运行foo.py将运行过程中产生的名字都丢到模块的名称空间去
# 3、在当前名称空间拿到一个名字,该名字与模块名称空间中的某一个内存地址
# from foo import x # x=模块foo中值0的内存地址
# from foo import get
# from foo import change

# print(x)
# print(get)
# print(change)
# x=333333333
# print(x)
# get()
# change()
# get()

# print(x)
# from foo import x # x=新地址
# print(x)

# from...impot...导入模块在使用时不用加前缀
# 优点:代码更精简
# 缺点:容易与当前名称空间混淆
# from foo import x # x=模块foo中值1的内存地址
# x=1111


# 一行导入多个名字(不推荐)
# from foo import x,get,change

# *:导入模块中的所有名字
# name='egon'
# from foo import *
# print(name)

from socket import *


# 了解:__all__
# from foo import *
# print(x)
# print(get)
# print(change)


# 起别名
from foo import get as g
print(g)

03 模块的搜索路径优先级

# 无论是import还是from...import在导入模块时都涉及到查找问题
# 优先级:
# 1、内存(内置模块)
# 2、硬盘:按照sys.path中存放的文件的顺序依次查找要导入的模块

# import sys
# 值为一个列表,存放了一系列的对文件夹
# 其中第一个文件夹是当前执行文件所在的文件夹
# print(sys.path)

# import foo # 内存中已经有foo了
# foo.say()
#
# import time
# time.sleep(10)
#
# import foo
# foo.say()


# 了解:sys.modules查看已经加载到内存中的模块
import sys
# import foo # foo=模块的内存地址
# del foo

# def func():
#     import foo # foo=模块的内存地址
#
# func()
#
# # print('foo' in sys.modules)
# print(sys.modules)


import sys
# 找foo.py就把foo.py的文件夹添加到环境变量中
sys.path.append(r'/Users/linhaifeng/PycharmProjects/s14/day21/aa')
# import foo
# foo.say()

from foo import say

04 函数的类型提示

#            str  int   ('play','music')
# def register(name:str,age:int,hobbbies:tuple)->int:
#  print(name)
#  print(age)
#  print(hobbbies)
#  return 111
#
# # register(1,'aaa',[1,])
# res=register('egon',18,('play','music'))



# def register(name:str='egon',age:int=18,hobbbies:tuple=(1,2))->int:
#  print(name)
#  print(age)
#  print(hobbbies)
#  return 111
#
# # register(1,'aaa',[1,])
# # res=register('egon',18,('play','music'))
# res=register()


def register(name:"必须传入名字傻叉",age:1111111,hobbbies:"必须传入爱好元组")->"返回的是整型":
 print(name)
 print(age)
 print(hobbbies)
 return 111

# register(1,'aaa',[1,])
# res=register('egon',18,('play','music'))
# res=register('egon',19,(1,2,3))

print(register.__annotations__)

05 包的使用

'''
1、包就是一个包含有__init__.py文件的文件夹
    
    
2、为何要有包
    包的本质是模块的模块的一种形式,包是用来被当做模块导入
'''

#1、产生一个名称空间
#2、运行包下的__init__.py文件,将运行过程中产生的名字都丢到1的名称空间中
#3、在当前执行文件的名称空间中拿到一个名字mmm,mmm指向1的名称空间
# import mmm
# print(mmm.x)
# print(mmm.y)
# mmm.say()

# from mmm import x


# 模块的使用者:egon老湿

# 环境变量是以执行文件为准备的,所有的被导入的模块或者说后续的其他文件引用
# 的sys.path都是参照执行文件的sys.path
import sys
sys.path.append('/aaaaaaaaaaaaaaaaaaaaaaaaaa')
# print(sys.path)

sys.path.append(r'/Users/linhaifeng/PycharmProjects/s14/day21/aa')


# import foo # foo下__init__.py
# #
# #
# foo.f1()
# foo.f2()
# foo.f3()

# from foo import f1,f2,f3,f4

# f1()
# f2()
# f3()
# f4()

# import foo
# foo.f4()

# 强调:
# 1.关于包相关的导入语句也分为import和from ... import ...
# 两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:
# 凡是在导入时带点的,点的左边都必须是一个包,否则非法。
# 可以带有一连串的点,如import 顶级包.子包.子模块,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
# 例如:
# from a.b.c.d.e.f import xxx
# import a.b.c.d.e.f
# 其中a、b、c、d、e 都必须是包


# 2、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
#
# 3、import导入文件时,产生名称空间中的名字来源于文件,
# import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件


# import foo
# # print(foo.f1)
# # print(foo.f2)
# # print(foo.f3)
# # print(foo.f4)
#
# foo.f4()

# from foo import *
# print(f1)
# print(f2)
# print(f3)
# print(f4)

01 时间模块

# 时间模块优先掌握的操作
#一:time
import time

# 时间分为三种格式:
# 1、时间戳:从1970年到现在经过的秒数
#    作用:用于时间间隔的计算

# print(time.time())

# 2、按照某种格式显示的时间:2020-03-30 11:11:11
#    作用:用于展示时间

# print(time.strftime('%Y-%m-%d %H:%M:%S %p'))
# print(time.strftime('%Y-%m-%d %X'))

# 3、结构化的时间
#    作用:用于单独获取时间的某一部分

# res=time.localtime()
# print(res)
# print(res.tm_year)
# print(res.tm_yday)

#二:datetime
import datetime

# print(datetime.datetime.now())
# print(datetime.datetime.now() + datetime.timedelta(days=3))
# print(datetime.datetime.now() + datetime.timedelta(weeks=1))



# 时间模块需要掌握的操作
# 1、时间格式的转换
# struct_time->时间戳
import time
# s_time=time.localtime()
# print(time.mktime(s_time))

# 时间戳->struct_time
# tp_time=time.time()
# print(time.localtime(tp_time))

# 补充:世界标准时间与本地时间
# print(time.localtime())
# print(time.gmtime()) # 世界标准时间,了解
# print(time.localtime(333333333))
# print(time.gmtime(333333333))


# struct_time->格式化的字符串形式的时间
# s_time=time.localtime()
# print(time.strftime('%Y-%m-%d %H:%M:%S',s_time))

# print(time.strptime('1988-03-03 11:11:11','%Y-%m-%d %H:%M:%S'))


# !!!真正需要掌握的只有一条:format string<------>timestamp
# '1988-03-03 11:11:11'+7

# format string--->struct_time--->timestamp
# struct_time=time.strptime('1988-03-03 11:11:11','%Y-%m-%d %H:%M:%S')
# timestamp=time.mktime(struct_time)+7*86400
# print(timestamp)

# format string<---struct_time<---timestamp
# res=time.strftime('%Y-%m-%d %X',time.localtime(timestamp))
# print(res)

# time.sleep(3)

# 了解知识
# import time
# print(time.asctime())


import datetime
# print(datetime.datetime.now())
# print(datetime.datetime.utcnow())

print(datetime.datetime.fromtimestamp(333333))

02 random模块

import random

# print(random.random()) #(0,1)----float    大于0且小于1之间的小数
# print(random.randint(1, 3))  # [1,3]    大于等于1且小于等于3之间的整数

# print(random.randrange(1, 3))  # [1,3)    大于等于1且小于3之间的整数
#
# print(random.choice([111, 'aaa', [4, 5]]))  # 1或者23或者[4,5]
#
# print(random.sample([111, 'aaa', 'ccc','ddd'],2))  # 列表元素任意2个组合
#
# print(random.uniform(1, 3))  # 大于1小于3的小数,如1.927109612082716
#
# item = [1, 3, 5, 7, 9]
# random.shuffle(item)  # 打乱item的顺序,相当于"洗牌"
# print(item)

# 应用:随机验证码

# import random
#
# res=''
# for i in range(6):
#     从26大写字母中随机取出一个=chr(random.randint(65,90))
#     从10个数字中随机取出一个=str(random.randint(0,9))
#
#     随机字符=random.choice([从26大写字母中随机取出一个,从10个数字中随机取出一个])
#     res+=随机字符


import random

def make_code(size=4):
    res=''
    for i in range(size):
        s1=chr(random.randint(65,90))
        s2=str(random.randint(0,9))
        res+=random.choice([s1,s2])
    return res

print(make_code(6))

03 os模块

import os

# 获取某一个文件夹下所有的子文件以及子文件夹的名字
# res=os.listdir('.')
# print(res)
#
#
# size=os.path.getsize(r'/Users/linhaifeng/PycharmProjects/s14/day22/01 时间模块.py')
# print(size)



# os.remove()  删除一个文件
# os.rename("oldname","newname")  重命名文件/目录



# 应用程序----》"ls /"
# os.system("ls /")

# 规定:key与value必须都为字符串

# os.environ['aaaaaaaaaa']='111'
# print(os.environ)


# print(os.path.dirname(r'/a/b/c/d.txt'))
# print(os.path.basename(r'/a/b/c/d.txt'))


# print(os.path.isfile(r'笔记.txt'))
# print(os.path.isfile(r'aaa'))
# print(os.path.isdir(r'aaa'))

# print(os.path.join('a','/','b','c','d'))




# 推荐用这种
BASE_DIR=os.path.dirname(os.path.dirname(__file__))
# print(BASE_DIR)


# BASE_DIR=os.path.normpath(os.path.join(
#     __file__,
#     '..',
#     '..'
# ))
# print(BASE_DIR)

# 在python3.5之后,推出了一个新的模块pathlib
from pathlib import Path

# res = Path(__file__).parent.parent
# print(res)


# res=Path('/a/b/c') / 'd/e.txt'
# print(res)

# print(res.resolve())

04 sys模块

01 json与pickle模块

# 1、什么是序列化&反序列化
#   内存中的数据类型---->序列化---->特定的格式(json格式或者pickle格式)
#   内存中的数据类型<----反序列化<----特定的格式(json格式或者pickle格式)

#   土办法:
#   {'aaa':111}--->序列化str({'aaa':111})----->"{'aaa':111}"
#   {'aaa':111}<---反序列化eval("{'aaa':111}")<-----"{'aaa':111}"

# 2、为何要序列化
#   序列化得到结果=>特定的格式的内容有两种用途
#   1、可用于存储=》用于存档
#   2、传输给其他平台使用=》跨平台数据交互
#        python                 java
#         列表     特定的格式      数组

#   强调:
#       针对用途1的特定一格式:可是一种专用的格式=》pickle只有python可以识别
#       针对用途2的特定一格式:应该是一种通用、能够被所有语言识别的格式=》json


# 3、如何序列化与反序列化
# 示范1
# import json
# # 序列化
# json_res=json.dumps([1,'aaa',True,False])
# # print(json_res,type(json_res)) # "[1, "aaa", true, false]"
#
# # 反序列化
# l=json.loads(json_res)
# print(l,type(l))


# 示范2:
import json

# 序列化的结果写入文件的复杂方法
# json_res=json.dumps([1,'aaa',True,False])
# # print(json_res,type(json_res)) # "[1, "aaa", true, false]"
# with open('test.json',mode='wt',encoding='utf-8') as f:
#     f.write(json_res)

# 将序列化的结果写入文件的简单方法
# with open('test.json',mode='wt',encoding='utf-8') as f:
#     json.dump([1,'aaa',True,False],f)


# 从文件读取json格式的字符串进行反序列化操作的复杂方法
# with open('test.json',mode='rt',encoding='utf-8') as f:
#     json_res=f.read()
#     l=json.loads(json_res)
#     print(l,type(l))

# 从文件读取json格式的字符串进行反序列化操作的简单方法
# with open('test.json',mode='rt',encoding='utf-8') as f:
#     l=json.load(f)
#     print(l,type(l))


# json验证: json格式兼容的是所有语言通用的数据类型,不能识别某一语言的所独有的类型
# json.dumps({1,2,3,4,5})

# json强调:一定要搞清楚json格式,不要与python混淆
# l=json.loads('[1, "aaa", true, false]')
# l=json.loads("[1,1.3,true,'aaa', true, false]")
# print(l[0])

# 了解
# l = json.loads(b'[1, "aaa", true, false]')
# print(l, type(l))

# with open('test.json',mode='rb') as f:
#     l=json.load(f)


# res=json.dumps({'name':'哈哈哈'})
# print(res,type(res))

# res=json.loads('{"name": "\u54c8\u54c8\u54c8"}')
# print(res,type(res))

# 4、猴子补丁
# 在入口处打猴子补丁
# import json
# import ujson
#
# def monkey_patch_json():
#     json.__name__ = 'ujson'
#     json.dumps = ujson.dumps
#     json.loads = ujson.loads
#
# monkey_patch_json() # 在入口文件出运行


# import ujson as json # 不行

# 后续代码中的应用
# json.dumps()
# json.dumps()
# json.dumps()
# json.dumps()
# json.dumps()
# json.dumps()
# json.dumps()
# json.dumps()
# json.loads()
# json.loads()
# json.loads()
# json.loads()
# json.loads()
# json.loads()
# json.loads()
# json.loads()
# json.loads()
# json.loads()
# json.loads()



# 5.pickle模块
import pickle
# res=pickle.dumps({1,2,3,4,5})
# print(res,type(res))

# s=pickle.loads(res)
# print(s,type(s))

02 configparser模块

import configparser

config=configparser.ConfigParser()
config.read('test.ini')

# 1、获取sections
# print(config.sections())

# 2、获取某一section下的所有options
# print(config.options('section1'))

# 3、获取items
# print(config.items('section1'))

# 4、
# res=config.get('section1','user')
# print(res,type(res))

# res=config.getint('section1','age')
# print(res,type(res))


# res=config.getboolean('section1','is_admin')
# print(res,type(res))


# res=config.getfloat('section1','salary')
# print(res,type(res))

03 hashlib模块

# 1、什么是哈希hash
#    hash一类算法,该算法接受传入的内容,经过运算得到一串hash值
#    hash值的特点:
#I 只要传入的内容一样,得到的hash值必然一样
#II 不能由hash值返解成内容
#III 不管传入的内容有多大,只要使用的hash算法不变,得到的hash值长度是一定

# 2、hash的用途
# 用途1:特点II用于密码密文传输与验证
# 用途2:特点I、III用于文件完整性校验

# 3、如何用
# import hashlib
#
# m=hashlib.md5()
# m.update('hello'.encode('utf-8'))
# m.update('world'.encode('utf-8'))
# res=m.hexdigest() # 'helloworld'
# print(res)
#
# m1=hashlib.md5('he'.encode('utf-8'))
# m1.update('llo'.encode('utf-8'))
# m1.update('w'.encode('utf-8'))
# m1.update('orld'.encode('utf-8'))
# res=m1.hexdigest()# 'helloworld'
# print(res)



# 模拟撞库
# cryptograph='aee949757a2e698417463d47acac93df'
# import hashlib
#
# # 制作密码字段
# passwds=[
#     'alex3714',
#     'alex1313',
#     'alex94139413',
#     'alex123456',
#     '123456alex',
#     'a123lex',
# ]
#
# dic={}
# for p in passwds:
#     res=hashlib.md5(p.encode('utf-8'))
#     dic[p]=res.hexdigest()
#
# # 模拟撞库得到密码
# for k,v in dic.items():
#     if v == cryptograph:
#         print('撞库成功,明文密码是:%s' %k)
#         break


# 提升撞库的成本=>密码加盐
import hashlib

m=hashlib.md5()

m.update('天王'.encode('utf-8'))
m.update('alex3714'.encode('utf-8'))
m.update('盖地虎'.encode('utf-8'))
print(m.hexdigest())









# m.update(文件所有的内容)
# m.hexdigest()
#
# f=open('a.txt',mode='rb')
# f.seek()
# f.read(2000) # 巨琳
# m1.update(文见的一行)
#
# m1.hexdigest()

04 subprocess模块

import subprocess

obj=subprocess.Popen('echo 123 ; ls / ; ls /root',shell=True,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE,
                 )

# print(obj)
# res=obj.stdout.read()
# print(res.decode('utf-8'))

err_res=obj.stderr.read()
print(err_res.decode('utf-8'))

01 logging模块

import logging

logging.basicConfig(
    # 1、日志输出位置:1、终端 2、文件
    filename='access.log', # 不指定,默认打印到终端

    # 2、日志格式
    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',

    # 3、时间格式
    datefmt='%Y-%m-%d %H:%M:%S %p',

    # 4、日志级别
    # critical => 50
    # error => 40
    # warning => 30
    # info => 20
    # debug => 10
    level=10,
)

logging.debug('调试debug') # 10
logging.info('消息info')   # 20
logging.warning('警告warn')# 30
logging.error('egon提现失败') # 40
logging.critical('严重critical') # 50

02 re模块

import re

# print(re.findall('\w','aAbc123_*()-='))
# print(re.findall('\W','aAbc123_*()-= '))
# print(re.findall('\s','aA\rbc\t\n12\f3_*()-= '))
# print(re.findall('\S','aA\rbc\t\n12\f3_*()-= '))
# print(re.findall('\d','aA\rbc\t\n12\f3_*()-= '))
# print(re.findall('\D','aA\rbc\t\n12\f3_*()-= '))
# print(re.findall('\D','aA\rbc\t\n12\f3_*()-= '))
# print(re.findall('\Aalex',' alexis alex sb'))
#                          alex
# print(re.findall('sb\Z',' alexis alexsb sb'))
#                                       sb\Z
# print(re.findall('sb\Z',"""alex
# alexis
# alex
# sb
# """))

# print(re.findall('^alex','alexis alex sb'))
# print(re.findall('sb$','alexis alex sb'))
# print(re.findall('sb$',"""alex
# alexis
# alex
# sb
# """))

# print(re.findall('^alex$','alexis alex sb'))
# print(re.findall('^alex$','al       ex'))
# print(re.findall('^alex$','alex'))

# 重复匹配:| . | * | ? | .* | .*? | + | {n,m} |
# 1、.:匹配除了\n之外任意一个字符,指定re.DOTALL之后才能匹配换行符
# print(re.findall('a.b','a1b a2b a b abbbb a\nb a\tb a*b'))
#                                                   a.b
# ['a1b','a2b','a b','abb','a\tb','a*b']
# print(re.findall('a.b','a1b a2b a b abbbb a\nb a\tb a*b',re.DOTALL))

# 2、*:左侧字符重复0次或无穷次,性格贪婪
# print(re.findall('ab*','a ab abb abbbbbbbb bbbbbbbb'))
#                                                ab*
#['a','ab','abb','abbbbbbbb']

# 3、+:左侧字符重复1次或无穷次,性格贪婪
# print(re.findall('ab+','a ab abb abbbbbbbb bbbbbbbb'))
#                         ab+

# 4、?:左侧字符重复0次或1次,性格贪婪
# print(re.findall('ab?','a ab abb abbbbbbbb bbbbbbbb'))
#                                                ab?
# ['a','ab','ab','ab']

# 5、{n,m}:左侧字符重复n次到m次,性格贪婪
# {0,} => *
# {1,} => +
# {0,1} => ?
# {n}单独一个n代表只出现n次,多一次不行少一次也不行

# print(re.findall('ab{2,5}','a ab abb abbb abbbb abbbbbbbb bbbbbbbb'))
#                                                           ab{2,5}
# ['abb','abbb','abbbb','abbbbb]

# print(re.findall('\d+\.?\d*',"asdfasdf123as1111111.123dfa12adsf1asdf3"))
#                                                                   \d+\.?\d*                                      \d+\.?\d+


# []匹配指定字符一个
# print(re.findall('a\db','a1111111b a3b a4b a9b aXb a b a\nb',re.DOTALL))
# print(re.findall('a[501234]b','a1111111b a3b a4b a9b aXb a b a\nb',re.DOTALL))
# print(re.findall('a[0-5]b','a1111111b a3b a1b a0b a4b a9b aXb a b a\nb',re.DOTALL))
# print(re.findall('a[0-9a-zA-Z]b','a1111111b axb a3b a1b a0b a4b a9b aXb a b a\nb',re.DOTALL))
#
# print(re.findall('a[^0-9a-zA-Z]b','a1111111b axb a3b a1b a0b a4b a9b aXb a b a\nb',re.DOTALL))
# print(re.findall('a-b','a-b aXb a b a\nb',re.DOTALL))
print(re.findall('a[-0-9\n]b','a-b a0b a1b a8b aXb a b a\nb',re.DOTALL))
posted @ 2020-06-27 16:10  xiongsheng  阅读(899)  评论(0编辑  收藏  举报