Python/数据库/Django笔记
【临时存储】
第一章 python环境配置
- 进制转换
一、进制转化
1、 二进制
2、 十进制
(1)、二进制→十进制(展权相加)
步骤:第一步:写“2”。 第二步:标指数→从右到左,从指数0开始标记。 第三步:乘系数(一一对应) 第四步:相加。
举例说明:二进制1101转换成十进制是多少?
第一步:先写“2 ” 2 2 2 2
第二步:标指数: 2^3, 2^2 ,2^1, 2^0
第三步:乘系数: 1*2^3 1*2^2 0*2^1 1* 2^0
第四步:相加: 1*2^3+1*2^2+0*2^1+1* 2^0=13
另一种算法:8421法 举例一: 1101 一 一对应
↓
8421
然后乘系数相加:1*8+1*4+0*2+1*1=13
举例二: 11010 一 一 对应
↓
168421 然后乘系数相加:16*1+1*8+0*4+1*2+0*1=26
(2)、十进制→二进制(除2取余)
第一步:用竖式对十进制的数依次除2,记录每一步的余数。 第二步:一直除到商0为止,从下到上记录余数。
(3)、八进制(O)→十进制(第一步:先写“8”。第二步:标指数。第三步:乘系数。第四步:相加)
(4)、十进制→八进制(第一步:用竖式对八进制的数依次除8,记录每一步的余数。第二步:一直除到商为0为止,从下到上记录余数)
(5)、十六进制(OX)→十进制
(6)、十进制→十六进制(0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F)
(7)、二进制→八进制(从右到左三位一组) 例如:10/111/001→2/7/1
(8)、八进制→二进制(一拆三) 例如:4/5/6→100/101/110
(9)、二进制→十六进制(从右到左四位一组) 例如:11/1110/0110→3/E/6
(10)、十六进制→二进制(一拆四) 例如:2/F/7/5→0010/1111/0111/0101
1.1python解释器安装
-
www.python.org下载python安装包
-
选择3.6.6版本下载
-
下载完成后双击安装,选择自定义安装
-
点击下一步
-
选择要安装的目录,点击install安装
-
安装完成,点击close关闭
1.2配置环境变量
-
桌面右击此电脑,点击属性
-
点击高级系统设置,点击环境变量
-
双击path,新建,将python的 安装路径复制进去,点击确定(python3和python2一样)
-
环境变量配置完成后,打开cmd命令台,输入python(python2,输入python2即可)
1.3pycharm环境安装配置
-
pycharm下载:http://www.jetbrains.com/pycharm/download/#section=windows,选择专业版下载
-
下载完成后,双击安装
-
选择自己要安装的路径,点击next
-
,根据自己的需要来勾选
-
点击install安装
-
安装完成
-
安装完成后双击打开,出现这个画面,点击新建项目
-
选择新建项目的路径,和添加python环境,点击保存
-
右击选择新建的项目,选择new,新建python文件
-
就可以开始学习python了
-
顺便说几个pycharm基础常用的快捷键
指令 快捷键 快速复制 ctrl+d 快速删除 ctrl+z 删除后恢复 ctrl+shift+z 快速注释(第二次消除注释) ctrl+? 美化规范代码 ctrl+alt+L
第二章 入门
Git基础入门
-
使用码云作为远程仓库,git作为管理工具
指令 含义 git init 创建一个git隐藏文件夹 git add . 将当前文件夹下的所有文件放到缓存区 git commit -m "备注" 从缓存区放到本地仓库,写上备注 git push -u origin master 从本地仓库上传到远程仓库 git add test 指定上传的文件
python入门
-
python历史
-
python2和python3的区别
python2的源码不统一,出现重复代码
python3统一了源码,不会出现重复代码
-
python是什么编程语言
python是一款解释性语言,具有开发效率高的优点,缺点是运行速度慢
-
python的种类
- cpython官方
- jython java编写
- ironpython .net
- pypy python 可以提高运行速度
-
-
变量
-
变量的命名规则
- 变量名由字母,数字_下划线组成
- 不能使用python的关键字
- 不能以数字开头
- 不能使用拼音和汉字
- 注意区分大小写
- 变量名要具有可描述性,可辨识性
- 驼峰式命名(推荐下划线的方式)
-
一个变量名在一个内存中,只可能存在一个
-
-
常量
- python中没有常量的概念,以变量名全部大写来识别
-
注释
# 代表单行注释 ''' '''或者""" """代表多行注释也可以包裹多行字符串
-
基础数据类型
-
int类型
int数字类型,一般用来计算和比较
-
str字符串类型
字母数字汉字都可以作为字符串必须用引号包裹起来
-
bool类型
True为真或者1
False为假或者0
-
-
输入输出
-
输出print
print('helloworld')
-
输入input(用户交互程序)
name=input('请输入姓名:') print(type(name))#字符串 #input所接收获取到的内容都是字符串
-
-
if流程控制语句
- if else 二选一
- if elif elif 多个选择一个或者零个
- if elif elif else 多个选一个
- if if if 多选多或零
- if 嵌套 进行多层判断 一般if嵌套写三层就可以了
# 用来代表单行注释
"""
多行注释
多行注释
多行注释
多行注释
多行注释
"""
# print输出
print('hello world')
# input输入,可以赋值给变量
name = input('请输入')
print(name)
# input输入为字符串格式,想要输出其他类型,要进行格式转换
age = int(input('输入:'))
print(type(age))
# 常量,python常量用大写的变量名来表示
LUCKY = 'luckycoffee'
# 字符串拼接,字符串只能和字符串相加
a = 'lijie'
b = 'guobaoyuan'
print(a + b)
# 字符串相乘
print(a * 3)
# if elif else流程判断
# 需求,编写一个用户交互程序
name2 = input('亲输入用户名:')
age = int(input('亲输入年龄:'))
sex = input('亲输入性别:')
if name2 == '王五' and age > 25 and sex == '男':
print('可以去城中村洗脚了')
if 50 > age > 35:
print('还是回家歇着吧')
elif 35 > age > 25:
print('小心腰')
else:
print('年少轻狂')
elif name2 == '王五' and 18 < age < 25 and sex == '女':
print('洗脚很挣钱')
else:
print('你是个?')
第三章 基础
while循环
-
while循环条件控制
sam=1 while sam<10:# print(sam) sam=sam+1
-
while循环break终止循环
sum=1 while True: if sum == 10: break print(sum) sum=sum+1
-
while循环continue跳出本次循环
sum1 = 1 while sum1<10: if sum1 ==8: sum1=sum1+1 continue print(sum1) sum1=sum1+1
-
while else循环
sum = int(input('请选择输入0或1:')) while sum == True: name = input('亲输入用户名:') pwd = input('亲输入密码') if name == 'lijie' and pwd == '123456': print('登陆成功') break else: print('用户名或密码错误') else: print('退出成功'
for循环
-
for循环基本结构
for+空格+in+可迭代对象+冒号(#整型和布尔值不能进行循环) 缩进 循环体 for i in 'asdf':#i是变量名 pass#pass和...是占位符 print(i)#当在外围打印i时,值应该是for循环变量最后所获得的值
格式化输出
-
%s%d格式化输出
name='lijie' age=23 #在格式化的时候想要使用%可以用%%进行转义 print(('姓名:%s,年龄:%d')%(name,age))
-
format格式化输出
-
通过顺序来传递参数
print(('{1},{0},{1}').format('boy','girl'))
-
通过变量名来传递参数
print(('{name}:{url}').format(name='python',url='www.python.org'))
-
通过字典来传递参数
dict={'name':'boy','sex':'男'} print(('{name},{sex}').format(**dict))
-
通过列表来传递参数
list=['boy','男','25'] list1=['哈哈','呵呵'] print(('{0[0]},{0[1]},{0[1]}').format(list,list1)
-
-
python3.6以上新增f方法
name='lijie' age=3 s=f'姓名:{name},年龄:{age}' print(s)
编码初识
-
ascii 不支持中文
-
gbk 中文2个字节,英文1个字节
-
unicode 中文4个字节,英文2个字节
-
utf-8 中文3个字节,欧洲2个字节,英文1个字节
-
# 编码:将文字转换成字节形式 encode # 解码:将字节转换成文字形式 decode
运算符
比较运算符 | > < >= <= == != |
---|---|
赋值运算符 | += -= *= /= //= **= %= |
成员运算符 | in not in |
逻辑运算符 | and or not |
算法运算符 | + - * / ** % // |
python数据类型
-
**数据类型转换 **
str转换int
a=int('33') print(a)#结果33#只有要转换的字符串是数字的时候才能转换
int转换str
n=str(56) print(n)#结果"56"
bool转换str
bool值不为空就是True,空就是False b=str(True) print(b)#结果true
bool转换int
b=int(True) print(b)#结果1
-
进制转换
-
十进制转换二进制
bin(23)#十进制转换二进制 十进制转换由下往上数
-
二进制转换十进制
int('1011',2)#要转换的十进制要用引号引起来,从右往左数
-
-
str字符串类型
-
字符串切片
# name = "今天是个好日子" # 0 1 2 3 4 5 6 #-7-6-5-4-3-2-1 # a = name[0] # b = name[1] # print(a+b) # 切片 # print(name[0:2]) # 顾头不顾尾 name[起始位置:终止位置] # print(name[:]) # 某个位置不指定的时候默认取最后或最前 # print(name[2:5]) # print(name[-2:-5]) # print(name[-2:-5:-1]) # [起始位置:终止位置:步长] 步长默认为1
-
字符串方法
upper()#将字符串全部大写 lower()#将字符串全部小写 startswith()#判断以什么开头,可以指定范围 endswith()#判断以什么结尾,可以指定范围 strip()#去除空格换行制表符,可以指定去除的字符 replace()#替换,可以指定次数 isalnum()#判断是不是数字字母汉字组成 isdigit()#判断是不是阿拉伯数字 isalpha()#判断是不是字母和汉字 isdecimal()#判断是不是十进制 len()#获取字符串的长度 split()#以空格换行制表符分割,可以指定分割符和次数 rsplit() #从右边开始分割 count()#获取字符出现的次数 find()#查找字符在字符串中出现的次数,可以指定开始与结束,有返回索引,否则返回-1 index()#与find一样,但是如果找不到就报错 capitalize()#把字符串的首字母大写 '_'.join(s)#使用指定的字符吧字符串的每个字符分割 casefold()#与lower一样,但是lower只对ascii由效 format()#格式化输出,用{}表示 center()#返回字符串居中,空格填充的指定长度的字符串 decode()#以指定的编码格式进行解码 encode()#以指定格式进行编码,二进制 expandtabs()#将字符串中的tab键转换成空格,默认为8个 isidentifier()#判断是不是有效的puthon标识符 isspace()#判断字符串中是不是值只包含空格 isnumeric()#判读字符串是不是只包含数字字符 isprinttable()#判断是不是都是可打印的字符或字符串,可以用来查看是不是包含转义符 ljust()#与center相似,字符串左对齐,空格补充至指定长度 rjust()#与ljust相反 partition()#与split相似,但是分割后分割字符保留,返回三元字符串 splitlines()#以换行符进行分割,返回分割后的列表 swapcase()#对字符串中的大小写进行反转
-
-
列表
-
元祖的表现形式是[ ]的形式:lst=['你好','哈哈']
-
列表是一个有序的,可变的数据类型,支持多种数据类型
-
列表的增删改查
#增 lst.append('哈哈')#在列表最后添加一位 lst.insert(0,'啊啊')#指定索引添加,后面的元素后移 lst.extend('今天下雨了')#将字符串的每个元素分别添加到列表中,迭代增加 #删 lst.pop(0)#默认删除最后一位,可以指定索引删除,删除后讲删除的值返回, lst.remove('哈哈')#指定元素删除,在有重命名的情况下,删除一个 lst.clear()#清除 del list[0] del list[0:5:2]#看可以使用下标,步长进行删除 #改 list[0]='呵呵'#通过赋值直接更改 list[0:3]='1232456'#元素可以超出切片的位数 list[0:4:2]='12'#元素与位置一一对应,不能多也不能少 #查 for i in lst: print(i)#用for循环遍历 count()#次数 sort(rever=False)#排序 reverce()#反转
-
列表的嵌套
lst=['你好',['哈哈',['呵呵']]#可以通过索引切片一层一层查找
-
-
元祖
-
元祖的表现形式是( )的形式:tu=('你好','哈哈')
-
元祖是不可变的,用来存储一些重要数据
-
可以通过切片,索引和for循环来查找,不能增删改
-
-
range
-
range的特性是顾头不顾尾
-
python2和python3中的区别
print(range(0,10)) #python2中直接返回列表,xrange()和python3中的range相似 #python3中作为迭代对象,怎么写就怎么打印,可以使用list()进行转换
-
range的语法
range(0,10)#起始位置和终止位置,起始位置是0时可以默认不写 range(10,1,-1)#也可以从大到小生成数据, range(1,100,2)#也可以用来生成奇数和偶数等
-
常见的问题
# lst = [] # for i in lst: # lst.append("alex") # print(lst) # 不会打印内容 因为lst是空的 # lst = [1,2] # for i in lst: # lst.append("alex") # print(lst) # 循环打印lst中的内容 -- 此循环是死循环 # lst = [1,2] # for i in lst: # lst.append("alex") # print(lst) # 死循环 -- 不会打印内容 # lst = [] # for i in range(5): # lst.append([]) # print(lst) # [[],[],[],[],[]] # lst = [1,2] # lst[0] = lst # print(lst) # [[...],2]
-
-
字典
-
字典是可变的,无序的
-
字典是由键值对构成,键必须是不可变的数据类型且唯一,值可以是任意类型
-
字典的增,删,改,查
#增加 dic['name']='哈哈'#暴力添加 dic,setdefault('age',18)#不存在就添加,存在就不添加 #删除 dic.pop('name')#通过键来删除键值对,返回值:返回的是被删除的值 del dic['name']#通过键来删除键值对 dic,clear()#清空 修改 dic['name']='呵呵'#暴力修改 dic.update({'name':'卡卡卡'})#update括号内部的字典高于前面的字典 查找 for i in dic:#获取的是所有的键 dic.get('name')#通过get方法和键,来获取值,存在就返回,不存在就是空 #其他操作 dic.keys()#获取所有的键,是一个高仿列表,可以遍历,不可下标 dic.values()#获取所有的值,是一个高仿列表,可以遍历,不可下标 # Python 字典 values() 方法,Python 字典 values() 方法以列表形式(并非直接的列表,若要返回列表值还需调用list函数)返回字典中的所有值。 D = {'Sex': 'female', 'Age': 7, 'Name': 'Zara'} print ("字典所有值为 : ", D.values()) print ("转换为列表 : ", list(D.values())) >>>字典所有值为 : D_values(['Zara', 'female', 7]) >>>转换为列表 : ['Zara', 'female', 7] dic.items()#返回所有的键值,返回的是一个列表,键值对是元祖形式 diat=dic.fromkeys('123456',[2])#批量添加,值会共用 dic.popitem()#随机删除#3.6史默认删除最后一个
dic.values()和dic.keys()实际操作场景
a = [{341960: 'Completed'}, {341961: 'Completed'}, {341962: 'Completed'}, {341963: 'In Queue'}, {341964: 'In Queue'}, {341965: 'In Queue'}, {341966: 'In Queue'}, {341967: 'In Queue'}, {341968: 'In Queue'}, {341969: 'In Queue'}, {341970: 'In Queue'}, {341971: 'In Queue'}, {341972: 'In Queue'}, {341973: 'In Queue'}, {341974: 'In Queue'}, {341975: 'In Queue'}, {341976: 'In Queue'}, {341977: 'In Queue'}, {341978: 'In Queue'}, {341979: 'In Queue'}, {341980: 'Completed'}, {341981: 'Error'}, {341982: 'Error'}, {341983: 'Error'}, {341984: 'Error'}, {341985: 'Error'}, {341986: 'Error'}, {341987: 'Error'}, {341988: 'Error'}, {341989: 'Error'}, {341990: 'Error'}, {341991: 'Error'}, {341992: 'Error'}, {341993: 'Error'}, {341994: 'Error'}, {341995: 'Error'}, {341996: 'Error'}, {341997: 'Error'}, {341998: 'Error'}, {341999: 'Error'}, {342000: 'Error'}, {342001: 'Error'}, {342002: 'Error'}, {342003: 'Error'}, {342004: 'Error'}, {342005: 'Error'}, {342006: 'Error'}, {342007: 'Error'}, {342008: 'Error'}, {342009: 'Error'}, {342010: 'Error'}, {342011: 'Error'}, {342012: 'Error'}, {342013: 'Error'}, {342014: 'Error'}, {342015: 'Error'}, {342016: 'Error'}, {342017: 'Error'}, {342018: 'Error'}, {342019: 'Error'}, {342020: 'Error'}, {342021: 'Error'}, {342022: 'Error'}, {342023: 'Error'}, {342024: 'Error'}, {342025: 'Error'}, {342026: 'Error'}, {342027: 'Error'}, {342028: 'Error'}, {342029: 'Error'}, {342030: 'Error'}, {342031: 'Error'}, {342032: 'Error'}, {342033: 'Error'}, {342034: 'Error'}, {342035: 'Error'}, {342036: 'Error'}, {342037: 'Error'}, {342038: 'Error'}, {342039: 'Error'}, {342040: 'Error'}, {342041: 'Error'}, {342042: 'Error'}, {342043: 'Error'}, {342044: 'Error'}, {342045: 'Error'}, {342046: 'Error'}, {342047: 'Error'}, {342048: 'Error'}, {342049: 'Error'}, {342050: 'Error'}, {342051: 'Error'}, {342052: 'Error'}, {342053: 'In Queue'}, {342054: 'In Queue'}, {342055: 'In Queue'}, {342056: 'In Queue'}, {342057: 'In Queue'}, {342058: 'In Queue'}, {342059: 'In Queue'}, {342060: 'In Queue'}, {342061: 'Completed'}, {342062: 'Error'}, {342063: 'Error'}, {342064: 'Error'}, {342065: 'Error'}, {342066: 'Error'}, {342067: 'Error'}, {342068: 'Error'}, {342069: 'Error'}, {342070: 'Error'}, {342071: 'Error'}, {342072: 'Error'}, {342073: 'Error'}, {342074: 'Error'}, {342075: 'Error'}, {342076: 'Error'}, {342077: 'Error'}, {342078: 'Error'}, {342079: 'Error'}, {342080: 'Error'}, {342081: 'Error'}, {342082: 'Error'}, {342083: 'Error'}, {342084: 'Error'}, {342085: 'Error'}, {342086: 'Error'}, {342087: 'Error'}, {342088: 'Error'}, {342089: 'Error'}, {342090: 'Error'}, {342091: 'Error'}, {342092: 'Error'}, {342093: 'Error'}, {342094: 'Error'}, {342095: 'Error'}, {342096: 'Error'}, {342097: 'Error'}, {342098: 'Error'}, {342099: 'Error'}, {342100: 'Error'}, {342101: 'Error'}, {342102: 'Error'}, {342103: 'Error'}, {342104: 'Error'}, {342105: 'Error'}, {342106: 'Error'}, {342107: 'Error'}, {342108: 'Error'}, {342109: 'Error'}, {342110: 'Error'}, {342111: 'Error'}, {342112: 'Error'}, {342113: 'Error'}, {342114: 'Error'}, {342115: 'Error'}, {342116: 'Error'}, {342117: 'Error'}, {342118: 'Error'}, {342119: 'Error'}, {342120: 'Error'}, {342121: 'Error'}, {342122: 'Error'}, {342123: 'Error'}, {342124: 'Error'}, {342125: 'Error'}, {342126: 'Error'}, {342127: 'Error'}, {342128: 'Error'}, {342129: 'Error'}, {342130: 'Error'}, {342131: 'Error'}, {342132: 'Error'}, {342133: 'Error'}, {342134: 'Error'}, {342135: 'Error'}, {342136: 'Error'}, {342137: 'In Queue'}, {342138: 'Error'}, {342139: 'Error'}, {342140: 'Error'}, {342141: 'Error'}, {342142: 'Error'}, {342143: 'Error'}, {342144: 'Error'}] error = [] completed = [] Queue = [] def func(): for i in a: if list(i.values())[0] == 'Error': error.append(list(i.keys())) elif list(i.values())[0] == 'Completed': completed.append(list(i.keys())) elif list(i.values())[0] == 'In Queue': Queue.append(list(i.keys())) print("error:", len(error), error) print("completed:", len(completed), completed) print("Queue:", len(Queue), (Queue)) func() >>>error: 154 [[341981], [341982], [341983], [341984], [341985], [341986], [341987], [341988], [341989], [341990]........... >>>completed: 5 [[341960], [341961], [341962], [341980], [342061]] >>>Queue: 26 [[341963], [341964], [341965], [341966], [341967], [341968], [341969], [341970], [341971], [341972], [341973], [341974]..................
-
解构
# a,b = 10,12 # print(a) # print(b) # a = 10 # b = 20 # a,b = b,a # print(a,b) # a,b = [1,2] # print(a,b) # a,b = (3,4) # print(a,b) # a,_,b = (3,4,5) # print(a,b) # 等号后边的值和前面的变量名要一一对应 # a = 10,12 # 本质就是一个元组 # print(a) # a,b = "23" # print(a,b) # a,b = {"1":"a","2":"b"} # print(a,b) # for i in dic1.items(): # print(i) # for k,v in dic1.items(): # print(k,v) # 获取每个元素的键和值
-
字典的嵌套
dic = {1001:["周杰伦","林俊杰"], 1002:{"汪峰":{"前妻1":["大烧饼"],"前妻2":["熊大","熊二"],"国际章":"肉丝"}}, 1003:{"陈冠希":["阿娇","阿萨","张柏芝"]}, 1004:{"韦小宝":[{"教主夫人":["教主"]}, {"阿珂":"刺客"}, {"双儿":"天地会"}, {"爱心觉罗建宁":"公主"}, {"独臂神尼":{"韦小宝师父":{"兰陵王":"隐身"},"花木兰":[ "唧唧复唧唧","木兰是战士",{"爸爸":["花和尚"]}] }}, {"陈圆圆":"丈母娘"},{"穆建平":"小郡主"}]}, 1005:{"常鑫":["大黑哥","大烧饼","吃大煎饼","肉夹馍","自行车","井盖",]} } # print(dic) # print(dic[1004]["韦小宝"][0]["教主夫人"][0]) # print(dic[1005]["常鑫"][-1]) # print(dic[1002]["汪峰"]["前妻2"][-1]) # print(dic[1004]["韦小宝"][4]["独臂神尼"]["韦小宝师父"]["兰陵王"]) # print(dic[1004]["韦小宝"][4]["独臂神尼"]["花木兰"][2]["爸爸"][0])
-
-
set集合
-
集合是没有值的字典,是无序的,可变的,天然去重
-
集合的增删改查
#增加 add()#往集合中添加一个元素 update('你好呀')#迭代增加 #删除 pop()#随机删除一个 remove('哈哈')#指定元素删除 clear()#清空 #修改 集合在修改的时候是先删除再修改 #查找 使用for循环进行查找 set('HAHAH')#迭代添加
-
集合其他操作
& #交集 | #并集 - #差集 ^ #对称差集 > #父集 < #子集 forzenset()#冻结集合 注意: # lst = [1,2,1,2,4,2,45,3,2,45,2345,] # print(list(set(lst))) # s = {1,2,3,4}
-
-
数据类型总结
-
# 列表删除 -- 从后向前删除 # 创建一个新的列表,删除旧的列表 # 字典删除 -- 循环的时候不能改变源数据的大小 (可以改变值) # 创建一个新的字典,删除旧的字典 # 集合删除 -- 循环的时候不能改变源数据的大小
-
# python数据类型: # 可变: # list ,dict ,set # 不可变: # int bool str tuple # 有序: # list,tuple,str,int,bool # 无序: # dict,set # 取值方式: # 索引: str list tuple # 直接: set ,int ,bool # 键: dict
-
小数据池和深浅拷贝
-
小数据池
# 代码块:一个文件,一个函数,一个类,一个模块,终端中每一个行是一个代码块 # 支持: # 数字: # 在同一代码块下 只要内容相同就采用相同的内存地址(-5以后就不是) # 数字在做乘法的时候范围 -5 ~ 256 **** # 数字在做乘法的时候不能使用浮点数 # 字符串: # 在同一代码块下 只要内容相同就采用相同的内存地址 # 乘法的时候总长度不能超过20 **** # 乘法的时候中文,特殊符号乘以1或0 # 布尔值: # 在同一代码块下 只要内容相同就采用相同的内存地址 # 小数据池: # 数字: -5 ~ 256 **** # 字符串: # 在同一代码块下 只要内容相同就采用相同的内存地址 # 乘法的时候总长度不能超过20 **** # 乘法的时候中文,特殊符号乘以0 # 布尔值: # 在同一代码块下 只要内容相同就采用相同的内存地址 # 小数据池的验证方法,必须脱离代码块才能进行验证 # 先执行代码块的规则,在执行小数据的规则 --(驻留机制)
-
深浅拷贝
#赋值: # 多个变量名指向同一个内存地址 # 一个变量对其进行操作,其他变量查看时都变动 #浅拷贝: # lst[1:10] -- 是浅拷贝 # 浅拷贝只拷贝第一层元素 # 修改第一层元素是,新开辟的不进行改变 #深拷贝: # 不可变的数据类型共用,可变的数据类型重新开辟一个空间 # 对源数据进行修改,深拷贝的内容不进行改变
-
细谈浅拷贝
a = [1,2,3,4,['jerry','mark'],6,7] >>> a = [1,2,3,4,['jerry','mark'],6,7] >>> a.copy() [1, 2, 3, 4, ['jerry', 'mark'], 6, 7] # 这里复制一份给b >>> b = a.copy() # 查看b >>> b [1, 2, 3, 4, ['jerry', 'mark'], 6, 7] # 查看a >>>a a = [1, 2, 3, 4, ['jerry', 'mark'], 6, 7] # 这里来看是复制了一份出来,通过ID来查看它们的内存地址还是指向相同的位置。 # 然后再改b中的一个值,例如更改b[2]为'A',这里是动了copy中的第一次元素. >>> b[2] = 'A' >>> b [1, 2, 'A', 4, ['jerry', 'mark'], 6, 7] # 再次更改b[4]中的值,将b[4][1]的'mark'改为'刘亦菲'这里动了copy中的第二层元素(因为‘刘亦菲’和‘jerry’套在了一个列表中的列表). >>> b[4][1] = '刘亦菲' >>> b [1, 2, 'A', 4, ['jerry', '刘亦菲'], 6, 7] # 分别更改了copy b中的第一层元素和第二层元素后,再看a中列表元素的变化。 >>> a [1, 2, 3, 4, ['jerry', '刘亦菲'], 6, 7] # 基于上次的操作,我们分别改了copy b中的b[2]='A'和b[4][1]中的刘亦菲,为什么再看a的时候更改的b[2]='A'对其(第一次元素)没有任何影响呢?反而观之b[4][1]中的‘mark'却变成了'刘亦菲'了呢? # 其实真相只有一个,我们可以通过id去查看其中的内存地址。 b中元素未修改的内存地址与a进行比较: >>> id(a[0]) 140728784914080 >>> id(b[0]) 140728784914080 b中元素修改后的内存地址与a进行比较: >>> id(a[2]) 140728784914144 >>> id(b[2]) 2072055866096 b中元素修改后的内存地址与a进行比较: >>> id(a[4]) 2072056767616 >>> id(b[4]) 2072056767616 浅拷贝我们得出的结论和真相就是: 使用浅拷贝的时候,如果copy后的变量在第一层元素中进行修改那么原数据的内存地址和修改后的内存地址指向不同(等于说是copy的元素重新开辟了新的内存地址,讲元素指向了新的内存地址)。 现象是:原数据不变,copy后的数据做了修改。 其次则是第二层元素的解答:如果copy后的变量在第二层元素中进行修改那么原数据的内存地址(这里的原数据指的是第二层元素的整体,也就是说是第二层列表的内存地址)不会改变,但是第二层中整体内的修改部分的元素的内存地址会改变) 表现的现象是:copy b中的元素改变,a中的元素也随之改变。 也可以这样理解第二层元素,假定你有一个固定不变的户口本(相当于第二层列表),这个户口本属于中国民政局的(这里的民政局相当于最外层的大列表)。比如说你的名字叫'jerry'和原配'mark'是一对夫妻,这个时候你出国了,由于国外的需要所以你复制了一份户口本,但是到了国外你喜欢上了刘亦菲,直接拿着复制后的户口本将'mark'改为了'刘亦菲'。这个时候你的户口本依然存在中国民 政局,但是原配'mark'的住址改了先配'刘亦菲'的住址。所以主动权在你,只要你愿意更换妻子那么你原配的户口本上则会直接将其除名换成现配的妻子的名字以及住址。反之如果你原配妻子出了轨,直接将你改为'Tom'那么你的那个本也会随之更改。所以爱是双向奔赴的,有一个变了心整体在民政局的位置也会不会变化,变化的只有现役配偶的住址。
-
粗讲深拷贝
>>>a [1, 2, 3, 4, ['jerry', '刘亦菲'], 6, 7] >>> import copy >>> c = copy.deepcopy(a) >>> c [1, 2, 3, 4, ['jerry', '刘亦菲'], 6, 7] >>> a [1, 2, 3, 4, ['jerry', '刘亦菲'], 6, 7] >>> b [1, 2, 'A', 4, ['jerry', '刘亦菲'], 6, 7] >>> a[4][1] = '佟丽娅' >>> a [1, 2, 3, 4, ['jerry', '佟丽娅'], 6, 7] >>> c [1, 2, 3, 4, ['jerry', '刘亦菲'], 6, 7] >>> 整体复制一份到c, >>> id(a) 2072056767552 >>> id(c) 2072056799424 >>> deepcopy 出来就跟原数据没有任何关系了,一方改变则与原来的内存地址完全不同。
-
总结
#代码块: 一个文件,一个函数,一个类,一个模块,终端中每一行 # 数字: -5 ~ 256 # 字符串: 乘法时总长度不能超过20 # 布尔值: 内容相同内存地址相同 #小数据池: # 数字: -5 ~ 256 # 字符串: 乘法时总长度不能超过20 # 布尔值: 内容相同内存地址相同 #先执行代码块后执行小数据池 #== is # == 判断等号两边值是否相等 # is 判断两边的值内存地址是否相等 # 浅拷贝的时候只拷贝第一层元素 # 浅拷贝在修改第一层元素(不可变数据类型)的时候,拷贝出来的新列表不进行改变 # 浅拷贝在替换第一层元素(可变数据类型)的时候,拷贝出来的新列表不进行改变 # 浅拷贝在修改第一层元素中的元素(第二层)的时候,拷贝出来的新列表进行改变 # 深拷贝开辟一个容器空间(列表),不可变数据公用,可变数据数据类型(再次开辟一个新的空间) # ,空间里的值是不可变的数据进行共用的,可变的数据类型再次开辟空间
文件操作
-
文件操作
#文件操作 # open---打开文件 # file---文件路径 # mode---文件操作模式 # encoding---文件编码集
-
文件操作模式
#r,w,a: # r:读模式 # read()读取全部内容 # read(3)r,w,a模式下为为字符 # readline()读取一行 # readlines()一行一行读取,保存在一个列表中 # w:写模式,先清空,后写 # write()只能写入字符串 # a:追加写模式: # 不管光标怎么移动都是在文件末尾进行追加写 ------------------------------------------------ #rb,wb,ab(字节模式,不用选择编码格式) # rb:读取字节模式 # read(3)rb,wb,ab模式下读取的字节, # wb:清空写(字节) # write()先清空,后写入 #----------------------------------------------- #r+,w+,a+ # r+(读写)一定要先读后写 # w+(写读)先清空,再写,后读 # a+(追加,读)在文件末尾追加,读的时候为空要移动光标
-
其他操作
#tell()查看光标的位置,返回的是字节的位置 #seek(): # seek(0,0)移动到文件的开头位置 # seek(0,1)光标的当前位置 # seek(0,2)移动到文件的末尾 # seek(3)#按照字节进行移动,字节计算按照编码进行计算 ------------------------------------------- with open(文件操作名,模式,编码)as f: 操作 with open的好处: 1.可以同时打开多个文件 2.能够自动关闭文件 ------------------------------------------- 修改文件内容: 1.创建一个新的文件 2.将文件中的内容进行替换 3.替换后的内容写入新文件中 4.改变文件名 路径: 绝对路径: 从磁盘根部进行查找 相对路径: ../返回上一级 --推荐使用 转义: 1."C:\\user\\ner" 2. r"C:\user\ner" -- 推荐使用
第四章 函数
函数初识
-
函数的基本结构
def 关键字--定义函数 func 函数名和变量的命名规则一样 () 格式,用来船体参数, :申明函数定义语句的结束 def func(): print('哈啊哈')#函数体 func()#调用函数
-
函数的返回值
return 返回值 return的内容返回给了函数的调用 return下方的代码不执行,终止这个函数 return 返回多个内容的时候还是元组形式 return 没有写返回值的时候返回的是None,不写return返回None def yue(): print("打开手机") print("打开微信") return 111 print("找到女友") print("晚上约吗") return "萝莉小姐姐","大妈","人妖" # return 返回 print("确实有点累") print(yue()) # 111 print(1234) ========================================= lst = [1,2,3,4,5] def func(): for i in lst: print(i) lst.append(input(">>>")) return lst
-
函数的参数
1:位置参数 def yue(a,b,c): # 形参 print("打开手机") print(f"打开{a},{c},{b}") print("附近的人") print("找个妹子") print("聊一聊") yue(True,(12,4,3),[1,2,3,4]) # 实参 2:默认参数 def userinfo(name,age,sex="男"): # 位置参数 > 默认参数 print(name,sex,age) count = 5 while count: name = input("name:") sex = input("sex(男性直接回车!):") age = input("age:") if sex == "女": userinfo(name,age,sex) else: userinfo(name, age) count -= 1 3:关键字参数: def func(a,c,b=1): # a,c位置参数 ,b=1 是默认参数 print(a,b,c) func(a=1,b=5,c=2) # a=1,b=5,c=2 是关键字参数 4:混合参数 def func(a,b,c): print(a,b,c) func(1,2,c=5) # 混合参数 ************************************************************** # 形参: 函数的定义中括号里是形参 # 实参: 函数的调用括号里是实参 # 位置传参时 形参和实参必须一一对应 # 传参: 将实参传递给形参的过程就是传参 # 函数的参数: # 形参: 函数定义的时候叫做形参 # 位置参数 # 默认参数 # 混合参数 # 实参: 函数调用的时候叫做实参 # 位置参数 # 关键字参数 # 混合参数 # 传参: 将实参传递给形参的过程叫做传参
函数的动态参数
#*args动态位置参数
def func(a,b,*args):#*args是万能的位置参数,*在函数定义的时候叫聚合
print(a,b,args)#接收的是元祖形式
def func(a,b,*args):
print(a,b*args)#*args在函数内部是打散的意思
位置参数>动态位置参数>默认参数
-------------------------------------------------
#**kwargs动态关键字参数
def func(a,b,**kwargs):#**kwargs接受的是关键字,字典的格式
print(a,b,kwargs)#字典的格式
def func(a,b,kwargs):
print(a,b,*kwargs)#*kwargs获取到的是字典的键
位置参数>动态位置参数>默认参数(关键字参数)>动态关键字参数
-------------------------------------------------
*args,**kwargs万能参数
def func(*args,**kwargs):
print(args,kwargs)
函数的注释
def func1(user,password):
"""
密码加密
:param user: 用户名 str
:param password: 密码 str
:return: 加密的密码 MD5
"""
print(user,password)
print(func.__doc__)#可以查看函数的注释
名称空间
-
命名空间
在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了, 至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空.
-
命名空间分类
命名空间分类: 1. 全局命名空间--> 我们直接在py文件中, 函数外声明的变量都属于全局命名空间 2. 局部命名空间--> 在函数中声明的变量会放在局部命名空间 3. 内置命名空间--> 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间
-
加载的顺序
#内置空间>全局空间>局部空间
-
取值的顺序
#局部空间>全局空间>内置空间
-
作用域
#全局作用域: 内置空间+全局空间 #局部作用域 局部空间
函数的嵌套
# 函数中套函数
# def func():
# a = 1
# def foo():
# b = 2
# print(b) # 2
# print(a) # 1
# def f1():
# print(b) # 2
# return f1()
# return foo()
# print(func())
------------------------------------
# 函数嵌套调用
# def func():
# a = 1
# foo()
# print(a)
#
# def foo():
# b = 2
# print(b)
# func()
-------------------------------------
# 函数嵌套参数的传递
# def func(a):
# foo(a) #10
#
# def foo(e):
# b(e) # return 10
#
# def b(c):
# print(c)
# return 10
#
# print(func(5))
-------------------------------------
# 函数嵌套返回值的传递
# def func(a):
# foo(a) #10
# return 10
# def foo(e):
# b(e)
# return 10
# def b(c):
# print(c)
# return 10
#
# print(func(5))
global和nonlacal
#global修改变量的值
# def func():
# global a # 声明修改全局变量的值
# a += 1
# print(a)
# func()
# print(a)
---------------------------------------------
#nonlocal在外层的函数中,修改局部空间的变量值.完全不涉及全局变量,
#只修改离它最近的一层,最近的一层没有变量继续向上找,直到找到最外层函数
函数名的使用
-
函数名可以当作值赋值给一个对象
def func(): print('哈哈') s=func s()
-
函数名可以当作元素存放在容器中
def func(): print('哈哈') lst=[func,func,func] for i in lst: i()
-
函数名可以当作另一个函数的参数
def func(f): f() def foo(): print('呵呵') func(foo)
-
函数名可以当作函数的返回值
def func(): print('啊哈哈') def foo(): print('呵呵') return foo func()
python3.6 f-string
#可以填充字符串
s=f"{'haha'}"
#可以填充变量
s1=f'{s}'
#可以填充计算公式
s2=f"{35+35}"
#可以填充表达式
s3=f"{a if 2>3 else b}"#三元表达式
#可以填充大括号
s4=f"{{{{1}}}}"#逢二取一
迭代器
-
#list,dict,tuple,str,set都是可迭代对象,优点是可以灵活使用,可以直接查值,缺点是:消耗内存,不能迭代取值 #__iter__()可以查看是不是一个可迭代对象 #dir(list)#可以查看数据类型的所有的方法 #同时拥有__iter__()和__next__()方法的就是一个迭代器 #迭代器的优点是:节省内存,惰性机制(调用一次,取一次值) #缺点是:不灵活,不能查看全部的值,比较繁琐 #迭代器的特性是: # 一次性使用,不能逆行取值,惰性机制节约内存 #当容器中的数据量较大时,可以使用迭代器
-
##具有__iter__()方法的都是可迭代的对象 # lst=[1,2,3,4,5,6,7,8,9] # new_lst=lst.__iter__()#可以将迭代对象转换成迭代器 #__next__()方法可以取值,每次取一个,无法回退, # print(new_lst.__next__()) # print(new_lst.__next__()) # print(new_lst.__next__()) # print(new_lst.__next__()) # print(new_lst.__next__()) # print(new_lst.__next__()) # print(new_lst.__next__()) # print(new_lst.__next__()) # print(new_lst.__next__())
for 循环的本质
lst=[1,2,3,4,56,7,89]
new_lst=lst.__iter__()
while True:
try:
print(new_lst.__next__())
except ExceptIteration
break
递归函数
#递归函数的特性
#1:函数自己调用自己(不断调用自己本身)
#2:有明确的结束条件
#递:函数一直执行到条件结束
#归:从结束条件返回
-------------------------------
def func(age):
if age==4:
return 18
else:
return func(age+1)-2
print(func(1))
生成器
-
什么是生成器
#迭代器是python自带的一种节省空间的工具 #生成器的本质就是一个迭代器 #迭代器和生成器的区别是,一个是python自带的,一个是我们自己写的
-
生成器的定义
def func(): print(1) yield '哈哈' print(2) yield '呵呵' g=func()#产生一个生成器 print(next(g))#一个__next__()对应一个yield for i in g:#生成器可以使用for循环遍历 print(i) --------------------------------------- print(func().__next__())#这种会不段产生新的生成器,这是 坑 坑 坑
-
生成器的使用场景
def func(): lst=[] for i in range(1000000): yield i g=func() foe i in range(50): print(next(g)) #当数据量过大时,可以使用生成器来节省空间
-
生成器的总结
#在函数中将return改成yield就是一个生成器 #yield会记录执行的位置,yield和return都是返回的意思 #return可以写多个,都是只能执行一个,yield可以写多个,还可以返回多次 #一个__next__()方法和一个yield一一对应,反则会报错 #生成器可以使用for循环进行遍历,获取值 #yield from可以将可迭代对象的元素逐个返回 #在函数的内部,可以使用yield将while和for循环暂时暂停
推导式
-
列表推导式
#循环模式 print([i for i in [1,2,3,4,5,6,7]]) #筛选模式 print([i+1 for i in [1,2,3,4,56,7,8,9] if i % 2==0]) #[变量(加工后的变量) for循环 加工方式]
-
字典推导式
#循环模式 print({i:i+1 for i in range(20)}) #筛选模式 print(i:i+1 for i in range(20) if i % 2==0) #{键:值 for循环 加工条件}
-
集合推导式
#循环模式 print({i for i in [1,2,3,4,6,7,9]}) #筛选模式 print({i+1 for i in range(20) if i %2==0}) #{变量(加工后的变量) for循环 加工条件}
-
生成器表达式
#循环模式 g=(i for i in range(20)) print(next(g)) #筛选模式 g=(i for i in range(20) if i %2==0) print(next(g)) print(list((i for i in range(20))))#list()方法内部有循环取值 #(变量(加工后的变量 for循环 加工条件))
内置函数一
内置函数 | 函数的意思 |
---|---|
all() | all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。 |
any() | any() 函数用于判断给定的可迭代参数 iterable 是否全部为 False,则返回 False,如果有一个为 True,则返回 True |
bytes() | bytes 函数返回一个新的 bytes 对象,该对象是一个 0 <= x < 256 区间内的整数不可变序列。它是 bytearray 的不可变版本 |
callable() | callable() 函数用于检查一个对象是否是可调用的。如果返回 True,object 仍然可能调用失败;但如果返回 False,调用对象 object 绝对不会成功。 |
chr() | chr() 用一个范围在 range(256)内的(就是0~255)整数作参数,返回一个对应的字符,返回值是当前整数对应的 ASCII 字符。 |
complex() | complex() 函数用于创建一个值为 real + imag * j 的复数或者转化一个字符串或数为复数。如果第一个参数为字符串,则不需要指定第二个参数。 |
divmod() | python divmod() 函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。 |
eval() | eval() 函数用来执行一个字符串表达式,并返回表达式的值。 |
exec() | exec 执行储存在字符串或文件中的Python语句,相比于 eval,exec可以执行更复杂的 Python 代码。 |
frozenset() | frozenset() 返回一个冻结的集合,冻结后集合不能再添加或删除任何元素。 |
globals() | globals() 函数会以字典类型返回当前位置的全部全局变量。 |
hash() | hash() 用于获取取一个对象(字符串或者数值等)的哈希值。 |
help() | help() 函数用于查看函数或模块用途的详细说明 |
id() | id() 函数用于获取对象的内存地址。 |
input() | 输入,获取到的是字符串类型 |
int() | 整数类型 |
iter() | iter() 函数用来生成迭代器。 |
locals() | locals() 函数会以字典类型返回当前位置的全部局部变量。对于函数, 方法, lambda 函式, 类, 以及实现了 call 方法的类实例, 它都返回 True。 |
next() | next() 返回迭代器的下一个项目。 |
oct() | oct() 函数将一个整数转换成8进制字符串。 |
ord() | ord() 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值,如果所给的 Unicode 字符超出了你的 Python 定义范围,则会引发一个 TypeError 的异常。 |
pow() | pow() 方法返回 xy(x的y次方) 的值 |
repr() | repr() 函数将对象转化为供解释器读取的形式。 |
round() | ound() 方法返回浮点数x的四舍五入值。 |
内置函数二
函数名 | 函数的意思 |
---|---|
dir() | 查看函数的所有方法 |
abs() | 绝对值,返回的是正数 |
enumerate() | 枚举,(''可迭代对象'','序号的起始值'),默认起始值为0 |
zip() | 拉链,数据合并,按照最小的进行合并,返回的是个对象的内存地址 list(zip("可迭代对象","可迭代对象")) 返回的是[(1,2),(2,3)] |
min() | 求最小值,key是比较的方法 min("可迭代对象",key=abs) #key指定查找最小值时的规则 |
max() | 求最大值,key是比较的方法 max("可迭代对象",key=abs) #key指定查找最大值时的规则 |
sum() | 求和 sum(list,tuple,set) |
range()和2.7xrange() | 获取的是一个可迭代对象,2.7中range获取的是一个列表 |
print() | 打印,sep元素之间的连接符,end是末尾的换行符 |
list() | 转换成列表类型,自带循环 |
dict() | 转换成字典类型,数据格式为dict=((1,2),(2,3)) |
format | '<'左对齐'>'右对齐^居中,,,,b,d,o,x进制转换,08八位显示 |
bin() | 十进制转换二进制 |
filter(过滤函数,迭代对象) | 过滤,获取的是一个内存地址 filter("函数名","可迭代对象") 写函数的时候可以指定过滤条件 |
map() | 映射对象, map("函数名","可迭代对象") 写函数的时候可以指定对元素的操作 |
reversed | 反转,获取的是一个可迭代对象 reversed("可迭代对象") # 对可迭代对象进行翻转(不改变源数据) |
sorted | 对数据进行排序,key指的是排序的规则 sorted("可迭代对象",key="函数名",reverse=True) key是指定排序的规则(默认是升序)写了reverse=True就是降序 |
reduce (from functools import reduce) | 累计算,根据计算的函数的条件进行计算 reduce("函数","可迭代对象") # 函数指定累计算的方式 (from functools import reduce) |
lambda匿名函数
lambda是一个定义函数的关键字,必须有返回值,没有也要写None,只能返回一个数据类型,形参可以不写
# f = lambda x,y:(x,y)
# print(f(1,2))
# print(f.__name__)
# print((lambda x:x)(2)) # 同一行定义 同一行调用
# lst = [lambda i:i*i for i in range(10)](面试)
# print(lst[2](2))
# lst = [lambda :i*i for i in range(10)](面试)
# print(lst[2]())
---------------------------------
# lst = list((lambda i:i*i for i in range(5)))
# print(lst[1](4))
# lst = [x for x in (lambda :i**i for i in range(5))]
# print(lst[2]())
#解构
# lst1 = []
# def func():
# for i in range(5):
# def foo():
# return i**i
# yield foo
#
# for x in func():
# lst1.append(x)
# print(lst1[2]())
闭包
在嵌套函数内,使用非全局变量(且不是本层变量) -- 就是闭包
__closure__ 判断是否是闭包
闭包的作用
1. 保证数据的安全性
2. 装饰器的本质
# print(ret.__code__.co_freevars) # 获取的是自由变量
# print(ret.__code__.co_varnames) # 获取的是局部变量
---------------------------------
# def func():
# avg_lst = [] # 自由变量
# def foo(pirce):
# avg_lst.append(pirce)
# avg = sum(avg_lst) / len(avg_lst)
# return avg
# return foo
# ret = func()
装饰器
- 装饰器的运行截图
通用装饰器写法
# 通用装饰器的写法:
def wrapper(fn): # wrapper: 装饰器 fn:目标函数
def inner(*args, **kwargs):
# 在目标函数之前........
ret = fn(*args, **kwargs) # 执行目标函数
# 在目标函数之后.........
return inner # 别加()
@wrapper
def target():
pass
target() # => inner()
加糖装饰器
def guanjia(game):
def inner():
print('开挂')
game()
print('关闭外挂')
return inner
@guanjia # 这个去掉用注释的两行用起来即可。
def play_dnf():
print('打开dnf')
@guanjia # 这个去掉用注释的两行用起来即可。
def play_lol():
print('打开lol')
#
# play_dnf = guanjia(play_dnf)
# play_dnf()
play_dnf()
play_lol()
- 有参装饰器
- 作用:有参装饰其是解决相似功能的装饰器出现两次
- 比标准版的多了两步
def guanjia(game):
def inner(*args, **kwargs):
print('开挂')
game(*args, **kwargs)
print('关闭外挂')
return inner
@guanjia
def play_dnf(username, password):
print('要开始玩dnf了.', username, password)
print('打开dnf')
@guanjia
def play_lol(username, password, hero):
print('要开始玩lol了.', username, password, hero)
print('打开lol')
#
# play_dnf = guanjia(play_dnf)
# play_dnf()
play_dnf('admin', '1234')
play_lol('admin', '1234','锤石')
- 有参装饰器在解决相似功能的例子
def guanjia(game):
def inner(*args, **kwargs):
print('开挂')
ret = game(*args, **kwargs)
print('关闭外挂')
return ret
return inner
@guanjia
def play_dnf(username, password):
print('要开始玩dnf了.', username, password)
print('打开dnf')
return '一把屠龙刀'
@guanjia
def play_lol(username, password, hero):
print('要开始玩lol了.', username, password, hero)
print('打开lol')
#
# play_dnf = guanjia(play_dnf)
# play_dnf()
ret = play_dnf('admin', '1234')
print(ret)
play_lol('admin', '1234','锤石')
一个目标函数被多个装饰器装饰
def wrapper1(fn):
def inner(*args, **kwargs):
print('这里是wrapper1 进入')
ret = fn(*args, **kwargs)
print('这里是wrapper1 出去')
return ret
return inner
def wrapper2(fn): # fn:target
def inner(*args, **kwargs):
print('这里是wrapper2 进入')
ret = fn(*args, **kwargs)
print('这里是wrapper2 出去')
return ret
return inner
@wrapper1 # target = wrapper2(target)
@wrapper2 # wrapper2先套的即: target = wrapper2(target) => target:wrapper2 →inner
def target():
print('目标函数')
target()
# 得出的结论
"""
这里是wrapper1 进入
这里是wrapper2 进入 →包裹
目标函数
这里是wrapper2 出去 →包裹
这里是wrapper1 出去
"""
- 练习装饰器
装饰器登录校验使用
login_status = False # 给其状态避免重复校验,这个东西后续的话会放在浏览器上或者服务器上都行.
def login_verify(fn):
def inner(*args, **kwargs):
global login_status
if login_status == False:
# 这里完成登录校验的工作
print("还未完成用户登录操作")
while 1:
username = input('>>>>>')
password = input('>>>>>')
if username == "admin" and password == '123':
print('登录成功')
login_status = True
break
else:
print('登录失败,用户名或密码错误')
print('123456')
ret = fn(*args, **kwargs) # 后续执行程序
return ret
return inner
@login_verify
def add():
print('添加员工信息')
@login_verify
def delete():
print('删除员工信息')
def update():
print('更新员工信息')
def search():
print('查找员工信息')
add()
delete()
update()
search()
-
装饰器的规则
# 开放封闭原则: # 扩展是开放的(增加新功能) # 修改源码是封闭(修改已经实现的功能) # 在不改变源代码及调用方式的基础下额外增加新的功能 # 装饰器:用来装饰的工具
-
# 版一: import time # start_time = time.time() # def func(): # time.sleep(2) #睡眠 (模拟网络延时) # print("我要飞") # func() # print(time.time() - start_time) # start_time = time.time() # def foo(): # time.sleep(3) #睡眠 (模拟网络延时) # print("我是小明,我飞的比你高") # foo() # print(time.time() - start_time) -------------------------------------------------- # 版二: # def times(f): # start_time = time.time() # f() # print(time.time() - start_time) # def foo(): # time.sleep(3) #睡眠 (模拟网络延时) # print("我是小明,我飞的比你高") # def func(): # time.sleep(1) #睡眠 (模拟网络延时) # print("我是业儿,我起不来") # s = func # func = times # s = foo # foo = times # foo(s) ---------------------------------------------------- # 版三(初识版装饰器): # def times(f): # def inner(): # start_time = time.time() # f() # print(time.time() - start_time) # return inner # def foo(): # time.sleep(1) #睡眠 (模拟网络延时) # print("我是李业,我快!") # foo = times(foo) # foo() -------------------------------------------------- import time # def wrapper(f): # def inner(*args,**kwargs): # "被装饰前" # start_time = time.time() # f(*args,**kwargs) # func("alex") # print(time.time() - start_time) # "被装饰后" # return inner # 切记不要加括号 # # # def func(*args,**kwargs): # print(f"这是{args}函数,李业还是不行") # time.sleep(2) #模拟网络延时 # # # func = wrapper(func) # func("alex","sur") ---------------------------------------------------- # import time # def wrapper(f): # def inner(*args,**kwargs): # "被装饰前" # start_time = time.time() # f(*args,**kwargs) # func("alex") # print(time.time() - start_time) # "被装饰后" # return inner # 切记不要加括号 # # @wrapper # func = wrapper(func) # def func(*args,**kwargs): # print(f"这是{args}函数,李业还是不行") # time.sleep(2) #模拟网络延时 # # @wrapper # foo = wrapper(foo) # def foo(*args,**kwargs): # print(f"这是{args}函数,常鑫穿齐*小短裤") # time.sleep(3) #模拟网络延时 # func = wrapper(func) # foo = wrapper(foo) # func("alex","sur") # foo("alex","sur") ---------------------------------------------------
-
语法糖 # 语法糖 -- 甜 # 语法糖必须放在被装饰的函数正上方 import time # def wrapper(f): # def inner(*args,**kwargs): # "被装饰前" # start_time = time.time() # ret = f(*args,**kwargs) # func("alex") # print(time.time() - start_time) # "被装饰后" # return ret # return inner # 切记不要加括号 # # @wrapper # func = wrapper(func) # def func(*args,**kwargs): # print(f"这是{args}函数,李业还是不行") # time.sleep(2) #模拟网络延时 # return "alex" # print(func())
-
标准版装饰器 # 标准版(装饰器): # def func(a): #a是要被装饰的函数名 # def foo(*args,**kwargs): # "装饰之前的操作" # ret = a(*args,**kwargs) # "装饰之后的操作" # return ret # return foo # @func # def f1(*args,**kwargs): # print(f"这是一个{args}") # return "我可以返回了" # f1(1,2,3,34,4,5)
带参数的装饰器
在装饰器的基础上再套一层
login_dic = {
"username": None,
"flag": False
}
# 正确的案例
msg = """
QQ
微信
抖音
邮箱
请输入您要选择登陆的app:
"""
chose = input(msg).upper()
def auth(argv):
def wrapper(func):
def inner(*args,**kwargs):
if login_dic["flag"]:
func(*args,**kwargs)
else:
if argv == "QQ":
print("欢迎登陆QQ")
user = input("username:")
pwd = input("password:")
if user == "alex" and pwd == "alex123": # qq
login_dic["flag"] = True
login_dic["username"] = user
func(*args,**kwargs)
else:
print("用户名或密码错误!")
elif argv == "微信":
print("欢迎登陆微信")
user = input("username:")
pwd = input("password:")
if user == "1351101501" and pwd == "alex": # 微信
login_dic["flag"] = True
login_dic["username"] = user
func(*args, **kwargs)
else:
print("用户名或密码错误!")
elif argv == "抖音":
print("来了,老弟!")
user = input("username:")
pwd = input("password:")
if user == "alexdsb" and pwd == "alex": # 抖音
login_dic["flag"] = True
login_dic["username"] = user
func(*args, **kwargs)
else:
print("用户名或密码错误!")
else:
print("欢迎登陆dab邮箱")
user = input("username:")
pwd = input("password:")
if user == "alexdsb@dsb.com" and pwd == "alex": # 邮箱
login_dic["flag"] = True
login_dic["username"] = user
func(*args, **kwargs)
else:
print("用户名或密码错误!")
return inner
return wrapper
@auth("QQ")
def foo():
print("这是一个被装饰的函数")
# wrapper = auth(chose)
# foo = wrapper(foo)
foo()
"""
# @auth(chose) 相等于以下两行代码的解构
# wrapper = auth(chose)
# foo = wrapper(foo)
"""
多个装饰装饰一个函数
# 先执行离被装饰的函数最近的语法糖
# 小技巧:进入装饰器从上往下,走到最会一个装饰器执行被装饰的函数,退出装饰器从下往上走
# def wrapper1(func):
# def inner1(*args,**kwargs):
# print(1)
# func(*args,**kwargs)
# print(11)
# return inner1
#
# def wrapper2(func): # func == foo
# def inner2(*args,**kwargs):
# func(*args, **kwargs)
# print(22)
# return inner2
#
# def wrapper3(func):
# def inner3(*args,**kwargs):
# print(3)
# func(*args, **kwargs)
# print(33)
# return inner3
# @wrapper1 # 1 11
# @wrapper3 # 3 33
# @wrapper2 # 8 22
# def foo():
# print(8)
#foo()
第五章 模块
自定义模块
-
模块分类
#1.内置模块(标准库) -- python解释器自带的.py文件(模块) #2.第三方模块(各种大神写的) -- 需要额外下载的 (pypi) #3.自定义模块(自己写的) -- 不需要额外下载
-
模块的优点
#1:避免写重复代码 #2:可以多次利用 #3:拿来主义
-
模块导入及模块导入时发生的事情
import #导入(拿工具箱) #模块导入时,发生的事情: #1:当前的名称空间中开辟一个新的空间(模块) #2:将模块中所有的代码执行 #3:通过模块名,进行函数查找(工具) ------------------------------------ import time print(time.time()) ------------------------------------ #错误实例 import time.py print(time.py.time()) ------------------------------------
-
使用别名可以使模块名变短
import time as t print(t.time()) ------------------------------------- #使用别名也可以做一些模块的兼容性 # 做一兼容性 # choose = input(msg) # if choose == "1": # import meet # meet.func() # elif choose == "2": # import test # test.func() # # 做一兼容性 # choose = input(msg) # if choose == "1": # import meet as t # elif choose == "2": # import test as t # # t.func()
-
from调用方法
import和from的区别 import是直接吧工具箱拿过来 1:优点是不会和当前文件定义的变量或函数发生冲突 2:缺点是占用内存比较大 # import test # name = "宝元" # print(test.name) # print(name from 是导入模块中的一些函数或者变量,(直接拿工具) 1:优点是内存占用小 2:缺点是会和当前的文件定义的变量或者函数发生冲突 # from test import * 会出现覆盖的现象,不能解决 # name = "宝元" # from test import name # print(name) # 解决方法: # name = "宝元" # from test import name as n # print(name) # print(n)
-
__all__方法
# __all__ = ["可以被导入的函数名和变量名"]#在被导入的模块中使用
-
模块的两种用法
#1.脚本(在cmd中执行 python test.py) #2.模块(不使用或者导入)
-
main方法
# from test import * # if __name__ == '__main__': # 测试接口 # func() # 在当前模块中使用__name__ 就是 "__main__" # 当模块被导入的时候__name__就是被导入的模块名
-
导入路径
# import meet # print(meet.name) -------------------------------------------- # 使用相对路径: # from day15.t1 import meet # print(meet.name) ---------------------------------------- # 使用绝对路径: # 错误示例: # from r"D:\" import meet # from ../ ========================================== # 正确的绝对路径: # from sys import path # path.insert(0,"D:\\") # import meet # print(meet.name)
time模块
import time
print(time.time())#获取时间戳 浮点数
print(time.sleep(2))#睡眠,阻塞
print(time.strftime('%Y-%m-%d %H:%M:%S'))#时间显示格式,页面显示的格式
print(time.gmtime())#结构化时间,元祖的形式(命名元祖),可以根据索引和元素进行查找
time.struct_time(tm_year=2019, tm_mon=7, tm_mday=25, tm_hour=8, tm_min=10, tm_sec=50, tm_wday=3, tm_yday=206, tm_isdst=0)
#time.localtime获取的是当地时间
# print(time.gmtime()[0])
# print(time.gmtime().tm_year)
#将时间戳转换成字符串时间
print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime(1564028611.631374)))
#将字符串时间转换成时间戳
print(time.mktime(time.strptime("2024-3-16 12:30:30","%Y-%m-%d %H:%M:%S")))
---------------------------------------
重点:
# time重点:
# time.time()
# time.sleep()
# time.gmtime() / time.localtime() #
# time.strftime("格式化","结构化时间") #
# time.strptime("字符串","格式化")
# time.mktime()
****************************************************************
datatime模块
print(type(datetime.now()))获取当前时间,获取的是一个对象
print(datetime(2019,5,21,15,14,00) - datetime(2019,5,20,14,20,00))计算时间差
# 将当前时间转化成时间戳
# t = datetime.now()
# print(t.timestamp())
-----------------------------------------
# 将时间戳转化成当前时间
# import time
# print(datetime.fromtimestamp(15000000000))
-----------------------------------------------------
# 将字符串转成对象
# print(type(datetime.strptime("2019-10-10 22:23:24","%Y-%m-%d %H:%M:%S")))
-----------------------------------------------------
# 将对象转成字符串
# print(str(datetime.now()))
# print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
------------------------------------------------------
# datetime加减
# print(datetime.now() + timedelta(hours=30 * 24 * 12))
# print(datetime.now() - timedelta(hours=30 * 24 * 12))
***********************************************************
# datatime模块
import datetime
now_time = datetime.datetime.now() # 现在的时间
# 只能调整的字段:weeks days hours minutes seconds
print(datetime.datetime.now() + datetime.timedelta(weeks=3)) # 三周后
print(datetime.datetime.now() + datetime.timedelta(weeks=-3)) # 三周前
print(datetime.datetime.now() + datetime.timedelta(days=-3)) # 三天前
print(datetime.datetime.now() + datetime.timedelta(days=3)) # 三天后
print(datetime.datetime.now() + datetime.timedelta(hours=5)) # 5小时后
print(datetime.datetime.now() + datetime.timedelta(hours=-5)) # 5小时前
print(datetime.datetime.now() + datetime.timedelta(minutes=-15)) # 15分钟前
print(datetime.datetime.now() + datetime.timedelta(minutes=15)) # 15分钟后
print(datetime.datetime.now() + datetime.timedelta(seconds=-70)) # 70秒前
print(datetime.datetime.now() + datetime.timedelta(seconds=70)) # 70秒后
current_time = datetime.datetime.now()
# 可直接调整到指定的 年 月 日 时 分 秒 等
print(current_time.replace(year=1977)) # 直接调整到1977年
print(current_time.replace(month=1)) # 直接调整到1月份
print(current_time.replace(year=1989,month=4,day=25)) # 1989-04-25 18:49:05.898601
# 将时间戳转化成时间
print(datetime.fromtimestamp(1232132131)) # 2009-01-17
random模块
print(random.random())#在0~1之间随机生成一个浮点数
print(random.uniform(0,10))#在0~10时间随机生成一个浮点数,可以指定范围
print(random.randint(1,10))#随机生成一个整数,可以指定范围
print(random.randrange(1,5,2))#起始终止步长,生成一个数字
print(random.chioce([1,2,3,4,5,6]))#随机选择一个元素
print(random.chioces([1,2,3,4,5,6,7]),k=2)#随机选择两个元素,会有重复的
print(random.sample((1,2,3,4,5,6,7,8)),k=2)#随机选择两个元素,不会有重复的,除非只有两个
print(random.shuffle(lst))#打乱顺序
*************************************************
>>> import random
#随机小数
>>> random.random() # 大于0且小于1之间的小数
0.7664338663654585
>>> random.uniform(1,3) #大于1小于3的小数
1.6270147180533838
#随机整数
>>> random.randint(1,5) # 大于等于1且小于等于5之间的整数***
>>> random.randrange(1,10,2) # 大于等于1且小于10之间的奇数***
#随机选择一个返回
>>> random.choice([1,'23',[4,5]]) # #1或者23或者[4,5]
#随机选择多个返回,返回的个数为函数的第二个参数***
>>> random.choices([1,2,3,4],k=2) # 选择两个元素,会有重复,可控制元素个数***
>>> random.sample([1,'23',[4,5]],k=2) # #列表元素任意2个组合,不会重复(原列表有重复就会出现重复),可控制元素个数***
[[4, 5], '23']
#打乱列表顺序
>>> item=[1,3,5,7,9]
>>> random.shuffle(item) # 对原列表打乱次序
>>> item
[5, 1, 3, 7, 9]
>>> random.shuffle(item)
>>> item
[5, 9, 7, 1, 3]
序列化模块
-
json
# 1.dumps loads # lit = [1,22,3,3,45] # print(json.dumps(lit),type(json.dumps(lit))) # str_lst = json.dumps(lit) # lst = json.loads(str_lst) # print(lst,type(lst)) # dumps 将对象转换(序列化)成字符串 # loads 将字符串转换(反序列化)成对象 # dic = {'username':'宝元'} # str_dic = json.dumps(dic) # 序列化 # str_dic = json.dumps(dic,ensure_ascii=False) # ensure_ascii=False 关闭ascii码 # print(str_dic,type(str_dic)) # dic1 = json.loads(str_dic) # 反序列化 # print(dic1,dic1["username"]) # 2.dump load # import json # lit = [1,22,3,3,45] # 同时写多个内容 进行序列化 # lst = [1,2,3,4,56,] # f = open("info","w",encoding="utf-8") # f.write(json.dumps(lst) + "\n") # f.write(json.dumps(lst) + "\n") # f.write(json.dumps(lst) + "\n") # f.write(json.dumps(lst) + "\n") # f.write(json.dumps(lst) + "\n") # f.close() # dump: 将对象转换(序列化)成字符串,写入文件 # load: 将文件中字符串转换(反序列)成对象 # 同时读多个内容进行反序列 # f1 = open("info","r",encoding="utf-8") # for i in f1: # l = json.loads(i) # print(l) # f1.close()
-
pickle模块
# pickle 序列化 - nb(python所有对象进行转换) # python自带的(只有python可以用) # 两组4个方法: #1. dumps loads # import pickle # lst = [12,3,4,5,768] # t_list = pickle.dumps(lst) # 转换成类似字节 # print(t_list) # print(pickle.loads(t_list)[-1]) # dic = {"user":"郭宝元"} # t_list = pickle.dumps(dic) # 转换成类似字节 # print(t_list) # print(pickle.loads(t_list)) # def func(): # print(111) # import json # fun = json.dumps(func) # print(fun) # fun = pickle.dumps(func) # print(fun) # pickle.loads(fun)() #2. dump load # import pickle # dic = {"usern":"baoyuian"} # dic = {"usern":"宝元"} # pickle.dump(dic,open("info","wb")) # print(pickle.load(open("info","rb"))) # import pickle # dic = {"user":"123"} # pickle.dump(dic,open("info","ab")) # import pickle # dic = {"1":2} # f = open("info","wb") # s = "\n".encode("utf-8") # f.write(pickle.dumps(dic)+ s) # f.write(pickle.dumps(dic)+ s) # f.write(pickle.dumps(dic)+ s) # f.close() # # f1 = open("info","rb") # for i in f1: # print(pickle.loads(i)) # 推荐使用json # json是各种语言通用的
os模块
-
os模块是程序员通过python向操作系统发送指令的交互接口
import os #工作目录 # print(os.getcwd())#获取当前的工作路径 # print(os.chdir())#修改工作路径 # print(os.curdir) # print(os.pardir) #文件夹 # print(os.mkdir('aaa')) # print(os.rmdir('aaa')) # print(os.makedirs('aaa/bbb/ccc')) # print(os.removedirs('aaa/bbb/ccc')) # print(os.listdir('E:\python24期笔记\day17')) #文件相关 # print(os.rename('aa.txt','bb.txt'))#修改文件名 # print(os.remove('sss'))#删除文件 #路径相关 # print(os.path.abspath('F:\oldboy\day17\os模块.py'))#获取绝对路径 # print(os.path.dirname('F:\oldboy\day17\os模块.py'))#获取文件夹路径 # print(os.path.basename('F:\oldboy\day17\os模块.py'))#获取文件目录 # print(os.path.split('F:\oldboy\day17\os模块.py'))#对文件夹和文件分割 # print(os.path.isabs('F:\oldboy\day17\os模块.py'))#判断是不是绝对路径 # print(os.path.isdir('F:\oldboy\day17'))#判断是不是一个目录 # print(os.path.isfile('F:\oldboy\day17\os模块.py'))#判断是不是一个文件名 # print(os.path.exists('F:\oldboy\day17\os模块.py'))#判断路径存不存在 # print(os.path.join())拼接路径 # os.path.getatime()查看文件的最后访问时间 # os.path.getmtime()#查看文件的最后修改时间 # os.path.getctime()#文件的创建时间 # os.path.getsize()#路径的字节大小,按照kb返回
hashlib模块
# md5,sha1,sha256,sha512
# 1.只要明文相同密文就是相同的
# 2.只要明文不相同密文就是不相同的
# 3.不能反逆(不能解密) -- md5中国人破解了
# 加密:
# 1.加密的内容
# 2.将要加密的内容转成字节
# 最常用是的md5,平时加密的时候使用sha1
# 加盐
# 加固定盐
# import hashlib
# md5 = hashlib.md5("常鑫".encode("utf-8"))
# md5.update("alex123".encode("utf-8"))
# print(md5.hexdigest())
#
# md5 = hashlib.md5()
# md5.update("alex123".encode("utf-8"))
# print(md5.hexdigest())
# 动态加盐
# user = input("username:")
# pwd = input("password")
#
# import hashlib
# md5 = hashlib.md5(user.encode("utf-8"))
# md5.update(pwd.encode("utf-8"))
# print(md5.hexdigest())
# md5 = hashlib.md5()
# md5.update(pwd.encode("utf-8"))
# print(md5.hexdigest())
# 767db14ed07b245e24e10785f9d28e29
# f = open(r"F:\s24\day17\python-3.6.6-amd64.exe","rb")
# import hashlib
# md5 = hashlib.md5()
# md5.update(f.read())
# print(md5.hexdigest())
# ss = "baoyuanalextaibai"
# s = "baoyuan"
# s1 = "alex"
# s2 = "taibai"
# import hashlib
# md5 = hashlib.md5()
# md5.update(ss.encode("utf-8"))
# print(md5.hexdigest())
#
#
# md5 = hashlib.md5()
# md5.update(s.encode("utf-8"))
# md5.update(s1.encode("utf-8"))
# md5.update(s2.encode("utf-8"))
# print(md5.hexdigest())
# 节省内存
# f = open(r"F:\s24\day17\python-3.6.6-amd64.exe","rb")
# import hashlib
# md5 = hashlib.md5()
# while True:
# msg = f.read(1024)
# if msg:
# md5.update(msg)
# else:
# print(md5.hexdigest())
# break
collections模块
collections模块
在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
1.namedtuple: 生成可以使用名字来访问元素内容的tuple
2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
3.Counter: 计数器,主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
====================================================================================
namedtuple
我们知道tuple可以表示不变数据,例如,一个点的二维坐标就可以表示成:
p = (1, 2)
但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。
这时,namedtuple就派上了用场:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p)
结果:Point(x=1, y=2)
类似的,如果要用坐标和半径表示一个圆,也可以用namedtuple定义:
namedtuple('名称', [属性list]):
Circle = namedtuple('Circle', ['x', 'y', 'r'])
deque
使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
----------------------------------------------------------------------------------
deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
q
deque(['y', 'a', 'b', 'c', 'x'])
deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。
------------------------------------------------------------------------
OrderedDict
使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。
如果要保持Key的顺序,可以用OrderedDict:
from collections import OrderedDict
d = dict([('a', 1), ('b', 2), ('c', 3)]) # 另一种定义字典的方式
print(d)
# 结果:
{'a': 1, 'c': 3, 'b': 2}
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
print(od)
# 结果:
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:
>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> od.keys() # 按照插入的Key的顺序返回
['z', 'y', 'x']
--------------------------------------------------------------------------
defaultdict
有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。
即: {'k1': 大于66 , 'k2': 小于66}
li = [11,22,33,44,55,77,88,99,90]
result = {}
for row in li:
if row > 66:
if 'key1' not in result:
result['key1'] = []
result['key1'].append(row)
else:
if 'key2' not in result:
result['key2'] = []
result['key2'].append(row)
print(result)
from collections import defaultdict
values = [11, 22, 33,44,55,66,77,88,99,90]
my_dict = defaultdict(list)
for value in values:
if value>66:
my_dict['k1'].append(value)
else:
my_dict['k2'].append(value)
使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:
from collections import defaultdict
dd = defaultdict(lambda: 'N/A')
dd['key1'] = 'abc'
# key1存在
print(dd['key1'])
dd['key2'] # key2不存在,返回默认值
print(dd['key2'])
-------------------------------------------------
Counter
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。
c = Counter('abcdeabcdabcaba')
print c
输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})
re模块
s='lijie_李杰_l\tlilililijiee123@'
#\w匹配字母数字,下划线包括中文
print(re.findall('\w',s))
#\W匹配非字母数字,下划线包括中文
print(re.findall('\W',s))
#\s匹配任意空格,换行符,制表符
print(re.findall('\s',s))
#\S匹配非任意空格,换行符,制表符
print(re.findall('\S',s))
#\d匹配数字
print(re.findall('\d',s))
#\D匹配非数字
print(re.findall('\D',s))
#A或^匹配开头的内容
print(re.findall('\Alijie',s))
print(re.findall('^lijie',s))
#\Z或$匹配结尾的内容
print(re.findall('123@\Z',s))
print(re.findall('123@$',s))
#\n \t 匹配换行符和制表符
print(re.findall('\n',s))
print(re.findall('\t',s))
#.匹配任意一个内容(换行符除外)
print(re.findall('l.j',s))
print(re.findall('l.j',s,re.DOTALL))#.匹配任意时,可以匹配所有
#[]指定匹配的范围
print(re.findall('[A-Za-z0-9]',s))
#[^]匹配指定范围之外的
print(re.findall('[^a-z]',s))
#*匹配0个或多个内容
print(re.findall('li*',s))#贪婪匹配
#+匹配1个或多个内容
print(re.findall('li',s))#贪婪匹配
#?匹配0个或一个内容
print(re.findall('li?',s))
#{}重复匹配指定字符几次
print(re.findall('l{1}',s))
#{1,6}指定重复匹配指定字符的次数范围
print(re.findall('l{1,6}',s))
#|或者
print(re.findall('li|jie',s))
#()匹配括号里的内容
print(re.findall('l(.+?)j',s))
print(re.findall('l(?:.+?)l',s))#()匹配时?:可以将括号外面的一起返回
#search匹配一个,匹配到返回的是一个对象,查看元素用group()方法
print(re.search('li',s))
#match从字符串的开头查找,返回一个对象,查看元素用group()方法
print(re.match('li',s))
#finditer返回一个迭代器
a=re.finditer('\w','你好世界')
print(next(a).group())#用group查看值
#split分割
print(re.split('l',s))
#sub替换
print(re.sub('li','哈哈','lijieljie'))
#?P分组起名
print(re.findall('(?P<aaa>\w)jie',s).group('aaa'))
#\.转义
# 匹配所有的数字(包含小数包含负号)
# print(re.findall("-?\d+\.\d+|-?\d+",s))
模块和包
我们今天来讲解一下模块和包,模块我们已经知道是什么东西了,我们现在来看看这个包是个什么? 我说的包可不是女同胞一看见就走不动的包,而是程序中一种组织文件的形式.
只要文件夹下含有__init__.py文件就是一个包,包是干什么的呢?
回想一下,之前我们没有学习模块的时候将一个整体的功能写入到文件中,为了能够充分的将某个功能进行重用 我们使用了模块,但是慢慢的模块就会越来越多.我们想提高程序的结构性可维护性,就使用包将模块进行统一管理
包能够管理多个模块,我们想要使用包里的模块怎么办呢?
使用import 和from xx import xx 现有如下结构
bake
├── __init__.py
├── api
├── __init__.py
├── policy.py
└── versions.py
├── cmd
├── __init__.py
└── manage.py
└── db
├── __init__.py
└── models.py
我们在bake同级创建一个test.py进行导入policy.py 我们使用模块的import的时候只能将api添加到sys.path的路劲中,我们来看看包使用import导入
import bake.api.policy
bake.api.policy.get()
导入的太长了下边使用的时候还需要在重复写一遍,我们可以使用as起别名
import bake.api.policy as p
p.get()
这样的操作只支持包,普通的文件夹无效,有人一定在想我把bake拿过来然后一层一层的打开那拿工具就可以了
import bake
bake.api.policy.get()
不好使,这样导入是只将policy导入了,有人想怎么将api包下的模块全部导入不要急,先说单独导入的方式
咱们能够使用import进行导入,在来看看from的导入方式
from bake.api import policy
policy.get()
from bake import api
print(api.versions.name)
还是不好使,通过这两个我们能够感觉都导入的时候指定要导入的内容,不能再导入后在进行开箱子
我们现在说了单独导入一个模块,现在来说道说道怎么导入某个包下的所有模块,想要导入某个包下的所有的模块 我们就需要在包中的__init__.py做点手脚
bake包下的__init__.py
from . import api
.是当前路径,因为from的时候不能空着
api包下的__init__.py
from . import policy
我们将包下的__init__配置好,然后在test.py进行导入
import bake
bake.api.policy.get()
又好使了,这是为什么呢?我们import导入bake这个包,因为bake是一个文件夹不能进行任何操作,就让__init__.py代替它 去将api这包中的模块导入,api也是一个文件夹不能操作就需要让api下边的__init__.py去找api下边的两个模块
这个和公司的上下级关系一样,打比方现在test.py就是一个ceo要和policy这个小员工谈话,ceo先把这个想法人事经理,人事经理就是 bake这个包,人事经理通知人事让人事查找一下policy在那个部门,人事查到后通知部门的负责人,部门的负责人在通知部门的主管,主管告诉policy这个员工, 说ceo要找你,部门的主管带着policy去找人事,人事带着policy,人事然后在带着policy去找ceo.最后成功的和ceo进行了一番交流
如果在传达的时候中间一个环节忘记传递了,policy就不知道ceo在找他,ceo等了好久不来ceo就生气报错了
使用的时候需要注意: 有的同学,想在policy文件中导入versions就是直接使用import,在policy文件使用没有问题,很美,很高兴.但是在test.py执行的时候就会报错 因为我们在test.py中执行的import versions 相当于在test.py文件进行查找,肯定不会找到,我们需要在policy文件中向sys.path添加了当前的路劲就可以了 具体操作如下:
import os
import sys
sys.path.insert(os.path.dirname(__file__)
__file__获取的是当前文件的路径,这样我们就能在test中正常使用了,我们使用from也能够将某个包下所有的模块全都导入 比如我们现在想将cmd包下的所有的模块导入需要在bake包下的__init__.py进行设置
from . import *
我们需要在api包下设置__init__.py
__all__ = ["policy","versions"]
或
from . import policy
from . import versions
我们需要在db包下设置__init__.py
__all__ = ["models"]
或
from . import models
我们需要在cmd包下设置__init__.py
__all__ = ["manage"]
或
from . import manage
以上两种推荐使用下from . import manage 灵活,可读性高
test.py调用如下:
from bake.api import *
print(versions.name)
policy.get()
from bake.db import *
models.register_models(123)
from bake.cmd import *
print(manage.name)
在使用import有个注意点,python2中如果import包,没有__init__.py文件就会报错 python3 import没有__init__.py文件的包不会报错 from 包 import 包或者模块(在import后边不能在进行.操作)
路径: 绝对路径:从最外层(bake)包.查找的就是绝对路径 相对路径:.就是相对路径, ..是上一级目录 例如:我们在bake/api/version.py中想要导入bake/cmd/manage.py
# 绝对路径:
from bake.cmd import manage
manage.main()
#相对路径:
from ..cmd import manage
manage.main()
注意在使用相对路径的时候一定要在于bake同级的文件中测试 我们需要在和bake同级的test.py中测试
from bake.cmd import manage
logging日志模块
我们来说一下这个logging模块,这个模块的功能是记录我们软件的各种状态,你们现在和我一起找到红蜘蛛的那个图标,然后右键找一找是不是有个错误日志.其实每个软件都是有错误日志的,开发人员可以通过错误日志中的内容对他的程序进行修改
这只是一种应用场景,有的还会将日志用于交易记录.比如你给我转账应该做记录吧,
我们使用的信用卡,每消费的一笔都会记录,我们来看看这个日志怎么用?
我们先来看一下函数式简单配置
import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING
(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),
默认的日志格式为日志级别:Logger名称:用户输出消息。
我们自己用函数写的这个可以正常使用但是不够灵活,我们看看这个灵活的
灵活配置日志级别,日志格式,输出位置:
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='/tmp/test.log',
filemode='w')
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:
filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置记录日志的级别
stream:用指定的stream创建StreamHandler。可以指定输出到
sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息
logger对象配置
import logging
logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8')
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过
fh.setLevel(logging.Debug)单对文件流设置某个级别。
================================================================
import logging
logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8')
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
logging日志旗舰版
"""
logging配置
"""
import os
import logging.config
# 定义三种日志输出格式 开始
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
# 定义日志输出格式 结束
logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录
logfile_name = 'all2.log' # log文件名
# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(logfile_dir):
os.mkdir(logfile_dir)
# log文件的全路径
logfile_path = os.path.join(logfile_dir, logfile_name)
# log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {},
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
#打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
},
},
}
def load_my_logging_cfg():
logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置
logger = logging.getLogger(__name__) # 生成一个log实例
logger.info('It works!') # 记录该文件的运行状态
if __name__ == '__main__':
load_my_logging_cfg()
第六章 面向对象
规范化目录
-
规范化目录的优点
#1:加载速度块 #2:可读性高 #3:查询修改代码时都简单
-
规范化目录分析
-
划归固定的路径
将文件目录的固定路径划分完成
-
settings.py配置文件
#1:基本存储的都是变量 #2:静态路径,数据库的链接,配置,静态文件的的路径,基本不发生改变的
-
src.py主逻辑函数
#主逻辑函数,核心函数:贯穿整个项目的主要功能
-
common.py公共组件
#放置一些公用的函数,功能,方便与其他的函数或者业务需求,如:装饰器
-
start启动文件
#单独的启动文件,将所有项目的功能单独放置一个文件中,开启项目方便,醒目
-
register
#用户信息,数据相关,多个文件
-
logging日志文件
#记录用户的访问次数,转账,取钱,充钱等等.极了用户干了什么.
-
README描述文件
#1:软件定位,软件的基本功能。 #2:运行代码的方法: 安装环境、启动命令等。 #3:简要的使用说明。 #4:代码目录结构说明,更详细点可以说明软件的基本原理。 #5:常见问题说明。
-
-
规范化目录sys模块路径加载
#版本一 sys模块内置模块,文件运行时,sys内置模块就会将一些模块 自动 加载到内存. 内置模块. time,json pickle等等.以及当前目录的. 如何引用到一个模块最本质的原因在于这个模块名称空间在不在内存. 如果直接引用不到一个模块,他必定不是内置或者当前目录下的py文件. 所以,我们要手动将其添加到内存. sys.path.append()就是手动的将一些模块添加到内存,添加完毕之后,就可以直接引用了. #================================================ import sys #版本二: 繁琐,我要将整个项目作为根目录,添加到内存中. sys.path.append(r'F:\s24\day20\模拟博客园代码\blog\core') sys.path.append(r'F:\s24\day20\模拟博客园代码\blog\conf') sys.path.append(r'F:\s24\day20\模拟博客园代码\blog\db') from src import run run() #================================================ #版本三: 你把项目路径写死了,所有的开发人员如果共同开发这个项目,必须都得按照这#个目录结构去构建. import sys sys.path.append(r'F:\s24\day20\模拟博客园代码\blog') from core.src import run run() #================================================ # 版本四: import sys import os # print(__file__) # print(os.path.dirname(os.path.dirname(__file__))) # sys.path.append(r'F:\s24\day20\模拟博客园代码\blog') # from core.src import run # run() BASE_PATH = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_PATH) from core.src import run if __name__ == '__main__': run()
面向对象编程的优势
#易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
面向对象初识
'''
想要学习面向对象必须站在一个上帝的角度去分析考虑问题.
类: 具有相同属性和功能的一类事物.
对象:某个类的具体体现.
汽车: 汽车类, 楼下停着一个车牌号为9nb11的奥迪对象.
猫科类: 类. 陈硕家的养的那个大橘.对象.
鸡类: 一个类. 家里养的一只鸡.
男神:是一类. 太白对象.
面向对象的第二优点: 你要站在上帝的角度构建代码,类就是一个公共的模板,对象就是从模板实例化出来的.
得到对象就得到了一切.
'''
面向对象的结构
class Human:
"""
类的具体结构
"""
# 第一部分:静态属性
mind = '有思想' # 类的属性 (静态属性, 静态字段)
language = '使用语言'
# 第二部分: 动态方法
def work(self):
print('人类都会工作')
def eat(self):
print('人类都需要吃饭')
从类名的角度研究类
# class Human:
# """
# 类的具体结构
# """
# # 第一部分:静态属性
# mind = '有思想' # 类的属性 (静态属性, 静态字段)
# language = '使用语言'
#
# # 第二部分: 动态方法
# def work(self):
# print('人类都会工作')
#
# def eat(self):
# print('人类都需要吃饭')
# 1. 类名操作类中的属性
# 1. 类名查看类中所有的内容
# print(Human.__dict__)
# 2. 类名操作类中的静态属性 万能的点.
# 增:
# Human.body = '有头和四肢'
# 删:
# del Human.mind
# 改:
# Human.mind = 'liye脑残'
# 查:
# print(Human.language)
# print(Human.__dict__)
# 2. 类名调用类中的方法(一般类中的(静态方法,类方法)方法不会通过类名调用)
# Human.work(111)
# 总结:
# 一般类名就是操作类中的属性.
从对象角度研究类
# class Human:
# """
# 类的具体结构
# """
# # 第一部分:静态属性
# mind = '有思想' # 类的属性 (静态属性, 静态字段)
# language = '使用语言'
#
# def __init__(self):
# # print(f'self---->: {self}')
# # print(666)
# self.name = '李业'
# self.age = 18
#
# # 第二部分: 动态方法
# def work(self):
# print('人类都会工作')
#
# def eat(self):
# print('人类都需要吃饭')
#
# obj = Human() # 实例化过程
# 得到一个返回值,这个返回值就是 对象,实例.
# print(f'obj---> {obj}')
=================
# 实例化一个对象发生了三件事(重点++++):
'''
1. 触发__new__方法 ,开辟一个对象空间.
2. 自动执行__init__方法,并且将对象地址传给self.
3. 运行__init__方法内的代码,给对象空间封装属性.(完整版)
'''
class Human:
"""
类的具体结构
"""
# 第一部分:静态属性
mind = '有思想' # 类的属性 (静态属性, 静态字段)
language = '使用语言'
def __init__(self, name, age):
# print(f'self---->: {self}')
# print(666)
self.n = name
self.a = age
# 第二部分: 动态方法
def work(self):
# print(f'self---> {self}')
print(f'{self.n}都会工作')
def eat(self):
print(f'{self.n}都需要吃饭')
# obj = Human('李业',18) # 实例化过程
# print(obj.n)
# print(obj.a)
# print(obj.__dict__)
# 一:对象操作对象空间的属性
# 1. 对象查看对象的空间的所有属性
# obj = Human('李业',18)
# print(obj.__dict__)
# 2. 对象操作对象空间的属性
# obj = Human('李业',18)
# 增:
# obj.sex = 'laddy_boy'
# 删:
# del obj.a
# 改:
# obj.a = 1000
# 查:
# print(obj.n)
# print(obj.__dict__)
# 二 对象查看类中的属性
# obj = Human('李业',18)
# # print(obj.mind)
# obj.mind = '无脑的'
# print(obj.mind)
# print(Human.mind)
# 三 对象调用类中的方法
# obj = Human('孙戴维', 23)
# # print(f'obj---> {obj}')
# obj.work()
# obj.eat()
# 一个类可以实例化多个对象
# obj1 = Human('李业',18)
# obj2 = Human('小可爱', 16)
# obj3 = Human('怼姐', 18)
# 变量,函数名:
# age_of_oldboy = 73
# Ageofoldboy
从空间角度研究类
对象空间与类空间有相同的名字, 对象. 肯定先从对象空间查找.
查询顺序:
对象.名字: 对象空间 类对象指针_--> 类空间 ---> 父类空间
类名.名字: 类空间 -----> 父类空间
类与类之间的关系
-
依赖关系
# 依赖关系: 将一个类的类名或者对象传入另一个类的方法中 # #1. 依赖关系: 主从之分. # class Elephant: # def __init__(self,name): # self.name = name # def open(self,obj): # print(f'{self.name} 默念三声: 3,2,1 开门') # obj.be_open() # def close(self): # print(f'{self.name} 默念三声: 3,2,1 关门') # # class Refrigerator: # def __init__(self, name): # self.name = name # def be_open(self): # print(f'{self.name}冰箱 被打开了') # def be_close(self): # print(f'{self.name}冰箱 被关闭了')
-
组合关系
#给一个类的对象封装一个属性,此属性为另一个类的对象 #class Boy: # def __init__(self,name,age,girlfriend=None): # self.name=name # self.age=age # self.girlfriend=girlfriend # def eat(self): # if self.girlfriend: # print(f'{self.name}和{self.girlfriend.name}') # else: # print('吃个屁') # class Girl: # def __init__(self,name,age): # self.name=name # self.age=age # p=Boy('李业',30) # g=Girl('如花',56) # p.girlfriend=g # p.eat()
继承
-
初识继承
#字面意思: 儿子可以完全使用父亲的所有内容 #专业角度: 如果B类继承A类, # B类就称为子类,派生类. # A类就称为父类,基类,超类. #面向对象三大特性之一:继承,封装,多态. #继承: 单继承,多继承.
-
继承的优点
#减少重复代码. #增加类之间的耦合性. #代码更加清晰,流畅.
-
单继承
#类名执行父类属性方法 #对象执行父类属性方法 #在子类中既执行字类方法又执行父类方法
-
多继承
#python 类分为两种: #python2x : # python2.2之前,都是经典类.python2.2之后,经典类与新式类共存. #python3x: # 全部都是新式类. #经 典类: 不继承object类, 深度优先原则. #新式类:继承object类. mro(C3)算法 #经典类的深度优先 #新式类的mro算法 =============================================== #如果想执行父类的func方法,这个方法并且子类中夜用,那么就在子类的方法中写上: #1:父类.func(对象,其他参数) #2:利用super,super().func(参数)
-
super的用法(重点++++)
1:super 可以重构父类的方法 2:在新式类的多继承中,super严格按照 self 对象从属于类的mro顺序进行查找,默认执行本类 的下一个类(简单的记就是:跳过本类,按照Mro算法的执行顺序,执行下一类的操作)
-
mro(C3)算法
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2)
如计算merge( [E,O], [C,E,F,O], [C] ) 有三个列表 : ① ② ③ 1 merge不为空,取出第一个列表列表①的表头E,进行判断 各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表 2 取出列表②的表头C,进行判断 C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除 merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] ) 3 进行下一次新的merge操作 ......
mro(A) = mro( A(B,C) ) 原式= [A] + merge( mro(B),mro(C),[B,C] ) mro(B) = mro( B(D,E) ) = [B] + merge( mro(D), mro(E), [D,E] ) # 多继承 = [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O] = [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D = [B,D,E] + merge([O] , [O]) = [B,D,E,O] mro(C) = mro( C(E,F) ) = [C] + merge( mro(E), mro(F), [E,F] ) = [C] + merge( [E,O] , [F,O] , [E,F] ) = [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除 = [C,E,F] + merge([O] , [O]) = [C,E,F,O] 原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C]) = [A,B] + merge( [D,E,O], [C,E,F,O], [C]) = [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E = [A,B,D,C] + merge([E,O], [E,F,O]) = [A,B,D,C,E] + merge([O], [F,O]) # 跳过O = [A,B,D,C,E,F] + merge([O], [O]) = [A,B,D,C,E,F,O]
-
简述面向对象的新式类与经典类
#经典类 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.经典类采用深度优先遍历方案 #新式类 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类,python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object,新式类采用C3算法遍历原则,MRO序列
面向对象的三大特性
-
封装
#对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜B的函数. 那这个也可以被称为封装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装.
-
继承
#⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容. 说⽩了, ⼉⼦可以随便⽤爹的东⻄. 但是朋友们, ⼀定要认清楚⼀个事情. 必须先有爹, 后有⼉⼦. 顺序不能乱, 在python中实现继承非常简单. 在声明类的时候, 在类名后⾯添加⼀个⼩括号,就可以完成继承关系. 那么什么情况可以使⽤继承呢? 单纯的从代码层⾯上来看. 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取⼀个⽗类, 这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中出现了x是⼀种y. 这时, y是⼀种泛化的概念. x比y更加具体. 那这时x就是y的⼦类. 比如. 猫是⼀种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的"动"这个属性. 再比如, ⽩骨精是⼀个妖怪. 妖怪天⽣就有⼀个比较不好的功能叫"吃⼈", ⽩骨精⼀出⽣就知道如何"吃⼈". 此时 ⽩骨精继承妖精.
-
多态
#多态,同一个对象,多种形态。python默认支持多态。
-
三大特性总结
#继承:单继承和多继承,子承父业 如果B继承A,那A称作父类,基类,B称作子类,派生类 B继承A,那么B就可以拥有A所有的属性和方法,一个类可以多个父类 #多态 多种形态,Python中有很多地方都体现了多态,例如:定义一个变量a,a=2,这时a是个整型 我也可以再给a赋值,a = '你好',这时的a就是一个字符串类型,一个变量有多种形态,体现的就是多态 #封装 python中的函数 模块 类 都属于封装,把固定功能的代码封装到一个代码块中,就属于封装
类的约束
-
约束的概念
#约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种: #1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c#. 所以使⽤频率还是很少的 #2. 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError. 这样比较专业, ⽽且错误比较明确.(推荐)
-
约束的两种方式
#第一种 class Payment: """ 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。 """ def pay(self,money): raise Exception("你没有实现pay方法") class QQpay(Payment): def pay(self,money): print('使用qq支付%s元' % money) class Alipay(Payment): def pay(self,money): print('使用阿里支付%s元' % money) class Wechatpay(Payment): def fuqian(self,money): print('使用微信支付%s元' % money) def pay(obj,money): obj.pay(money) a = Alipay() b = QQpay() c = Wechatpay() pay(a,100) pay(b,200) pay(c,300) #======================================================== #第二种 from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类 @abstractmethod def pay(self):pass # 抽象方法 class Alipay(Payment): def pay(self,money): print('使用支付宝支付了%s元'%money) class QQpay(Payment): def pay(self,money): print('使用qq支付了%s元'%money) class Wechatpay(Payment): # def pay(self,money): # print('使用微信支付了%s元'%money) def recharge(self):pass def pay(a,money): a.pay(money) a = Alipay() a.pay(100) pay(a,100) # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能 q = QQpay() q.pay(100) pay(q,100) w = Wechatpay() pay(w,100) # 到用的时候才会报错 # 抽象类和接口类做的事情 :建立规范 # 制定一个类的metaclass是ABCMeta, # 那么这个类就变成了一个抽象类(接口类) # 这个类的主要功能就是建立一个规范
super()的深入了解
#严格按照mro的执行顺序去执行
#super(Foo,self).f2() # 按照self对象从属于类的mro的顺序,执行Foo类的下一个类.
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self):
print('in Bar')
class Info(Foo,Bar):
def f1(self):
super().f1()
print('in Info f1')
obj = Info()
obj.f1()
'''
in Bar
in Foo
in Info f1
'''
print(Info.mro()) # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
python2和python3 字符和字节的区别(待查)
鸭子类型
-
什么是鸭子类型
#对相同的功能定义了相同的名字,这样方便开发,两种方法互称为鸭子模型,比如:list str tuple 都有index方法,这种就是统一了规范,互为鸭子模型.
#python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
#对于代码上的解释其实很简答:
class A:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
class B:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
obj = A()
obj.f1()
obj.f2()
obj2 = B()
obj2.f1()
obj2.f2()
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。
# 这样的例子比比皆是:str tuple list 都有 index方法,这就是统一了规范。
# str bytes 等等 这就是互称为鸭子类型。
类的私有成员
-
类的私有属性
#类的私有属性,只能在类的内部使用,不能在类的外部和派生类中使用 class A: name='李业' __name='李业' def func(self): print(self.name) print(self.__name) class B(A): def func(self): print(self.name) print(self.__name) p=A() p.func() b=B() b.func()#报错
-
私有对象属性
#私有对象属性,只能在类的内部使用,不能在类的外部或派生类中使用 class A: def __init__(self,name,age): self.name=name self.__age=age def func(self): print(self.__age) class B(A): def func(): print(self.__age) p=A() p.func() b=B() b.func()#报错
-
类的私有方法
#类的私有方法只能在类的内部使用,不能在类的外部或者派生类中使用 class A: def __init__(self,name,age): self.name=name self.__age=age def __func(self): print(self.__age) def func(self): self.__func() class B(A): def func(): self.__func() print(self.__age) p=A() p.func() b=B() b.func()#报错
-
类的私有成员总结
#私有成员来说: 当你遇到重要的数据,功能,(只允许本类使用的一些方法,数据)设置成私有成员. # python所有的私有成员都是纸老虎,形同虚设. class A: name = '李业' -name = "宝哥"#程序员之间约定俗称的 __name = '钢哥' # 私有类的属性 def __func(self): print('in __func') print(A.__dict__) print(A._A__name) # 类从加载时,只要遇到类中的私有成员,都会在私有成员前面加上_类名
-
类方法
# 类方法 class A: def func(self): print('实例方法') @classmethod def cls_func(cls): # print(f'cls---->{cls}') obj = cls() print(obj) print('类方法') print(A) A.cls_func() obj = A() obj.cls_func() # 类方法: 一般就是通过类名去调用的方法,并且自动将类名地址传给cls, # 但是如果通过对象调用也可以,但是传的地址还是类名地址. # A.cls_func() # 类方法有什么用??? # 1. 得到类名可以实例化对象. # 2. 可以操作类的属性. # 简单引用 # 创建学生类,只要实例化一个对象,写一个类方法,统计一下具体实例化多少个学生? # class Student: # # count = 0 # def __init__(self,name,id): # # self.name = name # self.id = id # Student.addnum() # # @classmethod # def addnum(cls): # cls.count = cls.count + 1 # # @classmethod # def getnum(cls): # return cls.count # # obj1 = Student('liye', 12343243243) # obj1 = Student('liye', 12343243243) # obj1 = Student('liye', 12343243243) # print(Student.getnum())
-
静态方法
# 静态方法 # class A: # # def func(self): # print('实例方法') # @classmethod # def cls_func(cls): # pass # # @staticmethod # def static_func(): # print('静态方法') # # # 静态方法是不依赖于对象与类的,其实静态方法就是函数. # 保证代码的规范性,合理的划分.后续维护性高. # def func(): # pass import time class TimeTest(object): area = '中国' def __init__(self, hour, minute, second): self.hour = hour self.minute = minute self.second = second def change_time(self): print(f'你想调整的时间: {self.hour}时{self.minute}分{self.second}秒') @staticmethod def showTime(): return time.strftime("%H:%M:%S", time.localtime()) def showTime(): return time.strftime("%H:%M:%S", time.localtime()) def time1(): pass def time2(): pass # t = TimeTest(2, 10, 10) # # t.change_time() # print(TimeTest.showTime())
-
属性方法
# class Bmi: # # def __init__(self,name,height,weight): # # self.name = name # self.height = height # self.weight = weight # # def bmi(self): # return self.weight/self.height**2 # # obj = Bmi('赵嘎', 1.83, 65) # print(obj.bmi()) # 结果虽然实现了,但是逻辑上感觉不合理.bmi应该是类似于name,age,height,等名词, # 但是你把它当做方法使用了. # class Bmi: # # def __init__(self,name,height,weight): # # self.name = name # self.height = height # self.weight = weight # # @property # def bmi(self): # return self.weight/self.height**2 # # obj = Bmi('赵嘎', 1.83, 65) # print(obj.bmi) # property 将执行一个函数需要函数名()变换成直接函数名. # 将动态方法 伪装 成了一个属性,虽然在代码级别上没有什么提升,但是让你看起来更合理. # obj.bmi # obj.bmi # obj.bmi = 666 # # del obj.bmi # property 他是一个组合. # class Foo: # @property # def bmi(self): # print('get的时候运行我啊') # # @bmi.setter # def bmi(self,value): # print(value) # print('set的时候运行我啊') # # return 111 # 无法得到返回值 # # @bmi.deleter # def bmi(self): # print('delete的时候运行我啊') # # return 111 # 无法得到返回值 # # obj = Foo() # # obj.bmi # obj.bmi = 666 # 操作命令 这个命令并不是改变bmi的值,而是执行被bmi.setter装饰器装饰的函数 # # obj.bmi(666) # del obj.bmi # 应用场景: # 1, 面试会考一些基本的调用,流程. # 2, 工作中如果遇到了一些类似于属性的方法名,可以让其伪装成属性. # 设置属性的两种方式: # 1, 利用装饰器设置属性. # class Foo: # @property # def bmi(self): # print('get的时候运行我啊') # # @bmi.setter # def bmi(self,value): # print(value) # print('set的时候运行我啊') # # return 111 # 无法得到返回值 # # @bmi.deleter # def bmi(self): # print('delete的时候运行我啊') # # return 111 # 无法得到返回值 # 2. 利用实例化对象的方式设置属性. # class Foo: # def get_AAA(self): # print('get的时候运行我啊') # # def set_AAA(self,value): # print('set的时候运行我啊') # # def delete_AAA(self): # print('delete的时候运行我啊') # # AAA = property(get_AAA,set_AA,delete_AAA) #内置property三个参数与get,set,delete一一对应 # f1=Foo() # f1.AAA # f1.AAA='aaa' # del f1.AAA
-
内置函数isinstance和issubclass
# isinstance 判断的是对象与类的关系 class A: pass class B(A): pass obj = B() # isinstance(a,b) 判断的是 a是否是b类 或者 b类派生类 实例化的对象. # print(isinstance(obj, B)) # True # print(isinstance(obj, A)) # True # issubclass 类与类之间的关系 class A: pass class B(A): pass class C(B): pass # issubclass(a,b) 判断的是 a类是否是b类 或者 b类派生类 的派生类. # issubclass(a,b) 判断的是 a类是否是b类 子孙类. # print(issubclass(B,A)) # print(issubclass(C,A))
Python中如何判断一个对象是否可调用?如果定义一个类,使其对象本身变成可调用对象
# 第一种方法callable,返回True有可能调用失败,但是返回False,那绝对不能调用
def func():
print(1)
func()
print(callable(func))
# 第二种方法,判断对象类型是否属于FunctionType,若为True,则可调用
from types import FunctionType
print(isinstance(func,FunctionType))
# 第三种方法,判断对象是否实现__call__方法
print(hasattr(func,'__call__'))
# 静态方法属于函数,类方法和实例方法分别依赖于类和对象,所以他们是method,其余我们自己定义的都是函数,函数就可调用若想让一个类的实例化对象可调用,可在类中定义__call__方法,即可实现
单例加锁代码实现
import threading
import time class Singleton:
instance = None
lock = threading.RLock()
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
if cls.instance:
return cls.instance
with cls.lock:
if cls.instance:
return cls.instance
time.sleep(0.1)
cls.instance =object.__new__(cls)
return cls.instance
def task():
obj = Singleton('x')
print(obj)
for i in range(10):
t = threading.Thread(target=task) t.start()
# 执行1000行代码
data = Singleton('asdfasdf') print(data)
元类
#python中一切皆对象,类在某种意义上也是一个对象,python中自己定义的类,以及大部分的内置类,都是由type元类(构建类)实例化来的
===================================================
#type与object的关系
object是type类的一个实例 print(type(object))
object是type类的父类 print(issubclass(type,object))
#class A:
# pass
# obj = A()
# print(type('abc'))
# print(type([1,2,3]))
# print(type((22,33)))
# # type 获取对象从属于的类
# print(type(A))
# print(type(str))
# print(type(dict))
-
说说type元类与object类的区别与联系
type元类是获取该对象从属于的类,而type类比较特殊,Python原则是:一切皆对象,其实类也可以理解为'对象', 而type元类又称作构建类,python中大多数内置的类(包括object)以及自己定义的类,都是由type元类创造实例化得来的。 * 而type类与object类之间的关系比较独特:object是type类的实例,而type类是object类的子类,这种关系比较神奇无法使用python的代码表述,因为定义其中一个之前另一个必须存在.
反射
-
反射的概念
#反射是程序对自己内部代码的一种自省方式 #反射是通过字符串去操作对象的方式
-
反射的主要作用
#反射主要作用与: # 1:实例对象 # 2:类 # 3:其他模块 # 4:本模块 ===================================== #反射的组合: # hasattr,getattr,setattr,delattr
-
代码演示
# 实例对象: class A: country = '中国' def __init__(self,name,age): self.name = name self.age = age def func(self): print('in A func') obj = A('赵海狗',47) # hasattr print(hasattr(obj,'name')) print(hasattr(obj,'country')) print(hasattr(obj,'func')) print(getattr(obj,'name')) print(getattr(obj,'func')) f = getattr(obj,'func') f() print(getattr(obj,'sex',None)) if hasattr(obj,'name'): getattr(obj,'name') # setattr,delattr 用的很少 obj.sex = '公' print(obj.sex) setattr(obj,'sex','公') print(obj.__dict__) delattr(obj,'name') print(obj.__dict__) # 从类的角度: class A: country = '中国' def __init__(self,name,age): self.name = name self.age = age def func(self): print(self) print('in A func') if hasattr(A,'country'): print(getattr(A,'country')) if hasattr(A,'func'): obj = A('赵海狗', 26) getattr(obj,'func')() getattr(A,'func')(obj) # 从其他模块: import tbjx print(getattr(tbjx,'name')) getattr(tbjx,'func')() import tbjx # 1. 找到tbjx对象 的C类,实例化一个对象. print(getattr(tbjx,'C')) obj = getattr(tbjx,'C')('123') # 2. 找到tbjx对象 的C类,通过对C类这个对象使用反射取到area. print(getattr(tbjx.C,'area')) # 3. 找到tbjx对象 的C类,实例化一个对象,对对象进行反射取值. obj = getattr(tbjx,'C')('赵海狗') print(obj.name) print(getattr(obj,'name')) #从当前模块研究反射: a = 666 def func1(): print('in 本模块这个对象') # def func1(): # print('in func1') # # def func2(): # print('in func2') # # def func3(): # print('in func3') # # def func4(): # print('in func4') # # func1() # # func2() # # func3() # # l1 = [func1,func2,func3,func4,] # import sys # # # print(sys.modules[__name__]) # # print(getattr(sys.modules[__name__],'a')) # # getattr(sys.modules[__name__],'func1')() # # getattr(sys.modules[__name__],'func2')() # # getattr(sys.modules[__name__],'func3')() # # func_lst = [f'func{i}' for i in range(1,5)] # # print(func_lst) # for func in func_lst: # getattr(sys.modules[__name__],func)() # class User: # def login(self): # print('欢迎来到登录页面') # # def register(self): # print('欢迎来到注册页面') # # def save(self): # print('欢迎来到存储页面') # # choose_dic = { # 1: User.login, # 2: User.register, # 3: User.save, # } # # while 1: # choose = input('请输入序号: \n1: 登录\n2: 注册\n3: 存储').strip() # obj = User() # choose_dic[int(choose)](obj) # class User: # # user_list = [('login','登录'),('register','注册'),('save', '存储')] # # def login(self): # print('欢迎来到登录页面') # # def register(self): # print('欢迎来到注册页面') # # def save(self): # print('欢迎来到存储页面') # # # while 1: # choose = input('请输入序号: \n1: 登录\n2: 注册\n3: 存储\n').strip() # 1 # obj = User() # getattr(obj, obj.user_list[int(choose)-1][0])() # getattr(obj,'login')
-
函数与方法的区别
#函数是显性传参,不依赖于类,对象 #方法是隐性传参,依赖于类,对象 #之前学的函数都函数 类中方法: #1.如果通过类名调用就是函数 #2.如果通过实例化对象调用就是方法 #类中的静态方法:是函数 #类中的类方法:是方法(最终总结) # 1. 通过打印函数名的方式区别什么是方法,什么是函数. (了解) # print(func1) # print(A.func) # 通过类名调用的类中的实例方法叫做函数. # obj = A() # print(obj.func) # 通过对象调用的类中的实例方法叫方法. # 2 可以借助模块判断是方法还是函数. # from types import FunctionType # from types import MethodType # # def func(): # pass # # # class A: # def func(self): # pass # # obj = A() # print(isinstance(func,FunctionType)) # True # print(isinstance(A.func,FunctionType)) # True # print(isinstance(obj.func,FunctionType)) # False # print(isinstance(obj.func,MethodType)) # True # 总结: # python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类, # 以及大部分内置类,都是由type元类(构建类)实例化得来的. # python 中一切皆对象, 函数在某种意义上也是一个对象,函数这个对象是从FunctionType这个类实例化出来的. # python 中一切皆对象, 方法在某种意义上也是一个对象,方法这个对象是从MethodType这个类实例化出来的. ================================================= class A: @classmethod def func(cls,a): pass @staticmethod def func1(): pass # A.func(222) # A.func() # obj = A() # obj.func() # 总结: 如何判断类中的是方法还是函数. # 函数都是显性传参,方法都是隐性传参.
-
双下方法
# 特殊的双下方法: 原本是开发python这个语言的程序员用的.源码中使用的. # str : 我们不能轻易使用.慎用. # 双下方法: 你不知道你干了什么就触发某个双下方法. # __len__ # class B: # # def __init__(self,name,age): # self.name = name # self.age =age # # def __len__(self): # print(self.__dict__) # # return len(self.__dict__) # 2 # # b = B('leye',28) # print(len(b)) # dict # print(len({'name': 'leye', 'age': 28})) ================================================================== # class A(object): # # pass # # obj = A() # print(hash(obj)) # str # print(hash('fdsaf')) ========================================================== # *** # class A: # # def __init__(self,name,age): # self.name = name # self.age =age # # def __str__(self): # print(666) # return f'姓名: {self.name} 年龄: {self.age}' # # a = A('赵海狗',35) # b = A('李业',56) # c = A('华丽',18) # 打印对象触发__str__方法 # print(f'{a.name} {a.age}') # print(f'{b.name} {b.age}') # print(f'{c.name} {c.age}') # print(a) # print(b) # print(c) # 直接str转化也可以触发. # print(str(a)) ============================================================= # repr # print('我叫%s' % ('alex')) # print('我叫%r' % ('alex')) # print(repr('fdsaf')) # class A: # # def __init__(self,name,age): # self.name = name # self.age =age # # def __repr__(self): # print(666) # return f'姓名: {self.name} 年龄: {self.age}' # # a = A('赵海狗',35) # b = A('李业',56) # c = A('华丽',18) # # print(a) # print(repr(a)) # class A: # # def __init__(self,name,age): # self.name = name # self.age =age # # def __str__(self): # return '777' # # # def __repr__(self): # return '666' # # a = A('赵海狗',35) # b = A('李业',56) # c = A('华丽',18) # # print(a) # print(a) ================================================================ # __call__方法 *** # 对象() 自动触发对象从属于类(父类)的__call__方法 # class Foo: # # def __init__(self): # pass # # def __call__(self, *args, **kwargs): # print('__call__') # # obj = Foo() # obj() ========================================================== # __eq__ # class A(object): # def __init__(self): # self.a = 1 # self.b = 2 # # def __eq__(self,obj): # # if self.a == obj.a and self.b == obj.b: # # return True # return True # x = A() # y = A() # print(x == y) # x = 1 # y = 2 # print(x+y) ================================================================== # __del__析构方法 class A: def __del__(self): print(666) obj = A() del obj ================================================== # __new__ *** new一个对象 构造方法 # class A(object): # # def __init__(self): # # self.x = 1 # print('in init function') # # def __new__(cls, *args, **kwargs): # print('in new function') # return object.__new__(A) # object 342534 # # 对象是object类的__new__方法 产生了一个对象. # a = A() # 类名() # 1. 先触发 object的__new__方法,此方法在内存中开辟一个对象空间. # 2. 执行__init__方法,给对象封装属性. # print(a) =========================================================================== # python中的设计模式: 单例模式 # 一个类只允许实例化一个对象. # class A: # # pass # obj = A() # print(obj) # obj1 = A() # print(obj1) # obj2 = A() # print(obj2) # 手写单例模式 # class A: # __instance = None # # def __init__(self,name): # self.name = name # # def __new__(cls,*args,**kwargs): # if not cls.__instance: # cls.__instance = object.__new__(cls) # return cls.__instance # # # obj = A('alex') # print(obj) # obj1 = A('李业') # print(obj1.name) # print(obj.name)
__init__初始化,给对象封装属性 __new__构造方法,新生成一个对象 __del__析构方法,当对象在内存中被释放时,触发执行 __len__计算长度 __hash__判断是否可哈希 __str__返回内容 __repr__原形毕露,返回其原始值 __call__对象+()触发执行call方法 __eq__同一类的两个实例比较时会触发 __item__对对象进行类似字典的操作就会触发该方法 __enter__上下文管理,进入时 __exit__上下文管理,出来时
-
item系列
# __item__系列 # __getitem__ __setitem__ __delitem__ 对对象做类似于字典的(增删改查)触发__item__系列 # __delattr__ del obj.属性 就会触发此方法 # class Foo: # def __init__(self,name): # self.name=name # # def __getitem__(self, item): # # print(item) # # print(666) # return self.__dict__[item] # # def __setitem__(self, key, value): # # self.__dict__[key]=value # print(key) # print(value) # # def __delitem__(self, key): # print('del obj[key]时,我执行') # # def __delattr__(self, item): # super().__delattr__(item) # print(f'对象的{item}属性已经删除') # # # f1=Foo('sb') # print(f1['name']) # f1[1] = 2 # # del f1[1] # del f1.name # print(f1.name) # f1['age']=18 # f1['age1']=19 # del f1.age1 # del f1['age'] # f1['name']='alex' # print(f1.__dict__)
-
上下文管理
# # 实例化对象的第二种方式: 必须基于 __enter__ 以及 __exit__这个两个方法. # with A('海狗') as obj: # print(obj.name) # class A: # # def __init__(self, text): # self.text = text # # def __enter__(self): # 开启上下文管理器对象时触发此方法 # self.text = self.text + '您来啦' # 第一步 # print(11111) # return self # 必须!!!将实例化的对象返回f1 # # def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法 # print(333) # 第三步 # self.text = self.text + ',这就走啦' # # with A('大爷') as f1: # print(2222) # print(f1.text) # 第二步 # print(f1.text) # 第四步
-
__iter__把对象编程一个可迭代的对象
class A: def __init__(self,name): self.name=name def __iter__(self): for i in range(10): yield i b=A('lijie') for i in b: print(i)
异常处理
-
什么是异常处理
调试Python程序时,经常会报出一些异常,异常的原因一方面可能是写程序时由于疏忽或者考虑不全造成了错误,这时就需要根据异常找到出错点,进行分析改正;另一方面,有些异常是不可避免的,但我们可以对异常进行捕获处理,防止程序终止. #注意事项: 1.异常处理要慎重使用,因为比较耗性能 2.异常处理的所包含的代码区域尽量精简,不要把整段代码都写入try,而是针对个别可能会抛异常的位置进行异常处理
-
异常处理中fifinally的用途
在出现异常之前执行,所以,不管怎样都会执行 finally 出不出现异常都执行,异常出现前执行fianlly 用途: 1关闭文件句柄,关闭数据库链接. 2 函数return之前能够执行finally代码. 3 break之前可以执行finally
-
异常处理结构分支
# 结构1:单分支 try: num = int(input('>>>')) # 出现ValueError错误之后,直接跳转到except语句. dic = {'name': '嘉欣'} print(dic['age']) print(111) except ValueError: print(666) # 结构2: 多分支 try: num = int(input('>>>')) # 出现ValueError错误之后,直接跳转到except语句. dic = {'name': '嘉欣'} print(dic['age']) l1 = [1, 2] print(l1[100]) print(111) except ValueError: print('输入的有非数字元素') except KeyError: print('没有此键') except IndexError: print('没有此下标') print(666) # 结构3: 万能异常: 处理所有pyhton识别的异常. try: dic = {'name': '嘉欣'} # print(dic['age']) l1 = [1, 2] print(l1[100]) print(111) for i in 123: pass except Exception as e: print(e) print(666) # 什么时候用万能? 什么时候用多分支? # 如果你对错误信息不关心,只是想要排除错误让程序继续运行. 用万能异常. # 你对错误信息要进行明确的分流,让你的程序多元化开发. # 结构4: 多分支+万能异常 def func(): pass def func1(): pass dic = { 1: func, 2: func1,} try: num = int(input('请输入序号')) dic[num]() except ValueError: print('请输入数字') except KeyError: print('请输入范围内的序号') except Exception: print('程序出现意料之外的错误....') # 结构5: try else finally try: dic = {'name': '嘉欣'} # print(dic['age']) l1 = [1, 2] # print(l1[100]) print(111) except KeyError: print('没有此键') except IndexError: print('没有此下标') else: print('如果没有出现异常则执行这里') finally: print('finally 666') # except 必须依赖于try, else必须依赖于except和try # finally只是依赖于try. # finally : 在异常出现之前,执行finally语句. try: dic = {'name': '嘉欣'} print(dic['age']) l1 = [1, 2] print(l1[100]) except KeyError: print('没有此键') except IndexError: print('没有此下标') finally: print('finally 666') # finally 用在 关闭数据库连接,文件句柄关闭,数据保存等,用到finally. with open('test1',encoding='utf-8',mode='r+') as f1: try: for i in f1: print(i) if ....: finally: f1.close() # 在return结束函数之前,执行finally代码. def func(): try: print(111) return 666 finally: print(222) print(func()) # 结构6: 主动触发异常. raise ValueError('出现了value错误') # 结构7: 断言: 展现出一种强硬的态度. # assert 条件 name = 'alex' n1 = input('请输入:') assert name == n1#只有assert得条件成立才会执行下面得代码 print(111) print(222) # 自定义异常 # python中给你提供的错误类型很多,但是不是全部的错误. class LiYeError(BaseException): def __init__(self,msg): self.msg=msg def __str__(self): return self.msg try: # 三行 raise LiYeError('socket.connent.....') except LiYeError as e: # e = LiYeError('类型错误') print(e)
第七章 网 络编程
C/S和B/S架构
-
C/S和B/S架构的介绍
#C:client客户端 #B:browse浏览器端 #S:server服务器端
-
C/S和B/S架构的优缺点
#C/S架构 基于客户端与服务端之间的通信 #优点:个性化设置,相应速度快 #缺点:开发成本高,维护成本高,占用空间,用户固定 ======================================================= #B/S架构 基于浏览器与服务端之间的通信 #优点:开发成本低,占用空间小,用户不固定 #缺点:功能相对单一,没有个性化设置,响应速度相对慢一点
网络通信原理
#1:两台计算机之间要有一堆物理链接介质连接
#2:找到对方计算机的位置
#3:遵循一揽子(osi七层协议)互联网通讯协议
OSI七层协议
-
物理层
#物理层值得就是网线,光纤,双绞线等物理连接介质 #物理层发送的是比特流
-
数据链路层
#数据链路层是对比特流进行分组
-
以太网协议
#以太网协议:对比特流进行合理的分组 #一组数据叫做一帧,数据报 #head头:固定的长度是18个字节: #源地址:6个字节 #目标地址:6个字节 #数据类型:6个字节 #data:最少是46个字节,最大是1500个字节 #一帧数据最少是64个字节,最大是1518个字节
-
mac地址
#mac地址就是计算机网卡上标注的地址,由12位16进制的数字组成,前六位是厂商编号,后六位是流水线号 #同一个局域网通过广播的形式发送数据: #交换机的mac的地址学习功能: #我们的前提是什么? 你必须知道对方的mac地址你才可以以广播的形式发消息.实际上,网络通#信中,你只要知道对方的IP与自己的IP即可.
-
计算机通信的方式
#同一个局域网内,通过广播的形式通信 #消息一经广播发出,局域网所有的计算机都能接收到消息,分析消息,是否是我的,不是就丢弃 #通讯是软件与软件之间的通讯,不是计算机之间的通讯
-
-
网络层
-
IP协议
#IP确定局域网(子网)的位置 #ip是四段是四段十进制 如:192.168.1.1,,取值范围是:0~255.0~255.0~255.0~255 #子网掩护:C类子网掩码: 255.255.255.0 #通过ip地址+子网掩护,按照为与运算,计算出是否在同一局域网(子网,网段) #如果想要给另一个计算机发送数据,就必须知道对方的ip地址
-
ARP协议
#ARP协议是通过对方的ip地址获取对方的mac地址
-
-
传输层
-
端口协议
#端口协议是确定软件在计算机的位置
-
UDP和TCP协议
#TCP(Transmission Control Protocol) 可靠的、面向连接的协议(eg:打电话)、流式协议, 传输效率低全双工通信(发送缓存& 接收缓存)、面向字节流。使用 #TCP的应用:Web浏览器;文件传输程序。 UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延 小),一对一、一对多、多对一、多对多、面向报文(数据包),尽最大努力服务,无拥塞控 制。使用UDP的应用:域名系统(DNS);视频流;IP语音(VoIP)。
-
TCP协议的三次握手和四次挥手
#syn洪水攻击:制造大量的假的无效的IP请求服务器.致使正常的IP访问不了服务器.
-
-
应用层
-
自己定义的协议
#用户的数据
-
-
总结
#广播(局域网内) + mac地址(计算机位置) + ip(局域网的位置) + 端口(软件在计算机的位置) #有了以上四个参数:你就可以确定世界上任何一个计算机的软件的位置 ========================================= #前提:知道目标mac: 计算机A 发送一个消息给 计算机B 源码mac 目标mac 源IP 目标IP 数据 单播的形式发送到交换机,交换机会检测自己的 对照表有没有目标mac,如果有,单播传.如果没有, 交由上一层: 路由器: 路由器收到消息: 对消息进行分析: 要确定目标计算机与本计算机是否在同一网段, 如果在同一网段,直接发送给对应的交换机,交换机在单播发给目标mac. ==================================================== #前提:不知道目标mac: 计算机A 发送一个消息给 计算机B 源码mac 目标mac不知道 源IP 目标IP 数据 单播的形式发送到交换机,交换机交由上一层路 由器:路由器收到消息: 对消息进行分析: 要确定目标计算机与本计算机是否在同一网段, 如果在同一网段通过 IP以及ARP协议获取到对方的mac地址,然后在通信.
-
五层协议详细图
知识点回顾
单播:单独联系某一个人. 广播:给所有人发送消息(群发) 比特流: bit就是 0101 跟水流一样的源源不断的发送 010101001. 以太网协议: 将数据进行分组:一组称之为一帧,数据报. head | data head: 18个字节: 源mac地址 | 目标mac地址| 数据类型 data: 最少46个字节, 最多是1500个字节. mac地址: 就是计算机网卡上记录的地址,世界上所有的计 算机独一无二的标识. 用于局域网内广播(单播)时查找的计 算机的位置. 交换机: 分流连接计算机的作用. 交换机的mac学习功能: 第一次发送消息广播的形式,当学习表记录上端口与mac 地址对应关系之后,在发送消息: 单播的形式发送. 端口1: 1C-5F-4B-3E-35-2C 端口2: 1C-5F-4B-6E-35-2C 广播风暴: 所有的计算机都在广播的形式发送消息. IP协议: 四段分十进制 172.168.0.1 子网掩码: A: 255.0.0.0 B: 255.255.0.0 C: 255.255.255.0 路由器: 外网(公网)IP, 内网(局域网)IP 都是假的,DHCP协议: 路由器自动分发的 IP地址,网关等等. 端口: 0~1023系统的, 自己选取端口8080 以后都可以. ARP协议: 通过IP获取计算机mac地址. TCP协议: 面向链接的协议,流式协议.安全可靠效率低的协 议, 传输文件,浏览器等. UDP协议: 用户数据报协议,效率高,不可靠的协议, 微信.
socket套接字
-
socket套接字介绍**
#socket是处于应用层与传输层之间的抽象层,他是一组操作起来非常简单的接口(接受数据)此接口接受数据之后,交由操作系统. #为什么存在socket抽象层? #如果直接与操作系统数据交互非常麻烦,繁琐,socket对这些繁琐的的操作高度的封装,简化.
-
recv的工作原理
# 1,验证服务端缓冲区数据没有取完,又执行了recv执行,recv会继续取值。 # 2,验证服务端缓冲区取完了,又执行了recv执行,此时客户端20秒内不关闭的前提下,recv处于阻塞状态。 # 3 验证服务端缓冲区取完了,又执行了recv执行,此时客户端处于关闭状态,则recv会取到空字符串。recv空字符 串: 对方客户端关闭了,且服务端的缓冲区没有数据了,我再recv取到空bytes.
-
基于UDP协议的网络通信
##=====server端 import socket server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 基于网络的UDP协议的socket server.bind(('192.168.14.198',9000)) while 1: from_client_data = server.recvfrom(1024) # 阻塞,等待客户来消息 print(f'\033[1;35;0m来自客户端{from_client_data[1]}: {from_client_data[0].decode("utf-8")} \033[0m') to_client_data = input('>>>').strip() server.sendto(to_client_data.encode('utf-8'),from_client_data[1]) # 1. 基于udp协议的socket无须建立管道,先开启服务端或者客户端都行. # 2. 基于udp协议的socket接收一个消息,与发送一个消息都是无连接的. # 3. 只要拿到我的ip地址和端口就都可以给我发消息,我按照顺序接收消息. #=======client端 import socket client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 基于网络的UDP协议的socket while 1: to_server_data = input('>>>:').strip() client.sendto(to_server_data.encode('utf-8'),('127.0.0.1',9000)) data,addr = client.recvfrom(1024) print(f'来自服务端{addr}消息:{data.decode("utf-8")}')
-
粘包现象
-
缓存区
#每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区 write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。 TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。 read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。 这些I/O缓冲区特性可整理如下: 1.I/O缓冲区在每个TCP套接字中单独存在; 2.I/O缓冲区在创建套接字时自动生成; 3.即使关闭套接字也会继续传送输出缓冲区中遗留的数据; 4.关闭套接字将丢失输入缓冲区中的数据 #须知:只有TCP有粘包现象,UDP永远不会粘包!
-
产生粘包现象的两种情况
#1,接收方没有及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收 了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) #2,发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据也很小,会合到一起,产生粘包)
-
粘包的解决方案
#问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总数按照固定字节发送给接收端后面跟上总数据,然后接收端先接收固定字节的总字节流,再来一个死循环接收完所有数据。
-
多进程
进程的基础
-
什么是程序
#程序就是一堆静态的代码文件
-
什么是进程
#一个由操作系统操控调用交由CPU运行的程序就是一个进程
操作系统
-
什么是操作系统
#操作系统的定义:操作系统就是一个协调、管理和控制计算机硬件资源和软件资源的控制程序
-
操作系统的作用
#1:将一些复杂丑陋的借口,变成一些简单美丽的接口(为应用程序员提供调用硬件资源的更好,更简单,更清晰的模型(系统调用接口)。应用程序员有了这些接口后,就不用再考虑操作硬件的细节,专心开发自己的应用程序即可。) #2:将应用程序对硬件资源的竞态请求变得有序化(多个进程抢占一个资源的时候,操作系统会将你的执行变的合理有序) #例如:很多应用软件其实是共享一套计算机硬件,比方说有可能有三个应用程序同时需要申请打印机来输出内容,那么a程序竞争到了打印机资源就打印,然后可能是b竞争到打印机资源,也可能是c,这就导致了无序,打印机可能打印一段a的内容然后又去打印c...,操作系统的一个功能就是将这种无序变得有序。 阻塞:input,read,write,sleep,recv,accept,sendto,recvfrom........
-
操作系统与不同软件的区别
# 1.主要区别是:你不想用暴风影音了你可以选择用迅雷播放器或者干脆自己写一个,但是你无法写一个属于操作系统一部分的程序(时钟中断处理程序),操作系统由硬件保护,不能被用户修改。 # 2.操作系统与用户程序的差异并不在于二者所处的地位。特别地,操作系统是一个大型、复杂、长寿的软件,
-
操作系统发展史须知点
===================== #第一代计算机的优缺点(1940~1955): #优点: 个人独享整台计算机 #缺点: 1:硬件调试插线,耗时 2:所有程序都是串行执行 ====================== #第二代:磁带存储__批处理系统(1955~1965) #优点: 1:不用程序员亲自对硬件进行插线操控,效率提高 2:可以进行批量处理 #缺点" 1:程序员不能独自使用计算机 2:所有程序还是串行 ===================== #第三代:集成电路,多道程序系统(物理隔离) #大背景 1:集成电路:把所有的硬件变小,线路板 2:将两套不同的生产线合并成一条生产线 #多道技术 #1:空间上的复用 将内存分区域,,一个内存可以同时加载多个进程 #2:时间上的复用 实现将CPU在多个进程之间来回切换,并且保留状态 当进程遇到IO阻塞或者长时间运行时,操作系统会将此进程挂起,保留状态,会将CPU强行 的切换到另一个进程 #每个人占用计算机的时间时有限的
进程的理论
-
串行和并行
#串行:所有的任务一个一个的排队让CPU执行 #并发:一个CPU完成多个任务,看起来像是同时完成. 如果是IO密集型,CPU来回切换提升效率 如果是计算密集型,CPU来回切换降低效率 #并行:多个CPU执行多个任务,真正的同时完成 #阻塞:CPU遇到IO就是阻塞 #非阻塞:没有IO,就叫非阻塞 =============================== 一个程序可一开启多个进程
-
进程的创建
1:一个主进程开启多个子进程(一个子进程必须依赖与一个主进程才能开启) #wondows:操作系统调用CreatePrecess处理进程的创建,创建一个子进程,会copy主进程的所有资源,但是会发生一些改变 #mac(UNIX)fork创建子进程,创建一个子进程,会完完全全复制一个主进程的所有资源
-
进程的三种状态
#运行,阻塞,就绪
进程创建的两种方式
-
第一种
from multiprocessing import Process import time def task(name): print(f'{name} is running') time.sleep(3) print(f'{name} is gone') if __name__ == '__main__':#在windows下必须使用__main__方法 P=Process(target=task,args=('立业',))#创建一个进程对象 P.start()#只是向操作系统发出一个开辟子进程的信号然后就执行下一行了, #这个信号操作系统接受以后,会从内存中开辟一个子进程空间,然后再将主进程所有的数据copy加载到子进程,然后在调用CPU去执行 #开辟子进程开销是很大 print('===主线程') #所以永远会先执行主进程的代码
-
第二种
class MyProcess(Process): def __init__(self,name): super().__init__() self.name=name def run(self):#run方法必须写,开启子进程调用的就是run方法 print(f'{self.name} is running') time.sleep(3) print(f'{self.name} is done') if __name__ == '__main__': P=MyProcess('立业') P.start() print('哈哈哈')
-
简单的场景
#简单应用 from multiprocessing import Process import time def task(name): print(f'{name} is running') time.sleep(1) print(f'{name} is gone') def func(name): print(f'{name} is running') time.sleep(1) print(f'{name} is gone') def foo(name): print(f'{name} is running') time.sleep(1) print(f'{name} is gone') if __name__ == '__main__': start_time=time.time() p=Process(target=task,args=('立业',)) p1=Process(target=func,args=('还够',)) p.start() p1.start() foo('lijie') print(f'{time.time()-start_time}')
获取进程的pid
-
代码获取子进程和父进程的pid
import os from multiprocessing import Process import time def task(): print(os.getpid())#查看子进程的pid print(os.getppid())#查看父进程的pid if __name__ == '__main__': p=Process(target=task) p.start() print(f'{os.getpid()}===')#查看主线程的pid print(os.getppid())#查看pycharm的pid
-
cmd终端获取pid
#tasklist获取所有进程的pid
#tasklist | findstr pycharm 指定获取某一个进程
验证进程之间的空间隔离
from multiprocessing import Process
import time
#不可变数据类型
name='理解'
def task():
global name
name='haha'
print(f'--子进程name:{name}')
if __name__ == '__main__':
p=Process(target=task)
p.start()
print('==主进程')
time.sleep(1)
print(f'==主进程{name}')
#可变数据类型
lst=['田彩']
def func():
lst.append('李杰')
print(f'--子进程lst:{lst}')
if __name__ == '__main__':
p=Process(target=func)
p.start()
print(f'==主线程开始')
time.sleep(1)
print(f'==主线程lst:{lst}')
#也可以理解成深拷贝的概念(思想)
join(阻塞)
-
join的意思
# join让主进程等待子进程结束之后,再执行主进程
-
单个子线程代码实例
#简单示例 from multiprocessing import Process import time def task(name): print(f'{name} is running') time.sleep(1) print(f'{name} is gone') if __name__ == '__main__': p=Process(target=task,args=('立业',)) p.start() p.join() print('==主进程') #打印结果:(主线程是在子线程结束之后才执行的) # 立业 is running # 立业 is gone # ==主进程
-
多个子线程示例
#多个子线程执行join #错误示范(串行示例) def task(name): print(f'{name} is running') time.sleep(1) print(f'{name} is gone') if __name__ == '__main__': for i in range(4): p=Process(target=task,args=('liye',)) p.start() p.join() print('==主线程执行') #打印结果: # liye is running # liye is gone # liye is running # liye is gone # liye is running # liye is gone # liye is running # liye is gone # ==主线程执行 #正确示例(并行或并发示例) def task(name): print(f'{name} is running') time.sleep(1) print(f'{name} is gone') if __name__ == '__main__': lst=[] for i in range(4): p=Process(target=task,args=('liye',)) p.start() lst.append(p) for y in lst: y.join() print('==主线程执行') #打印结果: # liye is running # liye is running # liye is running # liye is running # liye is gone # liye is gone # liye is gone # liye is gone # ==主线程执行
进程的其他参数
#杀死进程terminate
#name,给子进程起名字
#is_alive判断子进程是否存活(返回True或者False)
from multiprocessing import Process
import time
def task(name):
print(f'{name} is running')
time.sleep(2)
print(f'{name} is gone')
if __name__ == '__main__':
p=Process(target=task,args=('立业',),name='alex')
p.start()
print(p.name)#打印子进程的名字
p.terminate()#杀死子进程
time.sleep(1)
print(p.is_alive())#判断子进程是否存活
print('==主线程开始')
守护进程
-
守护进程的概念
# 守护进程: # 古时候 太监守护这个皇帝,如果皇帝驾崩了,太监直接也就死了. # 子进程守护着主进程,只要主进程结束,子进程跟着就结束,
-
代码示例
from multiprocessing import Process import time def task(name): print(f'{name} is running') time.sleep(2) print(f'{name} is gone') if __name__ == '__main__': p = Process(target=task, args=('立业',)) p.daemon = True #将子进程p设置成守护进程,只要主进程结束,守护进程也马上结束 p.start() time.sleep(1) print('==主进程执行') #打印结果 # 立业 is running #主进程结束,子进程也随之结束, # ==主进程执行
僵尸进程和孤儿进程
-
僵尸进程和孤儿进程只会出现在Unix,linux,macos上面,windows上不会出现
-
进程的概念
#1:主进程需要等待子进程结束之后,主进程才结束 主进程时刻监视子进程的运行状态,当子进程结束之后,一段时间之内,将子进程进行回收
-
为什么主进程不在子进程结束后马上对其进行回收
#1:主进程和子进程时异步关系,主进程无法马上捕获子进程什么时候结束 #2:如果子进程结束后马上在内存中释放资源,主进程就没有办法监视子进程的状态了
-
Unix针对上面的问题,提供了一个机制
#所有的子进程结束之后,立马会释放文件的操作链接,内存中的大部分数据,但会保留一些内容:进程号,结束时间,运行状态,等待主进程监测,回收
-
僵尸进程
#所有的子进程在结束之后,在被主进程回收之前都会进入僵尸状态
-
僵尸进程是有害的
#如果父进程不对僵尸进程进行回收,产生大量的僵尸进程,这样就会占用内存,占用进程pid号
-
僵尸进程如何解决
#父进程产生了大量子进程,但是不回收,这样就会形成大量的僵尸进程,解决方式就是直接杀死父进程,将所有的僵尸进程变成孤儿进程进程,由init进行回收
-
孤儿进程
#父进程由于某种原因结束了,但是你的子进程还在运行,这样你的这些子进程就变成了孤儿进程,你的父进程如果结束了,你的所有的孤儿进程,就会被init进程回收,init就变成了父进程,对孤儿进程进行回收
互斥锁
-
什么是互斥锁
#互斥锁就是在保证子进程串行的同时,也保证了子进程执行顺序的随机性,以及数据的安全性 使用互斥锁的注意点: 使用互斥锁不能连续锁,不然会造成阻塞和死锁
-
代码示例
from multiprocessing import Process from multiprocessing import Lock import time import os import random import sys def task1(lock): lock.acquire() print(f'{os.getpid()}开始打印了') time.sleep(random.randint(1,3)) print(f'{os.getpid()}打印结束了') lock.release() def task2(lock): lock.acquire() print(f'{os.getpid()}开始打印了') time.sleep(random.randint(1, 3)) print(f'{os.getpid()}打印结束了') lock.release() def task3(lock): lock.acquire() print(f'{os.getpid()}开始打印了') time.sleep(random.randint(1, 3)) print(f'{os.getpid()}打印结束了') lock.release() if __name__ == '__main__': lock=Lock() for i in ['task1','task2','task3']: p=Process(target=getattr(sys.modules[__name__],i),args=(lock,)) p.start()
-
示意图
-
join和Lock锁的共同点和不同点
#共同点: 都可以把并发改成串行,保证了执行的顺序 #不同点: join是人为的设置顺序,Lock锁时让其争抢顺序,保证了公平性
-
基于文件的进程之间的通信
#进程在内存级别是隔离的,但是文件在磁盘上 #使用lock锁实现文件上的通讯 from multiprocessing import Process from multiprocessing import Lock import json import time import os import random # 当多个进程共抢一个数据时,如果要保证数据的安全,必须要串行. # 要想让购买环节进行串行,我们必须要加锁处理. def search(): time.sleep(random.randint(1,3)) # 模拟网络延迟(查询环节) with open('ticket.json',encoding='utf-8') as f1: dic = json.load(f1) print(f'{os.getpid()} 查看了票数,剩余{dic["count"]}') def paid(): with open('ticket.json', encoding='utf-8') as f1: dic = json.load(f1) if dic['count'] > 0: dic['count'] -= 1 time.sleep(random.randint(1,3)) # 模拟网络延迟(购买环节) with open('ticket.json', encoding='utf-8',mode='w') as f1: json.dump(dic,f1) print(f'{os.getpid()} 购买成功') def task(lock): search() lock.acquire() paid() lock.release() if __name__ == '__main__': mutex = Lock() for i in range(6): p = Process(target=task,args=(mutex,)) p.start() #当很多进程共强一个资源(数据)时, 你要保证顺序(数据的安全),一定要串行. #互斥锁: 可以公平性的保证顺序以及数据的安全.
-
基于文件的进程间通讯的特点
#1:效率低 #2:自己加锁麻烦而且容易出现死锁
队列
-
队列的特点
#1:把队列当成一个容器,这个容器可以承载一些数据 #2:队列的特性是数据保持先进先出原则,FIFO
-
队列的示例代码
from multiprocessing import Queue q = Queue(3) q.put(1) q.put('alex') q.put([1,2,3]) q.put(5555) # 当队列满了时,在进程put数据就会阻塞. print(q.get()) print(q.get()) print(q.get()) print(q.get()) # 当数据取完时,在进程get数据也会出现阻塞,直到某一个进程put数据. from multiprocessing import Queue q = Queue(3) # maxsize q.put(1) q.put('alex') q.put([1,2,3]) # q.put(5555,block=False) # print(q.get()) print(q.get()) print(q.get()) print(q.get(timeout=3)) # 阻塞3秒,3秒之后还阻塞直接报错. # print(q.get(block=False)) # block=False 只要遇到阻塞就会报错.
-
使用基于文件和队列的进程通信方式的优缺点
#基于文件的进程通讯方式,在写入文件的时候耗费性能,效率低,在枷锁的时候,又可能出现锁死或递归锁的情况,相比之下队列的效率更高,也不会出现锁死或者递归锁的情况
多线程
-
什么是多线程
#线程是计算机中可以被cpu调度的最小单位。一个进程中可以有多个线程,同一个进程中的线程可以共享此进程中的资源,一个进程中至少有一个线程。线程中的资源小于进程的内存占用。
-
多线程的应用
import threading def task(arg): pass #实例化一个线程对象 t = threading.Thread(target=task,args=('xxx',)) # 将线程提交给cpu t.start()
import threading def task(arg): ret = requests.get(arg) file_name = arg.rsplit('/', maxsplit = 1)[-1] with open(file_name,mode='wb')as f: f.write(ret.content) for url in url_list: #实例化一个线程对象 t = threading.Thread(target = task,args = (url,)) #将线程提交给cpu t.start()
-
基于socket和多线程实现的socketserver功能的模块
import socket import threading def task(connect,address): pass server = socket.socket() server.bind(('127.0.0.1',9000)) server.listen(8) while True: conn,addr = server.accept() # 处理用户请求 t = threading.Thread(target = task,args=(conn,addr,)) t.start()
-
线程安全
#多个线程同时去操作一个"东西",不要存在数据混乱。 #线程安全:logging模块/列表 #线程不安全:自己做文件操作/同时修改一个数字 #使用锁来保证数据安全,来了多个线程,使用锁保证数据安全,来了多个线程,使用锁让他们排队,逐一执行。
协程
- 协程
# 安装greenlet pip3 install greenlet
from greenlet import greenlet
def test1():
print('i1')
gr2.switch()
print('i3')
gr2.switch()
def test2():
print('i2')
gr1.switch()
print('i4')
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
-
协程+IO切换
# 安装gevent; pip3 install gevent from gevent import monkey monkey.patch_all() import gevent import time def eat(): print('eat food 1') time.sleep(3) print('eat food 2') def play(): print('play 1') time.sleep(3) print('play 2') g1 = gevent.spawn(eat) g2 = gevent.spawn(play) gevent.joinall([g1, g2])
-
协程+IO切换+爬虫实例
from gevent import monkey monkey.patch_all() import gevent import requests def f1(url): print('GET: %s' % url) data = requests.get(url) print('%d bytes received from %s.' % (len(data.content), url)) def f2(url): print('GET: %s' % url) data = requests.get(url) print('%d bytes received from %s.' % (len(data.content), url)) def f3(url): print('GET: %s' % url) data = requests.get(url) print('%d bytes received from %s.' % (len(data.content), url)) gevent.joinall([gevent.spawn(f1, 'https://www.python.org/'), gevent.spawn(f2,'https://www.yahoo.com/'), gevent.spawn(f3,'https://github.com/'),])
三程面试题
进程/线程/协程的区别?
- 1.进程是计算器最小资源分配单位
- 2.线程是CPU调度的最小单位
- 3.进程切换需要的资源很最大,效率很低
- 4.线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
- 5.协程切换任务资源很小,效率高(协程本身并不存在,是程序员通过控制IO操作完成)
- 6.多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发
#进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大。
#线程: 调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
#协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
生产者消费者模型
- 队列
""" 队列:
Queue
redis中的列表
rabbitMQ
"""
from queue import Queue
q = Queue()
"""
q.put('123')
q.put(456)
v1 = q.get()
v2 = q.get()
print(v1,v2)
"""
# 默认阻塞
v1 = q.get()
print(v1)
-
发邮件实例
1.申请邮箱
#代码示例 """ 1. 申请126或163邮箱 2. 开启服务+授权码 3. 通过代码发送 """ import smtplib from email.mime.text import MIMEText from email.utils import formataddr # 写邮件的内容 msg = MIMEText('老板,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["炮手", 'zh309603@163.com']) msg['To'] = formataddr(["老板", '424662508@qq.com']) msg['Subject'] = "情爱的导演" server = smtplib.SMTP_SSL("smtp.163.com", 465) server.login("zh309603", "zhzzhz123") # 授权码 server.sendmail('zh309603@163.com'['424662508@qq.com', ], msg.as_string()) server.quit()
2.生产者消费者模型
import threading from queue import Queue import time q = Queue() 总结 1. 线程池&进程池 [用法+示例2] 2. 协程 (进程/线程/协程的区别?) 最重要 3. 发邮件的功能 4. 锁 5. 线程安全 6. 生产者消费者模型 def send(to,subject,text): import smtplib from email.mime.text import MIMEText from email.utils import formataddr # 写邮件的内容 msg = MIMEText(text, 'plain', 'utf-8') msg['From'] = formataddr(["炮手", 'zh309603@163.com']) msg['To'] = formataddr(["老板", to]) msg['Subject'] = subject server = smtplib.SMTP_SSL("smtp.163.com", 465) server.login("zh309603", "zhzzhz123") # 授权码 server.sendmail('zh309603@163.com', [to, ], msg.as_string()) server.quit() def producer(i): """ 生产者 :return: """ print('生产者往队列中放了10个任务',i) info = {'to':'424662508@qq.com', 'text':'你好','subject':'好友请求'} q.put(info) def consumer(): """ 消费者 :return: """ while True: print('消费者去队列中取了任务') info = q.get() print(info) send(info['to'],info['subject'],info['text']) for i in range(10): t = threading.Thread(target=producer,args=(i,)) t.start() for j in range(5): t = threading.Thread(target=consumer) t.start()
并发编程,多进程,多线程,多协程总结
多进程
# 并发编程:
# IO操作:input/output
# 阻塞 非阻塞(get_nowait) 同步 异步(start terminate submit map)并发 并行
# 进程的三状态图:阻塞 运行 就绪
# 进程 计算机中最小的资源分配单位
# 进程之间数据隔离\资源不共享
# 可以利用多个cpu
# 开启和销毁的开销大
# 由操作系统负责调度
# multiprocessing模块
# Process 类:开启进程
# 各种操作进程的方法
# 守护进程
# IPC: 进程之间通信
# 基于文件Queue Pipe\基于网络socket, 第三方工具
# 进程中的互斥锁 Lock:性能好
# 进程中的递归锁 RLock: 效率低
# 递归锁可以锁多次不会发生死锁
多线程
# 并发编程
# IO操作:input/output
# 阻塞 非阻塞(get_nowait) 同步 异步(start terminate submit map) 并发 ,并行
# 进程的三状态图:阻塞 运行 就绪
# 计算机中能够被操作系统调度的最小单位
# 线程之间资源共享
# 可以利用多核
# 开启和销毁的开销小
# 由操作系统负责调度
# GIL锁:全局解释器下 互斥锁
# 导致了Cpython解释器下 同一个进程下的多个线程 不能利用多核
# 由于垃圾回收机制gc不能在多线程环境下正常进行引用计数
# threading模块
# Thread类
# 开启线程
# 守护线程:守护整个主线程的
# 子线程先结束
# 主线程结束
# 主进程结束
# 主进程结束了 如果还存在守护线程,那么守护线程会随着进程的结束被回收
# 主线程结束意味着主进程就结束了,一旦主进程结束,所有的属于这个进程的资源都被回收了
# 主线程必须等待子线程结束
-
优先级队列
from queue import PriorityQueue pq = PriityQueue() pq.put((10,'alex')) pq.put((5,'engon')) pq.put((15,'eval_J')) #优先级队列,类似于注册会员,优先级队列,根据优先级吐数据
-
回调函数
import requests from concurrent.futures import ThreadPoolExector def get_url(name,url): ret = requests.get(url) return name,ret.content def dump(res): with open(res.result()[0],mode='wb') ad f: f.write(res.result()[1]) tp = ThreadPoolExector(4) dic = { 'baidu':'http://www.baidu.com', 'taobao':'http://www.taobao.com', 'jd':'http://www.jd.com', 'sina':'http//www.sina.com', 'cnblog':'https://www.cnblogs.com/Eva-J/articles/9676220.html', } for k in dic: ret = tp.submit(get_url,k,dic[k]) ret.add_done_callback(dump) # 回调函数,url里面的东西谁先先执行,谁先返回
协程
# 协程
# 协程是微线程
# 由程序控制的,不是由操作系统调度的
# gevent 第三方模块
# 协程能够识别的IO操作:网络操作sleep
"""
协程文件操作不行,目前只有网路和时间模块
"""
第八章 数据库
数据库管理系统
数据库管理系统(DBMS)
# 网络应用服务端
# 我们使用服务端的数据 - 需要有一个客户端
# 客户端可以自己写 :未来写代码的时候
# 也可以自己写:第三方的工具 数据库管理软件的公司出版的官方客户端
# 数据库管理系统本质上也是管理,堆文件
# 只不过人家的福安理论方式比我们更高效
# 数据库管理员(DBA维护数据库)
# 搭建数据库服务环境
# 用户的创建 权限的管理
# 性能/语句的优化
# 数据库的二次开发:让数据具有公司的特质
# 软件
# mysql (火,因为不要钱)小公司,互联网企业
# 甲骨文 oracle:事业单位,金融企业用,跟钱有关系的。
# 微软 sql server
# sqllite
# 数据库的各个版本
# 5.6(基础版本),5.7(有坑公司不会用),直接跳到8.0(新的东西没有尝试)
# 名词
# DB数据库-文件夹(DB)
# 文件相当于一张表(table)
# 表里的每一行我们称之为一条数据(data)
# 数据库的分类
# 关系型数据库(mysql,oracle,sqlserver,sqllite)
# 非关系型数据库(redis,mongodb,memcache,hbase)
# 例如:{'alex':[84,'不详',13838384388],}只有key和vaule的关系,通过值里的东西不能找到键。
#
-
数据库要做的事情
# SQL语言主要用于存取数据、查询数据、更新数据和管理关系数据库系统,SQL语言由IBM开发。SQL语言分为3种类型: 1.DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程,例如CREATE DROP ALTER 2.DML语句 数据库操纵语言: 插入数据INSERT、删除数据DELETE、更新数据UPDATE、查询数据SELECT 3.DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT、REVOKE
-
数据库的简单操作
1. 操作文件夹(库) 增:create database db1 charset utf8; 查:show databases; 改:alter database db1 charset latin1; 删除: drop database db1; 2. 操作文件(表) 先切换到文件夹下:use db1 增:create table t1(id int,name char); 查:show tables; 改:alter table t1 modify name char(3); alter table t1 change name name1 char(2); 删:drop table t1; 3. 操作文件中的内容(记录) 增:insert into t1 values(1,'egon1'),(2,'egon2'),(3,'egon3'); 查:select * from t1; 改:update t1 set name='sb' where id=2; 删:delete from t1 where id=1; 清空表: delete from t1; #如果有自增id,新增的数据,仍然是以删除前的最后一样作为起始。 truncate table t1;数据量大,删除速度比上一条快,且直接从零开始, *auto_increment 表示:自增 *primary key 表示:约束(不能重复且不能为空);加速查找
MySql链接
Eva_J的博客:
MySql支持的数据类型:
https://www.cnblogs.com/Eva-J/articles/9683316.html
表的完整性约束:
https://www.cnblogs.com/Eva-J/articles/9687915.html
mysql创建表的时候如何理清表与表之间的关系:
https://blog.csdn.net/qq_44540112/article/details/93889051
数据库命令
1.dbms 数据库管理系统
dba 数据库管理员
db 数据库/文件夹
table 表/文件
data 表中具体数据
2.关系型 mysql oraccle sqlserver sqllite
非关系型 redis mongodb hbase
基本命令:
mysqld install 安装sql服务
net start mysql 启动服务
net stop mysql 停止服务
mysql -uroot -h192.168.12.45 -p
Enter password:
mysql>
# 你启动的mysql.exe是客户端S 你安装好的服务是server
# 在客户端需要指定 在登陆的数据库所在的ip 以及用户名和密码
# mysql -uroot -p123 -h192.168.12.45
# mysql>set password = password('123');设置密码。
# 用户
# create user '用户名'@'允许的网段'identified
grant usage on 数据库.表 to 'eva'@'%';
grant select on 数据库.* to 'eva'@'%';
grant update on *.* to 'eva'@'%';
grant insert on *.* to 'eva'@'%';
grant delete on *.* to 'eva'@'%';
grant all on ftp.* to 'eva'@'%';
show databases; 查看当前的所有库
create database ftp;
mysql -ueva -h192.168.12.22 -p123
mysql> select user();
数据库的基本操作
库,表,数据,增删改查
1. 操作文件夹(库)
增:create database db1 charset utf8;
查:show databases;
改:alter database db1 charset latin1;
删除: drop database db1;
2. 操作文件(表)
先切换到文件夹下:use db1
增:create table t1(id int,name char);
查:show tables;
改:alter table t1 modify name char(3);
alter table t1 change name name1 char(2);
删:drop table t1;
3. 操作文件中的内容(记录)
增:insert into t1 values(1,'egon1'),(2,'egon2'),(3,'egon3');
查:select * from t1;
改:update t1 set name='sb' where id=2;
删:delete from t1 where id=1;
清空表:
delete from t1; #如果有自增id,新增的数据,仍然是以删除前的最后一样作为起始。
truncate table t1;数据量大,删除速度比上一条快,且直接从零开始,
*auto_increment 表示:自增
*primary key 表示:约束(不能重复且不能为空);加速查找
创建表
# 语法:
create table 表名(
字段名1 类型[(宽度) 约束条件],
字段名2 类型[(宽度) 约束条件],
字段名3 类型[(宽度) 约束条件]
);
# 注意:
1. 在同一张表中,字段名是不能相同
2. 宽度和约束条件可选
3. 字段名和类型是必须的
# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
创建一个表的过程:
# 1.创建库create database staff;———
# 2.用库use staff;————
# 3.创建表create table staff_info(变量 大小,变量 大小,)————
# 4.查看表show tables;————
# 5.查看表结构desc staff_info;/查看表构造show create table 表名;————
# 6.查看表里的东西select id,name,sex from staff_info;/查看表select * from staff_info;
# 7.向表里添加数据insert into staff_info (id,name,age,sex,phone,job) values(1,'alex',83,'female',13636364361,'IT');
# 8.基于上面继续添加insert into staff_info values(要添加的数据);
# 9.最后在查看表
- 创建表需要注意的事项
# mysql 中表与表之间的关系(如何找出两张表的对应关系)
分析步骤:
1.先从左表的角度去找。
是否左表的多条记录可以对应右表的一条记录,如果是,则证明左表的一个字段foreign key 右表一个字段 (通常是id)
2.再从右表的角度去找。
是否右表的多条记录可以对应左表的一条记录,如果是,则证明右表的一个字段foreign key 左表一个字段(通常是id)
3.总结
多对一:
如果只有步骤1成立,则是左表多对一右表
如果只有步骤2成立,则是右表多对一左表
多对多:
如果步骤1和2同时成立,则证明这两张表是一个双向多对一,既多对多。
需要定义一个这两张表的关系表来专门放二者的关系,(建第三张表)。
一对一:
如1和2都不成立,而是左表的一条记录唯一对应右表的一条记录,则为一对一。反之亦然,这种情况很简单,就是左表foreign key 右表的基础上,将左表的外键字段设置成unique即可。
修改表结构
- 修改表结构
语法:
1. 修改表名
ALTER TABLE 表名
RENAME 新表名;
2. 增加字段
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…],
ADD 字段名 数据类型 [完整性约束条件…];
3. 删除字段
ALTER TABLE 表名
DROP 字段名;
4. 修改字段
ALTER TABLE 表名
MODIFY 字段名 数据类型 [完整性约束条件…];
ALTER TABLE 表名
CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];
ALTER TABLE 表名
CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];
5.修改字段排列顺序/在增加的时候指定字段位置
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…] FIRST;
ALTER TABLE 表名
ADD 字段名 数据类型 [完整性约束条件…] AFTER 字段名;
ALTER TABLE 表名
CHANGE 字段名 旧字段名 新字段名 新数据类型 [完整性约束条件…] FIRST;
ALTER TABLE 表名
MODIFY 字段名 数据类型 [完整性约束条件…] AFTER 字段名;
-
alter操作非空和唯一(了解就行)
create table t(id int unique,name char(10) not null); #去掉null约束 alter table t modify name char(10) null; # 添加null约束 alter table t modify name char(10) not null; # 去掉unique约束 alter table t drop index id; # 添加unique约束 alter table t modify id int unique; alter处理null和unique约束 alter操作非空和唯一(了解)
-
alter操作主键(了解)
1、首先创建一个数据表table_test: create table table_test( `id` varchar(100) NOT NULL, `name` varchar(100) NOT NULL, PRIMARY KEY (`name`) ); 2、如果发现主键设置错了,应该是id是主键,但如今表里已经有好多数据了,不能删除表再重建了,仅仅能在这基础上改动表结构。 先删除主键 alter table table_test drop primary key; 然后再增加主键 alter table table_test add primary key(id); 注:在增加主键之前,必须先把反复的id删除掉。
-
为表添加外键(了解)
创建press表 CREATE TABLE `press` ( `id` int(11) NOT NULL, `name` char(10) DEFAULT NULL, PRIMARY KEY (`id`) ) ; 创建book表 CREATE TABLE `book` ( `id` int(11) DEFAULT NULL, `bk_name` char(12) DEFAULT NULL, `press_id` int(11) NOT NULL, KEY `press_id` (`press_id`) ) ; 为book表添加外键 alter table book add constraint fk_id foreign key(press_id) references press(id); 删除外键 alter table book drop foreign key fk_id;
-
实例
mysql> desc staff_info; # 表重命名 mysql> alter table staff_info rename staff; Query OK, 0 rows affected (0.00 sec) mysql> desc staff; # 删除sex列 mysql> alter table staff drop sex; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc staff; # 添加列 mysql> alter table staff add sex enum('male','female'); Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0 # 修改id的宽度 mysql> alter table staff modify id int(4); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc staff; # 修改name列的字段名 mysql> alter table staff change name sname varchar(20); Query OK, 4 rows affected (0.03 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> desc staff; # 修改sex列的位置 mysql> alter table staff modify sex enum('male','female') after sname; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc staff; # 创建自增id主键 mysql> alter table staff modify id int(4) primary key auto_increment; Query OK, 4 rows affected (0.02 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> desc staff; # 删除主键,可以看到删除一个自增主键会报错 mysql> alter table staff drop primary key; ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key # 需要先去掉主键的自增约束,然后再删除主键约束 mysql> alter table staff modify id int(11); Query OK, 4 rows affected (0.02 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> desc staff; mysql> alter table staff drop primary key; Query OK, 4 rows affected (0.06 sec) Records: 4 Duplicates: 0 Warnings: 0 # 添加联合主键 mysql> alter table staff add primary key (sname,age); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 # 删除主键 mysql> alter table staff drop primary key; Query OK, 4 rows affected (0.02 sec) Records: 4 Duplicates: 0 Warnings: 0 # 创建主键id mysql> alter table staff add primary key (id); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc staff; # 为主键添加自增属性 mysql> alter table staff modify id int(4) auto_increment; Query OK, 4 rows affected (0.02 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> desc staff; 示例
表操作
#删除表
drop table 表名; # 不建议使用
单表查询
-
单表查询语法
SELECT DISTINCT 字段1,字段2... FROM 表名 WHERE 条件 GROUP BY field HAVING 筛选 ORDER BY field LIMIT 限制条数
-
关键字执行的优先级
from where group by select distinct having order by limit 1.找到表:from 2.拿着where指定的约束条件,去文件/表中取出一条条记录 3.将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组 4.执行select(去重) 5.将分组的结果进行having过滤 6.将结果按条件排序:order by 7.限制结果的显示条数
-
简单的实例创建
# 需求信息 company.employee 员工id id int 姓名 emp_name varchar 性别 sex enum 年龄 age int 入职日期 hire_date date 岗位 post varchar 职位描述 post_comment varchar 薪水 salary double 办公室 office int 部门编号 depart_id int #创建表 create table employee( id int not null unique auto_increment, emp_name varchar(20) not null, sex enum('male','female') not null default 'male', #大部分是男的 age int(3) unsigned not null default 28, hire_date date not null, post varchar(50), post_comment varchar(100), salary double(15,2), office int, #一个部门一个屋子 depart_id int ); #查看表结构 mysql> desc employee; #插入记录 #三个部门:教学,销售,运营 insert into employee(emp_name,sex,age,hire_date,post,salary,office,depart_id) values ('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',7300.33,401,1), #以下是教学部 ('alex','male',78,'20150302','teacher',1000000.31,401,1), ('wupeiqi','male',81,'20130305','teacher',8300,401,1), ('yuanhao','male',73,'20140701','teacher',3500,401,1), ('liwenzhou','male',28,'20121101','teacher',2100,401,1), ('jingliyang','female',18,'20110211','teacher',9000,401,1), ('jinxin','male',18,'19000301','teacher',30000,401,1), ('成龙','male',48,'20101111','teacher',10000,401,1), ('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门 ('丫丫','female',38,'20101101','sale',2000.35,402,2), ('丁丁','female',18,'20110312','sale',1000.37,402,2), ('星星','female',18,'20160513','sale',3000.29,402,2), ('格格','female',28,'20170127','sale',4000.33,402,2), ('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门 ('程咬金','male',18,'19970312','operation',20000,403,3), ('程咬银','female',18,'20130311','operation',19000,403,3), ('程咬铜','male',18,'20150411','operation',18000,403,3), ('程咬铁','female',18,'20140512','operation',17000,403,3) ; #ps:如果在windows系统中,插入中文字符,select的结果为空白,可以将所有字符编码统一设置成gbk 准备表和记录
-
简单实例的查询语句
#简单查询 SELECT id,emp_name,sex,age,hire_date,post,post_comment,salary,office,depart_id FROM employee; SELECT * FROM employee; SELECT emp_name,salary FROM employee; #避免重复DISTINCT SELECT DISTINCT post FROM employee; #通过四则运算查询 SELECT emp_name, salary*12 FROM employee; SELECT emp_name, salary*12 AS Annual_salary FROM employee; SELECT emp_name, salary*12 Annual_salary FROM employee; #定义显示格式 CONCAT() 函数用于连接字符串 SELECT CONCAT('姓名: ',emp_name,' 年薪: ', salary*12) AS Annual_salary FROM employee; CONCAT_WS() 第一个参数为分隔符 SELECT CONCAT_WS(':',emp_name,salary*12) AS Annual_salary FROM employee; 结合CASE语句: SELECT ( CASE WHEN emp_name = 'jingliyang' THEN emp_name WHEN emp_name = 'alex' THEN CONCAT(emp_name,'_BIGSB') ELSE concat(emp_name, 'SB') END ) as new_name FROM employee;
-
where约束查询
where字句中可以使用: 1. 比较运算符:> < >= <= <> != 2. between 80 and 100 值在80到100之间 3. in(80,90,100) 值是80或90或100 4. like 'e%' 通配符可以是%或_, %表示任意多字符 _表示一个字符 5. 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not #1:单条件查询 SELECT emp_name FROM employee WHERE post='sale'; #2:多条件查询 SELECT emp_name,salary FROM employee WHERE post='teacher' AND salary>10000; #3:关键字BETWEEN AND SELECT emp_name,salary FROM employee WHERE salary BETWEEN 10000 AND 20000; SELECT emp_name,salary FROM employee WHERE salary NOT BETWEEN 10000 AND 20000; #4:关键字IS NULL(判断某个字段是否为NULL不能用等号,需要用IS) SELECT emp_name,post_comment FROM employee WHERE post_comment IS NULL; SELECT emp_name,post_comment FROM employee WHERE post_comment IS NOT NULL; SELECT emp_name,post_comment FROM employee WHERE post_comment=''; 注意''是空字符串,不是null ps: 执行 update employee set post_comment='' where id=2; 再用上条查看,就会有结果了 #5:关键字IN集合查询 SELECT emp_name,salary FROM employee WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ; SELECT emp_name,salary FROM employee WHERE salary IN (3000,3500,4000,9000) ; SELECT emp_name,salary FROM employee WHERE salary NOT IN (3000,3500,4000,9000) ; #6:关键字LIKE模糊查询 通配符’%’ SELECT * FROM employee WHERE emp_name LIKE 'eg%'; 通配符’_’ SELECT * FROM employee WHERE emp_name LIKE 'al__';
-
5个聚合函数
# count # max # min # avg # sum
-
分组聚合group by
# 查询岗位名以及岗位包含的所有员工名字 # select post,group_concat(emp_name) from employee group by post; # 查询各部门年龄在20岁以上的人的平均薪资 # select post,avg(salary) from employee where age>20 group by post; # select * from 表 where 条件 group by 分组
-
过滤having(group by + 聚合函数)
# 查询平均薪资大于1w的部门 # select avg(salary) from employee group by post having avg(salary) > 10000 # 1. 查询各岗位内包含的员工个数小于2的岗位名、岗位内包含员工名字、个数 # select post,emp_name,count(id) from employee group by post having count(id)<2 # 2. 查询各岗位平均薪资大于10000的岗位名、平均工资 # select post,avg(salary) from employee group by post having avg(salary) > 10000 # 3. 查询各岗位平均薪资大于10000且小于20000的岗位名、平均工资 # select post,avg(salary) from employee group by post having avg(salary) between 10000 and 20000;
-
order by
# 升序 # select * from employee order by salary; # select * from employee order by salary asc; # 降序 # select * from employee order by salary desc; # select * from employee order by age,salary; # select * from employee order by age,salary desc; # select * from employee order by age desc,salary;
-
limit
# select * from 表 order by 列 limit n; 取前n条 # select * from 表 order by 列 limit m,n; 从m+1开始,取n条 # select * from 表 order by 列 limit n offset m; 从m+1开始,取n条 # select * from 表 where 条件 group by 分组 having 过滤 order by 排序 limit n;
多表查询
-
表内连接
#重点:外链接语法 SELECT 字段列表 FROM 表1 INNER|LEFT|RIGHT JOIN 表2 ON 表1.字段 = 表2.字段; SELECT 字段列表,字段列表可以as新名字 FROMM 表1 INNER|LEFT|RIGHT JOIN 表2 ON 表1.字段 = 表2.字段; INNER内连接只链接量数据有相连的部分 LEFT连接需要显示左边全部信息 右边的无联系为空 RIGHT连接需要显示右边全部信息 左边的无联系为空。
-
表外连接
#以左表为准,即找出所有员工信息,当然包括没有部门的员工 #本质就是:在内连接的基础上增加左边有右边没有的结果 SELECT 字段列表 FROM 表1 INNER|LEFT|RIGHT JOIN 表2 ON 表1.字段 = 表2.字段; 内,左,右同内连一样
数据操作
初识数据库
初识数据库
为什么要用数据库
-
为什么要用数据库
-
数据库的优势
认识数据库
-
什么是数据(Data)
-
什么是数据库管理系统(DataBase Management System简称DBMS)
-
数据库服务器,数据管理系统,数据库,表与记录的关系(重点)
初识MySql
-
mysql工作方式时常实例
-
SQL的三种工作方式
-
MySql表操作
mysql中的存储引擎
-
什么是存储引擎
-
mysql支持哪些存储引擎?
-
存储引擎相关的sql语句
1. 2.
-
mysql的工作流程
创建表
-
创建表
-
建表
-
插入数据
查看表结构
mysql支持的数据类型
- 数值类型
- 日期时间类型
- 字符串类型
- enum和set类型
表的完整性约束
- 概览
- not null
- unique
- primary key
- foreign key
修改表结构
-
修改表结构基本语法
-
alter操作非空和唯一(了解)
-
alter操作主主键(了解)
-
为表添加外键(了解)
-
示例
删除表
多表结构的创建与分析
-
如何找出两个表之间的关系
-
建立表之间的关系
-
sql示例
-
其他示例
-
sql示例
-
其他示例
-
sql示例
-
其他示例
作业
mysql记录操作
插入数据insert
1. 插入完整数据(顺序插入)
语法一:
INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n);
语法二:
INSERT INTO 表名 VALUES (值1,值2,值3…值n);
2. 指定字段插入数据
语法:
INSERT INTO 表名(字段1,字段2,字段3…) VALUES (值1,值2,值3…);
3. 插入多条记录
语法:
INSERT INTO 表名 VALUES
(值1,值2,值3…值n),
(值1,值2,值3…值n),
(值1,值2,值3…值n);
4. 插入查询结果
语法:
INSERT INTO 表名(字段1,字段2,字段3…字段n)
SELECT (字段1,字段2,字段3…字段n) FROM 表2
WHERE …;
更新数据update
语法:
UPDATE 表名 SET
字段1=值1,
字段2=值2,
WHERE CONDITION;
示例:
UPDATE mysql.user SET password=password(‘123’)
where user=’root’ and host=’localhost’;
删除数据delete
语法:
DELETE FROM 表名
WHERE CONITION;
示例:
DELETE FROM mysql.user
WHERE password=’’;
练习:
更新MySQL root用户密码为mysql123
删除除从本地登录的root用户以外的所有用户
单表查询
- 单表查询语法
SELECT DISTINCT 字段1,字段2... FROM 表名
WHERE 条件
GROUP BY field
HAVING 筛选
ORDER BY field
LIMIT 限制条数
- 关键字执行的优先级
from|where|group by|select|distinct|having|order by|limit (优先级执行顺序)
1.找到表:from
2.拿着where指定的约束条件,去文件/表中取出一条条记录
3.将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组
4.执行select(去重)
5.将分组的结果进行having过滤
6.将结果按条件排序:order by
7.限制结果的显示条数
- where约束
where字句中可以使用:
1. 比较运算符:> < >= <= <> !=
2. between 80 and 100 值在80到100之间
3. in(80,90,100) 值是80或90或100
4. like 'e%'
通配符可以是%或_,
%表示任意多字符
_表示一个字符
5. 逻辑运算符:在多个条件直接可以使用逻辑运算符 and or not
- group by
单独使用GROUP BY关键字分组
SELECT post FROM employee GROUP BY post;
注意:我们按照post字段分组,那么select查询的字段只能是post,想要获取组内的其他相关信息,需要借助函数
GROUP BY关键字和GROUP_CONCAT()函数一起使用
SELECT post,GROUP_CONCAT(emp_name) FROM employee GROUP BY post;#按照岗位分组,并查看组内成员名
SELECT post,GROUP_CONCAT(emp_name) as emp_members FROM employee GROUP BY post;
GROUP BY与聚合函数一起使用
select post,count(id) as count from employee group by post;#按照岗位分组,并查看每个组有多少人
#强调:如果我们用unique的字段作为分组的依据,则每一条记录自成一组,这种分组没有意义
多条记录之间的某个字段值相同,该字段通常用来作为分组的依据
- 聚合函数
#强调:聚合函数聚合的是组的内容,若是没有分组,则默认一组
示例:
SELECT COUNT(*) FROM employee;
SELECT COUNT(*) FROM employee WHERE depart_id=1;
SELECT MAX(salary) FROM employee;
SELECT MIN(salary) FROM employee;
SELECT AVG(salary) FROM employee;
SELECT SUM(salary) FROM employee;
SELECT SUM(salary) FROM employee WHERE depart_id=3;
- having过滤
1.having与where不一样的地方在于!!!!!
#!!!执行优先级从高到低:where > group by > having
#1. Where 发生在分组group by之前,因而Where中可以有任意字段,但是绝对不能使用聚合函数。
#2. Having发生在分组group by之后,因而Having中可以使用分组的字段,无法直接取到其他字段,可以使用聚合函数
- limit限制查询的记录数
select * from employee order by salary desc limit3;
# 只取倒序的前三条数据
select * from employee order by salary desc limit 0,5;
# 从第0开始,查询0~5行之间的数据。
select * from employee order by salary desc limit 5,5;
- 使用正则表达式查询
select * from employee where emp_name regexp '^ale';
多表查询
- 多表连接查询
#重点:外链接语法
SELECT 字段列表
FROM 表1 INNER|LEFT|RIGHT JOIN 表2
ON 表1.字段 = 表2.字段;
第九章 前端
H5类
前端介绍
基本标签-1
前端
内容的展示
browser
后端
逻辑的处理
请求和响应
html 显示的内容
css 样式 美化
js 动态效果
HTML 超文本标记语言
超文本:图片 视频 音频
标记 标签 标记
标记的分类
双边标记 双封闭标签
单边标记 单封闭标签
标签的分类
块级标签
h1-h6
行内(内联)标签
span
br 换行
b strong 加粗
i em 斜体
s del 删除线
u 下划线
img 图片
src
来源
网络地址
本地路径
alt 图片的提示
width 宽度
height 高度
a anchor 锚 超链接
href
网址
# 回到顶部
页面锚点
标签添加id
a标签加name
target
_self(默认) 当前页面刷新
_blank 新建一个页面窗口
HTML标签
head 一个的思维
meta 元信息
charset 编码
<meta http-equiv="refresh" content="2;URL=http://www.luffycity.com">
description 描述
Keywords 关键字
title 标题
<style></style> <!-- css -->
<link rel="stylesheet" href=""> <!-- 连接 -->
<script></script> <!-- js -->
body 一个人的身体
- 基本标签-2
<!doctype html>
<html lang="en">
<head>
<!-- <meta charset="UTF-8">-->
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
<!-- <meta http-equiv="refresh" content="2;URL=http://www.luffycity.com">-->
<title>Document</title>
</head>
<body>
<a href="#ddk1">跳转到DDK1</a>
<a href="#xxx">跳转到底部</a>
<h1>这是h1标签</h1><h2>这是h2标签</h2><h3>这是h3标签</h3><h4>这是h4标签</h4><h5>这是h5标签</h5><h6>这是h6标签</h6>
<span>国庆 <b>国庆</b> <strong>国庆</strong> <i>国庆</i> <em>国庆</em> <del>国庆</del> <s>国庆</s> <u>国庆</u> </span>
<br>
<span>结束了</span>
<a href="https://www.mi.com/" target="_blank">小米官网</a>
<h1 id="ddk1">跳转到这</h1><h2>这是h2标签</h2><h3>这是h3标签</h3><h4>这是h4标签</h4><h5>这是h5标签</h5><h6>这是h6标签</h6>
<a href="#">回到顶部</a>
<!--<img src="img/timg.jpg" alt="校花图片" >-->
</body>
</html>
- 建立服务端
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 9999))
sk.listen()
conn, addr = sk.accept()
data = conn.recv(1024)
print(data)
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
conn.send("""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="gbk">
<title>Title</title>
</head>
<body>
国庆已经结束了!
</body>
</html>""".encode('GBK'))
conn.close()
sk.close()
排版/列表/表格/表单标签
- 排版标签
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 9999))
sk.listen()
conn, addr = sk.accept()
data = conn.recv(1024)
print(data)
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
conn.send("""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="gbk">
<title>Title</title>
</head>
<body>
国庆已经结束了!
</body>
</html>""".encode('GBK'))
conn.close()
sk.close()
- 列表标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--<ul >-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ul>-->
<!--<ul type="none">-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ul>-->
<!--<ul type="circle">-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ul>-->
<!--<ul type="square">-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ul>-->
<!--<ul type="disc">-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ul>-->
<!--<ol>-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ol>-->
<!--<ol type="1">-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ol>-->
<!--<ol type="a" start="25">-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ol>-->
<!--<ol type="A">-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ol>-->
<!--<ol type="I">-->
<!-- <li>手机</li>-->
<!-- <li>电脑</li>-->
<!-- <li>iPad</li>-->
<!--</ol>-->
<dl>
<dt>城市</dt>
<dd>北京</dd>
<dd>上海</dd>
<dd>深圳</dd>
<dt>城市</dt>
<dd>北京</dd>
<dd>上海</dd>
<dd>深圳</dd>
</dl>
</body>
</html>
- 表格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1" cellpadding="20px" cellspacing="20px">
<thead>
<tr align="left">
<th> 序号</th>
<th> 姓名</th>
<th> 年龄</th>
</tr>
</thead>
<tbody>
<tr align="center" >
<td>1</td>
<td >alex</td>
<td rowspan="2" valign="top">84</td>
</tr>
<tr align="center" valign="top">
<td>2</td>
<td >alex</td>
</tr>
<tr>
<td>2</td>
<td>wusir</td>
<td rowspan="2">2208</td>
</tr>
</tbody>
</table>
<table border="1" cellpadding="20px" cellspacing="20px">
<tbody>
<tr align="center" valign="bottom">
<td>1</td>
<td >alex</td>
<td >84</td>
</tr>
<tr align="center" valign="top">
<td>2</td>
<td >alex</td>
</tr>
<tr>
<td>2</td>
<td>wusir</td>
<td rowspan="2">2208</td>
</tr>
</tbody>
</table>
</body>
</html>
- 表单标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:9999" >
<!-- <input type="text" name="user" placeholder="请输入用户名"> <!–name:提交数据的key value:值 placeholder:占位的内容 –>-->
<!-- <input type="password" name="pwd">-->
<!-- <input type="radio" name="sex" value="1" checked > 男-->
<!-- <input type="radio" name="sex" value="2"> 女-->
<!-- <input type="checkbox" name="hobby" value="1" checked="checked"> 跳-->
<!-- <input type="checkbox" name="hobby" value="2"> 唱-->
<!-- <input type="checkbox" name="hobby" value="3"> rap-->
<!-- <input type="checkbox" name="hobby" value="4"> 篮球-->
<!-- <input type="submit">-->
<!-- <p>-->
<!-- <label for="i1">用户名:</label><input id="i1" type="text" name="user" placeholder="请输入用户名">-->
<!-- </p>-->
<!-- <p>-->
<!-- 密码:<input type="password" name="pwd" >-->
<!-- </p>-->
<!-- <input type="hidden" name="alex" value="alexdsb">-->
<!-- <input type="reset">-->
<!-- <input type="button" value="提交"> <!– 普通的按钮 –>-->
<!-- <select name="city" id="" size="4" multiple>-->
<!-- <option value="1" selected="selected">北京</option>-->
<!-- <option value="2">上海</option>-->
<!-- <option value="3">深圳</option>-->
<!-- </select>-->
<!-- <input type="file" name="f1">-->
<input type="text">
<button>提交</button>
</form>
</body>
</html>
- CSS引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:9999" >
<!-- <input type="text" name="user" placeholder="请输入用户名"> <!–name:提交数据的key value:值 placeholder:占位的内容 –>-->
<!-- <input type="password" name="pwd">-->
<!-- <input type="radio" name="sex" value="1" checked > 男-->
<!-- <input type="radio" name="sex" value="2"> 女-->
<!-- <input type="checkbox" name="hobby" value="1" checked="checked"> 跳-->
<!-- <input type="checkbox" name="hobby" value="2"> 唱-->
<!-- <input type="checkbox" name="hobby" value="3"> rap-->
<!-- <input type="checkbox" name="hobby" value="4"> 篮球-->
<!-- <input type="submit">-->
<!-- <p>-->
<!-- <label for="i1">用户名:</label><input id="i1" type="text" name="user" placeholder="请输入用户名">-->
<!-- </p>-->
<!-- <p>-->
<!-- 密码:<input type="password" name="pwd" >-->
<!-- </p>-->
<!-- <input type="hidden" name="alex" value="alexdsb">-->
<!-- <input type="reset">-->
<!-- <input type="button" value="提交"> <!– 普通的按钮 –>-->
<!-- <select name="city" id="" size="4" multiple>-->
<!-- <option value="1" selected="selected">北京</option>-->
<!-- <option value="2">上海</option>-->
<!-- <option value="3">深圳</option>-->
<!-- </select>-->
<!-- <input type="file" name="f1">-->
<input type="text">
<button>提交</button>
</form>
</body>
</html>
H5内容回顾
内容回顾
前后端怎么交互
浏览器发送一个请求到后端,后端处理逻辑,把结果(HTML文本)返回给浏览器。
前端
HTML 骨架 内容
css 样式
js 动态效果
HTML 超文本标记语言
标记 标签
分类
单边标记\双边标记
head
<meta> 编码 关键字 描述
<title>标题的内容</title>
link style script
body
内联(行内)标签
字体
加粗 b strong
斜体 i em
上下标 sup sub
中划线 下划线 del s u
<span></span>
<br>
<a href="链接" target="_blank" title >页面显示的内容</a>
href: 链接地址
锚点: #id
target:打开方式
_blank: 新建一个窗口
_self: 当前窗口
title: 鼠标悬浮上显示的标题
<img src="图片的地址" alt='' title width="20px" height="100%" >
src: 网络地址、本地地址(相对路径、绝对路径)
alt : 链接地址有问题时提示的内容
title: 鼠标悬浮上显示的标题
width: 设置图片的宽度
height:设置图片的高度
width和height选择一个
特殊字符:
 : 空格
块级标签
h1 - h6
今日内容
块级标签
排版标签
p:一个文本级别的段落标签 前后有间距
P标签中不嵌套其他的块级标签
div 没有任何样式的块级标签
hr 分割线
列表
无序列表
type="原点的样式"
<!-- 样式 disc(实心圆、默认)、 circle(空心圆)、none(无)、square(方点)-->
<ul >
<li>手机</li>
<li>电脑</li>
<li>iPad</li>
</ul>
<ul type="none">
<li>手机</li>
<li>电脑</li>
<li>iPad</li>
</ul>
<ul type="circle">
<li>手机</li>
<li>电脑</li>
<li>iPad</li>
</ul>
<ul type="square">
<li>手机</li>
<li>电脑</li>
<li>iPad</li>
</ul>
有序列表
type="数字的样式" start =“起始值”(数字)
<!-- 样式 1(数字)、 a(小写字母)、A(大写)、I(罗马数字)-->
<ol>
<li>手机</li>
<li>电脑</li>
<li>iPad</li>
</ol>
<ol type="1">
<li>手机</li>
<li>电脑</li>
<li>iPad</li>
</ol>
<ol type="a" start="25">
<li>手机</li>
<li>电脑</li>
<li>iPad</li>
</ol>
<ol type="A">
<li>手机</li>
<li>电脑</li>
<li>iPad</li>
</ol>
<ol type="I">
<li>手机</li>
<li>电脑</li>
<li>iPad</li>
</ol>
定义列表
dt 标题
dd 内容
<dl>
<dt>城市</dt>
<dd>北京</dd>
<dd>上海</dd>
<dd>深圳</dd>
<dt>城市</dt>
<dd>北京</dd>
<dd>上海</dd>
<dd>深圳</dd>
</dl>
表格
<!--有表头的表格-->
<!--tbale 嵌套 thead tbody
thead和tbody嵌套tr
tr嵌套 th td
-->
<!--tbale 属性
border 边框
cellpadding 元素和单元格的边距
cellspacing 单元格和边框的间距
-->
<!--tr 属性
align 内容的水平排列 left center right
valign 内容的垂直排列 top middle bottom
-->
<!--td 属性
rowspan 占几行
colspan 占几列
-->
<table border="1" cellpadding="20px" cellspacing="20px">
<thead>
<tr align="left">
<th> 序号</th>
<th> 姓名</th>
<th> 年龄</th>
</tr>
</thead>
<tbody>
<tr align="center" valign="bottom">
<td>1</td>
<td >alex</td>
<td >84</td>
</tr>
<tr align="center" valign="top">
<td>2</td>
<td >alex</td>
</tr>
<tr>
<td>2</td>
<td>wusir</td>
<td rowspan="2">2208</td>
</tr>
</tbody>
</table>
<!-- 无表头的表格-->
<table border="1" cellpadding="20px" cellspacing="20px">
<tbody>
<tr align="center" valign="bottom">
<td>1</td>
<td >alex</td>
<td >84</td>
</tr>
<tr align="center" valign="top">
<td>2</td>
<td >alex</td>
</tr>
<tr>
<td>2</td>
<td>wusir</td>
<td rowspan="2">2208</td>
</tr>
</tbody>
</table>
表单
<!-- form 标签
action: 提交的地址
-->
<!-- input 标签
type: 类型
text:普通文本
password:密码 密文
radio: 单选框
checkbox: 复选框
submit: 提交按钮
能提交数据 input有name属性 有value值
-->
<button>提交</button>
<!--
form表单中button和type=‘submit’的input的作用是一样的
-->
<form action="http://127.0.0.1:9999">
<input type="text" name="user" placeholder="请输入用户名"> <!--name:提交数据的key value:值 placeholder:占位的内容 -->
<input type="password" name="pwd" value="3714">
<input type="radio" name="sex" value="1"> 男
<input type="radio" name="sex" value="2" checked > 女 <!-- checked默认选中 -->
<input type="checkbox" name="hobby" value="1"> 跳
<input type="checkbox" name="hobby" value="2"> 唱
<input type="checkbox" name="hobby" value="3"> rap
<input type="checkbox" name="hobby" value="4"> 篮球
<input type="submit">
<button>提交</button
</form>
label
<!--给input标签定义id 给label标签的for填上id-->
<label for="i1">用户名:</label>
<input id="i1" type="text" name="user" placeholder="请输入用户名">
其他的input
<input type="hidden" name="alex" value="alexdsb"> <!-- 隐藏的input框 -->
<input type="reset"> <!-- 重置按钮 -->
<input type="button" value="提交"> <!-- 普通的按钮 -->
<button type="button">提交</button> <!-- 普通的按钮 -->
<input type="date"> <!-- 日期格式 -->
select option
<!--下拉框 单选 -->
<!--size 框的大小 -->
<select name="city" id="" size="4" >
<option value="1">北京</option>
<option value="2" selected >上海</option> <!-- selected默认选中 -->
<option value="3">深圳</option>
</select>
<!--下拉框 多选 -->
<!--size 框的大小 -->
<select name="city" id="" size="4" multiple>
<option value="1">北京</option>
<option value="2">上海</option>
<option value="3">深圳</option>
</select>
上传文件
<input type="file" name="f1">
<form enctype="multipart/form-data"> <!--编码指定为multipart/form-data-->
CSS
引入方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--内联引入-->
<style>
div {
color: #ffef6b
}
</style>
<!--外联引入:链接 使用较多 -->
<link rel="stylesheet" href="index.css">
<!--外联引入:导入-->
<style>
@import url('index.css');
</style>
</head>
<body>
<!--行内引入-->
<div style="color: red">黄焖鸡米饭</div>
<div>黄焖鸡排骨</div>
</body>
</html>
简单的样式
color: #ffef6b; /*字体颜色*/
width: 200px; /*宽度*/
height: 200px; /*高度*/
background: blue; /*背景颜色*/
选择器
基本选择器
标签\id\类\通用选择器
<style>
div { 标签
color: #ffef6b;
}
a {
color: green;
}
span {
color: #42ff68;
}
#sp1 { id
color: chartreuse;
}
.cai { 类
color: #192aff;
}
.x1 {
background: #3bff00;
}
* {
background: #3bff00;
}
</style>
<body>
<!--<div >黄焖鸡米饭</div>-->
<!--<div>黄焖鸡排骨</div>-->
<div>黄焖鸡米饭
<span class="cai">鸡</span>
<span>米饭</span>
<a href="xxxx">外卖连接</a>
</div>
<div>黄焖鸡排骨
<span class="cai x1 x2">排骨</span>
<span>米饭</span>
</div>
<span id="sp1">米饭</span>
</body>
CSS类
JS类
节点的查找和文本值
day47: dom,document object model 文档对象模型,查找元素,
-
直接查找
document.getElementById('div1') // 通过ID查找 返回一个节点 document.getElementsByClassName('son') // 通过类名查找 返回一个对象 对象中包含多个节点 document.getElementsByTagName('div') /// 通过标签名查找
-
间接查找
节点.parentNode // 找到父节点 节点.children // 找子节点 多个节点 节点.firstElementChild // 找第一个子节点 节点.lastElementChild // 找最后一个子节点 节点.nextElementSibling //找下一个兄弟节点 节点.previousElementSibling //找上一个兄弟节点
-
节点的属性操作
节点.getAttribute('属性') //获取属性 节点.setAttribute('属性','值') //设置属性 节点.removeAttribute('属性') //删除属性
-
节点的文本操作
节点.innerText // 标签的文本内容 节点.innerHTML // 标签内部的HTML文本 节点.innerText='设置的文本' // 标签的文本内容 节点.innerHTML='设置HTML的文本' // 标签内部的html的文本
-
节点的值操作
// input, select, textarea 节点.value // 获取节点的值 节点.value = '值' // 设置节点的值
-
节点的类操作
节点.classList // 节点所有的class 节点.classList.add('类名') // 给节点添加一个类 节点.classList.remove('类名') // 给节点删除一个类 节点.classList.toggle('类名') //转换,
-
节点的操作
document.createElement('标签的名字') // 创建一个标签节点 div a span 添加节点到文档中 父节点.appendChild(子节点) // 添加一个子节点到父节点的后面 父节点.insertBefore(新节点,父节点的子节点) // 添加一个子节点到父节中的指定子节点前 删除节点 父节点.removeChild(子节点) // 通过父节点删除子节点 替换节点 节点.replaceChild(新节点,节点的子节点) 复制节点 节点.cloneNode() // 不写数字或者0 只拷贝节点 节点.cloneNode(1) // 拷贝节点和它的子孙节点
事件
-
事件的绑定
// 方式一 <div onclick="alert('你点我了')"> 事件示例 </div> // 方式二 <div onclick="func()"> 事件示例2 </div> <script> function func() { alert('你点我了') alert('你还点') } </script> // 方式三 <div id="div1"> 事件示例3 </div> <script> var div1 = document.getElementById('div1') div1.onclick = function () { alert('你点我了'); alert('你还点'); alert('你还点!!!'); } </script>
-
事件的种类
属性 | 当以下情况发生时,出现此事件 |
---|---|
onblur | 元素失去焦点 |
onchange | 用户改变域的内容 |
onclick | 鼠标点击某个对象 |
ondblclick | 鼠标双击某个对象 |
onerror | 当加载文档或图像时发生某个错误 |
onfocus | 元素获得焦点 |
onkeydown | 某个键盘的键被按下 |
onkeyup | 某个键盘的键被松开 |
onload | 某个页面或图像被完成加载 |
onmousemove | 鼠标被移动 |
onmouseout | 鼠标从某元素移开 |
onmouseover | 鼠标被移到某元素之上 |
onmouseup | 某个鼠标按键被松开 |
onreset | 重置按钮被点击 |
onresize | 窗口或框架被调整尺寸 |
onselect | 文本被选定 |
onsubmit | 提交按钮被点击 |
-
滚动事件
<script> //实施监听滚动事件 window.onscroll = function () { console.log(1111) console.log('上' + document.documentElement.scrollTop) console.log('左' + document.documentElement.scrollLeft) console.log('宽' + document.documentElement.scrollWidth) console.log('高' + document.documentElement.scrollHeight) } </script>
BOM
browser object model
- 窗口
打开新窗口
window.open(url,target)
关闭窗口
window.close() // 只能关闭用open打开的窗口
窗口的宽高
window.innerHeight 高度
window.innerWidth 宽度
- 定时器**
定时器 **
// setTimeout 某段时间结束后触发执行
function func(){
alert('是否已满18岁')
}
setTimeout(func,2000)
// setInterval 设置时间间隔的定时器 每隔一段时间要触发执行函数
var ret= setInterval(func, 500); // 开启定时器
clearInterval(ret) // 关闭定时器
- location
location.href // 当前的地址
location.href = '地址' // 当前页面会跳转到新页面
jQuery
- jQuery的优点
- 浏览器的兼容性好
- 隐式循环
- 链式编程
- Jquery对象和DOM对象的关系,转换
Jquery对象内部封装了DOM对象、方法
DOM对象 ——》 Jquery对象
Jquery(DOM对象) $(DOM对象)
Jquery对象 ——》 DOM对象
Jquery对象[索引] $(DOM对象)[]
Jquery和$是一个东西
- jQuery的选择器
- 基本选择器
id选择器 类选择器 标签选择器 通用选择器
$('#id')
$('.类名')
$('标签名')
$('*')
交集选择器
$('li.city#l1')
并集选择器
$('div,li,a')
- 层级选择器
后代选择器 空格 子代选择器 > 毗邻选择 + 弟弟选择器 ~
$('ul li') // 选择ul 下的所有li标签
$('ul>a') //选择ul 下的子代中的a标签
$('#l1+li') //选择id为l1的标签后的一个li标签
$('#l1~li') //选择id为l1的标签后的所有的li标签
- 属性选择器
$('[属性]')
$("标签[属性]") // 选择某个包含某个属性的标签
$('[属性=“值”]')
$('[属性$=“值”]') // 属性结尾为某个值的标签
$('[属性^=“值”]') // 属性开头为某个值的标签
$('[属性*=“值”]') // 属性包含某个值的标签
- jQuery的筛选器
- 基本筛选器
$('选择器:筛选器')
$('选择器:first')
$('选择器:last')
eq(索引) 等于某索引的标签
gt(索引) 大于某索引的标签
lt(索引) 小于某索引的标签
odd 奇数
even 偶数
not(选择器) // 在当前的标签内排除某些标签
-
type筛选器
$(':text') $(':radio') $(':checkbox') $(':password') $(':submit') $(':button') $(':file') 注意: date 不支持
-
状态选择器
$(':disabled') // 禁用的标签
$(':enabled') // 可使用的标签
$(':checked') // radio、checkbox、select(option) 选中的标签
$(':selected') // select 选中的option标签
- jQuery的筛选器方法
.children() // 子代
.parent() // 父代
.parents() // 父辈们
.parentsUntil('选择器') // 找父辈们,直达某个标签,且不包含该标签
.siblings() // 所有兄弟标签
.prev() // 上一个
.prevAll() // 前面所有的兄弟
.prevUntil() // 前面的兄弟到某个标签位置
.next() // 下一个
.nextAll() // 后面所有的兄弟
.nextUntil() // 后面的兄弟到某个标签位置
first()
last()
eq()
has() // $('li').has('a') 选择一个包含a标签的li标签
find() // $('li').find('a') 在li标签下找所有的a标签
not() // 在所有的标签内排除某些标签
filter() // 获取一些满足条件的标签 交集选择器
第十章 Django
Django基础篇
- Django的下载与基本操作
**命令台下载**
这里默认的是从官网下载的。
输入:pip -v
输入:pip install django==1.11.25 //后面不加版本号,默认是最新版的。
pip install django==1.11.25 -i https://pypi.tuna.tsinghua.edu.cn/simple
**Pycharm中下载**
settings p
1.命令台创建django项目:
django-admin startproject day01
//django-admin 管理django里面所有的项目,
而所创建的文件day01里面的manager.py管理当前的django
2.在pycharm里面创建的是有manage.py和day52的,
但是它里面多了一个templates这里面是要放html文件的。
cmd命令台上没有,我们可以自己创建。
settings里面的配置信息,有一个叫做templates的文件,以后写的html文件
我们放在这里就叫他模板。
settings里面还有一个叫做:TEMPLATES里面的。
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
'DIRS': [os.path.join(BASE_DIR, 'templates')]
这个是pycharm自己给你写的。在cmd中需要自己写。
**启动项目**
1.命令行的方式:
django-admin自己的本地用户在哪里自己找。
在命令台上输入
dir//查看用户下的目录情况
cd dya52//切换至所创建的文件夹
dir//再查看day52下面的文件加会有manage.py
输入python manage.py runserver
在浏览器中输入:127.0.0.1:8000
表示的是我自己在用。
还可以改端口:
python manage.py runserver 80
正式部署的时候,这个ip端口是有问题的
要让大家都可以访问,需要在settings里面加上配置。
在pycharm里面找到settings然后在修改为'*' ALLOWED_HOSTS = ['*']
端口号改为:0.0.0.0:8002(端口自定义8000以上,避免占用端口)
注意项目名称相同时,要改本项目的ALLOWED_HOSTS= ['*']
同一局域网内,不同ip链接时候需要输入本机的ip加端口号。
**注意**
前期开发的时候用pycharm一点问题都没有,
后期部署的时候都已经封装好了,只能用linux里面的命令行。
**了解**
settings 是配置文件环境变量用的
urls 可以向templates写入网页
格式如下:
from django.shortcuts import HttpResponse, render
def index(request):
# 逻辑
# return HttpResponse('欢迎来到项目')
return render(request, 'index.html')
urlpatterns = [
url(r'^index/', index),
]
需要在templates里面写入网页。
作业:
用bootstrap写登陆页面,使用Django返回给浏览器。