# 19022720088 **Repository Path**: python_stack_20/19022720088 ## Basic Information - **Project Name**: 19022720088 - **Description**: 张翔宁 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-04-28 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # -Python学习笔记 ## 第一章 计算机基础 ### 1.1 硬件 计算机基本的硬件由:CPU / 内存 / 主板 / 硬盘 / 网卡 / 显卡 等组成,只有硬件但硬件之间无法进行交流和通信。 ### 1.2 操作系统 操作系统用于协同或控制硬件之间进行工作,常见的操作系统有那些: - windows - xp - win7 - win10 - linux 免费、开源 - centos 【公司线上一般用】 - ubuntu - redhat - mac ### 1.3 解释器或编译器 编程语言的开发者写的一个工具,将用户写的代码转换成010101交给操作系统去执行。 #### 1.3.1 解释和编译型语言 解释型语言就类似于: 实时翻译,代表:Python / PHP / Ruby / Perl 编译型语言类似于:说完之后,整体再进行翻译,代表:C / C++ / Java / Go ... ### 1.4 软件(应用程序) 软件又称为应用程序,就是我们在电脑上使用的工具,类似于:记事本 / 图片查看 / 游戏 ### 1.5 进制 对于计算机而言无论是文件存储 / 网络传输数据本质上都是:二进制(010101010101),如:电脑上存储视频/图片/文件都是二进制; QQ/微信聊天发送的表情/文字/语言/视频 也全部都是二进制。 进制: - 2进制,计算机内部。 - 8进制 - 10进制,人来进行使用一般情况下计算机可以获取10进制,然后再内部会自动转换成二进制并操作。 - 16进制,一般用于表示二进制(用更短的内容表示更多的数据),一版是:\x 开头。 | 二进制 | 八进制 | 十进制 | 十六进制 | | ------ | ------- | ------ | -------- | | 0 | 0 | 0 | 0 | | 1 | 1 | 1 | 1 | | 10 | 2 | 2 | 2 | | 11 | 3 | 3 | 3 | | 100 | 4 | 4 | 4 | | 101 | 5 | 5 | 5 | | 110 | 6 | 6 | 6 | | 111 | 7 | 7 | 7 | | 1000 | 10 —> 8 | 8 | 8 | | 1001 | 11 | 9 | 9 | | 1010 | 12 | 10 | a | | 1011 | 13 | 11 | b | | 1100 | 14 | 12 | c | | 1101 | 15 | 13 | d | | 1110 | 16 | 14 | e | | 1111 | 17 | 15 | f | | 20000 | 20 | 16 | 10 —> 16 | ## 第二章 Python入门 ### 2.1 py2与py3的区别: - 1. 字符串类型不同 - py2: unicode 类型 str 字节类型 ​ v = u'alex' v = 'alex' - py3: str 字符串类型 bytes 字节类型 ​ v1 ='alex' v1 = b'alex' ![1555923572224](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555923572224.png) 2. 默认解释器编码 - py2 : ascii - py3 : utf-8 3. 输入 - py2 : raw_input() - py3 : input() 4. 输出 - py2: print+空格+'你好' - py3 : print('你好') 5. int类型 - py2 : 有 int 和 long两种类型 - py3 : 只有 int 6. int整除 - py2 : 只能保留整数部分(加一行代码:?可以保留小数部分) - py3 : 能保留所有 7. range和xrange py2: - range 在内存中立即把所有的值都创建 - xrange 不会在内存中立即创建,而是在循环时,边循环边创建 py3: - range 不会在内存中立即创建,而是边循环边创建 8. 模块和包 - py2 : 文件夹/包中必须有_ _ init _ _.py - py3 : 不需要有_ _ init _ _.py(可有可无) 9. 字典 .keys/.values/.items - py2 : 返回列表 - py3 : 返回迭代器,可以循环但不可以索引 10. map/filter - py2 : 返回列表 - py3 : 返回迭代器,可以循环但不可以索引 11. 类的不同 - py2 分为经典类、新式类 - py3 只有新式类 12. ### 2.1 环境的安装 - 解释器:py2 / py3 - 开发工具:pycharm - 环境变量:方便在命令行(终端)执行可执行程序,将可执行程序所在的目录添加到环境变量,那么以后无需再输入路径。 ### 2.2 编码 #### 2.2.1 编码基础 - ascii 只能用于英文,只能用1个字节=8位来表示,共有2**8=256种。 - unicode 万国码,可以用于各种语言,用4个字节=32位来表示,共有2**32种,但是有点浪费存储空间,目前只用到了21位。 unicode用于内存计算 - utf-8 是Unicode的压缩,最少用1个字节=8位来表示,占位是8的倍数,一个中文用3个字节表示 utf-8用于网络传输、数据存储 - gbk 一个中文用2个字节表示 - gb2312 一个中文用2个字节表示 注:1. 字符串:'中国' 'Hello' ​ 2. 字符:中是一个字符,e是一个字符 ​ 3. 字节:中是3个字节,e是1个字节 ​ 4. 位:01010101是8位,其中0或1分别是1位 #### 2.2.2 python编码相关 对于Python默认解释器编码: - py2: ascii - py3: utf-8 如果想要修改默认编码,则可以使用: ```python # -*- coding:utf-8 -*- ``` 注意:对于操作文件时,要按照:以什么编码写入,就要用什么编码去打开。(建议将Pycharm设置成UTF-8编码) ![1555918490304](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555918490304.png) ### 2.3 变量 1. 变量:创建一个变量,给变量赋一个值,变量与值用“=”连接 变量规则: - 1.只能包含字母、数字、下划线 - 2.不能用数字开头 - 3.不能用python的关键字 建议: - 1.见名知意 - 2.变量比较长用下划线“_”连接,如:user_name='玛丽' 问:为什么要有变量? 为某个值创建一个“外号”,以后在使用时候通过此外号就可以直接调用。 ```python name = 'alex' ``` 2. 全局变量 全局变量名要大写 ```python NAME = "oldboy" ``` 3. 函数 ```python def func_list(): pass ``` 4. 常量 不允许修改的值,python中执行约定。 ### 2.4 if条件判断语句 - 1. if…else ```P if + 判断条件: (缩进4个空格)print('') else: (缩进4个空格)print('') ``` - 2. if …elif…else ```P if + 判断条件: (缩进4个空格)print('') elif + 判断条件: (缩进4个空格)print('') else: (缩进4个空格)print('') ``` 注:elif 可以写无数个 - 3. if 最简单的结构 ```P if + 判断条件: (缩进4个空格)print('') ``` - 4. 三元运算 三元运算又叫三目运算。(是为了赋值的) ```P v = 前面 if 条件 else 后面 #条件为真,v取if前面的值;条件为假,v取if后面的值 # 三元运算是if条件判断的简化版 if 条件: v = '前面' else: v = '后面' ``` ```python val = v if v else 666 val = v or 666 # 源码中会出现(三元运算也可以写成这样) ``` 练习题 ```P # 让用户输入值,如果值是整数,则转换成整数,否则赋值为None data = input('>>>') value = int(data) if data.isdecimal() else None ``` 注意:现阶段我们要先用复杂的 if 写出来,再去考虑是否能用简化的。 ​ 先做出来,再思考如何简化。 ### 2.5 while循环语句 while循环有四种语句: - 1. while基本结构 例1:循环显示“人生苦短,及时行乐。” ```P while True: print('人生苦短,及时行乐。') ``` 例2:while后加条件:通过循环显示1,2,3,4,5,6,7,8,9,10 ```P count = 1 while count <= 10: print(count) count = count + 1 print('结束') ``` 断点:用debug模式可以看每一步是如何执行的 - 2. break 终止当前循环 例:请通过循环1,2,3,4,5,6,7,8 ```P count =1 while True: print(count) if count == 8 break count = count + 1 print('结束了') ``` - 3. continue 如果循环中遇到了continue,循环不会再执行下一步,而是回到while条件的位置 例:通过循环:1,2,3,4,5,7,8,9,10 ```P count=1 while count <= 10: if count == 6: count = count + 1 continue print(count) count = count + 1 ``` - 4. while…else 只有while后面的条件不成立或为False时才触发else,通过其他条件强制终止while时(如break)是不会触发else的 ### 2.6 输出 print - print('输出内容') - py2与py3的区别: py2:print+空格+'你好' py3:print('你好') ### 2.7 输入 input - 1. 输入内容永远是字符串 - 2. py2与py3的区别: py2:raw_input('请输入内容') py3:input('请输入内容') ### 2.8 注释 - 1.单行注释:#+注释内容 - 2.多行注释: """ 注释内容 """ ## 第三章 数据类型 ### 3.1 整型(int) #### 3.1.1 整型的长度 py2中有:int/long py3中有:int (int/long) #### 3.1.2 整除 py2和py3中整除是不一样。 py2:结果有小数存在,只保留整数部分 py3:结果保留全部 #### 3.1.3其他进制转换成十进制 int('0b11011',base = 2) ### 3.2 布尔(bool) 布尔值就是用于表示真假。True和False。 其他类型转换成布尔值: - str 除空字符串"" 以外的所有字符串都是 True - int 除0以外的所有数字都是True - list 除空列表[] 以外的所有列表都是True - tuple 除空元组() 以外的所有元组都是True - dict 除空字典{} 以外的所有字典都是True - set 除空集合set() 以外的所有集合都是True 对于:None / "" / 0 / [] / () / {} /set() 转换成布尔类型都是 false ### 3.3 字符串(str) 字符串类型,一般用于内存中做数据操作 ```python v = 'alex' # 在py3中用unicode编码存储在内存 ``` - 3.3.1.字符串是写代码中最常见的,python内存中的字符串是按照:unicode 编码存储。对于字符串是不可变。 - 3.3.2.字符串在python中可以相乘,如: ​ name='yangjie' ​ new_name=name*3 ​ print=(new_name) ​ 输出显示:yangjieyangjieyangjie - 3.3.3.字符串格式化 字符串格式化的意义:做占位符 %s 用来代替字符串 %d用来代替数字 %%用来代替想打印中的% - 1.%s ```python msg = '我是%s,年龄%s'%('alex',19,) # % 后面跟的是元组 msg = '我是%(name)s,年龄%(age)s'%{name:'alex','age':19} # % 后面跟的是字典 ``` 2.format (可以无限传参数) ```python v1 = '我是{0},年龄{1}'.format('alex',19) # 位置传参,format后面的参数相当于*args (也可写成:)v1 = '我是{0},年龄{1}'.format(*('alex',19)) ``` ```python v2 = '我是{name},年龄{age}'.format(name = 'alex',age = 19) # 关键字传参,相当于**kwargs (or)v2 = '我是{name},年龄{age}'.format(**(name = 'alex',age = 19)) ``` - 3.3.4.字符串自己有很多方法,如: 1. 大写: upper ``` v = 'ALEX' v1 = v.upper() print(v1) v2 = v.isupper() # 判断是否全部是大写 print(v2) ``` 2. 小写:lower ``` v = 'alex' v1 = v.lower() print(v1) v2 = v.islower() # 判断是否全部是小写 print(v2) ############ 了解即可 v = 'ß' # 将字符串变小写(更牛逼) v1 = v.casefold() print(v1) # ss v2 = v.lower() print(v2) ``` 3. 判断是否是数字: isdecimal ``` v = '1' # v = '二' # v = '②' v1 = v.isdigit() # '1'-> True; '二'-> False; '②' --> True v2 = v.isdecimal() # '1'-> True; '二'-> False; '②' --> False v3 = v.isnumeric() # '1'-> True; '二'-> True; '②' --> True print(v1,v2,v3) # 以后推荐用 isdecimal 判断是否是 10进制的数。 # ############## 应用 ############## v = ['alex','eric','tony'] for i in v: print(i) num = input('请输入序号:') if num.isdecimal(): num = int(num) print(v[num]) else: print('你输入的不是数字') ``` 4. strip 去空白+\t+\n + 指定字符串 ```python v1 = "alex " print(v1.strip()) v2 = "alex\t" print(v2.strip()) v3 = "alex\n" print(v3.strip()) v1 = "alexa" print(v1.strip('al')) ``` 5. 替换 replace 6. 开头 / 结尾 starstswith /endswith 7. encode 编码转换,把字符串转换成二进制 8. format 字符串的格式化 9. join 用什么连接 10. split 切割 11. 其他【可选】 ### 3.4 字节(bytes) 字节类型,一般用于数据存储和网络传输。 ```python v = 'alex'.encode('utf-8') # 将字符串转换成字节(由unicode编码转换为utf-8编码) v = 'alex'.encode('gbk') # 将字符串转换成字节(由unicode编码转换为gbk编码) ``` ### 3.5 列表 (list) - 1. append 追加 2. insert 插入 3. remove 删除 4. pop 删除 5. clear 清除 6. extend 循环添加 7. reverse 反转 8. sort 从大到小或从小到大排列 ### 3.6 元组 (tuple) ### 3.7 字典 (dict) 3.7.1 独有方法 - 1.keys 获取所有的键 - 2.values 获取所有的值 - 3.items 获取所有的键值对 - 4.get 判断索引是否存在 - 5.pop 删除 - 6.update 无则添加,有则更新 3.7.2 有序字典 ```python from collections import OrderedDict info = OrderedDict() info['k1'] = 123 info['k2'] = 456 print(info.keys()) print(info.values()) print(info.items()) ``` ### 3.8 集合 (set) - 1.add 添加 - 2.discard 删除 - 3.update 批量添加 - 4.intersection 交集 - 5.union 并集 - 6.difference 差集 - 7.symmetric_difference 对称差集 ### 3.9 公共功能 - len 排除:int / bool - 索引 排除:int / bool / set - 切片 排除:int / bool /dict / set - 步长 排除:int / bool / dict / set - for循环 排除:int / bool / set - 删除 :list / dict - 修改 :list / dict ### 3.10 嵌套 ## 第四章 文件操作 ### 4.1 文件基本操作 ```python obj = open('路径',mode='模式',encoding='编码') obj.write() obj.read() obj.close() ``` ### 4.2 打开模式 - r / w / a - r+ / w+ / a+ - rb / wb / ab - r+b / w+b / a+b ### 4.3 操作 - read() , 全部读到内存 - read(1) - 1表示一个字符 ```python obj = open('a.txt',mode='r',encoding='utf-8') data = obj.read(1) # 1个字符 obj.close() print(data) ``` - 1表示一个字节 ```python obj = open('a.txt',mode='rb') data = obj.read(3) # 1个字节 obj.close() ``` - write(字符串) ```python obj = open('a.txt',mode='w',encoding='utf-8') obj.write('中午你') obj.close() ``` - write(二进制) ```python obj = open('a.txt',mode='wb') # obj.write('中午你'.encode('utf-8')) v = '中午你'.encode('utf-8') obj.write(v) obj.close() ``` - seek(光标字节位置),无论模式是否带b,都是按照字节进行处理。 ``` obj = open('a.txt',mode='r',encoding='utf-8') obj.seek(3) # 跳转到指定字节位置 data = obj.read() obj.close() print(data) obj = open('a.txt',mode='rb') obj.seek(3) # 跳转到指定字节位置 data = obj.read() obj.close() print(data) ``` - tell(), 获取光标当前所在的字节位置 ``` obj = open('a.txt',mode='rb') # obj.seek(3) # 跳转到指定字节位置 obj.read() data = obj.tell() print(data) obj.close() ``` - flush,强制将内存中的数据写入到硬盘 ``` v = open('a.txt',mode='a',encoding='utf-8') while True: val = input('请输入:') v.write(val) v.flush() v.close() ``` ### 4.4 关闭文件 文艺青年 ```python v = open('a.txt',mode='a',encoding='utf-8') v.close() ``` 二逼 ```python with open('a.txt',mode='a',encoding='utf-8') as v: data = v.read() # 缩进中的代码执行完毕后,自动关闭文件 ``` ### 4.5 文件内容的修改 ```python with open('a.txt',mode='r',encoding='utf-8') as f1: data = f1.read() new_data = data.replace('飞洒','666') with open('a.txt',mode='w',encoding='utf-8') as f1: data = f1.write(new_data) ``` 大文件修改 ``` f1 = open('a.txt',mode='r',encoding='utf-8') f2 = open('b.txt',mode='w',encoding='utf-8') for line in f1: new_line = line.replace('阿斯','死啊') f2.write(new_line) f1.close() f2.close() ``` ``` with open('a.txt',mode='r',encoding='utf-8') as f1, open('c.txt',mode='w',encoding='utf-8') as f2: for line in f1: new_line = line.replace('阿斯', '死啊') f2.write(new_line) ``` ## 第五章 函数 ### 5.1面向过程编程与函数式编程 截至目前我们所接触、所写的编成为:面向过程式编程【可读性差/可重用性差】 ```P # 面向过程编程 user_input = input('请输入角色:') if user_input == '管理员': import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('管理员,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["管理员", '344522251@qq.com']) msg['Subject'] = "情爱的导演" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', ['管理员', ], msg.as_string()) server.quit() elif user_input == '业务员': import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('业务员,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["业务员", '业务员']) msg['Subject'] = "情爱的导演" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', ['业务员', ], msg.as_string()) server.quit() elif user_input == '老板': import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('老板,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["老板", '老板邮箱']) msg['Subject'] = "情爱的导演" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', ['老板邮箱', ], msg.as_string()) server.quit() ``` ```P # 函数式编程 def send_email(): import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('老板,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["老板", '老板邮箱']) msg['Subject'] = "情爱的导演" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', ['老板邮箱', ], msg.as_string()) server.quit() user_input = input('请输入角色:') if user_input == '管理员': send_email() elif user_input == '业务员': send_email() elif user_input == '老板': send_email() ``` 对于函数编程: - 本质:将N行代码拿到别处并给他起个名字,以后通过名字就可以找到这段代码并执行。 - 场景: - 代码重复执行 - 代码特别多超过一屏,可以选择通过函数进行代码的分割 ### 5.2 函数的基本结构 ```P # 函数的定义 def 函数名(): # 函数名的命名规范、建议与变量的一样 # 函数内容 (缩进) pass # 函数的执行 函数名() ``` ```P def get_list_first_data(): v = [11,22,33,44] print(v[0]) get_list_first_data() # 注意:函数如果不被调用,则内部代码永远不会被执行。 ``` ```P # 假如:管理员/业务员/老板用的是同一个邮箱。 def send_email(): print('发送邮件成功,假设有10含代码') user_input = input('请输入角色:') if user_input == '管理员': send_email() elif user_input == '业务员': send_email() elif user_input == '老板': send_email() ``` 总结: ```P # 情况1 def f1(): pass f1() # 情况2 def f2(a1): pass f2(123) # 情况3 def f3(): return 1 v1 = f3() # 情况4 def f4(a1,a2): # ... return 999 v2 = f4(1,7) ``` ```python def show(name,age): """ 函数是干什么的... # 必须注明函数 :param name: :param age: :return: """ return None ``` 函数内部的数据是否会混乱:(函数与函数之间的执行互不影响) - 1.函数执行完毕 - 2.内部元素不被其他人使用 ---->销毁函数执行的内存数 ### 5.3 参数 ```P def get_list_first_data(aaa): # aaa叫形式参数(形参) v = [11,22,33,44] print(v[aaa]) get_list_first_data(1) # 2/2/1调用函数时传递叫:实际参数(实参) get_list_first_data(2) get_list_first_data(3) get_list_first_data(0) ``` 严格按照顺序传参数:位置方式传参 实际参数可以是任意类型 ```P # 假如:管理员/业务员/老板用的是同一个邮箱。 """ def send_email(to): import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('导演,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["导演", to]) msg['Subject'] = "情爱的导演" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', [to, ], msg.as_string()) server.quit() """ def send_email(to): template = "要给%s发送邮件" %(to,) print(template) user_input = input('请输入角色:') if user_input == '管理员': send_email('xxxx@qq.com') elif user_input == '业务员': send_email('xxxxo@qq.com') elif user_input == '老板': send_email('xoxox@qq.com') ``` 练习题 ```P # 1. 请写一个函数,函数计算列表 info = [11,22,33,44,55] 中所有元素的和。 def get_sum(): info = [11,22,33,44,55] data = 0 for item in info: data += item print(data) get_sum() # 2. 请写一个函数,函数计算列表中所有元素的和。 def get_list_sum(a1): data = 0 for item in a1: data += item print(data) get_list_sum([11,22,33]) get_list_sum([99,77,66]) v1 = [8712,123,123] get_list_sum(v1) # 3. 请写一个函数,函数将两个列表拼接起来。 def join_list(a1,a2): result = [] result.extend(a1) result.extend(a2) print(result) join_list([11,22,33],[55,66,77] # 4. 计算一个列表的长度 def my_len(arg): count = 0 for item in arg: count += 1 print(count) v = [11,22,33] my_len(v) len(v) # 5. 发邮件的示例 def send_email(role,to): template = "要给%s%s发送邮件" %(role,to,) print(template) user_input = input('请输入角色:') if user_input == '管理员': send_email('管理员','xxxx@qq.com') elif user_input == '业务员': send_email('业务员','xxxxo@qq.com') elif user_input == '老板': send_email('老板','xoxox@qq.com') ``` #### 5.3.1 形参 ##### 5.3.1.1 基本参数知识 - 参数可以是任意个数 - 可以是任意类型 ```P def func(a1,a2,a3,a4): print(a1,a2,a3,a4) func(2,'name',[1,2,3],False) ``` ##### 5.3.1.2默认参数 ```P def func(a1,a2,a3=9,a4=10): # 默认参数a3=9,a4=10 print(a1,a2,a3,a4) func(11,22) # 不给a3,a4传值,则a3,a4等于默认参数 func(11,22,10) func(11,22,10,100) func(11,22,10,a4=100) func(11,22,a3=10,a4=100) func(11,a2=22,a3=10,a4=100) func(a1=11,a2=22,a3=10,a4=100) ``` ##### 5.3.1.3 万能参数(用于打散) - *args 可以接受任意个数的位置参数,并将参数转换成元组。 1.调用函数无* ```P def func(*args): print(*args) func(1,2) ==> (1,2) func(1,2,[12,3,4]) ==> (1,2,[12,3,4]) func((11,22,33)) ==> ((11,22,33)) # 参数是一个元组,打印出来的效果是元组套元组。 ``` 2.调用函数有* ```P def func(*args): print(args) func(*(11,22,33)) ==>(11,22,33) # *是用来打散元组的,将元组中的每个元素作为参数。 func(*[11,22,33]) ==>(11,22,33) # *可以用来打散列表/元组 /字典/集合,只是循环内部元素 ``` 3.只能用位置传参 ```P def func(*args): print(args) func(1) func(1,2) # args=(1, 2) func((11,22,33,44,55)) # args=((11,22,33,44,55),) func(*(11,22,33,44,55)) # args=(11,22,33,44,55) ``` - **kwargs 可以接受任意个数的关键字参数,并见参数转换成字典 1.调用函数无* ```P def func(**kwargs): print(***kwargs) func(k=1) **kwargs = {'k':1} func(k1=1,k2=3) **kwargs = {'k1':1,'k2':3} ``` 2.调用函数有* ```P def func(**kwargs): print(kwargs) func(**{'k1':1,'k2':4,'k3':9}) **kwargs = {'k1':1,'k2':4,'k3':9} ``` 3.只能用关键字传参 - *args/**kwargs综合使用:无敌 + 无敌 => 真无敌 ```P def func(*args,**kwargs): print(args,kwargs) func(1,2,3,4,5,k1=2,k5=9,k19=999) *arg = (1,2,3,4,5) **kwargs = {'k1':2,'k5':9,'k19':999} func(*[1,2,3],k1=2,k5=9,k19=999) *arg = (1,2,3) **kwargs = {'k1':2,'k5':9,'k19':999} func(*[1,2,3],**{'k1':1,'k2':3}) *arg = (1,2,3) **kwargs = {'k1':1,'k2':3} func(111,222,*[1,2,3],k11='alex',**{'k1':1,'k2':3}) *arg = (111,222,1,2,3) **kwargs = {'k11':'alex','k1':1,'k2':3} ``` #### 5.3.2 实参 ##### 5.3.2.1 位置传参(调用函数并传入参数)(执行) 调用/执行函数的时候严格按照位置的顺序传入参数 ```P def func(a1,a2,a3): print(a1,a2,a3) func(66,'alex',3) ``` ##### 5.3.2.2 关键字传参(执行) 关键字传参就是将形参放入到实参中去使用 ```P def func(a1,a2): print(a1,a2) func(a1=22,a2=8) ``` 关键字传参与位置传参是可以混合使用的:位置传入的参数要放在前面,关键字传参要放在后面,最后等于总参数个数 ```P def func(a1,a2,a3): print(a1,a2,a3) func(1,2,a3=3) func(1,a2=2,a3=3) func(a1=1,a2=2,a3=3) func(a1=1,2,3) # 是错误的 ``` def func() : 自定义函数 open() 这两个为python的内置函数 ​ pass len() #### 5.3.3 参数相关的重点 - 定义函数 ```P def func(a1,a2): pass def func(a1,a2=None): # 对于默认值,不可变类型随便写,如果是可变类型(有坑)。 pass def func(*args,**kwargs): pass ``` 对于函数的默认值一般使用不可变类型,慎用可变类型: 如果要想给value设置默认值是空列表: ```python 不推荐使用(会有坑): def func(data,value = []) pass 推荐使用: def func(data ,value = None) if not value: value = [] ``` ```python 例: def func(data,value = [] value.append(data) return value v1 = func(1) # v1 = [1] v2 = func(2,[11,22,33]) # v2 = [11,22,33,2] v3 = func(3) # v3 = [1,3] ``` 面试题: - def func(a,b=[]) 有什么陷阱? 如果不给b传参数,则默认的都是同一个地址 - 看代码写结果 ```python def func(a,b=[]): b.append(a) return b l1 = func(1) l2 = func(2,[11,22]) l3 = func(3) print(l1,l2,l3) # [1,3] [11,22,2] [1,3] ``` - 看代码写结果 ```python def func(a,b=[]): b.append(a) print(b) func(1) # [1] func(2,[11,22,33]) # [11,22,33,2] func(3) # [1,3] ``` - 调用函数 位置参数在前,关键字参数在后。 ### 5.4 返回值 ```P def func(arg): # .... return 9 # 返回值为9 默认:return None val = func('adsfadsf') ``` ```P # 1. 让用户输入一段字符串,计算字符串中有多少A字符的个数。有多少个就在文件a.txt中写多少个“李邵奇”。 def get_char_count(data): sum_counter = 0 for i in data: if i == 'A': sum_counter += 1 return sum_counter def write_file(line): if len(line) == 0: return False # 函数执行过程中,一旦遇到return,则停止函数的执行。 with open('a.txt',mode='w',encoding='utf-8') as f: f.write(line) return True content = input('请输入:') counter = get_char_count(content) write_data = "李邵奇" * counter status = write_file(write_data) if status: print('写入成功') else: print('写入失败') ``` 函数没有返回值时,默认返回None。 函数内部执行过程中遇到return就终止。 ```P def func1(): return "完成" # 函数每次执行到此,就返回;所以下面代码永远不执行。 for i in range(10): print(i) func1() def func2(): for i in range(10): print(i) return "完成" print(666) func2() # 只打印0 ``` return可以返回任意值 特殊情况:return返回多个值时,返回的是元组,与返回值是元组时是一样的 ```P def func(): return (1,2,3) v = func() print(v) # 特殊:返回元组 def func(): return 5,8,"alex" v = func() print(v) ``` return的作用:a. 返回值 b.终止函数的执行 练习题 ```P # 1. 写函数,计算一个列表中有多少个数字,打印: 列表中有%s个数字。 # 提示:type('x') == int 判断是否是数字。 """ # 方式一: def get_list_counter1(data_list): count = 0 for item in data_list: if type(item) == int: count += 1 msg = "列表中有%s个数字" %(count,) print(msg) get_list_counter1([1,22,3,'alex',8]) # 方式二: def get_list_counter2(data_list): count = 0 for item in data_list: if type(item) == int: count += 1 return count v = get_list_counter1([1,22,3,'alex',8]) msg = "列表中有%s个数字" %(v,) print(msg) """ ``` ```P # 2. 写函数,计算一个列表中偶数索引位置的数据构造成另外一个列表,并返回。 """ # 方式一: def get_data_list1(arg): v = arg[::2] return v data = get_data_list1([11,22,33,44,55,66]) # 方式二: def get_data_list2(arg): v = [] for i in range(0,len(arg)): if i % 2 == 0: v.append(arg[i]) return v data = get_data_list2([11,22,33,44,55,66]) """ ``` ```P # 3. 读取文件,将文件的内容构造成指定格式的数据,并返回。 """ a.log文件 alex|123|18 eric|uiuf|19 ... 目标结构: a. ["alex|123|18","eric|uiuf|19"] 并返回。 b. [['alex','123','18'],['eric','uiuf','19']] c. [ {'name':'alex','pwd':'123','age':'18'}, {'name':'eric','pwd':'uiuf','age':'19'}, ] """ with open('a.log.txt',mode = 'r',encoding = 'utf-8') as f: data = f.read() print(data) def get_file(a): date1 = [] for i in a.split('\n'): date1.append(i) return date1 v1 = get_file(data) print(v1) def get_file1(b): date2 = [] d = [] for i1 in b.split('\n'): i1 = i1.split('|') d.append(i1) date2 += d return date2 v2 = get_file1(data) print(v2) def get_file2(c): date3 = [] e = {} for i2 in c.split('\n'): i2 = i2.split('|') e['name'] = i2[0] e['pwd'] = i2[1] e['age'] = i2[2] date3.append(e) return date3 v3 = get_file2(data) print(v3) ``` 1. 数据类型中的方法到底有没有返回值: - 无返回值 ```python v = [1,2,3,4] v.append(55) # 无返回值时不用写return了 ``` list : append / insert / remove / clear / extend / reverse dict : update set : add / discard / update - 仅有返回值 ```python v = 'ddff2dd554cvc' result = '-'.join(v) return result v = {'k1':12,'k2':'ased'} result = v.get('k2') result = v.keys() ``` str : upper / lower / replace / isdecimal / strip / split / startswith / endswith / encode / format / join list : find / index dict : keys / values / items / get set : intersection / union / difference / symmitric_difference - 有返回值 + 修改数据 pop ```python v = [11,22,33,44] result = v.pop(22) ``` - 常用需要记住的 索引、切片都有返回值 str : split 返回列表 ​ strip 返回字符串 ​ replace 返回字符串 ​ join 返回字符串 list : append 无 ​ insert 无 ​ remove 无 ​ pop 返回要删除的数据 ​ find 返回索引的位置 ​ index 返回索引的位置 dict : keys 获取所有的键 ​ values 获取所有的值 ​ items 获取所有的键值对 ​ get 索引存在:返回值 ,不存在:返回None ### 5.5 作用域 在python文件中: - py文件:全局作用域 - 函数:局部作用域 ```P a = 1 def s1(): x1 = 666 print(x1) print(a) print(b) b = 2 print(a) s1() a = 88888 def s2(): print(a,b) s1() s2() ``` - 每个作用域中的数据只有作用域自己可以调用,如果作用域中调用的数据没有,可以调用全局作用域的 全局作用域只能调用全局的 在全局作用域中的函数可以互相调用(调用已经存在的),但不可以直接调用作用域中的作用域 总结: - 1.一个函数就是一个作用域 - 2.作用域中查找数据规则:优先在自己的作用域找数据,自己没有就去“父级”-->“父级”-->直到全局,全局没有就报错。 (作用域的嵌套) 注意:父级作用域中的值到底是多少? ```P x = 10 def func(): x = 9 print(x) func() ``` 课上练习题 ```P x = 10 def func(): x = 9 print(x) def x1(): x = 999 print(x) func() x = 10 def func(): x = 9 print(x) def x1(): x = 999 print(x) x1() func() x = 10 def func(): x = 9 print(x) def x1(): x = 999 print(x) print(x) x1() func() x = 10 def func(): x = 8 print(x) def x1(): x = 999 print(x) x1() print(x) func() x = 10 def func(): x = 8 print(x) def x1(): print(x) x1() print(x) func() x = 10 def func(): x = 8 print(x) def x1(): print(x) x = 9 x1() x = 10 print(x) func() x = 10 def func(): x = 8 print(x) def x1(): print(x) x1() x = 9 x1() x = 10 print(x) func() ``` - 3.子作用域中只能只能找到父级中的值,默认无法重新为父级的变量进行赋值。 - 不能进行赋值,只能对可变类型进行内部修改 ```P # ##################### name = 'oldboy' def func(): name = 'alex' # 在自己作用域再创建一个这样的值。 print(name) func() print(name) # ##################### name = [1,2,43] def func(): name.append(999) print(name) func() print(name) ``` - 如果非要对全局的变量进行赋值需要加global(强制赋值) ```P #示例一 name = "老男孩“ def func(): global name name = 'alex' func() print name # 示例二 name = ["老男孩",'alex'] def func(): global name name = '我' func() print(name) # 示例三 name = "老男孩" def func(): name = 'alex' def inner(): global name name = 999 inner() print(name) func() print(name) ``` - 对父级的变量赋值用nonlocal,先找到父级的变量再进行赋值 (强制赋值) ```P name = "老男孩" def func(): name = 'alex' def inner(): nonlocal name # 找到上一级的name name = 999 inner() print(name) func() print(name) ``` 补充:全局变量必须全部要大写 ```P USER_LIST = [11,22,3] def func(): name = 'asdf' USER_LIST.append(12) USER_LIST.append(name) func() print(USER_LIST) ``` ### 5.6 函数小高级 ( 5* ) - 1. 函数名可以当作变量来使用 ```python def func(): print(123) v1 = func # func代表函数的地址 func() v1() # v1、func的函数地址相同,执行调用的函数也相同 ``` ```python def func(): print(123) func_list = [func, func, func] # func_list[0]() a # func_list[1]() b # func_list[2]() c for item in func_list: # a/b/c的简化形式 v = item() print(v) ``` ```python def func(): print(123) def bar(): print(666) info = {'k1': func, 'k2': bar} info['k1']() # 函数也可以作为字典的值(也可以做为键,但是没有意义) info['k2']() ``` 注意:函数是不可变的,可以做集合的元素,也可以作为字典的键 (但是做键没有太大意义)。 ​ 集合中可以放多个重复的函数,但只执行一次。(因为集合的特性:不可重复的) 混淆你 ```python def func(): return 123 func_list1 = [func,func,func] func_list2 = [func(),func(),func()] print(func_list1) # 打印的是func的函数地址 print(func_list2) # 打印的是func执行完返回的值 info = { 'k1':func, # 函数的地址 'k2':func(), # 函数执行完返回的值 } print(info) ``` 2. 函数也可以当作参数来进行传递 ```python def func(arg): print(arg) func(1) func([1,2,3,4]) def show(): return 999 func(show) # 执行函数func,参数为show,show没有+(),表示show没有执行只是代表该函数的地址。 ``` ```python def func(arg): v1 = arg() print(v1) def show(): print(666) func(show) ``` ```python def func(arg): v1 = arg() print(v1) def show(): print(666) result = func(show) print(result) ``` 面试题:多个函数的调用 ```P def func(): print('花费查询') def bar(): print('语音沟通') def base(): print('xxx') def show(): print('xxx') def test(): print('xxx') info = { 'f1': func, 'f2': bar, 'f3':base, 'f4':show, 'f5':test } choice = input('请选择要选择功能:') function_name = info.get(choice) if function_name: function_name() else: print('输入错误') ``` 总结:函数当作一个变量:参数传值 / 当作元素嵌套到字典、列表中 ### 5.7 lambda表达式 (匿名函数) 用于表示简单的函数 lambda表达式,为了解决简单函数的情况: ```P def func(a1,a2): =====> func = lambda a1,a2:a1+a2 # 函数直接得到返回值,这里隐藏了return return a1+a2 简化 ``` ```P # 三元运算,为了解决简单的if else的情况,如: if 1 == 1: a = 123 else: a = 456 a = 123 if 1 == 1 else 456 # lambda表达式,为了解决简单函数的情况,如: def func(a1,a2): return a1 + 100 func = lambda a1,a2: a1+100 ``` ```P func1 = lambda : 100 func2 = lambda x1: x1 * 10 func3 = lambda *args,**kwargs: len(args) + len(kwargs) DATA = 100 func4 = lambda a1: a1 + DATA v = func4(1) print(v) DATA = 100 def func(): DATA = 1000 func4 = lambda a1: a1 + DATA v = func4(1) print(v) func() func5 = lambda n1,n2: n1 if n1 > n2 else n2 v = func5(1111,2) print(v) ``` lambda表达式只能用一行来表示函数,只能用参数来作为变量。 练习题 ```python # 练习题1 USER_LIST = [] def func0(x): v = USER_LIST.append(x) return v result = func0('alex') print(result) # 练习题2 def func0(x): v = x.strip() return v result = func0(' alex ') print(result) ############## 总结:列表所有方法基本上都是返回None;字符串的所有方法基本上都是返回新值 ################# # 练习题3 USER_LIST = [] func1 = lambda x: USER_LIST.append(x) v1 = func1('alex') print(v1) print(USER_LIST) # 练习题4 func1 = lambda x: x.split('l') v1 = func1('alex') print(v1) # 练习题5 func_list = [lambda x:x.strip(), lambda y:y+199,lambda x,y:x+y] v1 = func_list[0]('alex ') print(v1) v2 = func_list[1](100) print(v2) v3 = func_list[2](1,2) print(v3) ``` 总结: 列表所有方法基本上都是返回None,字符串的所有方法基本上都是返回新值。 ### 5.8 内置函数 函数分为:自定义函数 和 内置函数 目前python的内置函数分为几大类: - 1.强制转换 bool() / int() / str() / list() / dict() /tuple() / set() - 2.输入输出 print() / input() - 3.其他 len() / open() / id() / range() / type() - 4.数学相关 - 1. abs() 绝对值 ```P v = abs(-1) print(v) # 1 ``` 2. float() 转换成浮点型(小数) ```P v = 55 v1 = float(v) print(v1) # 55.0 ``` 3. max() 找到最大值 ```P v = [1,2,33,5,9] result = max(v) print(result) # 33 ``` 4. min() 找到最小值 ```python v = [1,2,311,11,8] v2 = min(v) print(v2) # 1 ``` 5. sum() 求和 ```python v = [1,2,311,11,9] v1 = sum(v) print(v1) # 334 ``` 6. divmod() 两数相除的商和余数 ```python a,b = divmod(1001,5) print(a,b) # 200 1 ``` 补充:字符串格式化:'你少妻-%s' %(i,) ------>后面%(i,)如果括号中只有一个变量,可以写成:'你少妻-%s' %i ```python # 练习题 请通过分页对数据进行展示 """ 要求: 每页显示10条数据 让用户输入要查看的页面:页码 """ USER_LIST = [] for i in range(1,836): temp = {'name':'你少妻-%s' %i,'email':'123%s@qq.com' %i } USER_LIST.append(temp) # 数据总条数 total_count = len(USER_LIST) # 每页显示10条 per_page_count= 10 # 总页码数 max_page_num,a = divmod(total_count,per_page_count) if a>0: max_page_num += 1 while True: pager = int(input('要查看第几页:')) if pager < 1 or pager > max_page_num: print('页码不合法,必须是 1 ~ %s' %max_page_num ) else: """ # 第1页:USER_LIST[0:10] -> 0123456789 # 第2页:USER_LIST[10:20] # 第3页:USER_LIST[20:30] ... """ start = (pager-1) * per_page_count end = pager * per_page_count data = USER_LIST[start:end] for item in data: print(item) ``` - 7.pow pow(x,y) 表示x的y次方 ```Python v = pow(2,3) print(v) # 8 ``` - 8.round 保留小数点后几位小数,还会四舍五入。 ```python V = round(1.127,1/2) print(v) # 1.1 / 1.13 ``` - 5.进制转换相关 - bin() 将十进制转换成二进制 ```python num = 13 v1 = bin(num) print(v1) # 0b1101 ``` - oct() 将十进制转换成八进制 ```python num = 8 v1 = oct(num) print(v1) # 0o10 ``` - int() 将其他的进制转换成十进制 ```python # 二进制转化成十进制 v1 = '0b1101' result = int(v1,base=2) print(result) # 13 # 八进制转化成十进制 v1 = '0o1101' result = int(v1,base=8) print(result) # 十六进制转化成十进制 v1 = '0x1101' result = int(v1,base=16) print(result) ``` - hex() 将十进制转换成十六进制 ```p num = 16 v1 = hex(num) print(v1) # 0x10 ``` 面试题 ```p # 1字节等于8位 # IP: 192.168.12.79 -> 001010010 . 001010010 . 001010010 . 001010010 # 1. 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制并通过,连接起来生成一个新的字符串。 ip = "192.168.12.79" ip_list = ip.split('.') # ['192','168','12','79'] result = [] for item in ip_list: result.append(bin(int(item))) print(','.join(result)) # 2. 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制: # 0010100100001010010001010010001010010 -> 十进制的值。 # 3232238671 ip = "192.168.12.79" ip1 = ip.split('.') lis = [] for i in ip1: lis.append(bin(int(i))) # val = ','.join(lis) # b = val.replace('0b', '') # b1 = b.split(',') b1 = ','.join(lis).replace('0b', '').split(',') e = [] #f or c in b1: for c in ','.join(lis).replace('0b', '').split(','): if len(c) < 8: val = 8 - len(c) d = list(c) d.insert(0,'0' * val) d1 = ''.join(d) e.append(d1) else: e.append(c) f = ''.join(e) f1 = int(f,base = 2 ) print(f1) ``` - 6.编码相关 - chr 将十进制数字转换成Unicode编码中的对应字符串 ```python v = chr(65) print(v) # A ``` - ord 根据字符在Unicode编码中找到其对应的十进制 ```python v = ord('中') print(v) # 20013 ``` - 应用: ```python import random v = random.randint(65,90) print(v) # 随机获得65~90之间的数字 import random data = [] for i in range(6) v = random.randint(65,90) data.append(chr(v)) print(''.join(data)) # 6位随机字符串验证码 import random def get_random_code(length=6): data = [] for i in range(length): v = random.randint(65,90) data.append(chr(v)) return ''.join(data) code = get_random_code() print(code) # 6位随机字符串验证码 ``` ```python import random # 导入一个模块 v = random.randint(起始,终止) # 得到一个随机数 ``` - 7.高级一点的内置函数 - map 循环每个元素(第二个参数),然后让每个元素执行函数(第一个参数),将每个函数执行的结果保存到新的列表中,并返回。 ```python V1 = [11,22,33,44] # map(x,v1) 第一个参数必须是函数,第二个参数必须是可迭代类型(可以被for循环的) def func(arg): print(arg) # map(func,v1) # 执行后并不打印arg,这是py3的一个特性,py3现在还不执行以后会执行 result = map(func,v1) # 然后将函数的返回值添加到一个[]中 # print(result) py2会直接返回列表 # print(result) py3不会,会得到一个对象/东西,想返回列表的话需要强制转换成列表 print(list(ruselt)) # result得到的是一个对象,需要list()才能打印列表 ``` ```python v1 = [11,22,33,44] result = map(lambda x:x+100,v1) print(list(result)) # 特殊 ``` - filter result = filter(函数,参数) ```python v1 = [11,22,33,'asd',44,'xf'] def func(x): if type(x) == int: return True return False result = filter(func,v1) # [11,] print(list(result)) result = filter(lambda x: True if type(x) == int else False ,v1) print(list(result)) result = filter(lambda x: type(x) == int ,v1) print(list(result)) ``` - reduce 累计得到一个结果 reduce现在不在py3的内置函数种了 ,但py2的内置函数里包含。 ```python import functools v1 = ['wo','hao','e'] def func(x,y): return x+y result = functools.reduce(func,v1) print(result) result = functools.reduce(lambda x,y:x+y,v1) print(result) ``` - 8.类相关 - 1. type,查看类型 ```python class Foo: pass obj = Foo() if type(obj) == Foo: print('obj是Foo类的对象') ``` 2. issubclass 判断某个类是不是另一个类或其基类的子类。 issubclass(类1,类2) 类1—>子类名,类2—>基类名 ```python class Base: pass class Base1(Base): pass class Foo(Base1): pass class Bar: pass print(issubclass(Bar,Base)) print(issubclass(Foo,Base)) ``` 3. #### isinstance 判断某个对象是否是某个类或其基类的实例(对象) ```python class Base(object): pass class Foo(Base): pass obj = Foo() print(isinstance(obj,Foo)) # 判断obj是否是Foo类或其基类的实例(对象) print(isinstance(obj,Base)) # 判断obj是否是Foo类或其基类的实例(对象) ``` 4. ### super ```python class Base(object): def func(self): print('base.func') return 123 class Foo(Base): def func(self): v1 = super().func() print('foo.func',v1) obj = Foo() obj.func() # super().func() 去父类中找func方法并执行 ``` ```python class Bar(object): def func(self): print('bar.func') return 123 class Base(Bar): pass class Foo(Base): def func(self): v1 = super().func() print('foo.func',v1) obj = Foo() obj.func() # super().func() 根据类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了) ``` ```python class Base(object): # Base -> object def func(self): super().func() print('base.func') class Bar(object): def func(self): print('bar.func') class Foo(Base,Bar): # Foo -> Base -> Bar pass obj = Foo() obj.func() # 多继承 # super().func() 根据self对象所属类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了) ``` super().要查找的方法 super().func() 根据self对象所属类的继承关系(从左向右依次查找),按照顺序挨个找func方法并执行(找到第一个就不再找了) super 遵循mro顺序查找上一个类的 supper().func()不是查找父类,而是根据mro顺序,找到自己对应的下一个类 - 9.面试题: - 常用的内置函数有哪些 - filter/map/reduce是什么意思? - 什么是匿名函数 ```python def func(): pass v = [lambda x:x+100,] # lambda表达式 ``` ### 5.9 函数中高级 #### 5.9.1 函数可以做返回值 ```python def func(): print(123) def bar(): return func v = bar() v() ``` ```python name = 'oldboy' def func(): print(name) def bar(): return func v = bar() v() ``` ```python def bar(): def inner(): print(123) return inner v = bar() v() ``` ```python name = 'oldboy' def bar(): name = 'alex' def inner(): print(name) return inner v = bar() v() ``` ```python name = 'oldboy' def bar(name): def inner(): print(name) return inner v1 = bar('alex') # { name=alex, inner } # 闭包,为函数创建一块区域(内部变量供自己使用,存储的代码),为他以后执行提供数据。 v2 = bar('eric') # { name=eric, inner } v1() v2() ``` 练习题 ```python # 第一题 name = 'alex' def base(): print(name) def func(): name = 'eric' base() func() # {name=eric, } # 第二题 name = 'alex' def func(): name = 'eric' def base(): print(name) base() func() # 第三题 name = 'alex' def func(): name = 'eric' def base(): print(name) return base base = func() base() ``` 注意:函数在何时被谁创建? ​ 函数是由谁创建的,执行函数就从哪里开始找 面试题 ```python info = [] def func(): print(item) for item in range(10): info.append(func) info[0]() ``` ```python info = [] def func(i): def inner(): print(i) return inner for item in range(10): info.append(func(item)) info[0]() info[1]() info[4]() ``` #### 5.9.2 闭包 ```python def func(name): def inner(): print(name) return inner v1 = func('alex') v1() v2 = func('eric') v2() ``` 返回值——分析函数执行的内存。(闭包是内存其中的一种) ```python # 并不是闭包 def func(name) def inner(): return 123 return inner # 是闭包需要满足两个条件:1.封装值 2.内层函数需要使用 def func(name) def inner(): print(name) return 123 return inner ``` #### 5.9.3 高阶函数 - 把函数当作参数传递 - 把函数当作返回值 注意:对函数进行赋值 #### 5.9.4 小总结 - 1.函数执行流程的分析(函数到底是由谁创建的?) - 2.闭包概念:为函数创建一块区域并为其维护自己的数据以后执行时方便调用。(应用场景:装饰器 / SQLAlchemy源码) ### 5.10 装饰器(6**) #### 5.10.1目的、应用场景: - 目的: 在不改变原函数内部代码的基础上,在函数执行前后自定义功能。 - 应用场景: 想要为函数扩展功能时,可以选择用装饰器。 #### 5.10.2 编写装饰器和应用 - 1. 基本装饰器(非常重要5**) ```python # 装饰器的编写格式 (双层嵌套函数) def 外层函数(参数): def 内层函数(*arg,**kwarg) return 参数(*arg,**kwarg) return 内层函数 #装饰器的应用格式 @外层函数 def 要装饰的函数() pass # 执行函数,自动触发装饰器了 要装饰的函数() ``` 练习题 ```python def func(arg): def inner(): print('before') v = arg() print('after') return v return inner def index(): print('123') return '666' # 示例一 """ v1 = index() # 执行index函数,打印123并返回666赋值给v1. """ # 示例二 """ v2 = func(index) # v2是inner函数,arg=index函数 index = 666 v3 = v2() """ # 示例三 """ v4 = func(index) index = v4 # index ==> inner index() """ # 示例四 index = func(index) index() ``` ```python def func(arg): def inner(): v = arg() return v return inner # 第一步:执行func函数并将下面的函数参数传递,相当于:func(index) # 第二步:将func的返回值重新赋值给下面的函数名。 index = func(index) @func def index(): print(123) return 666 print(index) ``` ```python # 计算函数执行时间 def wrapper(func): def inner(): start_time = time.time() v = func() end_time = time.time() print(end_time-start_time) return v return inner @wrapper def func1(): time.sleep(2) print(123) @wrapper def func2(): time.sleep(1) print(123) def func3(): time.sleep(1.5) print(123) func1() ``` 注:问题:为什么要加*arg、**kwarg 理解: - 变量赋值 ```python def func(): print(1) v1 = func func = 666 ``` - 看看到底return的是什么? - 自己有找自己的,自己没有到上一级作用域去找 背会: ```python @xx # index = xx(index) def index(): pass index() ``` - 2. 关于参数 ```python def x(func): def inner(a1): return func(a1) return inner @x def index(a1): pass ``` ```python def x(func): def inner(a1,a2): return func(a1,a2) return inner @x def index(a1,a2): pass # index = inner index(1,2) # ################################### 参数统一的目的是为了给原来的index函数传参 def x(func): def inner(a1,a2): return func() return inner @x def index(): pass # func = 原来的index函数u # index = inner index(1,2) ``` 如果给好几个函数写一个统一的装饰器,怎么办? ```python def x1(func): def inner(*args,**kwargs): return func(*args,**kwargs) return inner @x1 def f1(): pass @x1 def f2(a1): pass @x1 def f3(a1,a2): pass ``` 装饰器建议写法: ```python def x1(func): def inner(*args,**kwargs): data = func(*args,**kwargs) return data return inner ``` - 3. 带参数的装饰器(4**) ```python # 第一步:执行 v1 = uuu(9) # 第二步:ret = v1(index) # 第三步:index = ret @uuu(9) def index(): pass ``` ```python # ################## 普通装饰器 ##################### def wrapper(func): def inner(*args,**kwargs): print('调用原函数之前') data = func(*args,**kwargs) # 执行原函数并获取返回值 print('调用员函数之后') return data return inner @wrapper def index(): pass # ################## 带参数装饰器 ##################### def x(counter): def wrapper(func): def inner(*args,**kwargs): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper @x(9) def index(): pass ``` 练习题 ```python # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,把每次结果添加到列表中,最终返回列表。 def xxx(counter): print('x函数') def wrapper(func): print('wrapper函数') def inner(*args,**kwargs): v = [] for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 v.append(data) return v return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v) # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,并返回最后一次执行的结果【面试题】 def xxx(counter): print('x函数') def wrapper(func): print('wrapper函数') def inner(*args,**kwargs): for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v) # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,并返回执行结果中最大的值。 def xxx(counter): print('x函数') def wrapper(func): print('wrapper函数') def inner(*args,**kwargs): value = 0 for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 if data > value: value = data return value return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v) ``` ``` def x(counter): print('x函数') def wrapper(func): print('wrapper函数') def inner(*args,**kwargs): if counter: return 123 return func(*args,**kwargs) return inner return wrapper @x(True) def fun990(): pass @x(False) def func10(): pass ``` 先欠两个装饰器: - 1. 元数据:flask框架 2. 多个装饰器:flask框架 ```python @x1 @x2 def func(): pass ``` ### 5.11 迭代器 自己不会写迭代器,只需要会用。 任务:请展示列表中所有的数据 - 1. while + 索引 + 计数器 2. 迭代器,对 某种对象(str/list/tuple/dict/set类创建的对象)-可迭代对象中的元素进行逐一获取 表象:具有_ _ next _ _方法且每次调用都获取可迭代对象中的元素(从前到后一个一个获取)。 - 1. 先将某对象(如列表)转换成迭代器 v1 = iter([11,22,33,44]) v1 = [11,22,33,44]_ _ iter _ _() _ 2. 迭代器想要获取每个值:反复调用(val = v1._ _ next _ _()) ```python v1 = [11,22,33,44] # 列表转换成迭代器 v2 = iter(v1) result1 = v2.__next__() print(result1) result2 = v2.__next__() print(result2) result3 = v2.__next__() print(result3) result4 = v2.__next__() print(result4) result5 = v2.__next__() # v1只有4个元素,第五次获取就会报错:StopIteration print(result5) v1 = "alex" v2 = iter(v1) while True: try: val = v2.__next__() print(val) except Exception as e: break ``` 3. 直到报错:StopIteration错误,表示已经迭代完毕。 ![1555853482921](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555853482921.png) 4. 如何判断一个对象是否是可迭代对象:内部是否有_ _ next _ _方法。 3. for循环: ```python v1 = [11,22,33,44] # 1.内部会将v1转换成迭代器 # 2.内部反复执行 迭代器.__next__() # 3.取完不报错 for item in v1: print(item) ``` ### 5.12 可迭代对象 - 1. 内部具有_ _ iter _ _()方法且返回一个迭代器 ```python v1 = [11,22,33,44] result = v1.__iter__() ``` 2. 可以被for循环的 ![1555854621680](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555854621680.png) ### 5.13 生成器(函数的变异) 判断一个函数是否是生成器函数:只需看函数内部是否有yield ```python # 生成器函数(内部是否包含yield) def func(): print('F1') yield 1 print('F2') yield 2 print('F3') yield 100 print('F4') # (只要有yield)函数内部代码不会执行,返回一个 生成器对象 。 v1 = func() # 生成器是可以被for循环,一旦开始循环那么函数内部代码就会开始执行。 for item in v1: print(item) ``` 循环流程: - 1. for循环开始第一次循环,先执行yield前面的代码,执行到yield时,返回yield的值给item并停止第一次循环。 2. 第二次循环:从上次循环的yield后面开始执行代码,执行到第二个yield(yield2)时,返回yield2的值给item并停止第二次循环。 3. 直到循环完所有的yield,循环自动终止 ```python def func(): count = 1 while True: yield count count += 1 val = func() for item in val: print(item) ``` 总结:函数中如果存在yield,那么该函数就是一个生成器函数,调用生成器函数会返回一个生成器,生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会获取yield返回的值。 ``` def func(): count = 1 while True: yield count count += 1 if count == 100: return val = func() for item in val: print(item) ``` 示例:读文件 ``` def func(): """ 分批去读取文件中的内容,将文件的内容返回给调用者。 :return: """ cursor = 0 while True: f = open('db', 'r', encoding='utf-8')# 通过网络连接上redis # 代指 redis[0:10] f.seek(cursor) data_list =[] for i in range(10): line = f.readline() if not line: return data_list.append(line) cursor = f.tell() f.close() # 关闭与redis的连接 for row in data_list: yield row for item in func(): print(item) ``` redis源码示例 ![1555858164688](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555858164688.png) 生成器作用: - 生成数据 - 是一种特殊的迭代器 ```python def func(): yield 1 yield 2 yield 3 v = func() result = v.__next__() print(result) result = v.__next__() print(result) result = v.__next__() print(result) result = v.__next__() print(result) ``` - 也是特殊的可迭代对象 ```python def func(): yield 1 v = func() result = v.__iter__() print(result) ``` 其他知识: - yeild from关键字 (从xxx中一点点获取) ```python def base(): yield 88 yield 99 def func(): yield 1 yield 2 yield from base() # 从base()中一点点获取 yield 3 result = func() for item in result: print(item) ``` ### 5.14 推导式 #### 5.14.1 列表推导式 - 1.目的 方便的生成一个列表 - 2.基本格式 - 变量 = [for循环的变量 for循环一个可迭代对象] - v1 = [i for i in 可迭代对象 ] v2 = [i for i in 可迭代对象 if 条件 ] # 条件为true时才进行append - 练习 ```python v1 = [ i for i in 'alex' ] # ['a','l','e','x'] v2 = [i+100 for i in range(10)] # [100,101,102,103,104,105,106,107,108,109] v3 = [99 if i>5 else 66 for i in range(10)] # [66,66,66,66,66,66,99,99,99,99] def func(): return 100 v4 = [func for i in range(10)] # [func,func,func,func,func,func,func,func,func,func,] v5 = [lambda : 100 for i in range(10)] # [lambda : 100,lambda : 100,lambda : 100,lambda : 100,lambda : 100,lambda : 100,lambda : 100,lambda : 100,lambda : 100,lambda : 100] result = v5[9]() # 100 v6 = [lambda :i for i in range(10)] # [lambda :i,lambda :i,lambda :i,lambda :i,lambda :i,lambda :i,lambda :i,lambda :i,lambda :i,lambda :i,] result = v6[5]() # 9 v7 = [lambda x:x*i for i in range(10)] # 新浪微博面试题 # 1.请问 v7 是什么? v7 = [lambda x:x*i,lambda x:x*i,lambda x:x*i,lambda x:x*i,lambda x:x*i,lambda x:x*i,lambda x:x*i,lambda x:x*i,lambda x:x*i,lambda x:x*i,] # 2.请问 v7[0](2) 的结果是什么? v7[0](2) = 18 # 面试题 def num(): return [lambda x:i*x for i in range(4)] # num() -> [函数,函数,函数,函数] print([ m(2) for m in num() ]) # [6,6,6,6] # ##################### 筛选 ######################### v8 = [i for i in range(10) if i > 5] # [6,7,8,9] ``` #### 5.14.2 集合推导式 - 1.目的 方便的生成一个集合 - 2.基本格式 - 变量 = {for循环的变量 for循环一个可迭代对象} - v1 = { i for i in 可迭代对象 } v2 = { i for i in 可迭代对象 if 条件 } # 条件为true时才进行append ```python v1 = { i for i in 'alex' } # {'a','l','e','x'} ``` #### 5.14.3 字典推导式 - 1.目的 方便的生成一个字典 - 2.基本格式 ```python v1 = { 'k'+str(i):i for i in range(10) } #{'K0':0,'K1':1,'K2':2,'K3':3,'K4':4,'K5':5,'K6':6,'K7':7,'K8':8,'k9':9} v1 = { 'k':i for i in range(10) } # {'k':9} #字典的键存在,则新值覆盖旧值,不存在则更新。 ``` #### 5.14.4 生成器推导式 ```python # def func(): # result = [] # for i in range(10): # result.append(i) # return result # v1 = func() v1 = [i for i in range(10)] # 列表推导式,立即循环创建所有元素。 print(v1) # def func(): # for i in range(10): # yield i # v2 = func() v2 = (i for i in range(10)) # 生成器推导式,创建了一个生成器,内部循环为执行。 # 面试题:请比较 [i for i in range(10)] 和 (i for i in range(10)) 的区别? ``` ```python # 示例一 # def func(): # result = [] # for i in range(10): # result.append(i) # return result # v1 = func() # for item in v1: # print(item) # 示例二 # def func(): # for i in range(10): # def f(): # return i # yield f # # v1 = func() # for item in v1: # print(item()) # 示例三: v1 = [i for i in range(10)] # 列表推导式,立即循环创建所有元素。 v2 = (lambda :i for i in range(10)) for item in v2: print(item()) ``` ### 5.15递归 函数自己调用自己。(缺点:效率低) python默认支持的递归最大数是1000次 ```python def func(): print(1) func() func() ``` ```python def func(i): print(i) func(i+1) func(1) ``` ```python def func(a,b): # 只能递归1000次的斐波那契 # 1 # 1 # 2 # 3 # 5 print(b) func(b,a+b) func(0,1) ``` ```python def func(a): if a == 5: return 100000 result = func(a+1) + 10 return result v = func(1) ``` ![1555402471461](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555402471461.png) ```python # 递归的返回值 def func(a): if a == 5: return 100000 result = func(a+1) + 10 v = func(1) name = 'alex' def func(): def inner(): print(name) return inner v =func() ``` ## 第六章 模块 import 导入,先导入某个模块,才能执行该模块下的功能’ ### 6.1模块分类和定义 #### 6.1.1 python内置模块 python内部提供的功能 内置模块安装的路径:python36\Lib 什么是模块? py文件 写好了的 对程序员直接提供某方面功能的文件 ##### 6.1.1.1 hashlib 摘要算法模块 可用于: - 密文验证 - 校验文件的一致性 1.将指定的“字符串”加密 ----md5的加密 ```python import hashlib obj = hashlib.md5() obj.update('要加密的字符串') # 这里是明文 result = obj.hexdigist() # result这里是密文。 这一步py2可以执行,但py3不行,会报错,需要加encode转换编码,默认的是Unicode编码,需要转换成gbk或utf-8压缩版 ``` md5加密永远不会被解密 ```python import hashlib def get_md5(data): obj = hashlib.md5() obj.update(data.encode('utf-8')) result = obj.hexdigest() return result val = get_md5('123') print(val) ``` 加盐 ```python import hashlib def get_md5(data): obj = hashlib.md5("sidrsicxwersdfsaersdfsdfresdy54436jgfdsjdxff123ad".encode('utf-8')) # 这里加了一点盐,表示让'123'与这里一起加密,加密后才得到密文。 obj.update(data.encode('utf-8')) result = obj.hexdigest() return result val = get_md5('123') print(val) ``` 应用: ```python import hashlib USER_LIST = [] def get_md5(data): obj = hashlib.md5("12:;idrsicxwersdfsaersdfsdfresdy54436jgfdsjdxff123ad".encode('utf-8')) obj.update(data.encode('utf-8')) result = obj.hexdigest() return result def register(): print('**************用户注册**************') while True: user = input('请输入用户名:') if user == 'N': return pwd = input('请输入密码:') temp = {'username':user,'password':get_md5(pwd)} USER_LIST.append(temp) def login(): print('**************用户登陆**************') user = input('请输入用户名:') pwd = input('请输入密码:') for item in USER_LIST: if item['username'] == user and item['password'] == get_md5(pwd): return True register() result = login() if result: print('登陆成功') else: print('登陆失败') ``` 2.sha sha是一个系列,一般常用sha1 ```python import hashlib md5 = hashlib.sha1('盐'.encode()) md5.update(b'str') print(md5.hexdigest()) # 863c5545d295eef3dffe556a141a48b30565c763 ``` ##### 6.1.1.2 getpass (输入密码时显示*)密码不显示(只能在终端运行)(黑框里输入时才会执行该功能) ```python import getpass pwd = getpass.getpass('请输入密码:') if pwd == '123': print('输入正确') ``` ##### 6.1.1.3 random 随机 1. random.randint ```python import random v = random.randint(65,90) print(v) # 随机获得65~90之间的数字 import random data = [] for i in range(6) v = random.randint(65,90) data.append(chr(v)) print(''.join(data)) # 6位随机字符串验证码 import random def get_random_code(length=6): data = [] for i in range(length): v = random.randint(65,90) data.append(chr(v)) return ''.join(data) code = get_random_code() print(code) # 6位随机字符串验证码 ``` ```python import random # 导入一个模块 v = random.randint(起始,终止) # 得到一个随机数 ``` 2. random.uniform(1,5) 3. random.choice([1,2,3,4,5]) # 验证码 抽奖 (抽取一个) 4. random.sample([1,2,3,4],3) # 一个奖项抽取多个人 5. shuffle # 洗牌 算法 ##### 6.1.1.4 time - time.time 时间戳 (获取当前时间 ,是从1970年1月1日 00:00 到现在所经历的秒数) ```python # 计算函数执行时间 def wrapper(func): def inner(): start_time = time.time() v = func() end_time = time.time() print(end_time-start_time) return v return inner @wrapper def func1(): time.sleep(2) print(123) @wrapper def func2(): time.sleep(1) print(123) def func3(): time.sleep(1.5) print(123) func1() func2() func3() ``` - time.sleep 等待秒数 - time.timezone ```python # https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=4ZwIFHM6iw==&tip=1&r=-781028520&_=1555559189206 ``` ##### 6.1.1.5 sys python解释器相关的数据 - 1. sys.getrefcount() 获取一个值的应用计数 ```python import sys a = [11,22,33] b = a print(sys.getrefcount(a)) # 3(表示a被引用了几次:a本身/b/print,共3次) ``` 2. sys.getrecursionlimit() 获取python默认支持的递归数量 3. sys.stdout.write() == print() 可以用于写入进度条 ```python sys.stdout.write('你好') sys.stdout.write('呀') ``` \n 换行符 \t 制表符 \r 回到当前行的起始位置 ```python print('123\r',end = '') # 打印完成后回到本行的起始位置 print('你好') # '你好'把'123'给覆盖掉了(因为在起始位置打印任何内容都会把以前的内容全部覆盖掉) ``` ```python import time for i in range(1,101): msg = "%s%%\r" %i print(msg,end='') time.sleep(0.05) ``` ```python import os # 1. 读取文件大小(字节) file_size = os.stat('20190409_192149.mp4').st_size # 2.一点一点的读取文件 read_size = 0 with open('20190409_192149.mp4',mode='rb') as f1,open('a.mp4',mode='wb') as f2: while read_size < file_size: chunk = f1.read(1024) # 每次最多去读取1024字节 f2.write(chunk) read_size += len(chunk) val = int(read_size / file_size * 100) print('%s%%\r' %val ,end='') ``` 4. sys.argv() ```python #!/usr/bin/env python # -*- coding:utf-8 -*- """ 让用户执行脚本传入要删除的文件路径,在内部帮助用将目录删除。 C:\Python36\python36.exe D:/code/s21day14/7.模块传参.py D:/test C:\Python36\python36.exe D:/code/s21day14/7.模块传参.py """ import sys # 获取用户执行脚本时,传入的参数。 # C:\Python36\python36.exe D:/code/s21day14/7.模块传参.py D:/test # sys.argv = [D:/code/s21day14/7.模块传参.py, D:/test] path = sys.argv[1] # 删除目录 import shutil shutil.rmtree(path) ``` 5. sys.exit(0) 程序终止 sys.exit(0) 其中的0表示正常终止,程序只要运行到这一步,立刻跳出程序,它下面所有的代码都不再运行 6. sys.path 默认Python去导入模块时,会按照sys.path中的路径挨个查找。 ``` # import sys # sys.path.append('D:\\') # import oldboy ``` 注意: sys.path的作用是什么? ![1555574640947](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555574640947.png) ![1555574686220](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555574686220.png) 练习题 ![1555574715023](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555574715023.png) 7. sys.modules 存储了当前程序中用到的所有模块,反射本文件中的内容 ##### 6.1.1.6 os 和操作系统相关的数据 - 1. os.path.exists(path) , 如果path存在,返回True;如果path不存在,返回False 2. os.stat('20190409_192149.mp4').st_size , 获取文件大小 3. os.path.abspath() , 获取一个文件的绝对路径 ``` path = '20190409_192149.mp4' # D:\code\s21day14\20190409_192149.mp4 import os v1 = os.path.abspath(path) print(v1) ``` 4. os.path.dirname ,获取路径的上级目录 ``` import os v = r"D:\code\s21day14\20190409_192149.mp4" print(os.path.dirname(v)) ``` 补充: - 转义 ```python # r 是将路径中所有关于‘\c、\s……’转换成‘\\c、\\s……’(防止python将\n1当成换行符) v1 = r"D:\code\s21day14\n1.mp4" (推荐) print(v1) v2 = "D:\\code\\s21day14\\n1.mp4" (不建议使用) print(v2) ``` 5. os.path.join ,路径的拼接 ``` import os path = "D:\code\s21day14" # user/index/inx/fasd/ v = 'n.txt' result = os.path.join(path,v) print(result) result = os.path.join(path,'n1','n2','n3') print(result) ``` 6. os.listdir , 查看一个目录下所有的文件【第一层】 ``` import os result = os.listdir(r'D:\code\s21day14') for path in result: print(path) ``` 7. os.walk , 查看一个目录下所有的文件【所有层】 ```python import os result = os.walk(r'D:\code\s21day14') for a,b,c in result: # a,正在查看的目录 b,此目录下的文件夹 c,此目录下的文件 for item in c: path = os.path.join(a,item) print(path) ``` 8. os.mkdir 创建目录(只能创建一级目录)(基本上不用) 9. os.makedirs 创建目录和子目录 ```python import os file_path = r'db\xx\xo\xxxxx.txt' file_folder = os.path.dirname(file_path) if not os.path.exists(file_folder): os.makedirs(file_folder) with open(file_path,mode='w',encoding='utf-8') as f: f.write('asdf') ``` 10. os.rename 重命名 ```python import os os.rename('db','sb') ``` 11. os.path.getsize 获取文件大小 ##### 6.1.1.7 shutil shutil.rmtree 删除目录 ```python import shutil shutil.rmtree(path) # 删除目录 ret = shutil.rmtree(path) print(ret) # None # 删除后没有返回值 ``` shutil.move 重命名、移动文件 ```python import shutil shutil.move('test','ttt') ``` shutil.make_archive 压缩文件 ```python import shutil shutil.make_archive('zzh','zip','D:\code\s21day16\lizhong') ``` shutil.unpack_archive 解压文件 ```python import shutil shutil.unpack_archive('zzh.zip',format='zip') # 解压到当前文件 shutil.unpack_archive('zzh.zip',extract_dir=r'D:\code\xxxxxx\xxxx',format='zip') # 解压到指定路径(文件的路径中没有的文件夹会自动新建) ``` 示例 ```python import os import shutil from datetime import datetime ctime = datetime.now() # 当前时间 ctime = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') # .strftime() 用于指定当前时间的显示格式 # 1.压缩lizhongwei文件夹 zip # 2.放到到 code 目录(默认不存在) # 3.将文件解压到D:\x1目录中。 if not os.path.exists('code'): os.makedirs('code') shutil.make_archive(os.path.join('code',ctime),'zip','D:\code\s21day16\lizhongwei') file_path = os.path.join('code',ctime) + '.zip' shutil.unpack_archive(file_path,r'D:\x1','zip') ``` ##### 6.1.1.8 json - 1. json是一个特殊的字符串。 【长的像列表/字典/字符串/数字/真假】 把一个int/str/list/bool/dict/tuple转换成json格式的字符串叫做序列化。 把json格式的字符串转换成列表/字典……叫做反序列化。 json的格式: - 1.里面只包含:int/str/list/bool/dict(不能有元组、集合) - 2.最外层必须是 list / dict - 3.内部str必须使用双引号“” - 4.存在字典,字典的key只能是str - 5.不能连续load多次 json.dumps 序列化 (被序列化后得到的是字符串类型) json.loads 反序列化 ```python import json # 序列化,将python的值转换为json格式的字符串。 v = [12,3,4,{'k1':'v1'},True,'asdf'] v1 = json.dumps(v) print(v1) # 反序列化,将json格式的字符串转换成python的数据类型 v2 = '["alex",123]' print(type(v2)) v3 = json.loads(v2) print(v3,type(v3)) ``` json只支持int / str / list / dict / False / True / float / None 注意: - 字典或列表中如有中文,序列化时想要保留中文显示: ```python v = {'k1':'alex','k2':'李杰'} import json val = json.dumps(v,ensure_ascii=False) print(val) ``` - dump ```pyhton import json v = {'k1':'alex','k2':'李杰'} f = open('x.txt',mode='w',encoding='utf-8') val = json.dump(v,f) print(val) f.close() ``` - load ``` import json v = {'k1':'alex','k2':'李杰'} f = open('x.txt',mode='r',encoding='utf-8') data = json.load(f) f.close() print(data,type(data)) ``` 2. jso的优点:所有语言通用; ​ 缺点:只能序列化基本的数据类型 list/dict/int... 3. ##### 6.1.1.9 pickle 优点:1.python中几乎所有的东西都能被他序列化(socket对象); ​ 2.支持连续load多次 缺点:序列化的内容只有python认识。 pickle.dumps 序列化 (被序列化后得到的是字节类型) pickle.loads 反序列化 ```python import pickle v = {1,2,3,4} val = pickle.dumps(v) print(val) data = pickle.loads(val) print(data,type(data)) def f1(): print('f1') v1 = pickle.dumps(f1) print(v1) v2 = pickle.loads(v1) v2() ``` pickle.dump pickle.load ```python v = {1,2,3,4} f = open('x.txt',mode='wb') val = pickle.dump(v,f) f.close() f = open('x.txt',mode='rb') data = pickle.load(f) f.close() print(data) ``` ##### 6.1.1.10 datetime UTC/GMT:世界时间 本地时间:本地时区的时间。 datetime.now 当前的本地时间 datetime.utcnow 当前UTC时间 ```python import time from datetime import datetime,timezone,timedelta # 导入模块时,短的模块在上面,长的在下面。 # ######################## 获取datetime格式时间 ######################## """ v1 = datetime.now() # 当前本地时间 print(v1) tz = timezone(timedelta(hours=7)) # 当前东7区时间 v2 = datetime.now(tz) print(v2) v3 = datetime.utcnow() # 当前UTC时间 print(v3) """ # ######################## 把datetime格式转换成字符串 #################### v1 = datetime.now() print(v1,type(v1)) val = v1.strftime("%Y-%m-%d %H:%M:%S") print(val) # ######################## 字符串转成datetime ############################ v1 = datetime.strptime('2011-11-11','%Y-%m-%d') print(v1,type(v1)) # ######################## datetime时间的加减 ############################ v1 = datetime.strptime('2011-11-11','%Y-%m-%d') v2 = v1 - timedelta(days=140) # 减140天后的时间 date = v2.strftime('%Y-%m-%d') # 把v2转换成字符串 print(date) # 用datetime时间的加减时,会用到字符串与datetime格式的转换 # ######################## 时间戳和datetime关系 ########################## ctime = time.time() print(ctime) v1 = datetime.fromtimestamp(ctime) # 把时间戳转换成datetime格式 print(v1) v1 = datetime.now() val = v1.timestamp() # 把datetime格式转换成时间戳 print(val) ``` time、datetime与str的转换关系 ![1555578387690](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555578387690.png) ##### 6.1.1.11 (特殊)模块:importlib 根据字符串的形式导入模块 ```python # 模块 = importlib.import_module('utils.redis') import importlib # 用字符串的形式导入模块。 redis = importlib.import_module('utils.redis') # 用字符串的形式去对象(模块)找到他的成员。 getattr(redis,'func')() ``` ```python # from utils import redis import importlib middleware_classes = [ 'utils.redis.Redis', 'utils.mysql.MySQL', 'utils.mongo.Mongo' ] for path in middleware_classes: module_path,class_name = path.rsplit('.',maxsplit=1) module_object = importlib.import_module(module_path)# from utils import redis cls = getattr(module_object,class_name) obj = cls() obj.connect() ``` ![1556269828948](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1556269828948.png) 以后只用改配置文件(middleware_classes)中的内容 ##### 6.1.1.12 logging(记录日志 ) ```python # 异常级别:由高到低 CRITICAL = 50 # 崩溃 FATAL = CRITICAL ERROR = 40 # 错误 一般常用ERROR级别 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 # 没有设置(毫无意义) # 异常级别等于or高于设置的级别时,才会写入日志文件 ``` 注意:日志默认只接受第一次的配置,后面的配置都无效 日志一般给两种人使用: - 1. 用户的,如:银行流水 2. 程序员的: ```python 1. 统计用的 2. 用来做故障排除的 debug 3. 用来记录错误,完成代码的优化的 ``` - 基本应用 有两种配置方式: - 1.logging.basicconfig 优点:使用方便 缺点:不能实现编码问题;不能同时向文件和屏幕上输出 用logging.debug / logging.warning等来操作 - 2.logger对象 优点:能实现编码问题;也能同时向文件和屏幕上输出 缺点:复杂 用logger对象来操作 ```python import logging # 创建一个logger对象 logger = logging.getLogger() # 创建一个文件操作符 fh = logging.FileHandler('log.log') # 创建一个屏幕操作符 sh = logging.StreamHandler() # 给logger对象绑定 文件操作符 logger.addHandler(fh) # 给logger对象绑定 屏幕操作符 logger.addHandler(sh) # 创建一个格式 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 给文件操作符 设定格式 fh.setFormatter(formatter) # 给屏幕操作符 设定格式 sh.setFormatter(formatter) # 用logger对象来操作 logger.warning('message') ``` - 日志处理本质:Logger/FileHandler/Formatter ```python import logging file_handler1 = logging.FileHandler('x2.log', 'a', encoding='utf-8') fmt1 = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s") file_handler1.setFormatter(fmt1) logger = logging.Logger('xxxxxx', level=logging.ERROR) logger.addHandler(file_handler1) logger.error('你好') ``` - 推荐处理日志方式 ```python import logging file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', handlers=[file_handler,], level=logging.ERROR ) logging.error('你好') ``` - 推荐处理日志方式 + 日志分割 (一般按d/h来分割) ```python import time import logging from logging import handlers # file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) file_handler = handlers.TimedRotatingFileHandler(filename='x3.log', when='s', interval=5, encoding='utf-8') logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', handlers=[file_handler,], level=logging.ERROR ) for i in range(1,100000): time.sleep(1) logging.error(str(i)) ``` 注意事项: ```python # 在应用日志时,如果想要保留异常的堆栈信息。 import logging import requests logging.basicConfig( filename='wf.log', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', level=logging.ERROR ) try: requests.get('http://www.xxx.com') except Exception as e: msg = str(e) # 调用e.__str__方法 logging.error(msg,exc_info=True) ``` 应用场景:对于异常处理捕获到的内容,使用日志模块将其保留到日志文件。 ##### 6.1.1.13 collections - 1. OrderedDict 有序字典 ```python from collections import OrderedDict info = OrderedDict() info['k1'] = 123 info['k2'] = 456 print(info.keys()) print(info.values()) print(info.items()) ``` ```python from collections import OrderedDict odic = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) print(odic) for k in odic: print(k,odic[k]) ``` 2. defaultdict 默认字典,可以给字典的value设置一个默认值 3. deque 双端队列 4. namedtuple 可命名元组 创建一个类,这个类没有方法,所有属性的值都不能修改 ```python from collections import namedtuple Course = namedtuple('Course',['name','price','teacher']) python = Course('python',19800,'alex') print(python) print(python.name) print(python.price) ``` ##### 6.1.1.14 copy copy.copy 浅拷贝 copy.deepcopy 深拷贝 #### 6.1.2 第三方模块 先从网上下载,再安装,安装完成后才可以使用。 第三方模块安装的路径:python36\Lib\site-packages 把pip.exe 所在的路径添加到环境变量中。 安装: - pip包管理工具: pip install xlrd - 源码安装: - 下载源码包:压缩文件。 - 解压文件 - 打开cmd窗口,并进入此目录:cd C:\Python36\Lib\site-packages - 执行:python36 setup.py build - 执行:python36 setup.py install pip install 要安装的模块名称 # pip install xlrd (在命令执行窗口去下载安装) - 网慢 ![1555488681105](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555488681105.png) - python36 -m pip install --upgrade pip(pip安装路径问题报错执行前面这句话) ![1555488869351](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555488869351.png) 安装完成后需要更新版本的 ![1555489009540](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1555489009540.png) - 安装完成后,如果导入不成功。 - 重启pycharm。 - 安装错了。 #### 6.1.3 自定义模块 1. 自定义模块安装的路径:当前执行python的路径 - xxxx.py ```python def f1(): print('f1') def f2(): print('f2') ``` - x1.py ```python # 调用自定义模块中的功能 import xxxx xxxx.f1() xxxx.f2() ``` - 运行 ```python python x1.py ``` 2. 定义模块 定义模块时可以把一个py文件或一个文件夹(包)当作一个模块,以方便于以后其他py文件的调用 什么是包? ```python 1.文件夹 存储了多个py文件的文件夹 2.如果导入的是一个包,这个包里的模块默认是不能用的 3.导入一个包相当于执行 __init__.py文件中的内容 ``` 3. 对于包的定义: py2:文件夹中必须有_ _ init _ _.py py3:不需要_ _ init _ _.py 推荐:以后写代码时,都要加上此文件。 ### 6.2模块的调用 导入模块,加载此模块中所有的值到内容。 #### 6.2.1 示例一 ```python # lizhongwei.py #!/usr/bin/env python # -*- coding:utf-8 -*- def show(): print('我司里种种') def func(): pass print(456) ``` ```python # 导入模块,加载此模块中所有的值到内存。 import lizhongwei print(123) # 调用模块中的函数 lizhongwei.func() ``` ```python # 导入模块 # 方法一 from lizhongwei import func,show # 1 该方法有弊端:容易重名 from lizhongwei import func from lizhongwei import show # 2 1和2执行结果一样 # 方法二 from lizhongwei import * # 导入lizhongwei中所有的函数 func() ``` ```python # 导入模块 # 方法三 from lizhongwei import func as f # 给lizhongwei中的func重新命名为f def func(): print(123) f() # 函数中的func与模块中的func重名了,需要给模块中的func重新命名后再执行。 ``` 导入模块: - import 模块 模块.函数() - from 模块 import 函数 函数() 【as起别名 / *】 - from 模块 import 函数 as 别名 别名() #### 6.2.2 示例二 ```python lizohng - jd.py - pdd.py - tb.py 包.py ``` ```python import lizhong.jd lizhong.jd.f1() ``` ```python from lizhong import jd jd.f1() ``` ```python from lizhong.jd import f1 f1() ``` #### 6.2.3 总结(普通导入) - 模块和要执行的py文件在同一目录 且 需要 模块中的很多功能时,推荐用: import 模块 - 其他推荐:from 模块 import 模块 模块.函数() - 其他推荐:from 模块.模块 import 函数 函数() 导入: - 绝对导入: - import 模块 - from 模块.模块 import 模块 - from 模块.模块.模块 import 函数 - 相对导入【不推荐】 ```python from . import xxx from .. import xxx ``` 调用模块内部元素 - 函数() - 模块.函数() #### 6.2.4 多次导入 多次导入不会再重新加载 ```python # jd.py ===> print(123) import jd # 第一次加载:会加载一遍jd中所有的内容。 import jd # 由于已经加载过,就不再重新加载。 print(456) # 123 /n 456 ``` ```python import importlib import jd importlib.reload(jd) # 重新加载一遍jd中所有的内容 print(456) ``` 通过模块导入的特性也可以实现单例模式: ```python # jd.py class Foo(object): pass obj = Foo() ``` ```python # app.py import jd # 加载jd.py,加载最后会实例化一个Foo对象并赋值给obj print(jd.obj) ``` ## 第七章 面向对象 ### 7.1 基础概念 - 1.什么是类? 具有相同方法和属性的一类事物。 - 2.什么是对象、实例 ? 一个拥有具体属性值和动作的具体个体。 - 3.实例化 从一个类 得到一个具体对象的过程。 - 4.组合 一个类的对象作为另一个类对象的实例变量。 ### 7.2 面向对象的基本格式与作用 - 1.类(只要类存在,不需特地去执行)内部代码会自动从上到下依次执行,类变量会直接执行,方法只有被调用时,方法内部的代码才会执行。 - 2.类也可以嵌套到类里面(内部代码执行顺序同上)。 #### 7.2.1 面向对象的基本格式 ```python # ###### 定义类 ###### class 类名: def 方法名(self,name): print(name) return 123 def 方法名(self,name): print(name) return 123 def 方法名(self,name): print(name) return 123 # ###### 调用类中的方法 ###### # 1.创建该类的对象 obj = 类名() # 2.通过对象调用方法 result = obj.方法名('alex') print(result) ``` 应用场景:遇到很多函数,需要给函数进行归类和划分。 【封装】 面向对象中有三个关键词:类 / 对象 / 方法 面试题: - 1. 谈谈你了解的面向对象? 从面向对象的三大特性开始说起…… 2. 类和对象是什么关系? 对象是类的一个实例。 ```python class Foo: def __init__(self,name): self.name = name def run(self): pass obj1 = Foo('ale') obj2 = Foo('eric') ``` 3. self是什么? self就是一个形式参数,对象调用方法时,python内部会将该对象传给这个参数。 ```python class Foo: def run(self,num): pass obj = Foo() obj.run(5) ``` 练习题: ```python class Db: def db_read(self): pass def db_write(self): pass def db_delete(self): pass def db_update(self): pass class File: def file_read(self): pass def file_write(self): pass def file_delete(self): pass def file_update(self): pass class Redis: def redis_read(self): pass def redis_write(self): pass def redis_delete(self): pass def redis_update(self): pass ``` #### 7.2.2.对象的作用 存储一些值,以后方便自己使用。 ```python class File: def read(self): with open(self.xxxxx, mode='r', encoding='utf-8') as f: data = f.read() return data def write(self, content): with open(self.xxxxx, mode='a', encoding='utf-8') as f: f.write(content) # # 实例化了一个File类的对象 obj1 = File() # # 在对象中写了一个xxxxx = 'test.log' obj1.xxxxx = "test.log" # # 通过对象调用类中的read方法,read方法中的self就是obj。 # # obj1.read() obj1.write('alex') # 实例化了一个File类的对象 obj2 = File() # 在对象中写了一个xxxxx = 'test.log' obj2.xxxxx = "info.txt" # 通过对象调用类中的read方法,read方法中的self就是obj。 # obj2.read() obj2.write('alex') ``` ```python class Person: def show(self): temp = "我是%s,年龄:%s,性别:%s " %(self.name,self.age,self.gender,) print(temp) p1 = Person() p1.name = '李邵奇' p1.age = 19 p1.gender = '男' p1.show() p2 = Person() p2.name = '利奇航' p2.age = 19 p2.gender = '男' p2.show() ``` ```python class Person: def __init__(self,n,a,g): # 初始化方法,给对象的内部做初始化。 self.name = n self.age = a self.gender = g def show(self): temp = "我是%s,年龄:%s,性别:%s " % (self.name, self.age, self.gender,) print(temp) # 类() 实例化对象,自动执行此类中的 __init__方法。 p1 = Person('李兆琪',19,'男') p1.show() p2 = Person('利奇航',19,'男') p2.show() ``` 总结:将数据封装到对象,方便使用。 什么时候用面向对象? - 1. 函数(业务功能)比较多,可以使用面向对象来进行归类。 - 2. 想要做数据封装(创建字典存储数据时,可以使用面向对象)。 - 3. 游戏示例:创建一些角色并且根据角色需要再创建人物。 #### 7.2.3 总结 如果写代码时,函数比较多比较乱。 - 1. 可以将函数归类并放到同一个类中。 2. 函数如果有一个反复使用的公共值,则可以放到对象中。 ```python class File: def __init__(self,path): self.file_path = path def read(self): print(self.file_path) def write(self,content): print(self.file_path) def delete(self): print(self.file_path) def update(self): print(self.file_path) p1 = File('log.txt') p1.read() p2 = File('xxxxxx.txt') p2.read() ``` ```python # 1. 循环让用户输入:用户名/密码/邮箱。 输入完成后再进行数据打印。 # ########## 以前的写法 USER_LIST = [] while True: user = input('请输入用户名:') pwd = input('请输入密码:') email = input('请输入邮箱:') temp = {'username':user,'password':pwd,'email':email} USER_LIST.append(temp) for item in USER_LIST: temp = "我的名字:%s,密码:%s,邮箱%s" %(item['username'],item['password'],item['email'],) print(temp) # ########## 面向对象写法 class Person: def __init__(self,user,pwd,email): self.username = user self.password = pwd self.email = email USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)] while True: user = input('请输入用户名:') pwd = input('请输入密码:') email = input('请输入邮箱:') p = Person(user,pwd,email) USER_LIST.append(p) for item in USER_LIST: temp = "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,) print(temp) # ########## 面向对象写法 class Person: def __init__(self,user,pwd,email): self.username = user self.password = pwd self.email = email def info(self): return "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,) USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)] while True: user = input('请输入用户名:') pwd = input('请输入密码:') email = input('请输入邮箱:') p = Person(user,pwd,email) USER_LIST.append(p) for item in USER_LIST: msg = item.info() print(msg) ``` #### 7.2.4 练习:游戏开发 ```python class Police: def __init__(self,name) self.name = name self.hp = 10000 def tax(self): msg = "%s收了个税。" %(self.name,) print(msg) def fight(self): msg = "%s去战了个斗。" %(self.name,) lsq = Police('李邵奇') zzh = Police('渣渣会') tyg = Police('堂有光') class Bandit: def __init__(self,nickname) self.nickname = nickname self.hp = 1000 def murder(self,name): msg = "%s去谋杀了%s" %(self.nickname, name,) lcj = Bandit('二蛋') lp = Bandit('二狗') zsd = Bandit('狗蛋') # 1. 二狗去谋杀渣渣会,二狗生命值-100; 渣渣会生命值减5000 lp.murder(zzh.name) lp.hp = lp.hp - 100 zzh.hp = zzh.hp - 5000 # ... ``` ```python class Police: def __init__(self,name) self.name = name self.hp = 10000 def dao(self,other): msg = "%s个了%s一刀。" %(self.name,other.nickname) self.hp = self.hp - 10 other.hp = other.hp - 50 print(msg) def qiang(self): msg = "%s去战了个斗。" %(self.name,) def quan(self,other): msg = "%s个了%s一全。" %(self.name,other.nickname) self.hp = self.hp - 2 other.hp = other.hp - 10 print(msg) class Bandit: def __init__(self,nickname) self.nickname = nickname self.hp = 1000 def qiang(self,other): msg = "%s个了%s一全。" %(self.nickname,other.name) self.hp -= 20 other.hp -= 500 lcj = Bandit('二蛋') lsq = Police('李邵奇') lsq.dao(lcj) lsq.quan(lcj) lcj.qiang(lsq) ``` ### 7.3 面向对象的三大特性 #### 7.3.1 封装 封装思想:将同一类的函数封装到了同一个py文件中,以后方便使用。 面向对象也有封装的作用:将同一类的函数封装到一个类中。(广义) 广义的封装 :类中的成员 狭义的封装 :私有成员 ​ 只能在类的内部使用,既不能在类的外部调用,也不能在子类中使用 如果写代码时,函数比较多比较乱。 - 1. 可以将函数归类并放到同一个类中。 2. 函数如果有一个反复使用的公共值,则可以放到对象中。 ```python class File: def read(self): pass def write(self): pass ``` ```python class Person: def __init__(sef,name,age): self.name = name self.age = age p = Person('alex',19) ``` #### 7.3.2 继承 ```python # 父类(基类/超类) class Base: def f1(self): pass # 子类(派生类) class Foo(Base): def f2(self): pass # 创建了一个子类的对象 obj = Foo() # 执行对象.方法时,优先在自己的类中找,如果没有就是父类中找。 obj.f2() obj.f1() # 创建了一个父类的对象 obj = Base() obj.f1() ``` 问题:什么时候才能用到继承? - 多个类中如果有公共的方法,可以放到基类中避免重复编写。 ```python class Base: def f1(self): pass class Foo(Base): def f2(self): pass class Bar(Base): def f3(self): pass obj1 = Foo() obj2 = Bar() ``` 继承关系中的查找方法的顺序: ```python # 示例一 class Base: def f1(self): print('base.f1') class Foo(Base): def f2(self): print('foo.f2') obj = Foo() obj.f1() obj.f2() # 示例二 class Base: def f1(self): print('base.f1') class Foo(Base): def f2(self): self.f1() print('foo.f2') obj = Foo() obj.f2() # 示例三 class Base: def f1(self): print('base.f1') class Foo(Base): def f2(self): self.f1() print('foo.f2') def f1(self): print('foo.f1') obj = Foo() obj.f2() # 示例四 class Base: def f1(self): self.f2() print('base.f1') def f2(self): print('base.f2') class Foo(Base): def f2(self): print('foo.f2') obj = Foo() obj.f1() # 示例五 class TCPServer: pass class ThreadingMixIn: pass class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass # 示例六 class BaseServer: def serve_forever(self, poll_interval=0.5): self._handle_request_noblock() def _handle_request_noblock(self): self.process_request(request, client_address) def process_request(self, request, client_address): pass class TCPServer(BaseServer): pass class ThreadingMixIn: def process_request(self, request, client_address): pass class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass obj = ThreadingTCPServer() obj.serve_forever() ``` 注意事项: - self 到底是谁? - self 是哪个类创建的,就从此类开始找,自己没有就找父类。 - 如果自己和父类都有,希望自己和父类都调用,super()/指定类名直接调 多继承: 子类可以继承多个基类,自己没有时,先从基类中按从左到右的顺序,从左边第一个开始进行查找,查到根部都没有,再向右开始查找第二个基类,以此类推继续查找。如果所有基类都没有,代码会报错。 查找顺序: - 深度优先 - 广度优先 #### 7.3.3 多态 多态:多种形态/多种类型,也叫鸭子模型 一个类表现出来的多种状态 ===> 多个类表现出相似的状态 ```python # Python def func(arg): v = arg[-1] # arg.append(9) print(v) # java def func(str arg): v = arg[-1] print(v) ``` ```python def func(arg): # 多种类型,很多事物 arg.send() # 必须具有send方法,嘎嘎叫 ``` 面试题:什么是鸭子模型。 ```python 对于一个函数而言,Python对于参数的类型不会限制,那么传入参数时就可以是各种类型,在函数中如果有例如:arg.send方法,那么就是对于传入类型的一个限制(类型必须有send方法)。 这就是鸭子模型,类似于上述的函数我们认为只要能嘎嘎叫的就是鸭子(只有有send方法,就是我们要想的类型) ``` ### 7.4 成员 类成员: - 类变量 - 绑定方法 - 静态方法 - 类方法 - 属性 实例(对象)成员: 实例变量 #### 7.4.1 实例变量 实例变量(又叫做:字段/属性) ![1556087637267](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1556087637267.png) #### 7.4.2 类变量 类变量(又叫做:静态字段/属性) ![1556087567202](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1556087567202.png) 定义:写在类的下一级和方法同一级。 访问: - 1. 类.类变量名称 2. 对象.类变量名称 面试题: ```python class Base: x = 1 obj = Base() print(obj.x) # 先去对象中找,没有再去类中找。 obj.y = 123 # 在对象中添加了一个y=123的变量。 print(obj.y) obj.x = 123 # 在对象中添加了一个x=123的变量。(不可以修改类中的变量) print(obj.x) print(Base.x) Base.x = 666 # 类可以修改类中的变量 x = 666 ``` ```python class Parent: x = 1 class Child1(Parent): pass class Child2(Parent): pass print(Parent.x,Child1.x,Child2.x) # 1 1 1 Child1.x = 2 print(Parent.x,Child1.x,Child2.x) # 1 2 1 Child2.x = 3 print(Parent.x,Child1.x,Child2.x) # 1 2 3 ``` 总结: 找变量优先找自己,自己没有找类或基类;修改或赋值只能在自己的内部设置。 ![1556088462058](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1556088462058.png) #### 7.4.3 方法(绑定方法/普通方法) 定义:至少有一个self参数 执行:先创建对象,由对象.方法() ```python class Foo: def func(self,a,b): print(a,b) obj = Foo() obj.func(1,2) # ########################### class Foo: def __init__(self): self.name = 123 def func(self, a, b): print(self.name, a, b) obj = Foo() obj.func(1, 2) ``` 用到对象中封装值时,一般使用绑定方法。 #### 7.4.4 静态方法 定义: - @staticmethod装饰器 - 参数无限制 执行: - 类.静态方法名 () - 对象.静态方法名 ()(不推荐使用:因为没有意义) ```python class Foo: def __init__(self): self.name = 123 def func(self, a, b): print(self.name, a, b) @staticmethod # python中内置的,只需调用就可以用 def f1(): print(123) obj = Foo() obj.func(1, 2) Foo.f1() # 可以不用传参数,只需调用 obj.f1() # 不推荐 ``` #### 7.4.5 类方法 定义: - @classmethod装饰器 - 至少有cls参数,当前类。 执行: - 类.类方法() - 对象.类方法() (不推荐) ```python class Foo: def __init__(self): self.name = 123 def func(self, a, b): print(self.name, a, b) @staticmethod def f1(): print(123) @classmethod def f2(cls,a,b): print('cls是当前类',cls) print(a,b) obj = Foo() obj.func(1, 2) Foo.f1() Foo.f2(1,2) ``` 面试题: 问题: @classmethod和@staticmethod的区别? - 一个是类方法一个静态方法。 - 定义: 类方法:用@classmethod做装饰器且至少有一个cls参数。 静态方法:用staticmethod做装饰器且参数无限制。 - 调用: 类.方法直接调用。 对象.方法也可以调用。 #### 7.4.6 属性 在一个方法上加@property,方法就变成了属性,调用时不用加()。 定义: - @property装饰器 - 只有一个self参数 执行:对象.方法 不用加括号。 ```python class Foo: @property def func(self): print(123) return 666 obj = Foo() result = obj.func print(result) ``` ```python # 属性的应用 class Page: def __init__(self, total_count, current_page, per_page_count=10): self.total_count = total_count self.per_page_count = per_page_count self.current_page = current_page @property def start_index(self): return (self.current_page - 1) * self.per_page_count @property def end_index(self): return self.current_page * self.per_page_count USER_LIST = [] for i in range(321): USER_LIST.append('alex-%s' % (i,)) # 请实现分页展示: current_page = int(input('请输入要查看的页码:')) p = Page(321, current_page) data_list = USER_LIST[p.start_index:p.end_index] for item in data_list: print(item) ``` #### 7.4.7 特殊成员 ##### 7.4.7.1 `__init__` 初始化方法,用于给对象中赋值。 ```python class Foo: """ 类是干啥的。。。。 # 注释类 """ def __init__(self,a1): """ 初始化方法 :param a1: """ self.a1 = a1 obj = Foo('alex') ``` ##### 7.4.7.2 `__new__` 用于创建空对象,又叫构造方法 ```python class Foo(object): def __init__(self): """ 用于给对象中赋值,初始化方法 """ self.x = 123 def __new__(cls, *args, **kwargs): """ 用于创建空对象,构造方法 :param args: :param kwargs: :return: """ return object.__new__(cls) obj = Foo() ``` 类实例化一个对象:先执行`__new__`创建一个空对象,再执行`__init__`初始化对象 ##### 7.4.7.3 `__call__` 对象后面加(),就可以执行python的一个方法:`__call__`方法 ```python class Foo(object): def __call__(self, *args, **kwargs): print('执行call方法') obj = Foo() obj() =====> Foo()() ``` ```python #!/usr/bin/env python # -*- coding:utf-8 -*- from wsgiref.simple_server import make_server def func(environ,start_response): start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')]) return ['你好'.encode("utf-8") ] class Foo(object): def __call__(self, environ,start_response): start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')]) return ['你

不好

'.encode("utf-8")] # 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。 server = make_server('127.0.0.1', 8000, Foo()) server.serve_forever() ``` ##### 7.4.7.4`__getitem__ __setitem__ __delitem__` ```python class Foo(object): def __setitem__(self, key, value): pass def __getitem__(self, item): return item + 'uuu' def __delitem__(self, key): pass obj1 = Foo() obj1['k1'] = 123 # 内部会自动调用 __setitem__方法 val = obj1['xxx'] # 内部会自动调用 __getitem__方法 print(val) del obj1['ttt'] # 内部会自动调用 __delitem__ 方法 ``` ##### 7.4.7.5 ` __str__ ` ```python class Foo(object): def __str__(self): """ 只有在打印对象时,会自动化调用此方法,并将其返回值在页面显示出来 :return: """ return 'asdfasudfasdfsad' obj = Foo() print(obj) ``` ```python class User(object): def __init__(self,name,email): self.name = name self.email = email def __str__(self): return "%s %s" %(self.name,self.email,) user_list = [User('二狗','2g@qq.com'),User('二蛋','2d@qq.com'),User('狗蛋','xx@qq.com')] for item in user_list: print(item) ``` 注意:不要相信print打印出来的(显示出来的不一定是字符串,也可能是类实例化的对象) ##### 7.4.7.6 `__dict__` ```python class Foo(object): def __init__(self,name,age,email): self.name = name self.age = age self.email = email obj = Foo('alex',19,'xxxx@qq.com') print(obj) print(obj.name) print(obj.age) print(obj.email) val = obj.__dict__ # 去对象中找到所有变量并将其转换为字典 print(val) ``` ##### 7.4.7.7 上下文管理【面试题】 ```python class Foo(object): def __enter__(self): self.x = open('a.txt',mode='a',encoding='utf-8') return self.x def __exit__(self, exc_type, exc_val, exc_tb): self.x.close() with Foo() as ff: ff.write('alex') ff.write('alex') ff.write('alex') ff.write('alex') ``` ```python # 面试题 # 方法1 class Context: def __enter__(self): print('进入') return self def __exit__(self, exc_type, exc_val, exc_tb): print('推出') def do_something(self): print('内部执行') with Context() as ctx: print('内部执行') ctx.do_something() # 方法二 class Foo(object): def do_something(self): print('内部执行') class Context: def __enter__(self): print('进入') return Foo() def __exit__(self, exc_type, exc_val, exc_tb): print('推出') with Context() as ctx: print('内部执行') ctx.do_something() ``` ##### 7.4.7.8 两个对象相加 `__add__` ```python val = 5 + 8 print(val) val = "alex" + "sb" print(val) class Foo(object): def __add__(self, other): return 123 # __add__是由obj1触发的,self是obj1,other是obj2,返回的值给val. obj1 = Foo() obj2 = Foo() val = obj1 + obj2 print(val) ``` 特殊成员:就是为了能够快速实现执行某些方法而生。 ##### 7.4.7.9 可迭代对象 `__iter__` 表象:可以被for循环的对象就可以称之为是可迭代对象,如:'ax'、[1,2,3]、[] 如何让一个对象变成可迭代对象? 在类中实现`__iter__`方法且返回一个迭代器(或生成器)。 ```python class Foo: def __iter__(self): return iter([1,2,3,4]) obj = Foo() class Foo: def __iter__(self): yield 1 yield 2 yield 3 obj = Foo() ``` 记住:只要能被for循环就是去看它内部的iter方法。 ### 7.5 成员修饰符 成员分为公有和私有。 - 公有:所有地方都能访问到。 - 私有:只有自己可以访问到。 (子类都无法继承父类私有的) ​ 私有修饰符:_ _ 变量/方法 ```python class Foo: def __init__(self, name): self.__name = name def func(self): print(self.__name) obj = Foo('alex') # print(obj.__name) # 报错 obj.func() ``` ```python class Foo: __x = 1 # 私有的类变量 @staticmethod def func(): print(Foo.__x) # print(Foo.__x) # 报错 Foo.func() ``` ```python class Foo: def __fun(self): # 私有方法 print('msg') def show(self): self.__fun() obj = Foo() # obj.__fun() # 报错 obj.show() ``` 强制访问私有成员: ```python # 强制访问私有成员 class Foo: def __init__(self,name): self.__x = name obj = Foo('alex') print(obj._Foo__x) # 强制访问私有实例变量 ``` ### 7.6 嵌套 类/方法/对象 都可以当作变量或嵌套到其他类型中。 - 函数:参数可以是任意类型。 - 字典:对象和类都可以做字典的key和value - 继承的查找关系 1.对象可以嵌套到列表/字典……中 ```python class Foo: def __init__(self,num): self.num = num cls_list = [] for i in range(10): cls_list.append(Foo) for i in range(len(cls_list)): obj = cls_list[i](i) print(obj.num) ``` ```python class Foo: def __init__(self,num): self.num = num B = Foo obj = B('alex') ``` ```python class Foo: def f1(self): print('f1') def f2(self): print('f2') obj = Foo() v = [ obj.f1,obj.f2 ] for item in v: item() ``` ```python class Foo: def f1(self): print('f1') def f2(self): print('f2') def f3(self): v = [self.f1 , self.f2 ] for item in v: item() obj = Foo() obj.f3() ``` ```python class Account: def login(self): pass def register(self): pass def run(self): info = {'1':self.register, '2':self.login } choice = input('请选择:') method = info.get(choice) method() ``` 2.对象之间的嵌套 ```python class School(object): def __init__(self,title,addr): self.title = title self.address = addr class ClassRoom(object): def __init__(self,name,school_object): self.name = name self.school = school_object s1 = School('北京','沙河') s2 = School('上海','浦东') s3 = School('深圳','南山') c1 = ClassRoom('全栈21期',s1) c1.name c1.school.title c1.school.address # ############################################ v = [11,22,33,{'name':'山海','addr':'浦东'}] v[0] v[3]['name'] ``` 3.练习题 ```python class StarkConfig(object): pass class AdminSite(object): def __init__(self): self.data_list = [] def register(self,arg): self.data_list.append(arg) site = AdminSite() obj = StarkConfig() site.register(obj) ``` ```python class StarkConfig(object): def __init__(self,name,age): self.name = name self.age = age class AdminSite(object): def __init__(self): self.data_list = [] self.sk = None def set_sk(self,arg): self.sk = arg site = AdminSite() # data_list = [] sk = StarkConfig site.set_sk(StarkConfig) site.sk('alex',19) ``` ```python class StackConfig(object): pass class Foo(object): pass class Base(object): pass class AdminSite(object): def __init__(self): self._register = {} def registry(self,key,arg): self._register[key] = arg site = AdminSite() site.registry(1,StackConfig) site.registry(2,StackConfig) site.registry(3,StackConfig) site.registry(4,Foo) site.registry(5,Base) for k,v in site._register.items(): print(k,v() ) ``` ``` class StackConfig(object): list_display = '李邵奇' class UserConfig(StackConfig): list_display = '利奇航' class AdminSite(object): def __init__(self): self._register = {} def registry(self,key,arg=StackConfig): self._register[key] = arg def run(self): for key,value in self._register.items(): obj = value() print(key,obj.list_display) site = AdminSite() site.registry(1) site.registry(2,StackConfig) site.registry(3,UserConfig) site.run() ``` ```python class StackConfig(object): list_display = '李邵奇' def changelist_view(self): print(self.list_display) class UserConfig(StackConfig): list_display = '利奇航' class AdminSite(object): def __init__(self): self._register = {} def registry(self,key,arg=StackConfig): self._register[key] = arg def run(self): for key,value in self._register.items(): obj = value() obj.changelist_view() site = AdminSite() site.registry(1) site.registry(2,StackConfig) site.registry(3,UserConfig) site.run() ``` ### 7.7 经典类与新式类 ```python class Foo: pass class Foo(object): pass # 在python3中这两个类的写法是一样,因为所有的类默认都会继承object类,全部都是新式类。 # 如果在python2中这样定义,则称其为:经典类 class Foo: pass # 如果在python2中这样定义,则称其为:新式类 class Foo(object): pass class Base(object): pass class Bar(Base): pass Bar是新式类 # 不论是自己继承还是基类继承了object类,都是新式类 ``` py2与py3的区别: - py2 分为经典类、新式类 - py3 只有新式类 新式类与经典类的区别: 新式类: - 继承object - 支持super - 多继承 广度优先C3算法 - mro方法 经典类: - py2中不继承object - 没有super语法 - 多继承 深度优先 - 没有mro方法 ### 7.8 异常处理 #### 7.8.1 基本格式 ```python try: pass except Exception as e: pass ``` ```python try: val = input('请输入数字:') num = int(val) except Exception as e: print('操作异常') ``` ```python import requests try: ret = requests.get('http://www.google.com') print(ret.text) except Exception as e: print('请求异常') ``` ```python def func(a): try: return a.strip() except Exception as e: pass return False v = func('alex') if not v: print('函数执行失败') else: print('结果是',v) ``` ```python try: v = [] v[11111] # IndexError except ValueError as e: # ValueError pass except IndexError as e: # IndexError索引错误,超出索引范围 pass except Exception as e: print(e) # e是Exception类的对象,e中有一个错误信息。 ``` 特殊:finally ```python try: int('asdf') except Exception as e: print(e) # e是Exception类的对象,中有一个错误信息。 finally: print('最后无论对错都会执行') # #################### 特殊情况 ######################### def func(): try: # v = 1 # return 123 int('asdf') except Exception as e: print(e) # e是Exception类的对象,中有一个错误信息。 return 123 finally: print('最后') func() ``` 注意:在遇到return时,也会先执行完finally再去return。 练习题 ```python # 1. 写函数,函数接受一个列表,请将列表中的元素每个都 +100 def func(arg): result = [] for item in arg: if item.isdecimal(): result.append(int(item) + 100) return result # 2. 写函数去,接受一个列表。列表中都是url,请访问每个地址并获取结果。 import requests def func(url_list): result = [] try: for url in url_list: response = requests.get(url) result.append(response.text) except Exception as e: pass return result def func2(url_list): result = [] for url in url_list: try: response = requests.get(url) result.append(response.text) except Exception as e: pass return result func(['http://www.baidu.com','http://www.google.com','http://www.bing.com']) ``` #### 7.8.2 主动触发异常 ```python try: int('123') raise Exception('阿萨大大是阿斯蒂') # 代码中主动抛出异常 except Exception as e: print(e) ``` ```python def func(): result = True try: with open('x.log',mode='r',encoding='utf-8') as f: data = f.read() if 'alex' not in data: raise Exception() except Exception as e: result = False return result ``` #### 7.8.3 自定义异常 ```python class MyException(Exception): # 自定义异常,继承Exception pass try: raise MyException('asdf') except MyException as e: print(e) # asdf ``` ```python class MyException(Exception): def __init__(self,message): super().__init__() self.message = message try: raise MyException('asdf') except MyException as e: print(e.message) ``` ### 7.9 数据结构 #### 7.9.1 栈 Stack 后进先出 lifo 面试题: ```python class Stack(object): """ 后进先出 """ def __init__(self): self.data_list = [] def push(self, val): """ 向栈中压入一个数据(入栈) :param val: :return: """ self.data_list.append(val) # 从左向右压入 # (or) self.data_list.insert(0,val) # 从右向左压入 def pop(self): """ 从栈中拿走一个数据(出栈) :return: """ return self.data_list.pop() # 从右面开始拿走 # (or) return self.data_list.pop(0) # 从左面开始拿走 ``` #### 7.9.2 队列 Queue 先进先出 fifo ```python class Stack(object): """ 先进先出 """ def __init__(self): self.data_list = [] def push(self, val): """ 向栈中压入一个数据(入栈) :param val: :return: """ self.data_list.append(val) # 从左向右压入 def pop(self): """ 从栈中拿走一个数据(出栈) :return: """ return self.data_list.pop(0) # 从左开始拿走 ``` ### 7.10 约束(抽象类/接口类) 约束子类中必须写某个方法,如果不写,则调用时候就会抛出 某个异常。 (or)抽象类就是给子类定一个规范,让子类必须按照抽象类的规范来实现方法 ```python # 约束字类中必须写send方法,如果不写,则调用时候就报抛出 NotImplementedError class Interface(object): def send(self): raise NotImplementedError() class Message(Interface): def send(self): print('发送短信')z class Email(Interface): def send(self): print('发送邮件') ``` ```python # 不用约束也能执行,但是不够简洁、严谨 class Message(object): def msg(self): print('发短信') def email(self): print('邮件') def wechat(self): print('微信') obj = Message() obj.msg() obj.email() obj.wechat() ``` ```python class BaseMessage(object): def send(self,a1): raise NotImplementedError('字类中必须有send方法') class Msg(BaseMessage): def send(self): pass class Email(BaseMessage): def send(self): pass class Wechat(BaseMessage): def send(self): pass class DingDing(BaseMessage): def send(self): print('钉钉') obj = Email() obj.send() ``` ### 7.11 反射 根据字符串的形式去某个对象中操作他的成员。 - 1.getattr(对象,'字符串') 根据字符串的形式去某个对象中获取对象的成员。 ```python class Foo(object): def __init__(self,name): self.name = name obj = Foo('alex') # 获取变量 v1 = getattr(obj,'name') # 获取方法 method_name = getattr(obj,'login') method_name() ``` 总结: - 通过 对象 来获取 实例变量、绑定方法 - 通过 类 来获取 类变量、类方法、静态方法 - 通过 模块名 来获取 模块中的任意变量(普通变量 函数 类) - 通过 本文件 来获取 本文件中的任意变量 getattr(sys.modules[__name__],'变量名') # 反射当前文件的变量中的内容 - 2.hasattr(对象,'字符串') 根据字符串的形式去某个对象中判断是否有该成员。 ```python from wsgiref.simple_server import make_server class View(object): def login(self): return '登陆' def logout(self): return '等处' def index(self): return '首页' def func(environ,start_response): start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')]) # obj = View() # 获取用户输入的URL method_name = environ.get('PATH_INFO').strip('/') if not hasattr(obj,method_name): return ["sdf".encode("utf-8"),] response = getattr(obj,method_name)() return [response.encode("utf-8") ] # 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。 server = make_server('192.168.12.87', 8000, func) server.serve_forever() ``` - 3.setattr(对象,'变量','值') 根据字符串的形式去某个对象中设置成员。 ```python class Foo: pass obj = Foo() obj.k1 = 999 setattr(obj,'k1',123) # obj.k1 = 123 print(obj.k1) ``` - 4.delattr(对象,'变量') 根据字符串的形式去某个对象中删除成员。 ```python class Foo: pass obj = Foo() obj.k1 = 999 delattr(obj,'k1') print(obj.k1) ``` python中一切皆对象 - py文件(类/全局/函数) - 包/文件夹(文件……) - 类(类变量/方法……) - 对象(狭义的对象:实例变量/对象调用的方法……) python中一切皆对象,所以以后想要通过字符串的形式操作其内部成员都可以通过反射的机制实现。 反射(性能补充) ```python class Foo(object): def get(self): pass obj = Foo() # if hasattr(obj,'post'): # 不推荐使用 # getattr(obj,'post') v1 = getattr(obj,'get',None) # 推荐 (get方法存在,就执行;不存在,则返回None(可以写任意内容)) print(v1) ``` ### 7.12 单例模式(设计模式) 无论实例化多少次,永远用的都是第一次实例化出的对象。 ```python class Foo: pass # 多例,每实例化一次就创建一个新的对象。 obj1 = Foo() # 实例,对象 obj2 = Foo() # 实例,对象 # 单例,无论实例化多少次,都用第一次创建的那个对象。 obj1 = Foo() obj2 = Foo() ``` 单例模式标准 ```python class Singleton(object): instance = None def __new__(cls, *args, **kwargs): if not cls.instance: # cls = Singleton cls.instance = object.__new__(cls) return cls.instance obj1 = Singleton() obj2 = Singleton() # 不是最终,以后还需要加锁。 ``` 数据库连接 / 数据库连接池 会用到单例模式 文件的连接池 ```python class FileHelper(object): instance = None def __init__(self, path): self.file_object = open(path,mode='r',encoding='utf-8') def __new__(cls, *args, **kwargs): if not cls.instance: cls.instance = object.__new__(cls) return cls.instance obj1 = FileHelper('x') obj2 = FileHelper('x') ``` ### 7.13 项目结构目录 - 1.脚本 所有的类、函数等都写在一个py文件中 ![1556449347984](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1556449347984.png) - 2.单可执行文件 只从app.py文件运行程序 由文件夹:src(业务相关)、lib(公共类库/代码)、db(数据)、config(配置相关) 和 app.py等文件目录组成![1556449525128](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1556449525128.png) - 3.多可执行文件 有多个类似app.py文件放到一个文件夹bin中,可以分别从每个文件去运行程序。其他与单可执行文件相同。 ![1556450446410](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1556450446410.png) ```python # 添加根目录 base_path = os.path.dirname(os.path.dirname(__file__)) # (__file__) 绝对路径 sys.path.append(base_path) ``` ### 7.14 正则表达式 #### 7.14.1. 正则表达式 re模块:re模块本身只是用来操作正则表达式的,和正则本身没关系。 正则表达式:是一种规则 匹配字符串的规则。 为什么要有正则表达式? - 1.匹配字符串 ```python - 一个人的电话号码 - 一个人的身份证号 - 一台机器的ip地址 ``` - 2.表单验证 ```python - 验证用户输入的信息是否准确 11位 全数字 1开头 第二个数3-9之内的数 - 银行卡号 ``` - 3.爬虫 从网页源码中获取一些链接、重要数据 正则规则(元字符,量词): 第一条规则 : 本身是哪一个字符,就匹配字符串中的哪一个字符。 第二条规则 : 字符组[字符1字符2],一个字符组就代表匹配一个字符,只要这个字符出现在字符组里,那么就说明这个字 ​ 符能匹配上 - 字符组中还可以使用范围 所有的范围都必须遵循ascii码从下到大来指定。如:[0-9] [a-z] [A-Z] #### 7.14.2. 元字符 - 1. \d(digit) \w(word) \s(space) \t(table) \n(next) [0-9] \d 表示所有的数字 - d --> d - \d --> \是转义符,转义符转义了d,让d能够匹配所有0-9之间的数 - [\d] [0-9] \d 没有区别 都是要匹配一位数字 \w 表示 大小写字母、数字、下划线 \s 表示空白、空格、换行符、制表符 \t 匹配制表符 \n 匹配换行符 2. \D \W \S \D 表示所有的非数字 \W 表示除数字、字母、下划线之外的所有字符 \S 表示非空白 [\d\D] [\W\w] [\S\s] 匹配所有一切字符 3. . 表示除了换行符之外的任意内容 \ . 在.前加一个 转义符。表示取消.的意义。 4. [] [^] [] 字符组 :只要在中括号内的所有字符都是符合规则的字符 [^ ]非字符组 :只要在中括号内的所有字符都是不符合规则的字符 5. ^ $ ^ 表示一个字符的开始 ```python ^a abc abc abc # 表示要匹配开始的a ``` $ 表示一个字符的结束 ```python c$ abc abc abc # 表示要匹配结束的c ``` ^ $ 两个同时存在时,他俩之间的正则规定长度必须和要匹配的内容长度一致。 6. | () | 表示或,注意:如果两个规则有重叠部分,总是长的在前面,短的在后面 () 表示分组,给一部分正则规定为一组,| 这个符号的作用域就可以缩小了 #### 7.14.3. 量词 {n} 表示只能出现n次 {n,m}表示至少出现n次,至多出现m次 ? 表示匹配0次或1次 表示可有可无 但是有只能有一个 比如小数点 `+`表示匹配1次或多次 `*`表示匹配0次或多次 表示可有可无 但是有可以有多个 比如小数点后n位 什么时候会用到匹配0次? ```python 1.匹配任意的2位整数 \d{2} 2.匹配任意的保留两位小数的数字 \d\.\d{2} 3.匹配一个整数或者小数 \d+\.\d+|\d+ \d+\.?\d* \d+(\.\d+)? ``` #### 7.14.4. 贪婪匹配 正则表达式默认贪婪匹配,总是会在符合量词条件的范围内尽量多匹配。 正则表达式遵循了回溯算法,回溯算法导致了贪婪匹配。 \d{7,12} adljdkjsljdlj <.+> 非贪婪匹配 (惰性匹配):总是匹配符合条件范围内尽量小的字符串。 元字符 量词 ,在量词后面加一个?,表示去最少的匹配 元字符 量词 ? x :表示按照元字符规则在量词范围内匹配,一旦遇到x就停止 .*?x 匹配任意的内容任意多次遇到x就立即停止 (\d+?x .*?x )非贪婪匹配在爬虫中会常用 ```python # 身份证号 # 15位 全数字 首位不为0 # 18位 前17位全数字 首位不为0 最后一位可能是x和数字 [1-9](\d{16}(\d|x)|\d{14}) [1-9](\d{16}[\dx]|\d{14}) [1-9]\d{14}(\d{2}[\dx])? ``` ## 第八章 网络编程 ## 第九章 并发编程 ## 第十章 数据库 ## 第十一章 前端开发 ## 第十二章 Django框架 ## 1.录 常见错误和单词 ### 单词 | int | | 整型 | | -------------------- | ----------------------------------- | ---------------- | | bool | | 布尔类型 | | False | 假 | 布尔类型 | | True | 真 | 布尔类型 | | upper | 大写 | 字符串 | | lower | 小写 | 字符串 | | isdecimal | 判断是否能转换成数字 | 字符串 | | strip/rstrip/lstrip | 去除空白、、n/右边的空白/左边的空白 | 字符串 | | replace | 替换 | 字符串 | | split/rsplit | 切割/从右边开始切割n个 | 字符串 | | startswith | 以“ ”开头 | 字符串 | | endswith | 以“ ”结尾 | 字符串 | | format | 字符串的格式化 | 字符串 | | encode | 转换编码 | 字符串 | | join | 用什么符号连接 | 字符串 | | list | | 列表 | | append | 追加 | 列表 | | insert | 插入 | 列表 | | remove | 删除 | 列表 | | pop | 删除 | 列表/字典 | | clear | 清楚 | 列表 | | extend | 循环添加 | 列表 | | del | 删除 | 列表 | | tuple | | 元组 | | dict | | 字典 | | keys | 获取所有键 | 字典 | | values | 获取所有值 | 字典 | | items | 获取所有键值对 | 字典 | | update | 添加/批量添加 | 字典/集合 | | get | 判断索引是否存在 | 字典 | | set | | 集合 | | add | 添加 | 集合 | | discard | 删除 | 集合 | | intersection | 交集 | 集合 | | union | 并集 | 集合 | | difference | 差集 | 集合 | | symmetric_difference | 对称差集 | 集合 | | content | 容量 | | | assert | 生效 | py关键字 | | message | 信息 | | | gender | 性别 | | | unicode | 统一码(万国码) | | | template | 模板 | | | continue | | while循环 | | break | 终止当前循环 | while循环 | | value | 价值 | | | seek | 调节光标位置 | 文件操作 | | tell | 获取光标当前所在的字节位置 | 文件操作 | | flush | 强制将内存中的数据写入到硬盘 | | | deepcopy | 深拷贝 | | | iterable | 迭代、循环 | 出现在报错问题框 | | required | 缺少 | 出现在报错问题框 | | positional | 位置 | 出现在报错问题框 | | arguments | 参数 | 出现在报错问题框 | | keyword | 关键字 | 出现在报错问题框 | | multiple | 多个 | 出现在报错问题框 | | module | 找到 | 出现在报错问题框 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ### 快捷键 | ctrl+? | 快速多行注释与取消 | ctrl+d | 快速复制一行 | | --------- | ------------------ | ------ | ------------ | | shift+tab | 向左缩进 | tab | 向右缩进 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ### 转义符 | \n | 换行 | \t | 制表符 | | ---- | ------ | ---- | -------------------- | | != | 不等于 | \r | 回到当前行的起始位置 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ### 错误记录 #### 1. 缩进错误 ![1554698249295](C:\Users\oldboy-python\AppData\Roaming\Typora\typora-user-images\1554698249295.png) 2. #### 键错误 ![1554698317790](C:\Users\oldboy-python\AppData\Roaming\Typora\typora-user-images\1554698317790.png) 3. 读取文件时,已经遇到了文件结尾而无法读取 ![1554787849049](C:\Users\yj\AppData\Roaming\Typora\typora-user-images\1554787849049.png) 注:此题是day09课上练习出现的,真正错误原因是:将函数的参数认为成了函数内容里最后生成的变量名 4. 拒绝