Title

pythonm面向对象之前的知识点

目录

python

编程与编程语言

1 什么是语言
  1.1 语言就是人与人交流的媒介
2 什么是编程语言
  2.1 人与计算机之间的交流媒介
3 什么是编程
  3.1 编程就是程序员使用计算机能够读懂的语言把自己的思想逻辑写出来的过程

计算机的本质

电脑就是通电的大脑,通电之后无休止的干活

计算机的五大组成部分

# 1. 控制器
	控制各个硬件的协作	
# 2. 运算器
	数字运算:数字之间的运算
    逻辑运算:根据条件是否成立决定是否要做事情
  
# 3. 存储设备
	'''用来存储数据的'''
    1. 内存
    	# 内存条
        特点:就是存取速度快,基于电工作的,一旦断电数据立马丢失,不能永久保存数据
    2. 外存
    	# 磁带,光盘,U盘,硬盘,磁盘
        特点:可以永久保存数据,硬件不损坏的情况下
# 4. 输入设备
	eg:键盘,鼠标,麦克风
# 5. 输出设备
	eg:显示屏,音响,打印机...

计算机三大核心

# 1. 中央处理器(CPU)
	控制器+运算器
    '''CPU的功能:用来计算的'''
    Cpu一定是从内存中读取指令进行执行,CPU不存储数据
# 2. 内存
	'''程序要运行数据一定先存在于内存中'''
	就是存取速度快,基于电工作的,一旦断电数据立马丢失,不能永久保存数据
# 3. 硬盘
	用来存取数据的,速度比较慢
    
执行速度:CPU > 内存 > 硬盘

问1:程序要想运行,产生的数据必须首先存在于内存中,对不对?

问2:word文档写入数据之后,不手动保存,直接点击关闭按钮,提示你是否保存,这个过程中数据是如何变化的?

操作系统

# 功能:统筹硬件和软件
三层结构:
	应用软件
    系统软件
    计算机硬件
'''我们程序员写的代码都必须基于操作系统之上'''

常见的操作系统:
	PC:Windows系统
    	macOS
        Linux
    移动端:
    	安卓
         iOS
         鸿蒙

计算机内部存储数据原理

"""计算机内部只认识01二进制"""
是因为计算机是基于电工作的,而电是有高低电频之分
00000001   0000000100000001
# 存储单位
比特位(bit) 
8位= 1bytes(字节)
1024bytes = 1KB
1024KB = 1MB
1024MB = 1GB
1024GB = 1TB
...

编程语言的发展史

机器语言:内部使用01二进制表示
	# 计算机直接能够识别的
    优势:执行速度快
    劣势:学习难度大
汇编语言
	# 用简单的字母代表一串二进制
    优势:执行速度快
    劣势:学习难度大
高级语言
	Python C# C++ Java Go
	# 人类能够读懂的语言
    优势:学习难度大大降低,编程效率大大提高
    劣势:执行速度相比较慢了
'''技术是服务产品的'''

# 高级语言的存在必须要有翻译官的存在

编程语言分类

1. 编译型语言   # C++
	类似于谷歌翻译,翻译一次永久使用
    优点:方便
    劣势:不方便修改bug
2. 解释型语言   # python
	类似于同声传译 一次翻译一句
    劣势:执行效率低
    
'''
	问:如何让我的计算机能够识别编译型语言或者解释型语言?
		1. 识别C++语言
			安装C++编译器
		2. 识别python语言
			安装python解释器
'''

变量的命名规范

'''补充:快捷键注释代码:ctrl + ?'''
1. 必须有数字、字母、下划线任意的组合
	user@name  123_name _ my_password_123456
    '''_虽然满足我们的规范,但是我们不推荐使用,因为他有特殊的含义'''
2. 变量名不能以数字开头
3. 不能与关键字冲突
4. 变量名的命名一定要见名知意(重点)

变量的三要素

1. 变量值
2. 内存地址编号
3. 数据类型

"""
	一个变量名只能指向一个内存地址
	一个内存地址可以有多个变量指向
"""

python底层优化

'''小整数池'''
# 当数据量很小的时候,如果同时有多个变量使用,
#那么python就会让多个变量指向同一个内存地址

垃圾回收机制

1. 什么是垃圾数据?
	# 就是没有变量指向的数据
2. python开发出了一套自动回收方案
	1. 引用计数
    	# 当有变量指向内存中得数据时候,会同时加一个计数,当计数为零的时候,就说明是垃圾数据
    2. 标记清楚
    	# 当内存快被沾满的时候,那么python就会终止程序的运行,从头到位进行扫描数据,对垃圾数据进行标记,之后,统一进行清楚
    3. 分代回收
    	# 通过分不同的时间段,来降低被监管的频率

数据类型

1 整型
2 浮点型
3 字符串
4 列表
5 字典
6 布尔
7 元组
8 集合

格式化输出

(1) 什么是格式化输出?
	把一段字符串里面的某些内容替换掉之后再输出,就是格式化输出。
(2) 为什么要格式化输出?
	我们经常会输出具有某种固定格式的内容

基本运算符

# 算术运算符
% ** //

'''补充'''
# python中拼接字符串使用 +
s1 = 'hello'
s2 = 'world'
print(s1 + s2)
print(s1 * 10)

# 比较运算符
== !=

# 赋值运算符
n = 666
n += 4
n -= 3
n *= 2
n /= 2

# 交叉赋值(笔记题)
m = 10
n = 20

# 解压赋值  重点
names_list = ['kevin', 'tony', 'tank', 'tom']
l1 = names_list[0]
l2 = names_list[1]
l3 = names_list[2]
l4 = names_list[3]
'''左右两边的个数必须一致'''

逻辑运算符

and	 与  # 
# 可以用and连接多个条件,会按照从左到右的顺序依次判断,一旦某一个条件为False,则无需再往右判断,可以立即判定最终结果就为False,只有在所有条件的结果都为True的情况下,最终结果才为True。

# 练习题:
	 2 > 3 and 1 != 1 and True and 3 > 2
or   或
# 可以用or连接多个条件,会按照从左到右的顺序依次判断,一旦某一个条件为True,则无需再往右判断,可以立即判定最终结果就为True,只有在所有条件的结果都为False的情况下,最终结果才为False
# 练习题:
	 2 > 1 or 1 != 1 or True or 3 > 2 
not  非(取反)
	not True

成员运算

# 判断某个个体是否在某个群体中
符号:in(在)  not in(不在)

身份运算符

# 判断两个值是否相等
符号:is(比较的是内存地址) ==(比较的是值)

'''
	值相等的内存地址不一定相等
	内存地址相等的值一定相等
'''

流程控制

# 控制事物的执行流程
流程控制总共有3种情况:
    1. 顺序结构
    	# 就是自上而下的执行
    2. 分支结构
    	# 分支结构就是根据条件判断的真假去执行不同分支对应的子代码
    3. 循环结构
    	# 循环结构就是重复执行某段代码块

分支结构

"""
	注意事项:
		1. 根据条件的成立与否,决定是否执行if代码块
		2. 我们通过缩进代码块,来表示代码之间的从属关系
		3. 不是所有的代码都拥有子代码块
		4. 我们推荐使用缩进4格
		5. 同属于一个代码块的子代码块缩进量一定要一样
		ps:遇到冒号就要回车换行,缩进
"""
# 1. 单if判断
关键字:if
"""
	语法格式:
		if 判断条件:
    		print()
"""

# 2. 双分支结构
	"""
		语法格式:
			if 判断条件:
                条件成立执行的子代码块
            else:
                条件不成立执行的子代码块
	"""
# 3. 多分支结构
	"""
		语法格式:
			if 条件1:
                条件1成立执行的子代码块
            elif 条件2:
                条件1不成立条件2成立执行的子代码块
            elif 条件3:
                条件1、2不成立条件3成立执行的子代码块
            elif 条件4:
                条件1、2、3不成立条件4成立执行的子代码块
            else:
            	以上条件都不成立的时候执行的代码块
	"""
    
    # else语句是可有可无的

if判断之嵌套

循环结构while

"""
	while语法格式
		while 条件:
			循环体
"""

while +break#break停止运行

标志位 eg:flag=True
while +countinue #countinue重复循环

while + else

for 循环

"""
	语法格式:
        for 变量 in 可迭代对象:  字符串、列表、字典、元组
        	print(name)
"""
for + break
for + countinue
for + else

range关键字

内置方法

整型内置方法

1. 整型
# 进制转换
print(bin(10))  # 0b1010
print(oct(10))  # 0o12
print(hex(10))  # 0xa

# 记忆:0b代表二进制  0o代表八进制  0x代表十六进制

print(int('0b1010', 2))
print(int('0o12', 8))
print(int('0xa', 16))

浮点型内置方法

# float同样可以用来做数据类型的转换
>>> s = '12.3'
>>> res=float(s)
>>> res,type(res)
(12.3, <class 'float'>)

字符串的内置方法1

1 除了整型和浮点型
# 1.按索引取值(正向取,反向取):
# 1.1 正向取(从左往右)
>>> str1[6]
p
# 1.2 反向取(负号表示从右往左)
>>> str1[-4]
h
# 1.3 对于str来说,只能按照索引取值,不能改
>>> str1[0]='H' # 报错TypeError


# 2.切片(顾头不顾尾,步长)
# 2.1 顾头不顾尾:取出索引为0到8的所有字符
>>> str1[0:9]  
hello pyt
# 2.2 步长:0:9:2,第三个参数2代表步长,会从0开始,每次累加一个2即可,所以会取出索引0、2、4、6、8的字符
>>> str1[0:9:2]  
hlopt 
# 2.3 反向切片
>>> str1[::-1]  # -1表示从右往左依次取值
!nohtyp olleh

# 3.长度len
# 3.1 获取字符串的长度,即字符的个数,但凡存在于引号内的都算作字符)
>>> len(str1) # 空格也算字符
13

# 4.成员运算 in 和 not in	
# 4.1 int:判断hello 是否在 str1里面
>>> 'hello' in str1  
True
# 4.2 not in:判断tony 是否不在 str1里面
>>> 'tony' not in str1 
True
# 5.strip移除字符串首尾指定的字符(默认移除空格)
# 5.1 括号内不指定字符,默认移除首尾空白字符(空格、\n、\t)
>>> str1 = '  life is short!  '
>>> str1.strip()  
life is short!

# 5.2 括号内指定字符,移除首尾指定的字符
>>> str2 = '**tony**'  
>>> str2.strip('*')  
tony

# 6.切分split
# 6.1 括号内不指定字符,默认以空格作为切分符号
>>> str3='hello world'
>>> str3.split()
['hello', 'world']
# 6.2 括号内指定分隔字符,则按照括号内指定的字符切割字符串
>>> str4 = '127.0.0.1'
>>> str4.split('.')  
['127', '0', '0', '1']  # 注意:split切割得到的结果是列表数据类型


# 7.循环
>>> str5 = '今天你好吗?'
>>> for line in str5:  # 依次取出字符串中每一个字符
...     print(line)

字符串的内置方法1

# 1. lower upper
res = 'keViN123 oldBoY'
print(res.lower())  # kevin123 oldboy
print(res.upper())  # KEVIN123 OLDBOY

"""
    图片验证码不区分大小写
        思路:把用户输入的验证码全部转为大写或者小写,跟原来的验证码都转为大写或者小写进行比较
"""
# old_code = 'oldBoY'
# print('返回给你的验证码是:%s' % old_code)
# # 用户输入的验证码
# real_code=input('请输入验证码:')
# # if old_code.lower() == real_code.lower():
# if old_code.upper() == real_code.upper():
#     print('验证码输入正确')
# else:
#     print('验证码错误')

# 补充:
print(res.islower())  # False
print(res.isupper())  # False

a ='hello'
print(a.islower())  # True


res = 'Kevin123 OldGirl'
print(res.startswith('K'))  # True
print(res.startswith('kev'))  # True
print(res.startswith('Keva'))  # True

print(res.endswith('Girl'))
print(res.endswith('rl'))


# 格式化输出:%s %d
"""format方法格式化"""
'''第一种玩法'''
# s = 'my name is %s, my age is %s' % ('kevin', 18)
# s = 'my name is {}, my age is {},{}{}{}'
# print(s.format('kevin', 20, 'a', 'b', 'c'))  # my name is kevin, my age is 20

'''第二种玩法'''
# s = '{0}my name is {1}, my age is {0}{0}{0}{0}{0}, {2}'
# print(s.format('tony', 22, 'helloworld'))

'''第三种玩法'''
s = '{age}my name is {name}, my age is {age}{name}{name}{name}{name}{name}{name}'
print(s.format(name='kevin', age=20))

# join的用法
l = ['tony', 'kevin', 'jack', 'tom']
# |
print(l[0] + '|' + l[1] + '|' + l[2] + '|' + l[3]) # tony|kevin|jack|tom
print('|'.join(l))

# replace替换字符串
s = 'my name is kevin kevin kevin kevin'
print(s.replace('kevin', 'jack', 2))

s = '123'
# print(s.isdigit())
guess_age = input('请输入你的年龄:')
if guess_age.isdigit():
    if int(guess_age) == 18:
        print('猜对了')
else:
    print('你输入的年龄不合法')

列表的内置方法

1. 类型转换
# print(list(123))  不可
# print(list(1.11)) 不可
print(list('hello')) # ['h', 'e', 'l', 'l', 'o']
print(list([11, 22, 33, 44])) # [11, 22, 33, 44]
print((list({'username':"kevin", "age":20})))  # ['username', 'age']
print(list((11, 22, 33, 44)))  # [11, 22, 33, 44]
print(list({11, 22, 33, 44}))  # [33, 11, 44, 22]

2. 列表的增加和修改
# my_friends = ['tony', 'jason', 'tom', 4, 5]
# print(my_friends[0])
# 1. 修改值
# my_friends[0] = 'jack'
# print(my_friends)

'''列表的最大索引长度:len(l)-1'''

# l = ['kevin', 'jack', 'tom']
# l1 = ['a', 'b', 'c', 'd']
# l.extend(l1)  # for循环+append
# print(l)

# for i in l1:
#     l.append(i)
#
# print(l)

my_friends = ['tony', 'jason', 'tom', 4, 5, 6, 7, 8]
print(my_friends[0:3])  # (顾头不顾尾,步长)
print(my_friends[0:5:2])  # (顾头不顾尾,步长)

#  3.长度
print(len(my_friends))

列表的内置方法增加

# 2. 增加值:第一种方式
append()
# my_friends[5] = 666 # 不能这样增加
# my_friends.append(666)
# my_friends.append(777)
# my_friends.append(888)  # 追加到末尾位置
# print(my_friends)

# 增加值:第二种方式
insert()
# my_friends.insert(0, 999)
# my_friends.insert(1, 999)
# print(my_friends)


# 增加值:第三种方式
extend()
# my_friends.append([11, 22, 33, 44])  # 把列表的整体添加到末尾
# my_friends.extend([11, 22, 33, 44])    # 列表的合并
# print(my_friends)

列表的内置方法删除

'''删除'''
del()
# del # delete
# 第一种方式
# del my_friends[0]  # ['jason', 'tom', 4, 5, 6, 7, 8]
# del my_friends[0]
# del my_friends[4]
# print(my_friends)

# 第二种方式
remove()
my_friends = ['tony', 'jason', 'tom', 4, 5, 6, 7, 8]

# aa = my_friends.remove('jason')  # 括号中直接写删除的元素。可不是索引
# print(aa) # None 空
# print(my_friends)

# 第三种方式
pop() # 弹出元素
# my_friends.pop()  # 弹出元素
# my_friends.pop()
# my_friends.pop()
# aa = my_friends.pop()
# print(aa)
s = my_friends.pop(1)  # 用的也比较多
print(s)
print(my_friends)
# l = [11, 22, 33, 44]

# l.reverse()  # [44, 33, 22, 11]
# print(l[::-1])
# print(l)



l = [11,22,3,42,7,55]
# 列表排序
# l.sort()  # [3, 7, 11, 22, 42, 55]  # 从小到大排序 (前提是:纯数字比较)
# l.sort(reverse=True)  # [55, 42, 22, 11, 7, 3]  # 从大到小排序 (前提是:纯数字比较)
# print(l)


# 了解的知识
# 列表比较大小
# l1 = [666,777]
# l2 = [111, 222, 333, 444 ,555, 666]
# print(l1 > l2)  # True  列表的比较是比较索引对应位置的元素值,只要有一个比较出来,都不在往下比较


s1 = 'hello'
s2 = 'world'
print(s1 > s2) # 字符之间的大小取决于它们

字典的内置方法dict

# 1、按key存取值:可存可取
# 1.1 取
>>> dic = {
...     'name': 'xxx',
...     'age': 18,
...     'hobbies': ['play game', 'basketball']
... }
>>> dic['name']
'xxx'
>>> dic['hobbies'][1]
'basketball'
# 1.2 对于赋值操作,如果key原先不存在于字典,则会新增key:value
>>> dic['gender'] = 'male'  
>>> dic
{'name': 'tony', 'age': 18, 'hobbies': ['play game', 'basketball'],'gender':'male'}
# 1.3 对于赋值操作,如果key原先存在于字典,则会修改对应value的值
>>> dic['name'] = 'tony'
>>> dic
{'name': 'tony', 'age': 18, 'hobbies': ['play game', 'basketball']}


# 2、长度len
>>> len(dic) 
3


# 3、成员运算in和not in
>>> 'name' in dic  # 判断某个值是否是字典的key
True


# 4、删除
>>> dic.pop('name')  # 通过指定字典的key来删除字典的键值对
>>> dic
{'age': 18, 'hobbies': ['play game', 'basketball']}


# 5、键keys(),值values(),键值对items()
>>> dic = {'age': 18, 'hobbies': ['play game', 'basketball'], 'name': 'xxx'}
# 获取字典所有的key
>>> dic.keys()  
dict_keys(['name', 'age', 'hobbies'])
# 获取字典所有的value
>>> dic.values()
dict_values(['xxx', 18, ['play game', 'basketball']])
# 获取字典所有的键值对
>>> dic.items()
dict_items([('name', 'xxx'), ('age', 18), ('hobbies', ['play game', 'basketball'])])


# 6、循环
# 6.1 默认遍历的是字典的key
>>> for key in dic:
...     print(key)
... 
age
hobbies
name
# 6.2 只遍历key
>>> for key in dic.keys():
...     print(key)
... 
age
hobbies
name
# 6.3 只遍历value
>>> for key in dic.values():
...     print(key)
... 
18
['play game', 'basketball']
xxx
# 6.4 遍历key与value
>>> for key in dic.items():
...     print(key)
... 
('age', 18)
('hobbies', ['play game', 'basketball'])
('name', 'xxx')

get()
	用法 dict.get("key")

pop()
	用法:dict.pop("key")
popitem()
	用法:# 随机删除一组键值对,并将删除的键值放到元组内返回dict.popitem()
update()
	用法:dict.update("key")
fromkeys()
    dic = dict.fromkeys(['k1','k2','k3'],[])
    dic
    {'k1': [], 'k2': [], 'k3': []}

元组内置方法

"""
	小括号括起来,内部存放多个元素,元组之间逗号隔开,元素不可改变,元素类型不能是任意的,
"""

定义:t1 = (11, 22, 33, 44)
# 数据类型转变
# 但凡能被for循环的遍历的数据类型都可以传给tuple()转换成元组类型
# print(tuple(123))
# print(tuple(123.11))
print(tuple('hello'))  # ('h', 'e', 'l', 'l', 'o')
print(tuple([11, 22, 33, 44]))  # (11, 22, 33, 44)
print(tuple((1,2,3,4)))   # (1, 2, 3, 4)
print(tuple({'username':'kevin', 'age':19}))   # ('username', 'age')
print(tuple({111,222,33,444}))  # (33, 444, 222, 111)


# 1. 取值
# print(tuple1[0])
# print(tuple1[3])

print(tuple1[-1])
print(tuple1[-2])
print(tuple1[-3])

# 3、长度
>>> len(tuple1)  

'''元组笔试题'''
t = (111)
t1 = (111.11)
t2 = ('hello')
t3 = ('hello', )  # 当元组内部哪怕是一个元素,也要加一个逗号隔开,否则就不是元组类型
l = ['hello',]  # list
'''容器类型:可以存放多个元素的数据类型都是容器类型
    推荐:如果是容器类型,内部就算有一个元素,也最后都加上一个逗号隔开
'''
print(type(t)) # <class 'int'>
print(type(t1)) # <class 'float'>
print(type(t2)) # <class 'str'>
print(type(t3)) # <class 'tuple'>
print(type(l)) # <class 'tuple'>

集合内置方法

"""
	作用:去重、关系运算
	大括号括起来,内部存放多个元素,元素之间逗号隔开,数据类型只能是不可变的类型
	不能直接取值
"""
# 1.合集/并集(|):求两个用户所有的好友(重复好友只留一个)
>>> friends1 | friends2
{'kevin', 'ricky', 'zero', 'ly', 'Jy', 'qq'}

# 2.交集(&):求两个用户的共同好友
>>> friends1 & friends2
{'ly', 'qq'}

# 3.差集(-):
>>> friends1 - friends2 # 求用户1独有的好友
{'kevin', 'zero'}
>>> friends2 - friends1 # 求用户2独有的好友
{'ricky', 'Jy'}

# 4.对称差集(^) # 求两个用户独有的好友们(即去掉共有的好友)
>>> friends1 ^ friends2
{'kevin', 'zero', 'ricky', 'Jy'}

# 5.值是否相等(==)
>>> friends1 == friends2
False

# 6.父集:一个集合是否包含另外一个集合
# 6.1 包含则返回True
>>> {1,2,3} > {1,2}
True
>>> {1,2,3} >= {1,2}
True
# 6.2 不存在包含关系,则返回False
>>> {1,2,3} > {1,3,4,5}
False
>>> {1,2,3} >= {1,3,4,5}
False


# 7.子集
>>> {1,2} < {1,2,3}
True
>>> {1,2} <= {1,2,3}
True

字符编码

# 字符编码只跟文本文件和字符串有关,跟音频文件,视频文件之类的都没有关系
什么是字符编码?
	计算机内部只认识二进制,但是,我们人类语言有各种各样的样式,
    为了让计算机能够认识人类的语言,
    内部有一种机制就是讲人类语言转为计算机语言

# 字符编码:记录了人类语言与数据之间的对应关系

字符编码发展史

# 1. 一家独大
	由于计算机最开始是由美国人发明的,美国人为了让计算机识别英文字符
     ASCII码表:使用一个字节来记录一个英文字符
        	"""
        		所有字符加起来一共127个字符
        		使用一个字节(8位)可以记录255种字符
        	"""
      # 记忆:
    	    A-Z:65-90
        	a-z:97-122
            0-9:48-57
            '''小写字母对应的数字一定大于大写字母'''
      # 补充:
    	s = 'hello'
        s1 = 'world'
        print(s > s1)
# 2. 群雄割据
	中国人:我们中国人也要使用计算机,中国人也发明了一张编码表
    		GBK码:记录中文英文与数据之间的对应关系
            '''
                我们使用两个字节或者三个字节来记录中文字符
            '''
            2 ** 16 = 65535
    韩国人: 韩国人也要使用计算机,我们也发明了一张编码表、
    	Euc-kr表:只有韩文字符、英文字符与数字的一一对应关系
    日本人:
    	 Shift_JIS表: 1、只有日文字符、英文字符与数字的一一对应关系
       ...
# 3. 一统天下
	unicode表(万国码): # 存在所有语言中的所有字符与数字的一一对应关系,
    #即兼容万国字符
	'''结论:unicode码只在内存中起作用'''
   	# 使用至少2个字节保存数据
    
    utf8编码
'''我们日常使用的字符编码都是utf8编码,但是,utf系列还有utf16 utf32...  utf8mb4'''
# 一个字节保存一个英文字符
# 中文字符还是使用两个字节或者三个字节保存

# 补充:utf8只能存储正常的字符,utf8mb4可以存储表情

字符编码的使用

1. 如何解决乱码问题?
	文本文件使用什么字符编码保存,打开的时候就要使用对应的字符编码
2. python解释器版本不同带来的差异
	# python2 解释器使用的字符编码还是ASCII表
    # python3 使用的是utf8编码
3. 添加文件模板
	settings
    	Editor
        	File and code template
            	python script
4. 编码与解码(核心)
	  # 编码:
    		将人类能够读懂的语言转为计算机能够读懂的语言
    		
      # 解码:
    		将计算机能够读懂的语言转为人类能够读懂的语言


    # 编码:

    # bytes 字节,看成是二进制
    s1 = ss.encode('utf8')
    print(s1, type(s1)) # b'\xb3\xc3\xc4\xea\xc7\xe1\xa3\xac\xd1\xa7\xbc\xbc\xc4\xdc\xa3\xac\xd1\xf8\xbb\xee\xd7\xd4\xbc\xba'

    # 解码
    print(s1.decode('utf8'))

s = b'kevin123' # 只有英文字符和数字,要想编码的话,直接使用前缀b
print(s.encode('utf8'))

文件介绍

# 文件的类型:txt word excel py
'''python操作文件'''

# 三步骤(关键字:open)
	1. 打开文件
    2. 操作文件
    3. 关闭文件

 # 1. 打开文件
# open('文件路径', 'r', '字符编码')

f=open('a.txt', 'r', encoding='utf-8')
# print(f)  # <_io.TextIOWrapper name='a.txt' mode='r' encoding='utf8'>  文件句柄
print(f.read())
f.close()  # 关闭文件

"""
	语法格式:
		open('文件路径', '读写模式', '字符编码')
"""

# r的作用
'''当路径中可能存在有转移的字符时,字符串前面加上r来解决转义的问题'''
r'D:\python25\day09\a.txt'

文件读写模式

1. r  >>> read: 只读 # 只能读,不能写
2. w  >>> write:只写 # 只能写,不能读
3. a  >>> append: 追加
# 读写模式
# 1. r
# 路径不存在,直接报错
# with open(r'a.txt', 'r', encoding='utf-8') as f:
#     print(f.read())


# 2. w
# 如果路径不存在,会新建一个文件出来
# with open('b.txt', 'w', encoding='utf-8') as f:
#     pass

# 1. 会先清空文件中得内容 2. 在进行写内容
'''写文件的是一定要小心,它会清空文件的'''
with open('a.txt', 'w', encoding='utf-8') as f:
    f.write('oldboy\n')
    f.write('oldboy\n')
    f.write('oldboy\n')
    f.write('oldboy\n')
    f.write('oldboy\n')

# a:追加模式
# 路径不存在的时候,也会新建一个文件出来
# with open('a.txt', 'a', encoding='utf-8') as f:
#     f.write('oldgirl\n')

文件读写模式

r w a
'''以上三种模式只能操作文本'''

a w的区别
w: write 
	1. 文本不存在,会新建一个空文件
    2. 文件存在,会先清空文件数据,在从新写
    3. 写的数据类型一定是字符串类型
a: append 追加
	# 不会清空原来的数据

文件操作方式

1. 读方法
    # 1. 读系列
    # 句点符
    with open(r'a.txt', 'r', encoding='utf-8') as f:
        # print(f.read())  # 一次性读取文件内所有的数据
        # data = f.read()
        '''一次性读取文件所有的数据就会存在漏洞:导致内存溢出'''
        # print(f.readline())  # 一次读取一行

        # print(f.readable())  #判断是否可读 True

        '''把文件内的一行一行数据组装成列表元素返回,注意末尾的换行符'''
        # print(f.readlines()) 
2. 写方法
	
with open('a.txt', 'w', encoding='utf-8') as f:
    # f.write('hello\n')
    # f.write('hello\n')
    # f.write('hello\n')
    # print(f.writable()) # True
    # print(f.readable())  # False
    # print(f.writelines(['你好1\n', '你好2\n', '你好3\n']))
    pass

文件读操作优化

'''文件句柄f支持for循环'''
    # for line in f:
    #     print(line)  # 一次代码一行数据

    '''以后读取文件数据的时候,都使用for循环去一行一行的读取,
    不会出现内存溢出的情况'''
f.flush() # 把内存中得数据立刻刷到硬盘中

文件操作模式

1. r w a模式
	"""
		1. 只能操作文本文件
		2. 都是以字符为单位
		3. rt wt at  => t可以省略
		4. encoding参数必须写
	"""
2. b模式:二进制
	"""
		1. 能操作任何的数据类型,eg:文本,视频,音频...
		2. 写法:rb ab wb  >>>: 此时的b不能省略
		3. encoding参数不写
		4. 就是以字节为单位
	"""

文件二进制读操作

with open('a.txt', 'rb') as f:
    print(f.read(3).decode('utf-8'))

"""
    1. t模式
        read()里面的数字代表的是一个字符
    2. b模式
        read()里面的数字代表的是一个字节
"""

文件指针的移动

"""
    f.seek总共有3种模式
        1. offset参数
            偏移量,移动的位置
            如果是整数,从左往右读取
            如果是负数,从右往左读取
        2. whence参数
            # 0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
            # 1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
            # 2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的
"""

文件的修改

方式一
    # 1. 读取b.txt文件数据
    # 2. 把新的数据再次写入文件
方式二
	将文件写到一个新文件,删除原来的文件,将那个新文件改名为原来的文件名
    
# 掌握思路
1. 思路一
	1.1 先读取源文件内容
    1.2 使用字符串内置方法,替换数据
    1.3 再次把替换之后的数据写入文件
2. 重命名
	# 了解

函数

函数铺垫

"""
1. 我们现在写的代码冗余性比较强
2. 我们现在写的代码兼容性不强
3. 模仿len的功能实现原理
4. 我们自己写的这个函数没有返回值(就是函数执行之后,没有返回结果)
函数简介:
    类似于工具,提前准备好,方便后续使用
"""

函数的语法结构

def my_len(参数1, 参数2):
    '''求列表的长度'''
    print(123) # 函数体代码
    return 'hello' # 返回值

"""
1. def 定义或者说声明一个函数,不能省略
2. ()函数名(不能省略)
    就相当于是变量名,命名遵循变量的命名规范,见名知意
3. 参数(可有可无)
    函数的精髓
    什么是函数:在使用函数之前要满足的一定条件
4. 函数体代码注释(可有可无,推荐有)
    主要写一些函数功能的介绍,和一些参数的解释
5. 函数体代码(核心)
6. 返回值(可有可无)
    return
"""

函数的定义与调用

# 函数一定是两个阶段:定义,调用

#####################必须掌握###########################################
1. 函数必须先定义,后调用
2. 函数在定义阶段,如果有参数,调用阶段也需要给对应的参数
3. 函数在定义阶段只检测语法是否正确,不执行具体的代码功能
4. 函数在调用阶段会执行具体的函数体代码
5. 如何调用函数?# 函数名()
#####################必须掌握###########################################

函数的底层原理:
   	1. 申请一块内存空间,存储函数体代码
    2. 把函数体代码绑定给函数名
    3. 通过调用函数(函数名())来执行函数体代码

函数的分类

1. 内置函数
	# 在python解释器中提前存在的,我们可以直接使用
   	eg:len, print,之前学习的数据类型的内置方法都是内置函数
2. 自定义函数
	# 我们自己写的函数
    2.1. 无参函数:没有参数的函数
    2.2. 有参函数:带参数的函数
    2.3. 空函数:啥都没有
    #1.无参函数
# def my_len():
#     print(123)
# my_len()

# 2. 有参函数
def my_len(a,b):
    print('hello')
    print(a,b)
# my_len(1,2)
my_len('a','b')

# 3. 空函数
def my_func():
    # 1. 注册
    pass
    ...

函数的返回值

# 返回值:函数执行完毕之后,返回的结果
res = my_func1()  # 把函数的执行结果赋值给res变量,结果就是None
print(res)  # None
# 1. 当函数没有返回值的时候,没有return的时候,返回的是None
# 2. 当函数中只有return关键字的时候,返回的结果仍然是None
# 3. 当return后有数据的时候,写什么就返回什么
# 4. 当return后面跟多个数据的时候,会组织成元组形式返回
# 5. 如果你想返回多个值得时候,最后使用容器类型包一下
# 6. 在函数中,只要遇到return关键字,代码立刻终止执行,一个函数最多只有有一个return关键字
# 7. return 只能出现在函数中。if else中绝对不能出现

函数参数

1. 形式参数
	# 在函数定义阶段,括号中填入的变量名,就是形式参数,简称:形参
    	def my_func(a, b):
            pass
		# 此时,a,b就是函数my_func的形参
2. 实际参数
	# 在函数调用阶段,括号中传入的数据值,就是实际参数,简称:实参
    	my_func(1,2)
        # 此时,数据1,2就是函数my_func的实参
        
"""
	形参和实参的关系
		实际参数的变量名=数据值的形式进行传递
	
	形参和实参的表现形式
		形参的表现形式只有一种,就是变量名
		实参的表现形式有多种... 核心:都是数据值
"""

# 在函数调用阶段,实参和形参临时绑定,函数调用完毕,二者断开

位置参数

1. 位置参数
	在函数定义阶段,括号中填写的参数
2. 位置形参
	在函数定义阶段,括号中从左往右填写的变量名就是位置形参
        def index(a, b, c):
            pass
3. 位置实参
	在函数调用阶段,括号中从左往右传入的数据值就是位置实参
    	index(1,2,3)
        
# 定义一个函数,传入两个数字参数,功能是:返回大的
a = 10
b =20
if a>b:
    return a
else:
    return b

4. 关键字实参
	res = my_max(b=20, 111)  # 位置参数不能放在关键字参数的后面
	'''参数越简单,越靠前放'''

默认参数

# 默认形参
	'''在函数定义阶段,就可以给变量赋值了'''
    1. 在调用阶段如果你给了数据值,就使用你给的
    2. 在调用阶段如果你不传数据值,那就使用默认
'''注意:'''
1. 当有了默认参数,就可以传值和不传值了

可变长参数

# 1. 不管传入多少个位置参数,函数都可以正常运行
def index(x, y, *a):
    print(x,y)
    print(a) # (1, 2, 3, 4, 5, 6)

"""
    *在形参中得使用:接收多余的位置参数,并组装成元组的形式一一返回
"""
index(1, 2, 3, 4, 5, 6)

# 2. 不管传入多少个关键字参数,函数都可以正常运行
def func( **a):
    print(a)

func(age=20, name='kevin', salary=1000, gender='male')  # {'salary': 1000, 'gender': 'male'}

"""
**在形参中得使用:接收对于的关键字参数,并且把关键字参数组织成字典的形式
"""

# 3. 不管传入多少个位置参数和关键字参数,函数都可以正常运行
def index(a, b, name, *c, **d):
    print(a, b)
    print(name)
    print(c)
    print(d)


index(1, 2, 3, 4, 5, name='kevin', age=20, gender='male')


"""
	*和**后面的变量名可以随意的起名字,只是一个变量名而已
	python中推荐使用
		*args   arguments
		**kw args  keyword arguments
		
	def index(*args, **kwargs):
		pass
"""

# 补充:*和**在实参中得使用(重点)
# def index(a, b, *args ):
#     print(a, b, args)

# index(1, 2, 3)
# l = [11, 22, 33,44,55]
# t = (11, 22, 33,44,55)
# index(l[0], l[1], l[2])
"""
*在实参中得使用:把列表、元组内的各个元素打散,然后一一传值
"""
# index(*l) # index(11, 22, 33,44,55)
# index(*t) # index(11, 22, 33,44,55)
# print(*t)


def index(**kwargs):
    print(kwargs)  # {'username': 'kevin', 'age': '18', 'gender': 'male'}


# index(1, 2, name='kevin')

dict = {'username': 'kevin', 'age': '18', 'gender': 'male'}
# index(username='kevin', age='age', gender='male')
"""
**在实参中得使用:把字典内的元素打散,然后以关键字的形式一一传入
"""
index(**dict)
index(**{'username': 'kevin', 'age': '18', 'gender': 'male'})
# index(username='kevin', age='age', gender='male')

名称空间

# 存放变量名与变量值关系的地方

# 名称空间的分类
1. 内置的名称空间
	# 在python解释器中存在
2. 全局名称空间
	# 在py文件中,顶格写的代码都在全局名称空间中
    name = 'kevin'

    if  True:
        a = 1

    while True:
        x = 10
3. 局部名称空间
	# 在函数体代码执行完产生的数据
'''只要在函数中出现的都是局部的'''


4. 存活周期
	# 内置的:伴随python解释器的启动/关闭而产生/回收
	# 全局的:伴随python文件的开始执行/执行完毕而产生/回收
    # 局部的:伴随函数的调用/结束而临时产生/回收

名字的查找顺序

# 首先先确定你所在的位置
1. 如果在局部中:
	局部  >>>  全局 >>> 内置
2. 如果在全局中:
	全局 >>> 内置

名称空间的作用域

# 作用域:
	就是作用的范围
1. 内置的
	# 在任何阶段任何时间都可以使用  (全局有效)
2. 全局的
	# 在任何阶段任何时间都可以使用  (全局有效)
3. 局部的
	# 在函数内部阶段使用            (局部有效)

global与nonlacal关键字的使用

 global
"""
局部修改全局的
1. 修改的是不可变类型,必须使用global关键字声明一下
2. 修改的是可变类型,就不用global声明了,直接可以改
"""
nonlacal
"""
内部的局部修改外部的局部
1. 如果是不可变类型,必须使用nonlocal关键字声明一下
2. 如果是可变类型,就不需要使用nonlocal关键字声明一下
"""

函数对象

 1. 函数名可以当成变量赋值
# def index():
#     print('from index')

'''函数名不加括号就是函数的内存地址'''


# a  = index
# a()
# print(a)

2. 函数名可以当成函数的实参
# def index():
#     print('from index')
#
# def func(a):
#     # print(a) # a => index
#     a()
#     print('from func')
# func(index)
# func(index())

3. 函数名可以当成函数的返回值
# def index():
#     print('from index')
#
# def func():
#     print('from func')
#     return index  # 返回的就是index函数的内存地址
#
# res=func()  # res就是index函数的内存地址
# res()

 4. 函数名可以当成容器类型的元素

# def index():
#     print('from index')
#
#     return 'from index'
#
# # l = [11, 22, 33, index]
# l = [11, 22, 33, index()]
# print(l)


'''函数名只要加括号,就会执行!!!!!!!!!'''
func_dict = {
    '1': register,
    '2': login,
    '3': transfer,
    '4': shopping,
    '5': withdraw,
    '6': chongzhi,
}
while True:
    print("""
        1. 注册
        2. 登录
        3. 转账
        4. 购物
        5. 提现
        6. 充值
    """)
    choice = input('请输入编号:').strip()
    # 判断用户输入的编号在不在fund_dict这个字典里面
    if choice in func_dict:
        func_name=func_dict.get(choice)  # 函数的内存地址
        func_name()
    else:
        print('不存在')

#函数的嵌套调用

# def index():
#     print('from index')
#
# def func():
#     index()
#     print('from func')
#
# func()

def my_max(a, b):
    if a > b:
        return a
    return b

# 判断4个数的大小,返回大的
def many_max(a, b, c, d):
    res=my_max(a, b) # b
    res1=my_max(res, c)
    res2=my_max(res1, d)
    return res2

ret=many_max(1,2,3,4)
print(ret)

函数的嵌套定义

# 在函数内部定义函数
# 把复杂的功能隐藏起来,暴露给外界一个简单的接口

闭包函数

闭:定义在函数内部的函数
包:内部函数使用外部函数名称空间中得名字
'''只有同时满足以上两个条件的函数,才是闭包函数'''

装饰器

"""
	装饰器不是一个新的知识点,它是我们之前学习的:名称空间,函数对象,闭包函数组合而来
"""
装饰:为被装饰对象添加新的功能
器:工具

# 装饰器的核心思想:
	在不改变被装饰"对象内部代码"和"原有调用方式"的基础之上添加额外的功能

# 写一个认证装饰器
# 定义一个index函数,让用户输入用户名和密码,如果输入正确,就执行index函数,否则不能执行函数

'''升华:
    如果有一个函数被认证成功,后续的函数都不在认证了
'''
# 定义一个变量来存储是否认证成功
is_login={'is_login':False}

def login_auth(func_name):
    # func_name = index
    def auth():
        if is_login.get('is_login'):
            res = func_name()
            return res
        # 1. 让用户输入用户名和密码
        username = input('username:').strip()
        password = input('password:').strip()

        # 2. 要认证,判断用户名和密码是否正确
        if username == 'kevin' and password == '123':
            # 才是正常执行的函数
            res=func_name()
            is_login['is_login'] = True
            return res
        else:
            print('认证失败,不能执行函数')
    return auth
def outer(func):
    def inner(*args, **kwargs):
        print('在函数执行之前需要添加的功能')
        res=func(*args, **kwargs)
        print('在函数执行之后需要添加的功能')
        return res
    return inner

装饰器修复技术

from functools import wraps
def login_auth(func_name):
    # func_name = index
    @wraps(func_name)  # 修复技术是为了让被装饰对象不容易被察觉装饰了
    def auth():
        # 1. 让用户输入用户名和密码
        username = input('username:').strip()
        password = input('password:').strip()

        # 2. 要认证,判断用户名和密码是否正确
        if username == 'kevin' and password == '123':
            # 才是正常执行的函数
            res=func_name()
            return res
        else:
            print('认证失败,不能执行函数')
    return auth

有参装饰器

def outter(source_data,a,b,c,d,e,f, *args, **kwargs):
    source_data='file'
    def login_auth(func_name):
        # func_name = index
        def auth(*args, **kwargs):
            # 1. 让用户输入用户名和密码
            username = input('username:').strip()
            password = input('password:').strip()
    
            # 2. 要认证,判断用户名和密码是否正确
            if source_data == 'file':
                print('数据来源是文件')
            elif source_data=='mysql':
                print('数据来源是MySQL')
            elif source_data=='oracle':
                print('数据来源是oracle')
            else:
                print('认证失败,不能执行函数')
                
        return auth
    return login_auth


@outter('file',1,2,3,4,5,6,) # @login_auth
def index():
    print('from index')

语法糖

"""
语法糖的书写:要紧贴着被装饰对象的上方
语法糖的原理:会把被装饰对象的函数名自动当成参数传给装饰器函数的参数传入
"""

递归函数

# 什么是递归函数?
	就是直接或者间接的调用自己
# 递归函数的使用场景
递归:
    1. 递推
        逐层寻找答案
    2. 回溯
        根据最终的答案推导出最原始的答案
    3. 递归函数必须有结束条件!!!
"""

二分法

# 算法:做事的方法, 为了提高效率

# 二分法的使用
eg:l = [1, 22, 44 ,10, 3, 45, 66, 88,101, 20, 30 ,40]
# 判断这个列表中是否有20这个数字
'''二分法的原则:1、 列表中得数字必须要有序,不管是升序还是降序都可以,如果没有顺序就不能使用二分法'''
# 代码实现二分法
target_num = 100

def my_half(target_num, l):
    if len(l) == 0:
        print('不好依稀,没找到')
        return
    middle_index = len(l) // 2 # 小数 # 6
    if target_num > l[middle_index]:
        l_right=l[middle_index+1:] # l[7]
        print(l_right)
        my_half(target_num, l_right)
    elif target_num < l[middle_index]:
        l_left=l[:middle_index]
        print(l_left)
        my_half(target_num, l_left)
    else:
        print('找到了')

my_half(target_num, l)

三元表达式

'''三元表达式实现上述功能'''

def my_max(a, b):
    return a if a > b else b
"""
	语法结构:
		条件成立之后的结果 if 条件 else 条件不成功之后的结果
	使用场景:结果二选一的情况
"""

列表生成式

name_list = ['kevin', 'jack', 'ly', 'tony']
# 需求是:把列表中得名字都添加一个后缀:_NB

1. 传统做法:
	new_list = []
	for name in name_list:
        res='%s_NB' % name
        new_list.append(res)
        
    print(new_list)
    
# 需求:除了jack不加,其他都加,如果是jack直接去掉
name_list = ['kevin', 'jack', 'ly', 'tony']
# new_list = []
# for name in name_list:
#     if name == 'jack':
#         continue
#     else:
#         res = '%s_NB' % name
#         new_list.append(res)
# print(new_list)

# 列表生成式的使用
# res = ['%s_NB' % name for name in name_list if name != 'jack']

'''特殊用法'''
res = ['%s_NB' % name if name != 'jack' else '666' for name in name_list ]
print(res)

字典生成式,集合生成式

'''补充:'''
# count=0
# for i in l1:
#     print(count, i)
#     count+=1

# 记忆
"""
enumerate:使用for循环的时候,可以解压赋值出来两个值,一个是索引,一个是元素
            start:控制的是起始位置,默认是从0开始
"""
# for i, j in enumerate(l1, start=2):
#     print(i ,j)
# 2. 字典生成式
# res = {i:j for i, j in enumerate(l1)}
# print(res)

# 集合
# res = {i for i in l1}
# print(res)

# 元组
# 迭代器
res = (i for i in l1)
print(res)  # generator

匿名函数

# 没有名字的函数
def index():
    pass

index()
"""
语法格式:
    lambda 形参:返回值
    lambda x:x**2

匿名函数一般步单独使用,会配合其他函数使用
    map()
"""

配合匿名函数使用的方法

1. map(函数名, 要遍历的数据)  # 内部本质就是for循环,再记住两个参数的位置和作用
# 2. zip 拉链
# 3. max
'''如果是字典,比较的是key,说白了就是你暴露什么,就按照什么比较'''
def index(key):
    return d[key]
'''如果传了key参数,就是返回什么值就按照什么值比较'''
print(max(d, key=index))
print(max(d, key=lambda key:d[key]))

print(min(d, key=index))
print(min(d, key=lambda key:d[key]))
# 4. 过滤
l = [1, 10, 20, 55, 66, 77]
# ll = []
# for i in l:
#     if i > 20:
#         ll.append(i)
# print(ll)

def index(x):
    return x > 20
# res=filter(index, l)
res=filter(lambda x:x>20, l)
print(list(res))  # [55, 66, 77]

可迭代对象

# 什么是迭代
	迭代就是每一次的结果必须依赖于上一次的结果
v1.0  v2.0   v3.0

# 可迭代对象
	内置有__iter__方法的对象都是可迭代对象
    '''内置的意思是python自带的,解释器中已经存在的,我们可以直接使用的'''
# 目前我所学的数据类型中,有哪些是可迭代对象, 都支持for循环
	str, list, dict, tuple, set, 文件对象

迭代器对象

# 什么是迭代器对象
	既有__iter__方法, 也含有__next__方法

'''文件对象即是可迭代对象又是迭代器对象'''

# 如果生成迭代器对象
	可迭代对象调用__iter__方法

注意:
	迭代给我们提供了一种不依赖索引取值的方法

for循环内部原理

l = [1, 2, 3, 4, 5, 6, 7]
# 要求:循环打印出列表中每个元素,但是,不能使用for循环,__next__ next()

# 1. 可迭代对象要转为迭代器
# res = l.__iter__()
# 
# while True:
#     print(res.__next__())

# for i in l:
#     print(i)

'''for循环内部其实也报错了,只不过错误没让我们看见,内部处理了'''

"""
	for循环内部执行流程:
		1. 把关键字in后面的数据类型转为了迭代器 __iter__
		2. 循环next取值
		3. next取值完毕之后也报错了,自动处理错误并且结束while循环
"""

捕捉异常

1. 什么是异常?
	# 异常就是错误发生的信号,如果此信号不做处理,那么,从本行开始之后的代码都不能正常执行了
2. 异常
	2.1 Traceback
    2.2 XXXError
    	# 错误的类型
    2.3   XXXError冒号后面的内容,报错的详细原因,我们主要看的也是这部分,大致定位错误的原因 
3. 异常的种类
	1. 语法错误
    	# 是坚决不允许的,遇到之后要立刻改正,否则,代码不能运行
    2. 逻辑错误
    	# 是可以被允许的,但是,我们写逻辑的时候要尽可能的避免逻辑错误的发生
        
4. 常见的错误类型
	NameError
    IndexError
    KeyError
    ValueError
    ZeroDivisionError
    ...
5. 如何捕捉异常
	try:
      	被监测的代码
    except 错误的类型1 as e:
        错误处理,e:错误的原因
    except 错误的类型2 as e:
        错误处理,e:错误的原因
    except 错误的类型3 as e:
        错误处理,e:错误的原因
    except 错误的类型4 as e:
        错误处理,e:错误的原因
        
 '''万能异常'''
try:
    # print(username)
    # print(1/ 0)
    # l = [1,2,3,4]
    # print(l[6])
    d = {'a':1, 'b':2}
    print(d['c'])  #KeyError
except ZeroDivisionError as e:
    print('')
except NameError as e:
    print(123)
except IndexError as e:
    print(123)
except Exception as e:
    print(e) # name 'username' is not defined
    
    
    
"""
	try except异常捕捉需要注意
    	1. try里面被监测的代码尽量少
    	2. 在明显没有错误的代码不要被捕捉
"""
# 上周只学习了try,except的使用,还去其他关键字的使用
else, finally
# try:
#     l = [1, 2, 3]
#     print(l[1])
# except IndexError as e:
#     print(e)
# else:
#     #
#     print('当被监测的代码没有报错的时候执行else语句')
# finally:
#     print('不管被监测的代码有没有错误,都会走finally语句')

# try:
#     print('hello')
# else:
#     print(123)

'''try和else不能单独使用'''
try:
    print('hello')
except IndexError:
    print(123)
else:
    print(123)

生成器对象

# range()
'''生成器的作用:节省空间了'''

# 生成器就是迭代器的一种
def index():
    print('from index')
    print('hello world')
    yield 123
    print('second')
    print('second')
    print('second')
    print('second')
    print('second')
    yield 222
    print('three')

""""
函数中如果存在yield关键字,在调用函数之前,还是一个普通函数,
一旦调用函数,就把函数变成了生成器(迭代器)

****************
生成器一定是迭代器
迭代器不一定是生成器
***************
"""
res=index()  # 此时就是生成器
ret=res.__next__()   # 代码遇到yield关键字,会停住,夯住
ret=res.__next__()  # 再次执行__next__,代码从上一次被停住的位置继续往下执行
ret=res.__next__()
# print(ret)

生成器的案例:实现range方法

range(1, 10)
for i in range(1, 10):
    print(i)
    
for i in my_range(1, 10):
    print(i)
    
    
def my_range(start, stop=None, step=1):
    if start < stop:
        if not stop:
            stop = start
            start=0
        while start < stop:  # 0<stop
            yield start
            start += step
    else:
        return '好好传值,别乱来'

# for i in my_range(1, 10):
for i in my_range(50, 10):
    print(i)

yield传值

def eat():
    print('开始干饭')
    while True:
        food =  yield
        print('开始吃%s' % food)
res=eat()  # 只是把函数变成了生成器
res.__next__()  # 取值,取到第一次遇到yield,然后停住

# 1. 调用了__next__ 2. 传参数
res.send('臭豆腐')  # 
res.send('臭豆腐1')
res.send('臭豆腐2')
res.send('臭豆腐3')
res.send('臭豆腐4')

yield与return的对比

yield
	1. 可以有返回值
    2. 函数遇到yield不会结束,只会'停住'
    3. yield关键字把函数变成了生成器,支持迭代取值了
return
	1. 可以有返回值
    2. 遇到return关键字直接结束函数运行

常见内置函数

# print(abs(10))
# print(abs(-10))  # 绝对值

# l = [1, 2, 3, 0]
# print(all(l))  # True
# print(any(l))

arr = range(10)

myslice = slice(5)    # 设置截取5个元素的切片

"""
    100条数据  10条  10页
    99条      10    10页
    101条      101  11
"""

# page, more=divmod(100, 10)
# page, more=divmod(99, 10)
# page, more=divmod(2005, 10)
# if more:
#     page += 1
# print(page)

# res="""print('hello world')""" #
res="""
# 这是注释
for i in range(10):
    print(i)
""" #
# eval(res) # 识别简单的python代码
# exec(res)

# if type(123) is int:
#     print('123')
# print(type('123') is int)  # 判断数据类型的
# print(isinstance('123', int))
# print(isinstance(123, int))
# print(isinstance('123', str))
# print(isinstance([1,2,3,4], list))
# print(isinstance({'a':1}, dict))

# print(chr(65))
# print(chr(97))  # 根据ASCII码表,填入对应的十进制,返回对应的字符
# print(ord('A'))
# print(ord('z'))  # 根据ASCII码表,填入对应的字符,返回对应的十进制

# l = [10, 20, 30 ,40, 50]
# print(sum(l))  # 求和

# print(pow(4, 3))  # 4 ** 3
# print(pow(2, 3))  # 4 ** 3
s = '你好啊'
# res=s.encode('utf-8')
# print(res)
# ret = res.decode('utf-8')
# print(ret)

# res=bytes(s, 'utf-8')
# print(res)
# print(str(res, 'utf-8'))

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

# print(callable(index))  # 查看是否能够被调用

'''健壮性'''
# res=callable(index)
# if res:
#     index()
# else:
#     ''''''

# def func(name, age):
#     print(locals()) # {'name': 1, 'age': 2}
# func(1, 2)

# 复数,而不是负数
# 1+2j

# 四舍五入
print(round(3.4))
print(round(3.5))
print(round(3.6))

模块的简介

# 调包侠

1. 什么是模块?
	# 就是一系列功能的集合体
2. 为什么要用模块?
	# 拿来主义,极大地提高了开发效率
3. 模块的来源
	1. 内置的:# python解释器自带的,直接拿来使用的
    2. 第三方的 # 别人写的,如果想用,就要先下载在使用
    3. 自定义的 # 我们自己写的
4. 模块的存在形式
	1. 我们自己写的py文件(一个py文件就是一个模块)
    2. 包:一系列py文件的集合(文件夹)
    	# 一个包里面会有一个__init__.py文件
 """
 	以后再写一个复杂项目的功能时候,要先考虑有没有被人已经写好的模块,我们直接拿来使用
 """

import句式

# 在学习模块的时候,要区分开谁是执行文件,谁是导入文件

import md  # 导入模块的时候,文件名后缀不能加

"""
    23种设计模式:单例模式。
    在导入模块的时候,只有第一次会执行,其他的都不会执行
    
	首次导入模块发生了什么事情?
	    1. 运行执行文件,产生执行文件的全局名称空间
	    2. 运行导入文件(md.py)
	    3. 产生导入文件的全局名称空间,并且,把导入文件中产生的名字都保存到导入文件的全局名称空间
	    4. 在执行文件中,产生一个md的名字指向导入文件的全局名称空间
	    
    一旦你使用了import句式之后,我们就可以通过句点符的形式找到导入文件中得名字
"""

from...import...句式

"""
	首次导入只会执行一次,只会的导入都不在执行
    1. 运行执行文件,产生执行文件的全局名称空间
    2. 运行md.py文件
    3. 产生导入文件的全局名称空间,把运行之后产生的名字都保存到导入文件的全局名称空间中
    4. 在执行文件中,产生一个名字money指向导入文件中得money值
"""

导入文件的扩展用法

1. 起别名
	import mddddddddddddddddddddddddddddddddddddddd as md
	print(mddddddddddddddddddddddddddddddddddddddd.name)
    
    from mddddddddddddddddddddddddddddddddddddddd import namenamenamenamenamenamenamenamenamenamenamename as name
	print(name)
2. 连续导入
	import time
    import md
    import os
    import sys

	import time, md, os, sys # 等价于上面4行代码
    import 模块名1, 模块名2, 模块名3, 模块名4, 模块名5,
    # 推荐还是分开写好一些
3. 通用导入
	from md import *
    print(money)
    # print(read1())
    # print(read2())

判断文件类型

# 判断当前文件是执行文件还是导入文件

__name__在不同的文件中,结果是不一样的
    在执行文件中,结果是 __main__
    在导入文件中,结果是:模块名
    
if __name__ == '__main__':
    print('当前是执行文件')
    
if __name__ == '__main__':
    print('123')
    

循环导入

# 循环导入的现象在实际工作中,坚决不能出现
'''如果你的程序出现了循环导入,说明你的程序设计的不合理!!!!'''

模块的查找顺序

"""
	1. 先从内存中查找
	2. 再从内置模块中查找
	3. 从环境变量中查找sys.path (********************************)
"""

# 一定要注意以后的文件名命名坚决不能跟内置模块名重名(*********************)

# 当查找模块找不到的时候,如何解决?
	1. 把模块所在的路径添加到环境变量中
    	import sys
        sys.path.append('')
    2. from 模块名1.模块名2 import 模块3
    

绝对导入和相对导入

# 程序中,多个模块之间导入的时候,始终以执行文件所在的路径为基准

绝对导入
	# 始终以执行文件所在的环境变量sys.path为基准
 相对导入
	"""
		句点符(.)
			.代表的是当前路径
			..代表上一层路径
	"""
 # 相对导入打破了以执行文件所在的路径为基准的原则, 只考虑两个文件之间的位置

'''当文件中出现了相对导入的句式,该文件就不能当成执行文件运行了,只能被当成导入文件使用'''

import bbb
"""
导包发生了什么事?
    1. 运行执行文件,产生执行文件的名称空间
    2. 运行__init__.py文件, 把该文件中产生的名字保存在名称空间中
    3. 在执行文件中,产生一个包名字bbb指向包的名称空间
"""

# 导包就是在导__init__.py文件

print(bbb.x)

软件开发目录规范

bin
	# 一般是存放启动文件,当启动文件只有一个的时候,也可以写在项目根目录
db:databases
	# 一般存放数据相关的文件
conf: config # 配置
	# 一般存放配置文件 里面的变量一般都是全大写 HOST='127.0.0.1'
    settings.py
lib:library 库
	# 存放一些公共的文件
	common.py文件
core/api:核心的
	# 一般写项目的核心逻辑
    src.py
README
	# 一般写一些说明性的信息,介绍项目用的
# https://github.com/ 

正则表达式

'''
	正则表达式它跟任何一门语言都没有关系,它是一门独立的语言!!!
'''
# 什么是正则表达式?
	利用一些特殊符号来筛选出我们想要的数据
'''在python中,如果想使用正则表达式,我们需要借助于re模块!!!'''

字符组

[0123456789] ====> [0-9]  =>>>>>> \d  # 匹配0-9的数字
[a-z]  # 匹配a-z之间的任何一个字符
[A-Z]  # 匹配A-Z之间的任何一个字符
[0-9a-xA-X] # ...

字符

.  # 匹配除换行符以外的任意字符
\w #  匹配字母或数字或下划线
\d # 匹配数字
^  # 匹配字符串的开始
$  # 匹配字符串的结尾
a|b   # 匹配字符a或字符b
[^...] # ^如果写在中括号里面,

量词

1. 量词不能单独使用
2. 量词只会影响前面的一个字符 (ab+ 只会影响b)
3. 量词一定配合表达式使用
*   			# 重复零次或更多次
+				# 重复一次或更多次
?				# 重复零次或一次
{n}				# 重复n次	
{n,}			# 重复n次或更多次
{n,m}			# 重复n到m次

贪婪匹配和非贪婪匹配

# 字符串:
	<script>hello</script>
# 正则表达式
	<.*?>   # <script>   
# 结果是:
    <script>
    </script>

'''贪婪匹配 非贪婪匹配'''

# 取消贪婪匹配
'''非贪婪匹配就是尽可能的少匹配'''

# 正则表达式默认情况都是贪婪匹配

取消转义

r"\t"

内置模块之re模块

regluar express  => re  => regexp
'''
	在python中使用正则表达式,需要借助于re模块
'''
# 常用方法
import re

"""
    1. 如果匹配到了,就返回匹配到的结果,并且是列表形式,
    2. 匹配不到,返回[],并没有报错
"""
# res=re.findall('^a$', 'arertewtre')
# res=re.findall('^[1-9]\d{13,16}[0-9x]$', '110101198001017032')
# res=re.findall('0?(13|14|15|17|18|19)[0-9]{9}', '15838665930')
# print(res)

res=re.search('bbb', 'keain jack toay')
# print(res)  # <re.Match object; span=(2, 3), match='a'>
# print(res.group())  # a

# try:
#     print(res.group())
# except Exception:
#     print('没有匹配到')
# print(123)

if res:
    print(res.group())
else:
    print('没有匹配')
    
# res=re.match('a', 'keain jack toay')  # 同search,不过是在字符串开始处进行匹配
# print(res)
#
# try:
#     print(res.group())
# except Exception:
#     print('没有匹配到')
# print(123)

# if res:
#     print(res.group())
# else:
#     print('')

无名分组和有名分组

# res = re.search('^([1-9])(\d{14})(\d{2}[0-9x])?$','110105199812067023')
# print(res)
# print(res.group())
# print(res.group(1))  # 分组取值是按照索引取值,索引从1开始
# print(res.group(2))

'''
    findall方法,分组优先展示 (重点)
'''
# res = re.findall("^[1-9]\d{14}(\d{2}[0-9x])?$",'110105199812067023')
# print(res)

'''无名分组和有名分组'''

res = re.search('^[1-9](?P<name>\d{14})(?P<xxx>\d{2}[0-9x])?$','110105199812067023')
print(res.group())
print(res.group(1))
print(res.group(2))
print(res.group('name'))
print(res.group('xxx'))

time模块

# 处理时间相关的
"""
	1. 时间戳
	2. 结构化时间
	3. 格式化时间
"""
time.time()
time.sleep()
time.strftime('%y-%m-%d %H:%M:%S')
time.strftime('%y-%m-%d %X')
time.strftime('%y-%m')
time.localtime() # 结构化的时间
gmtime...
mktime...
time.time()
time.sleep()

"""
	时间的三种格式:
		1. 时间戳
		2. 结构化时间(不是让人看的,让计算机看的)
		3. 格式化时间 (2023-03-06 11:11:11)
"""
import time

# res=time.strftime('%Y-%m-%d')  # 返回当前时间格式化之后的结果
res=time.strftime('%Y-%m-%d %H:%M:%S')  # 返回当前时间格式化之后的结果
res2=time.strftime('%Y-%m-%d %h:%M')  # 返回当前时间格式化之后的结果
res3=time.strftime('%Y-%m-%d %H')  # 返回当前时间格式化之后的结果
res1=time.strftime('%y-%m-%d %X')  # 返回当前时间格式化之后的结果
print(res)
print(res1)
print(res2)
print(res3)


# time.struct_time(tm_year=2023, tm_mon=3, tm_mday=9, tm_hour=12, tm_min=12, tm_sec=12, tm_wday=3, tm_yday=68, tm_isdst=0)
res=time.localtime()
# print(res.tm_year)
# print(res.tm_mon)
# print(res.tm_hour)
# print(res[0])
# print(res[1])
# print(res[2])
# print(res[3])
# print(res[4])

datetime模块

# timedelta对象 重点
current_time = datetime.datetime.now()
# t_time = datetime.timedelta(days=3)
# t_time = datetime.timedelta(days=10, hours=11, minutes=50)
# t_time = datetime.timedelta(weeks=3)
# print(current_time - t_time)
# print(current_time)
# print(current_time - datetime.date(2019, 12, 21))
# print(datetime.date(2019, 12, 21))
# print(current_time - datetime.date(2019, 12, 21))  不能加减


'''时区问题:东八区时间'''
# UTC时间,
res1=datetime.datetime.utcnow()
print(res1)

random模块

import random

# print(random.random())  # 返回0-1的随机数

# print(random.randint(1, 10))  # 返回1-10的整数,包括两头的
# print(random.uniform(1, 5))  # 返回1-5之间的小数,不包括两头
# print(random.randrange(1, 10, 2))  # 大于等于1且小于10之间的奇数
# print(random.choice(['一等奖', '2等奖', '3等奖', '4等奖', '5等奖', '谢谢惠顾', '再来一瓶']))
# print(random.sample(['一等奖', '2等奖', '3等奖', '4等奖', '5等奖', '谢谢惠顾', '再来一瓶'],1))
# l = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A']
# random.shuffle(l)  # 打乱顺序
# print(l)

'''生成随机4位,5位,6位的验证码'''
# 随机验证码里面的字符,是数字,字母组成三种情况任意一种的组合
def get_code(n):
    code = '' # 存储生成的随机验证码
    # 6位的验证码
    for i in range(n):
        # 1. 产生0-9之间的任意一个数据
        random_int = str(random.randint(0, 9))

        # 2. 产生大写字母
        random_upper = chr(random.randint(65, 90)) # A-Z

        # 3. 产生小写字母
        random_lower = chr(random.randint(97, 122)) # a-z

        # 4. 要从以上三种情况中随机选出一个字符来
        temp = random.choice([random_int, random_lower, random_upper])
        # print(temp,end='')
        code += temp
    return code
# res=get_code(6)
res=get_code(4)
print(res)

os模块

os.makedirs('dirname1/dirname2')    可生成多层递归目录
os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove()  删除一个文件
os.rename("oldname","newname")  重命名文件/目录
os.stat('path/filename')  获取文件/目录信息

os.system("bash command")  运行shell命令,直接显示
os.popen("bash command).read()  运行shell命令,获取执行结果
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd

os.path
os.path.abspath(path) 返回path规范化的绝对路径os.path.split(path) 将path分割成目录和文件名二元组返回 
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是绝对路径,返回True
os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path)  返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小

sys模块

# system 它是跟解释器相关的
sys.argv           命令行参数List,第一个元素是程序本身路径
sys.exit(n)        退出程序,正常退出时exit(0),错误退出sys.exit(1)
sys.version        获取Python解释程序的版本信息
sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform  

序列化模块

# 什么是序列化?
	序列: 字符串
    序列化:把其他数据类型转为字符串的过程
    # json格式的数据
字典里面的key值一定是双引号  {}

# 序列化和反序列化
json.dumps(d)     json.loads()

# 配合文件使用的
json.dump(d, f)   json.load(f)

# 可以支持序列化的数据类型?
	json.JSONEncoder  # 集合不能被序列化
d = {'a':'你好'}
res=json.dumps(d,ensure_asicc=False)  # unicode  \u6223

pickle模块
dumps
loads

dump
load
'''pickle之后的结果是二进制类型'''
# 支持所有的数据类型,只能在python中使用
eg:
	d ={'a':1}  # dict
    l = [1,2,3]  # list
    s = str(d)  # str
    sl = str(l)  # str

# 什么是反序列化?
	把字符串转为其他数据类型的过程

'''
	可以直接写入文件的类型:
		1. 字符串
		2. 二进制
'''

# json格式数据
	'''就是实现了跨语言传输'''

pickle模块

'''
    json和pickle模块都支持dumps, loads;  dump, load
    
    pickle处理的数据只能在python中使用,只能自己跟自己玩
    pickle序列化之后的数据是二进制
    pickle在python中可以序列化所有的数据类型
'''
import pickle
d = {'a':1}
# res=pickle.dumps(d)
# print(pickle.loads(res))


# with open('c.txt', 'wb') as f:
#     pickle.dump(d, f)


# with open('c.txt', 'rb') as f:
#     print(pickle.load(f))

subprocess模块

# windows系统默认的编码格式是:gbk
import subprocess
"""
    1. 使用我们自己的电脑去链接别人的电脑 (socket模块)
"""
res=subprocess.Popen('tasklistaaa', shell=True,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE
                 )

print(res)  # <subprocess.Popen object at 0x000001ABB1970310>
# print(res.stdout.read().decode('gbk'))  # tasklist执行之后的正确结果返回
print(res.stderr.read().decode('gbk'))

hashlib模块

import hashlib

# 1. 先确定你要使用的加密方式: md系列,sha系列
md5 = hashlib.md5() # 指定加密方式

# 2. 进行明文数据的加密
data = '1234567890dfjkdfhsdjfhdskjfhsdjkfhddddddddddddddddddddddddddddddddds'

md5.update(data.encode('utf-8'))  # 括号里面加密数据必须是字节类型,bytes类型
"""
    1. 被加密的明文数据不管多长,得到的加密串的长度都是固定的
    2. 针对md5数据,密文数据能不能倒推出明文数据?
        记忆:不能倒推出明文数据
        
"""
# 3. 取出加密结果
print(md5.hexdigest()) 
print(md5.hexdigest())  # eeb9bad681184779aa6570e402d6ef6c
                        # eeb9bad681184779aa6570e402d6ef6c
                        # fc5e038d38a57032085441e7fe7010b0
                        # fc5e038d38a57032085441e7fe7010b0
            
"""加密方式的选择"""
"""
    1. 被加密的明文数据不管多长,得到的加密串的长度都是固定的
    2. 针对md5数据,密文数据能不能倒推出明文数据?
        记忆:不能倒推出明文数据

"""
# 3. 取出加密结果
print(md5.hexdigest())  # eeb9bad681184779aa6570e402d6ef6c
                        # eeb9bad681184779aa6570e402d6ef6c
                        # fc5e038d38a57032085441e7fe7010b0
                        # fc5e038d38a57032085441e7fe7010b0
                        # 6adfb183a4a2c94a2f92dab5ade762a47889a5a1
                        # 936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af
                        # 97982a5b1414b9078103a1c008c4e3526c27b41cdbcf80790560a40f2a9bf2ed4427ab1428789915ed4b3dc07c454bd9
"""
    1. 被加密的数据,密文结果越长代表越难被破解,内部的加密算法越复杂,数据也更安全
        被加密出来的结果越长,在发送数据的时候就会占用更多的资源
    2. 如何选择加密方式
        根据自己项目实际需求选择,一般情况下,md5足够了
        
"""

加盐处理

# ###############################4.固定加盐(干扰项)处理
# # 1. 先确定你要使用的加密方式: md系列,sha系列
# md5 = hashlib.md5()  # 指定加密方式
#
# # 2. 进行明文数据的加密
# # 2.1 内部在给他添加一个干扰项
# random_str = '!@#$%^&dsfsdghdf432534!@#$%%'
# data = '123456'
# result = random_str + data
# md5.update(result.encode('utf-8'))
# """
#     1. 被加密的明文数据不管多长,得到的加密串的长度都是固定的
#     2. 针对md5数据,密文数据能不能倒推出明文数据?
#         记忆:不能倒推出明文数据
#
# """
# # 3. 取出加密结果
# print(md5.hexdigest())  # eeb9bad681184779aa6570e402d6ef6c


###############################5.动态加盐(干扰项)处理
# 1. 先确定你要使用的加密方式: md系列,sha系列
md5 = hashlib.md5()  # 指定加密方式

# 2. 进行明文数据的加密
# 2.1 内部在给他添加一个干扰项
import s
random_str = s.get_code(6)
data = '123456'
result = random_str + data
md5.update(result.encode('utf-8'))
"""
    1. 被加密的明文数据不管多长,得到的加密串的长度都是固定的
    2. 针对md5数据,密文数据能不能倒推出明文数据?
        记忆:不能倒推出明文数据
    3. 以后我们在写项目的时候,只要牵涉到用的注册与登录,密码都要加密
"""
# 3. 取出加密结果
print(md5.hexdigest())  # eeb9bad681184779aa6570e402d6ef6c

第三方模块的安装(重点)

# 内置模块不能满足我们的开发需求,因此,我们需要借助于第三方模块来实现一些更复杂的需求

'''第三方模块需要基于网络下载!!!'''
# 第三方模块的下载需要借助于pip工具
用法1:
	pip install django
	pip install 模块名  # 默认是最新版本
    pip install 模块名==版本号
    pip install django==1.1
    pip install openpyxl
用法2:
	# 借助于pycharm安装
    ...

 '''pip安装模块默认在国外的服务器下载的,所以,下载速度可能会很慢,也有可能下载不成功'''

# 如何优化下载速度?
	换源 (换成国内的源)
 	pip36 install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple # 临时修改
"""
清华源:
https://pypi.tuna.tsinghua.edu.cn/simple

阿里云源:
http://mirrors.aliyun.com/pypi/simple/

中科大源: 
https://pypi.mirrors.ustc.edu.cn/simple/

豆瓣源:
http://pypi.douban.com/simple/
"""

# 下载模块的过程中,有可能会失败
'''
	1. 超时(timeout)
		再次点击下载尝试一下
	2. 除了超时,在遇到下载报错的模块,直接取百度搜索
'''
posted @ 2023-03-23 21:11  哈哈哈哼  阅读(50)  评论(1编辑  收藏  举报