第一章:python基础
1.单例模式
精髓:让__new__
只实例化一次
# 1.使用new方法
class Func(object):
"""new单例"""
__instance = None # 类属性 标记创建好的购物车实例对象
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance # 一定要返回对象
# 2.使用装饰器
from functools import wraps # 还原函数的名字
"""
由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题。Python 通过 functool.wraps 为我们解决了这个问题
"""
def singleton(cls):
instances = {}
@wraps(cls)
def getinstance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return getinstance
@singleton
class MyClass(object):
a = 1
# 3.使用模块
新建test
class MyClass(object):
def foo(self):
print("MyClass.foo")
my_class_obj = MyClass()
====分割线====
from test1 import my_class_obj
my_class_obj.foo()
2.斐波拉契
# 1.迭代器实现
# 迭代器,必须同时实现__iter__和__next__
class Fibs(object):
def __init__(self, n):
self.n = n # 元素个数
self.a = 0
self.b = 1
self.index = 0 # 记录位置的变量
# 返回一个对象引用,返回迭代器对象,
def __iter__(self):
return self
# 计算
def __next__(self):
if self.index < self.n: # 在范围内
ret = self.a
self.a, self.b = self.b, self.a+self.b
self.index += 1 # 位置改变
return ret
else:
raise StopIteration
# 创建对象
obj = Fibs(100)
tmp = iter(obj)
while True:
try:
v = next(tmp)
print("v = ", v)
except StopIteration:
break
# 2. 生成器实现
def create_fib(n):
a = 0
b = 1
for i in range(n):
yield a
a, b = b, a+b
gen = create_fib(5)
print(gen)
v = gen.send(none)
print(v)
3.乘法口诀
#乘法口诀
def func():
row=1
while row <= 9:
col = 1
while col <= row:
print("%d*%d=%d" %(col, row,(col*row)),end="\t")
col += 1
print()
row += 1
func() # 调用
4.字符串去重
str1 = "ascdabcddfasd"
str2 = ""
for a in str1:
if a not in str2:
str2 += a
5.打印菱形
# 1.打印图形
num = 1
while num <= 5:
j = 1
while j <= num:
print("*",end="")
j += 1
print() # 换行
num += 1
# 2.打印半菱形
i = 1
while i <=10:
if i <=5:
print("*"*i)
else:
print("*"*(10-i))
i +=1
# 3.打印菱形
i = 1
while i <= 9:
if i <= 5:
print(" " * (5 - i), "*" * (2 * i - 1)) # 空格符很重要,空格多少个 效果不一样
else:
print(" " * (i - 5), "*" * (2 * (10 - i) - 1))
i += 1
6.Python中 os 和 sys 模块
- os 模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;
- sys 模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境;
# OS 命令
os.sep: 取代操作系统特定的路径分隔符
os.name: 指示你正在使用的工作平台。比如对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix'。
os.getcwd: 得到当前工作目录,即当前python脚本工作的目录路径。(绝对路径)
os.getenv()和os.putenv:分别用来读取和设置环境变量
os.listdir(): 返回指定目录下的所有文件和目录名
os.remove(file):删除一个文件
os.chmod(file):修改文件权限和时间戳
os.mkdir(name):创建目录
os.rmdir(name):删除目录
os.removedirs(r“c:\python”):删除多个目录
os.system(): 运行shell命令
os.exit(): 终止当前进程
os.path.split():返回一个路径的目录名和文件名
os.path.isfile()和os.path.isdir()分别检验给出的路径是一个目录还是文件
os.path.existe():检验给出的路径是否真的存在
os.listdir(dirname):列出dirname下的目录和文件
os.getcwd(): 获得当前工作目录
os.chdir(dirname):改变工作目录到dirname
os.path.join(path,name):连接目录与文件名或目录
os.path.basename(path):返回文件名
os.path.dirname(path):返回文件路径
os.rename 对文件重命名
os.remove 对文件删除
os.mkdir 创建文件夹
os.getcwd 获取当前目录
os.chdir 更改默认目录
os.listdir 获取目录列表
os.rmdir 删除文件
os.getcwd 指的是运行程序的目录 (绝对路径)
# sys 命令
sys.argv 命令行参数List,第一个元素是程序本身路径
sys.modules.keys() 返回所有已经导入的模块列表
sys.exc_info() 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息
sys.exit(n) 退出程序,正常退出时exit(0)
sys.hexversion 获取Python解释程序的版本值,16进制格式如:0x020403F0
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.maxunicode 最大的Unicode值
sys.modules 返回系统导入的模块字段,key是模块名,value是模块
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
sys.stdout 标准输出
sys.stdin 标准输入
sys.stderr 错误输出
sys.exc_clear() 用来清除当前线程所出现的当前的或最近的错误信息
sys.exec_prefix 返回平台独立的python文件安装的位置
sys.byteorder 本地字节规则的指示器,big-endian平台的值是'big',little-endian平台的值是'little'
sys.copyright 记录python版权相关的东西
sys.api_version 解释器的C的API版本
# sys 实际用法
0. os.getcwd: 指的是当前目录,绝对路径
1、sys.path[0]:主要模块的目录(绝对路径),在模块运行的时候可以append方法 添加进去
2、sys.argv[0]:运行模块时,python后面的参数
3. __file__ : 表示所在模块文件的路径,和系统找到该模块的方式有关,你是用绝对路径去加载该模块,那么__file__就为绝对模块文件路径,如果你给系统提供相对路径去加载该模块,那么改文件路径为相对路径
7.__file__ 与argv[0] 路径问题
# sys.argv[0]
获取主执行文件路径的最佳方法是用sys.argv[0],它可能是一个相对路径,所以再取一下abspath是保险的做法
dirname, filename = os.path.split(os.path.abspath(sys.argv[0]))
----> os.path.abspath(xxx) 返回xxx规范化的绝对路径。
# __file__
- 按相对路径./test.py来执行,则打印得到的是相对路径,
- 按绝对路径执行则得到的是绝对路径。
- 而按用户目录来执行(~/practice/test.py),则得到的也是绝对路径(~被展开)
- 所以为了得到绝对路径,我们需要 os.path.realpath(__file__)。
注意: 而在Python控制台下,直接使用print __file__是会导致 name ‘__file__’ is not defined错误的,因为这时没有在任何一个脚本下执行,自然没有 __file__的定义了
8.Linux20个常用命令
0.man: 查看帮助信息
1.cd: 目录切换
2.ls: 查看目录信息
ls -[l a d h R(递归)]
3.tree: 以树状形式查看指定目录的内容
4.输出重定向命令:> >输出重定向会覆盖原来的内容,>>输出重定向则会追加到文件的尾部。
5.touch:
如果文件不存在, 创建新的空文件(只能是普通文件,不能是文件夹)
如果文件存在, 更新文件时间
6.ln: 命令主要用于创建链接文件 (硬连接和软连接)
7.mkdir: 命令可以创建一个新的目录(不能新建普通文件)。参数 -p 可递归创建目录。
8.rm: 删除文件或目录
9.cp: 命令的功能是将给出的文件或目录复制到另一个文件或目录中
10.mv: 命令来移动文件或目录,也可以给文件或目录重命名
11.cat: 将文件内容一次性输出到终端 (缺点:终端显示的内容有限,如果文件太长无法全部显示)
12.more: 命令将文件内容分页显示到终端
13.less: 命令将文件内容分页显示到终端,可以自由上下浏览
14.find: 命令在特定的目录下搜索符合条件的文件 find + 路径 + -name +“文件名”
15.grep: 允许对文本文件进行模式查找。如果找到匹配模式, grep打印包含模式的所有行
16.管道(|):一个命令的输出可以通过管道做为另一个命令的输入
17.压缩文件:zip -r 目标文件(可以不指定扩展名) 源文件
解压文件:unzip 压缩文件 -d 解压后目录文件
18.文件权限管理 :chmod u/g/o/a +/-/= rwx 文件
user group other all/增加权限 撤销权限 设定权限/read可读取 write可写入 excute可执行
19.exit: 退出
20.ifconfig: 查看网卡信息
21.ping: 来检测网络是否正常
22.ps aux | grep xxx : 查看进程 (A 显示所有的进程;a 不与terminal有关的所有进程;u 有效用户的相关进程; x 一般与a一起使用,可列出较完整的信息 )
23. 查看内存使用:
sudo atop :终端环境的监控命令,并且在搞负载的情况下进行了彩色标注
free -h :快速查看内存使用情况的方法
24. 指定端口
lsof -i:端口号查看某个端口是否被占用
25. kill / killall
26. vim
27. time
open ~/.ssh # 打开秘钥的目录
ls -al ~/.ssh # 显示所有的ssh文件
cat ~/.ssh/id_rsa.pub # 复制公钥
sudo find / -name ".gitconfig"
# ls 显示文件(目录)信息
帮助信息:man ls ls --help (有中文)
参数:
-a 显示所有文件,包括以.开头的隐藏文件
-l以长格式显示文件或子目录的详细信息
-R 递归的显示指定目录中的各个子目录中的文件
-S 以文件大小排序
-s 给出每个目录项所用的块数
-t 以文件的修改时间的先后顺序排序
-d 如果参数是目录,只显示其名称而不显示其下的各文件,往往与1选项一起使用,已得到目录的详细信息
-m 横向显示目录下的文件,文件名之间以逗号分隔。
-h 将文件容量以较易读的方式(GB KB)列出来
# linux中的&&和&,|和||
- & 表示任务在后台执行,如要在后台运行redis-server,则有 redis-server &
- && 表示前一条命令执行成功时,才执行后一条命令 ,如 echo "1" && echo "2"
- | 表示管道,上一条命令的输出,作为下一条命令参数,如 echo "yes" | wc -l
- || 表示上一条命令执行失败后,才执行下一条命令,如 cat nofile || echo "fail"
# 定时任务
Linux 的 Crontab 执行命令: sudo crontab -e
# 线上服务可能因为种种原因导致挂掉怎么办
Linux 下的后台进程管理利器 supervisor
每次文件修改后在 linux 执行:service supervisord restart
9.git 常用命令
git clone 克隆指定仓库
git status 查看当前仓库状态
git diff 比较版本的区别
git log 查看 git 操作日志 ; git reflog 可以查看所有分支的所有操作记录(包括commit和reset的操作),包括已经被删除的commit记录,git log 则不能察看已经删除了的commit记录
git reset 回溯历史版本 ;git reset --hard 版本号 # 复制前面7位数字
git add 将文件添加到暂存区
git commit 将文件提交到服务器
git checkout 切换到指定分支
git rm 删除指定文件
git add front_end_pc # 添加子目录front_end_pc 到本地缓存里 , 把写的代码添加到本地缓存中
git add . # 添加本地目录下的所有代码 到本地缓存里面
git status # 查看状态, 这个习惯要养成
git commit -m 'add front end files' # 提交到本地仓库里面 , -m:本次提交的描述信息
git push # 把本地仓库的代码推送到远程仓库 推送
git push origin dev:dev # 把本地仓库里的代码, 推送到远程仓库
git branch # 查看分支
git branch "分支名" # 创建分支
git checkout "分支名" # 切换分支
git checkout -b "分支名" # 创建并切换到分支 :"分支名"
git merge "分支名" # 合并某分支到当前分支
git branch -d "分支名" # 删除分支
git pull # 下拉
可以使用前端node.js 提供的服务器live-server作为前端开发服务器使用。
安装node.js的版本控制工具nvm,在终端中执行
10.常见状态码
1xx : 请求没完成,请求中
2xx : http 请求完成
3xx : 重定向
4XX : 客户端的请求有误
5xx : 服务器的响应错误
6xx 7xx : 开发者自定义的
=====
200 服务器成功返回用户请求的数据
201 用户新建或修改数据成功
202 表示一个请求已经进入后台排队(异步任务)
204 用户删除数据成功
300 多选择 针对请求,服务器可执行多种操作
301 永久移动
302 临时移动
305 请求中应该使用代理
307 临时重定向
400 用户发出的请求有误,服务器没有进行新建或修改数据的操作
401 用户没有权限
403 服务器拒绝请求
404 服务器找不到请求的页面
406 无法使用请求的内容特性响应请求的网页
410 用户请求的资源被删除
500 服务器遇到存储,无法完成请求
501 服务器不具备完成请求的功能
502 错误网关
503 服务器不可用
504 网关超时
505 HTTP版本不受支持
11.python大文件读取
# Pythonic,就是极具Python特色的Python代码(明显区别于其它语言的写法的代码)
with open('filename', 'r', encoding = 'utf-8') as f:
for line in f:
do_something(line)
# with 语句句柄负责打开和关闭文件(包括在内部块中引发异常时),for line in f 将文件对象 f 视为一个可迭代的数据类型,会自动使用 IO 缓存和内存管理,这样就不必担心大文件了。
12.python2 / python3 的区别
# 先说主要区别(字符集)
- 在python3中: 字符串是unicode编码后的字符串,str类型的,二进制是bytes类型的,编码使用的是encode,解码使用的decode, 默认字符集是utf-8
Unicode: type(s) -> str
非Unicode: type(s) -> bytes 二进制
- 在python2中:字符串也是Unicode编码后的字符串,是Unicode类型的,二进制是str类型的,编码使用的是encode,解码使用的decode, 默认字符集是ASCII码
Unicode: type(s) -> unicode
非Unicode: type(s) -> str 二进制
# Unicode字符集: 万国码, 占用两个字节, 一般程序内部使用,解决了各个国家编码不一致的请求,但是Unicode里每个字符都占用 3~4 个字节,导致文件过大。
--> 于是 utf-8 诞生(可变长的Unicode),可以根据字符的种类变换长度,如一个字母占 1 个字节,一个汉字 3 个字节,可以降低文件的大小占用
Python2 里默认代码文件头部编码声明是 ascii,只能在python代码里写 ascii 字符,如果有中文会报语法错误。所以需要手动声明:
#coding:utf-8
#
# python 2
1) 在代码最上行写: # -*- coding: utf8 -*-
2) 设置解释器编码 uft-8
reload(sys)
sys.setdefaultencoding('utf-8')
1).print
py2:print语句,语句就意味着可以直接跟要打印的东西,如果后面接的是一个元组对象,直接打印
py3:print函数,函数就以为这必须要加上括号才能调用,如果接元组对象,可以接收多个位置参数,并可以打印
如果希望在 Python2 中 把 print 当函数使用,那么可以导入 future 模块 中的 print_function
2).输入函数
py2:input_raw()
py3:input()
3).在使用super()的不同
py2:必须显示的在参数中写上基类
py3:直接无参数调用即可
4).1/2的结果
py2:返回0
py3:返回0.5,没有了int和long的区别
5).编码
py2:默认编码ascii
py3:默认编码utf-8
而且为了在py2中使用中文,在头部引入coding声明,不推荐使用
6).字符串
py2:unicode类型表示字符串序列,str类型表示字节序列
py3::str类型表示字符串序列,byte类型表示字节序列
7).True和False
py2:True 和 False 在 Python2 中是两个全局变量,可以为其赋值或者进行别的操作,初始数值分别为1和0,虽然修改是违背了python设计的原则,但是确实可以更改
py3:修正了这个变量,让True或False不可变
8).迭代器
py2:当中许多返回列表的方法,如range,字典对象的 dict.keys()、dict.values() 方法, map、filter、zip;并且迭代器必须实现next方法
py3:将返回列表的方法改为了返回迭代器对象,内置了__next__,不用特意去实现next
9).nonlocal
py2:没有办法在嵌套函数中将变量声明为一个非局部变量,只能在函数中声明全局变量
py3:nonlocal方法实现了,示例如下:
10).字符串 比较符合以下规则: "0" < "A" < "a", python3 中取消了这个
13.python中的新式类和旧式类
# 1.类继承Object
➤新式类都从object继承,经典类不需要。
➤新式类的MRO(method resolution order 基类搜索顺序)算法采用C3算法广度优先搜索,而旧式类的MRO算法是采用深度优先搜索
➤新式类相同父类只执行一次构造函数,经典类重复执行多次。
➤Python 2.x中默认都是经典类,只有显式继承了object才是新式类
➤Python 3.x中默认都是新式类,经典类被移除,不必显式的继承object
# 2.继承搜索的顺序
1).经典类多继承搜索顺序(深度优先):
先深入继承树左侧查找,然后再返回,开始查找右侧
2).新式类多继承搜索顺序(广度优先):C3算法
先在水平方向查找,然后再向上查找
14.同步阻塞 / 异步非阻塞
同步:多个任务之间有先后顺序执行,一个执行完下个才能执行。
异步:多个任务之间没有先后顺序,可以同时执行有时候一个任务可能要在必要的时候获取另一个同时执行的任务的结果,这个就叫回调!
阻塞:如果卡住了调用者,调用者不能继续往下执行,就是说调用者阻塞了。
非阻塞:如果不会卡住,可以继续执行,就是说非阻塞的。
同步异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。
15.python 内存管理机制和垃圾回收机制
# 内存管理
C语言的手工管理,Java的垃圾回收
以Python语言为例子,说明一门动态类型的、面向对象的语言的内存管理方式。
- 内存地址 ; is用于判断两个引用所指的对象是否相同
- 每个对象都有存有指向该对象的引用总数,即引用计数(reference count)
- sys包中的getrefcount(),来查看某个对象的引用计数
# 内存池机制
当创建大量消耗小内存的对象时,频繁调用new/malloc会导致大量的内存碎片,致使效率降低。内存池的概念就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后再申请新的内存。这样做最显著的优势就是能够减少内存碎片,提升效率
python中的内存管理机制都有两套实现
1).一套是针对小对象,就是大小小于256bits时,pymalloc会在内存池中申请内存空间;
2).当大于256bits,则会直接执行 new/malloc 的行为来申请新的内存空间。
# 垃圾回收机制 GC
一: 引用计数
引用计数通过记录对象被引用的次数来管理对象。
对对象的引用都会使得引用计数加1,移除对对象的引用,引用计数则会减1,当引用计数减为0时,对象所占的内存就会被释放掉。
引用计数可以高效的管理对象的分配和释放,但是有一个缺点,就是无法释放循环引用的对象
什么是循环引用:A和B相互引用而再没有外部引用A于B中的任何一个,如果是使用引用计数法来管理这两对象的话,他们并不会被回收,它会一直驻留在内存中,就会造成了内存泄漏(内存空间在使用完毕后未释放)
总结:只有容器对象才会出现循环引用
二: 标记清除
『标记清除(Mark—Sweep)』算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收.
对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器
*缺点*: 清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。
三: 分代回收
分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象
16.变量的声明周期 和 小缓存池
# 变量的声明周期
1.) 析构方法 __del__
2.) 当变量的引用为0的时候, 变量就会被回收
3.) 循环引用:A和B相互引用而再没有外部引用A于B中的任何一个,如果是使用引用计数法来管理这两对象的话,他们并不会被回收,它会一直驻留在内存中,就会造成了内存泄漏(内存空间在使用完毕后未释放)
# 小缓存池
python 定义的数值缓存范围是 -5 ~ 257
- 直接从缓存池中返回,不需要申请内存,如果超出就要申请内存
- 在 -5~257 范围内, ip都一样
17.变量作用域及调用优先级
1.变量作用域
- L(local) 局部作用域
- E(Enclosing) 闭包函数外的函数中
- G(Global) 全局作用域
- B(Built-in) 内建作用域
2.遵循LEGB原则:
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找
x = int(2.9) # 内建作用域
g_count = 0 # 全局作用域
def outer():
o_count = 1 # 闭包函数外的函数中
def inner():
i_count = 2 # 局部作用域
1).若内部作用域的想要修改外部作用域的变量,就要使用global关键字
2).nonlocal 关键字的使用方法和global关键字类似,修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量
def outer():
num = 10
def inner():
nonlocal num # nonlocal关键字声明
num = 100
print(num)
inner()
print(num)
outer()
运行结果为
100
100
闭包函数外的变量num值被修改
18.python解压zip文件
zip 与tar类似,先读取多个文件名称,然后解压。例如以下:
import zipfile, os
def un_zip(file_name):
"""unzip zip file"""
zip_file = zipfile.ZipFile(file_name)
if os.path.isdir(file_name + "_files"):
pass
else:
os.mkdir(file_name + "_files")
for names in zip_file.namelist():
zip_file.extract(names,file_name + "_files/")
zip_file.close()
19.设计模式(单例模式 工厂模式(简单/抽象) 装饰器 生成器)
- 设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案
- 为了解决面向对象系统中重要和重复的设计封装在一起的一种代码实现框架,可以使得代码更加易于扩展和调用
一.单例模式
1.保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
适用场景:
1.需要生成唯一序列的环境
2.需要频繁实例化然后销毁的对象。
3.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
4.方便资源相互通信的环境
优点:
1.实现了对唯一实例访问的可控
2.对于一些需要频繁创建和销毁的对象来说可以提高系统的性能。
缺点:
1. 不适用于变化频繁的对象
2.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出。
3.如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失。
二.工厂模式
工厂模式有一种非常形象的描述,建立对象的类就如一个工厂,而需要被建立的对象就是一个个产品;在工厂中加工产品,使用产品的人,不用在乎产品是如何生产出来的。从软件开发的角度来说,这样就有效的降低了模块之间的耦合。
1).简单工厂模式
适用于需创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂的情况下,而且用户只关心那种类型的实例被创建,并不关心其初始化过程时,比如多种数据库(MySQL/MongoDB)的实例,多种格式文件的解析器(XML/JSON)等。
2).工厂方法模式
继承了简单工厂模式的优点又有所改进,其不再通过一个工厂类来负责所有产品的创建,而是将具体创建工作交给相应的子类去做,这使得工厂方法模式可以允许系统能够更高效的扩展。实际应用中可以用来实现系统的日志系统等,比如具体的程序运行日志,网络日志,数据库日志等都可以用具体的工厂类来创建。
3).抽象工厂模式
在工厂方法基础上扩展了工厂对多个产品创建的支持,更适合一些大型系统,比如系统中有多于一个的产品族,且这些产品族类的产品需实现同样的接口,像很多软件系统界面中不同主题下不同的按钮、文本框、字体等等。
20.匿名函数 lambda
lambda 函数是匿名函数;使用 lambda 函数能创建小型匿名函数。这种函数得名于省略了用 def 声明函数的标准步骤
lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数
格式: lambda 形参 : 返回值
一次性函数,以表达式的形式定义一个函数,只能做一些简单处理
作用:
1、lambda 函数比较轻便,即用即仍,很适合需要完成一项功能,但是此功能只在此一处使用, 连名字都很随意的情况下;
2、匿名函数,一般用来给 filter, map 这样的函数式编程服务;
3、作为回调函数,传递给某些应用,比如消息处理
4. 因为函数没有名字,不必担心函数名冲突
def multipliers():
return [lambda x : i * x for i in range(4)]
print [m(2) for m in multipliers()]
结果: [6,6,6,6]
Lambda函数能接收任何数量的参数但只能返回一个表达式的值
匿名函数不能直接调用print,因为lambda需要一个表达式
sum = lambda arg1,arg2: arg1+arg2
print(sum(10,20))
1).自定义排序规则
print((lambda *args : [a **2 for a in args]) (1,3,5))
2).函数作为参数传递
21.高阶函数: map()函数 reduce()函数 filter()函数 sorted()函数
# 1.map()函数
它接收一个函数 f 和一个list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。
def f(x):
return x * x
print map(f,[1,2,3,4,5,6,7]) #list里的每个元素都会走一遍f(x)方法
结果: [1, 4, 9, 10, 25, 36, 49]
# 2.reduce()函数
reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。
def f(x ,y ):
return x * y
print reduce(f,[1,2,3,4]) #1*2*3*4=24
# 给初始值
def f(a,b):
return a+ b
print reduce(f,[1,2,3,4],10) #1+2+3+4+10.这里的第三个参数是做为初始值的。
# 3.filter()函数
filter()接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
def is_odd(x):
return x%2==1
print filter(is_odd,[1,2,3,4,5,6,7]) # [1, 3, 5, 7]
# 4.sorted() 函数对所有可迭代的对象进行排序操作。
sort 与 sorted 区别:
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
# sorted(iterable[, cmp[, key[, reverse]]])
1).iterable -可迭代对象。
2).cmp -比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
3).key -主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
4).reverse -排序规则,reverse = True 降序 , reverse = False 升序(默认)。
22.魔法方法
__new__ 创建实例(对象的构造器)
__init__ 初始化方法(对象的构造器)
__del__ 对象的销毁器,当对象在内存中被释放时,自动触发执行
__str__ 类的实例调用,自定义输出方法
__repr__ 机器可读的输出
__call__ 可调用对象的方法 允许你自己类的对象表现得像是函数,对象后面加括号,触发执行
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
__enter__() 和 __exit__() 方法的对象都可称之为上下文管理器 with 关键字( contextmanager 装饰器 也可以实现)
__doc__ 类的描述信息
__module__ 表示当前操作的对象在哪个模块
__class__ 表示当前操作的对象的类是什么
__dict__ 类或对象中的所有属性
__getslice__、__setslice__、__delslice__ 用于分片操作,如:列表
__getitem__、__setitem__、__delitem__ 用于索引操作,如字典。以上分别表示获取、设置、删除数据
__import__ 需要导入的模块的名字<字符串> 返回是导入的模块对象的引用
23.GIL锁
GIL:
全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码
在 Python 多线程下,每个线程的执行方式:
1、获取 GIL
2、执行代码直到 sleep 或者是 python 虚拟机将其挂起。
3、释放 GILcpython解释器内部多线程使用的 互斥锁(使用多线程的时候才会出现GIL, 多进程则不会出现)
目的: 防止解释器内部的全局资源产生资源竞争问题
影响: 不能有效利用多核资源
cpython多线程 实际上是并发执行的
-
什么时候会释放GIL锁?
- 超时自动释放,
- 使用计时器,tickets计数达到100释放GIL
- 线程被阻塞了,也会释放(recv 阻塞)
-
如何解决GIL 的影响= 如何才能使用多核
- 多进程
- 其它语言编写的代码(c语言)
- 换个其它解释器 pypy java
小知识点htop命令查询 linux系统资源占用情况
GIL锁爬虫情况下: 多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁
24.Copy (深拷贝,浅拷贝)
浅拷贝
- 浅拷贝是对于一个对象的顶层拷贝,照搬照抄
- 拷贝了引用,并没有拷贝内容
- 好处:节约内存空间,节约时间,提高效率
- 当给一个变量赋值时,其实就是将数据的引用复制了一份给另外一个变量=浅拷贝
- 分片表达式可以赋值一个序列 分片属于浅拷贝
- 列表 元组 字符串 可以分片操作, 字典因为是kv 不可以分片操作
- 列表是可变类型 后面新增了不会被b浅拷贝指向
- 元组 不可变类型,不会拷贝,只是变量地址的引用
- copy.copy对于可变类型,会进行浅拷贝,只会复制最顶层的那个列表
- copy.copy对于不可变类型,不会拷贝,仅仅是引用的指向(没有意义的)
深拷贝
- 深拷贝是对于一个对象所有层级的完全拷贝(递归)
25.私有化
使用私有化的意义
1.保护数据(增加代码复杂程度 防止用户意外修改)
2.增加访问控制权限(提供方法,间接访问 在类外不能直接访问
3.提高代码的规范性 减少出现错误的可能)
xx 公有变量
_xx 假的 口头的私有化,可以访问,需要单独导入才能使用
__xx 无法在类外访问,不可以被子类访问(名字重整了所有访问不到 print(dir类名)查看类里面的所有属性),但是子类可以通过父类提供的方法间接访问, 需要单独导入才能使用
__xx__ 用户名字空间的魔法对象或熟悉
xx_ 用于避免与python关键字冲突
26.import导入模块
# 1.sys.path
输入 sys.path ,就会列出一些目录,这些目录就是python会去找模块的路径
- '' 表示当前路径
- 列表中的路径先后顺序 代表了python解释器在搜索模块时的先后顺序
可以通过 sys.path.append('路径') 添加
.使用 sys.path.append('common/') 默认加在sys.path的最后
.使用 sys.path.insert(0,‘common/’) 后会将path目录加在最前面
当你导入一个模块时,Python解析器对模块位置的搜索顺序是:
①当前目录
②如果不在当前目录,Python则搜索PythonPath下的每个目录
③如果都找不到,Python会查看安装默认路径
# 2.第二种方法是设置环境变量pythonpath
1.模块只能导入一次
- 模块就是一个对象
- 模块只导入一次,第二次只会直接使用以及导入成功的模块对象
- 模块被导入后,import module不能重新导入模块,重新导入需用reload
- 导入模块只会导入一次,因此即使模块进行了修改,import也不会重新导入
- python 3 重新导入模块方法:from imp import reload
2.多模块开发时的注意点
- 如果模块属性是可变类型,import from…import 都可以修改模块的属性
- 如果模块属性是不可变类型,from…import 是不可能改变模块属性的, import 方式可以修改模块属性
- 都会创建对象
- import 会将创建的 模块对象的引用 保存在本地作用域
- from-import 会将创建的 模块对象的属性的引用 保存在本地作用域
- dir(模块名) 查看模块的所有属性
3.import过程分析
- 模块的引用
- 在搜索路径中找到,如果其中没有就搜索, 所有import成功的模块都放在sys.modules中,import 导入和语句所在位置有关系
- 执行模块代码, 创建模块对象和对应属性
- 将创建好的模块名导入当前local名字空间
- locals()查看本地名字空间当中所有的名字
- globals() 查看全局名字空间中所有的名字
4.from...import 过程分析
- 模块属性的引用
- 只导入模块中的名字(变量 对象 类 函数)
- 如果没有 则创建空模块对象A 执行模块代码 并且在local中创建和前同名的对象
- 如果模块对象中找到名字B 将该名字放入locals空间中
- sys.modules 查找模块A
27.多继承和MRO顺序 super
mro顺序作用:多继承中 能够保证所有的类按照该顺序进行初始化, 所有类只初始化一次
super(super是一个类)的作用: 查找mro顺序中当前类的下一个类,super和父类没有关系super是一个类,在python3中不需要加参数,在python2中(分经典类 新式类 )
28.静态方法 / 类方法 / 实例方法
- 类属性、实例属性
它们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,
- 实例属性属于实例对象
- 类属性属于类
- 类属性在内存中只保存一份,所有实例对象共享的属性
- 实例属性在每个对象中都要保存一份,所有实例对象分别拥有自己的实例属性
- 实例对象也可以获取类属性,但是不能修改,二义性,python解释器会认为是需要绑定一个同名的实例属性
- 类对象可以访问类属性,但是类对象不能访问实例属性(因为实例属性在实例对象的空间里)
- 实例方法、静态方法和类方法
- 在内存中都归属于类
- 区别在于调用方式不同:
- 1).实例方法:由对象调用;至少一个self参数;执行实例方法时,自动将调用该方法的对象赋值给self(区分哪个实例对象在调用实例方法);对实例属性操作的封装 ; 实例对象的代码保存在类对象中,需要时再调用(节约空间)
- 2).类方法@classmethod:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类赋值给cls;对类属性的封装 , cls参数 表示类 A.get_count() —>get_count(A)
- 3).静态方法@staticmethod:不需要访问类属性,和实例属性所有不需要cls self 由类调用;无默认参数; 静态方法也可以修改类属性, (类名. 修改类属性) 将类功能和类相关的普通函数封装在一个类中 防止名字扩散
- 相同点:对于所有的方法而言,均属于类,所以 在内存中也只保存一份
- 不同点:方法调用者不同、调用方法时自动传入的参数不同。
29.property
主要目的:把函数封装 让用户使用属性方式操作数据,并且对数据的修改进行了有效的存储控制
- 定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数
- 调用时,无需括号
class Cat(object):
def __init__(self):
self.__age = 0
# 主要目的 是 让用户使用属性方式操作数据 并且 对数据的修改进行了有效的存储控制
@property
def age(self):
print("正在获取年龄")
return self.__age
@age.setter
def age(self,age):
# 存取控制 封装 使用稍微有些复杂
if age > 200 or age < 0:
print("设置的年龄有问题")
else:
self.__age = age
@age.deleter
def age(self):
print("删除age属性")
c1 = Cat()
# 普通对象.属性方式 特点: 使用简单 对数据的存取没有有效的控制
print(c1.age)
c1.age = 18888
print(c1.age)
del c1.age
# c1.set_age(1888) # 对象.方法 特点: 使用稍微复杂一点点 但是对数据进行了存取控制
30.python内置模块(标准库) / 内置函数 / 内置变量 / 第三方模块(第三方库)
# 内置模块(内置库), 存放在安装路径下
1).re模块 正则表达式:search、match、split、findall(finditer)、sub
2).os模块 (文件和目录)用于提供系统级别的操作(os.getcwd/os.makedir/os.rmdir/os.remove)
3).sys模块 用于提供对解释器相关的操作 sys.argv命令行参数,sys.version,sys.exit()
4).logging 用于便捷记录日志且线程安全的模块;debug info warning error critical
5).datetime 模块:时间相关的操作,时间有三种表示方式:
6).random模块:随机数
7).json 和 pickle模块
- json,用于字符串 和 python数据类型间进行转换
- pickle,用于python特有的类型 和 python的数据类型间进行转换
8).hashlib模块:用于加密相关的操作,代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
9).threading: 线程
10).multiprocessing: 进程
11).socket
12).types模块,给类和实例动态添加方法;from types import MethodType
参数一: 要传递的函数
参数二: 需要给的对象
13).md5;sha模块
14).copy 拷贝
# 第三方模块(库) 存放在安装路径下的 sit-packages里面
# requirements.txt 文件里列出项目要安装的包
1).pip install 模块名
2).源码安装:下载源码 解压 进入目录 执行python setup.py install
image 模块: 操作图像的模块
pymysql
redis
pymongo
django
flask
gevent: 协程
requests :
pyGame: 用于编写游戏开发的跨平台应用程序框架
ipython:
pandas: 数据结构和数据分析工具的库
Beautiful Soup: 用于解析 HTML 并从中提取信息。尤其适用于网络抓取
Pillow: 影像库使你的 Python 解释器新增图像处理功能
djangorestframework
====flask中用过的第三方库
1)Flask-WTF==0.14.2 自带csrf保护
2)flask-sqlalchemy
3)flask-mysqldb
4)redis
5)
# 内置函数
all() input() open() int() str() type() staticmethod() print() super() del()
iter() tuple() len() range() list() float() format() max() min() next() id()
# 内置方法 = 魔法方法
# 内置变量
vars() 查看内置全局变量
31.python模块导入(内置模块,自定义模块,开源模块) 调用顺序
https://www.cnblogs.com/liu-yao/p/5186322.html
模块时一个包含定义的函数和变量的文件,后缀名是.py
import
from 模块名 impory 函数1, 函数2
理解: 内置模块先调用, 重写内置模块的方法就是自定义模块, 自定义模块先调用
32.__future__
Python为了确保你能顺利过渡到新版本,特别提供了__future__模块,让你在旧的版本中试验新版本的一些特性
Python的新版本会引入新的功能,但是,实际上这些功能在上一个老版本中就已经存在了。要“试用”某一新的特性,就可以通过导入__future__模块的某些功能来实现。
当新版本的一个特性与旧版本不兼容时,该特性将会在旧版本中添加到__future__中,以便旧的代码能在旧版本中测试新特性。
例如,Python 2.7的整数除法运算结果仍是整数:
>>> 10 / 3
3
但是,Python 3.x已经改进了整数的除法运算,“/”除将得到浮点数,“//”除才仍是整数:
>>> 10 / 3
3.3333333333333335
>>> 10 // 3
3
要在Python 2.7中引入3.x的除法规则,导入__future__的division:
>>> from __future__ import division
>>> print 10 / 3
3.3333333333333335
33.with 与上下文管理器
系统资源如文件、数据库连接、socket ,互斥锁 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。
需求: 及时 自动释放打开的资源(文件 套接字 互斥锁)
目的: 简化用户开发流程 增强程序的功能
当try...finally中间的逻辑复杂,并带着各种嵌套的话,代码就不容易维护
with 语句可以实现同样的功能
1.上下文管理器=用类来实现
任何实现了__ enter__() 和 __ exit__()
方法的对象都可称之为上下文管理器
__enter__()
方法会在with语句进入时调用,其返回值会赋值给as关键字后的变量
__exit__()
方法在with语句退出后自动调用
2.contextmanager装饰器 和 yield(生成器)来实现
[context_expression创建上下文管理器context_manager]
@contextlib.contextmanager
通过 yield 将函数分割成两部分:
yield 之前的语句在 __enter__()
方法中执行,
yield 之后的语句在__exit__()
方法中执行
yield 后面的值是函数的返回值。就是with语句块中的代码。如果yield后面带参数的话,我们就可以用as关键字赋值给后面的变量
注意: @contextlib.contextmanager”不像之前介绍的__exit__()
方法,遇到异常也会执行。也就是with语句块抛出异常的话,yield后面的代码将不会被执行。所以,必要时你需要对yield语句使用”try-finally”
上下文管理器的理解 : 上下文管理器的任务是 —— 代码块执行前准备,代码块执行后收拾
contextmanager最大的好处就是可以将不是上下文处理器的类变成一个类似上下文处理的方式来解决问题。
with语法格式 :with context_expression [as target(s)]:
- 这里context_expression返回的是一个上下文管理器对象.这个对象已经满足了上下文协议,也就是说这个对象已经有了
__exit__
()与__enter__
()方法,其中如果使用了as,那么将会将__enter__
()方法返回的值赋值给target(s)
34.闭包,装饰器 (语法糖)
闭包
1.)优点:闭包提高代码可复用性,减少代码的可移植性
2.)缺点:闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存
3.)概念:在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包,并返回
4.)闭包的三个特点
- 函数的嵌套定义
- 外层函数返回了内层函数的引用 return
- 在内存函数中可以使用外层函数提供的变量-自由变量 环境变量
装饰器
- 引入日志
- 函数执行时间统计 (import time)
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存 (data = list[] 把数据存在里面)
代码要遵循开放封闭原则:对代码修改时关闭 对代码功能扩展是开放的
1.装饰器的目的:在不修改函数代码的情况下,对函数功能进行扩展
2.装饰器函数特点: 满足闭包的特点,函数参数只有一个就是被装饰的函数的引用
35.from functools import wraps
- functools.wraps :还原函数的名字
- 由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下(比如测试时)会导致一些问题。Python 通过 functool.wraps 为我们解决了这个问题
36.虚拟环境
1).虚拟环境就是借助虚拟机docker来把一部分内容独立出来,我们把这部分独立出来的东西称作“容器”
2).各个容器之间互相隔离,互不影响
3).在实际项目开发中,我们通常会根据自己的需求去下载各种相应的框架库,如Scrapy、Beautiful Soup等,但是可能每个项目使用的框架库并不一样,或使用框架的版本不一样,这样需要我们根据需求不断的更新或卸载相应的库。直接对我们的Python环境操作会让我们的开发环境和项目造成很多不必要的麻烦,管理也相当混乱
4).pip3 install virtualenv
启动虚拟环境: workon 或者 source active
37.上下文的理解 context
上下文:已经处理过的数据叫上文,正在处理的数据叫正文,准备要处理的数据叫下文。上下文是程序相关的数据。
1.) with 语法格式
__exit__()与__enter__()方法
通过context_expression创建上下文管理器context_manager
38.列表推导式
a = [x for x in range(3,19,2)]
a = [x for x in range(3,10) if x%2 != 0] 结果[3,5,7,9]
a = [(x,y) for x in range(1,3) for y in range(3)] 结果[(1,0),(1,1),(1,2)..]
39.列表去重set
# set list tuple 之间可以相互转换
# set字典->list列表->tuple元组->list列表
In [1]: b = [1,2,3,12,3,1,3]
In [2]: c = set(b)
In [3]: type(c)
Out[3]: set
In [4]: c
Out[4]: {1, 2, 3, 12} # 字典
In [5]: d = list(c)
In [6]: d
Out[6]: [1, 2, 3, 12]
In [7]: e = tuple(d)
In [8]: e
Out[8]: (1, 2, 3, 12)
In [9]: f = list(e)
In [10]: f
Out[10]: [1, 2, 3, 12]
40.python运行程序的两种方式 if __name__ == '__main__'
if __name__ == '__main__'的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。
第一是直接作为脚本执行,第二是import到其他的python脚本中被调用(模块重用)执行
都包含内置的变量__name__,当运行模块被执行的时候,__name__等于文件名(包含了后缀.py);
#test.py
print "first"
print __name__
if __name = "__main__"
print "second"
直接运行:first
# __main__
second
被导入运行:first
# test
如果import到其他模块中,则__name__等于模块名称(不包含后缀.py)
1).__name__可以清晰地反映一个模块在包中的层次
2).运行Python程序的两种方式
python xxx.py,直接运行xxx.py文件
python -m xxx.py,把xxx.py当做模块运行
41.类和实例动态添加方法
from types import MethodType
参数一: 要传递的函数
参数二: 需要给的对象
这样可以给实例对象添加方法
- 添加类属性
1.实例对象.未知属性
2.类名.未知属性
42.单元测试框架 unittest
Pyhon工作原理—— 核心概念:test case, testsuite, TestLoder,TextTestRunner,TextTestResult, test fixture
TestCase(测试用例): 所有测试用例的基类,它是软件 测试中最基本的组成单元。
一个test case就是一个测试用例,是一个完整的测试流程,包括测试前环境的搭建setUp,执行测试代码(run),以及测试后环境的还原(tearDown)。测试用例是一个完整的测试单元,可以对某一问题进行验证。TestSuite(测试套件):多个测试用例test case集合就是TestSuite,TestSuite可以嵌套TestSuite
TestLoder:是用来加载 TestCase到TestSuite中,其中有几个loadTestsFrom_()方法,就是从各个地方寻找TestCase,创建他们的实例,然后add到TestSuite中,再返回一个TestSuite实例
TextTestRunner:是来执行测试用例的,其中的run(test)会执行TestSuite/TestCase中的run(result)方法。
TextTestResult:测试结果会保存到TextTestResult实例中,包括运行了多少用例,成功与失败多少等信息
TestFixture:又叫测试脚手,测试代码的运行环境,指测试准备前和执行后要做的工作,包括setUp和tearDown方法
42.pyc 和 pyd文件
# .pyd文件一般是其他语言编写的python扩展模块
# .pyc
pyc是a.py中的模块在b.py中导入,生成的一个二进制文件;下次再执行a.py文件,首先会执行这个.pyc文件,如果a.py文件中的内容未更新的话,就直接读取了该.pyc文件;类似一个缓存机制
43.PEP8检测工具 pylint
1.代码编排
2.文档编排
3.空格的使用
4.注释
5.文档描述
6.命名规范
7.编码建议
Pylint 是一个 Python 工具,除了平常代码分析工具的作用之外,它提供了更多的功能:如检查一行代码的长度,变量名是否符合命名标准,一个声明过的接口是否被真正实现等等。
- 安装 pip install pylint
- 为pylint.conf的文件,该文件中的配置项都是pylint的默认配置,比较大400多行
error 错误
warning 警告
refactor
convention 规范
44.文件读写操作
使用文件的目的: 数据持久化
访问模式:
r: 只读方式
w: 写入 文件存在则覆盖,不存在则创建
a: 追加 存在就追加,不存在就新建
rb wb ab (b 二进制文件)
45.字符串格式化与format的区别
最烦人的是%它无法同时传递一个变量和元组
"hi there %s" % name
如果name恰好是(1, 2, 3),它将会抛出一个TypeError异常
format用法(基本语法是通过{}和:来代替%。format函数可以接受不限个参数,位置可以不按顺序)
46.xrange 和range有啥区别
- python3中没有xrange
- range 生成一个序列 列表
- xrange 生成器(要生成很大的数字序列的时候使用,不需要开辟大的内存空间)每次调用返回其中的一个值
- 基本上在循环的时候使用
47.timeit模块
timeit模块可以用来测试一小段Python代码的执行速度
class timeit.Timer(stmt='pass', setup='pass', timer=)
Timer是测量小段代码执行速度的类。
stmt参数是要测试的代码语句(statment);
setup参数是运行代码时需要的设置;
timer参数是一个定时器函数,与平台有关。
timeit.Timer.timeit(number=1000000)
Timer类中测试语句执行速度的对象方法。number参数是测试代码时的测试次数,默认为1000000次。方法返回执行代码的平均耗时,一个float类型的秒数。
48.字典底层原理
参考链接: https://blog.csdn.net/dotedy/article/details/50414660
它的查询复杂度是 O(1)
# 哈希表(散列表)
哈希表(也叫散列表),根据关键值对(Key-value)而直接进行访问的数据结构。它通过把key和value映射到表中一个位置来访问记录,这种查询速度非常快,更新也快。而这个映射函数叫做哈希函数,存放值的数组叫做哈希表。 哈希函数的实现方式决定了哈希表的搜索效率
key value
哈希函数 哈希表
整数数字 下标的数组空间里 余数结果当做数组的下标
1).数据添加:把key通过哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里
2).数据查询:再次使用哈希函数将key转换为对应的数组下标,并定位到数组的位置获取value
对key进行hash的时候,不同的key可能hash出来的结果是一样的,尤其是数据量增多的时候,这个问题叫做哈希冲突。如果解决这种冲突情况呢?通常的做法有两种,一种是链接法,另一种是开放寻址法,Python选择后者
# 开放寻址法
开放寻址法中,所有的元素都存放在散列表里,当产生哈希冲突时,通过一个探测函数计算出下一个候选位置,如果下一个获选位置还是有冲突,那么不断通过探测函数往下找,直到找个一个空槽来存放待插入元素
49.列表 字典之间转换
# 使用zip()函数
1、现在有两个列表,list1 = ['key1','key2','key3']和list2 = ['1','2','3'],把他们转为这样的字典:{'key1':'1','key2':'2','key3':'3'}
>>>list1 = ['key1','key2','key3']
>>>list2 = ['1','2','3']
>>>dict(zip(list1,list2))
{'key1':'1','key2':'2','key3':'3'}
2. 将嵌套列表转换为字典
>>>new_list= [['key1','value1'],['key2','value2'],['key3','value3']]
>>>dict(list)
{'key3': 'value3', 'key2': 'value2', 'key1': 'value1'}
字典转换成列表
# 字典可以直接使用list转换成列表