Q:pytest失败重试
@pytest.mark.flaky(reruns=1)
pytest test_se.py --reruns 2 --reruns-delay=2
#失败重跑2次,在每次开跑前会等待2s
Q:pytest并发
pytest-xdist支持并发执行
Q:flask原理
在run.py文件中,定义了项目启动的入口函数,启动端口,Flask使用的底层WSGI库,进行路由分发
在Flask中,浏览器发送一个请求的流程后,WGSI服务器接收浏览器的HTTP请求、向浏览器发送HTTP应答,然后通过调用WSGI应用程序,针对HTTP请求的具体处理逻辑由哪个业务逻辑函数来处理,然后在函数中进行操作,取得所需的数据。再将取得的数据传给相应的模板文件中,由Jinja2负责渲染得到HTTP响应内容,即HTTP响应的HTML文件,然后由WGSI服务器返回响应内容
Q:logging模块-等级
FATAL:致命错误
CRITICAL:特别糟糕的事情,如内存耗尽、磁盘空间为空,一般很少使用
ERROR:发生错误时,如IO操作失败或者连接问题
WARNING:发生很重要的事件,但是并不是错误时,如用户登录密码错误
INFO:处理请求或者状态变化等日常事务
DEBUG:调试过程中使用DEBUG等级,如算法中每个循环的中间状态
Q:pytest参数化
通过装饰器@pytest.mark.parametrize来实现
Q:json.dumps()和dump()、json.loads()和load()的区别
主要区别:
1、dump(),load() 处理的是json文件
2、dumps(),loads() 处理的是字符串
Q:正则表达式中-贪婪模式和非贪婪模式的区别
贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配. ‘.’
而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。 ‘.?’
Q:readline和readlines区别
read()方法:
1、读取整个文件,将文件内容放到一个字符串变量中
2、如果文件大于可用内存,不可能使用这种处理
readline()方法:
1、readline()每次读取一行,比readlines()慢得多
2、readline()返回的是一个字符串对象,保存当前行的内容
readlines()方法:
1、一次性读取整个文件
2、自动将文件内容分析成一个行的列表
Q:Python ⾥ is 和 == 的区别?
https://www.cnblogs.com/wangkun122/p/9082088.html
Python中对象包含的三个基本要素,分别是:id(身份标识)、type(数据类型)和value(值)。
is 和 == 都是对对象进行比较判断作用的,但对对象比较判断的内容并不相同。
下面来看看具体区别:
is 被叫做同一性运算符,这个运算符比较判断的是对象间的唯一身份标识,也就是id是否相同
== 是python标准操作符中的比较操作符,用来比较判断两个对象的value(值)是否相等
Q:python中列表和元组的区别
相同点:
List 与 tuple 都是序列类型的容器对象,可以存放任何类型的数据、支持切片、迭代等操作
不同点:
1、最重要的一点是tuple是不可变类型,大小固定,而 list 是可变类型、数据可以动态变化。
2、tuple比列表操作速度快
3、tuple对数据"写保护"
4、tuple可用于字符串格式化中
5、tuple可作为字典的key
Dict底层使用的哈希表,为了支持快速查找使用了哈希表作为底层结构,哈希表平均查找时间复杂度为O(1)。
Q:python中遍历list和dict哪个速度更快?
遍历dict会更快,这种效率的差异是由于二者的存储结构不同.
list查找时,需要遍历,这与其线性的存储结构有关,因此数据量大时,就显得慢了.且处于list中越靠后,查询越慢;不在list中,更需遍历所有元素,速度最慢.
而dict默认采用hash_map存储,即使数据量很大,查找也非常快速.
Q:args和*kwargs区别
*args是可变参数,args接收的是一个tuple;
定义:可变参数就是传入的参数个数是可变的,可以是0个,1个,2个,……很多个。
**kw是关键字参数,kw接收的是一个dict。
定义:关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。在调用函数时,可以只传入必选参数。
Q:深拷⻉浅拷⻉的区别是什么?
浅拷贝会创建一个新的对象,但是,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址);
深拷贝也会创建一个新的对象,但是,对于对象中的元素,深拷贝都会重新生成一份,而不是简单的使用原始元素的引用(内存地址)
- Python中对象的赋值都是进行对象引用(内存地址)传递
- 使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.
- 如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝
- 对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有被拷贝一说
- 如果元祖变量只包含原子类型对象,则不能深拷贝,看下面的例子
Q:@classmethod 和 @staticmethod 的区别,以及分别运⽤在哪些使用场景?
https://blog.csdn.net/kaever/article/details/105808768
声明时:
@classmethod 的第一个参数为类本身,正如实例方法的第一个参数为对象本身(self)
@staticmethod 的第一个参数不需要传入self,故在@staticmethod无法访问类和对象的数据的。
调用时:都可以使用类名直接调用,也可以用实例对象调用。
总结
1.使用@staticmethod目的之一是为了增加可读性,不需要参数self的方法都可以加上@staticmethod增加可读性,因为,这个方法是类级别的,在调用时要使用类名。
2.使用@classmethod是为了处理一些init处理不了的赋值问题(一般是参数不对应),你可以当成有第二,第三个init方法,当然它要通过类名显示调用。
Q:lambda 函数怎么⽤?
https://www.cnblogs.com/huangbiquan/p/8030298.html
lambda语句构建的其实是一个函数对象。匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
lambda优点:
1、使用Python写一些执行脚本时,使用lambda可以省去定义函数的过程,让代码更加精简。
2、对于一些抽象的,不会别的地方再复用的函数,使用lambda不需要考虑命名的问题。
3、使用lambda在某些时候让代码更容易理解。
f=lambda x,n:x ** n
Q:什么是可迭代对象?可迭代对象的原理是什么?
Python中可迭代对象(Iterable)并不是指某种具体的数据类型,它是指存储了元素的一个容器对象,且容器中的元素可以通过iter( )方法或getitem( )方法访问。
iter方法的作用是让对象可以用for … in循环遍历,getitem( )方法是让对象可以通过“实例名[index]”的方式访问实例中的元素。老猿认为这两个方法的目的是Python实现一个通用的外部可以访问可迭代对象内部数据的接口。
一个可迭代对象是不能独立进行迭代的,Python中,迭代是通过for … in来完成的。凡是可迭代对象都可以直接用for… in…循环访问,这个语句其实做了两件事:第一件事是调用iter()获得一个可迭代器,第二件事是循环调用next()。
常见的可迭代对象包括:
a) 集合数据类型,如list、tuple、dict、set、str等;
b) 生成器(generator),包括生成器和带yield的生成器函数(generator function).
如何判断一个对象是可迭代对象呢?可以通过collections模块的Iterable类型判断,具体判断方法如下:
from collections import Iterable #导入Iterable 模块
isinstance(变量, Iterable) #判断一个变量是否为可迭代对象返回True表明是可迭代对象
Q:在Python中使用过什么代码检查工具?
1)PyFlakes:静态检查Python代码逻辑错误的工具。
2)Pep8: 静态检查PEP8编码风格的工具。
3)NedBatchelder’s McCabe script:静态分析Python代码复杂度的工具。
Python代码分析工具:PyChecker、Pylint
Q:new和init的区别
创建一个新实例时调用new,初始化一个实例时用init,这是它们最本质的区别。
new方法会返回所构造的对象,init则不会.new函数必须以cls作为第一个参数,而init则以self作为其第一个参数.
Q:函数装饰器的作用
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。有了装饰器,就可以抽离出大量与函数功能本身无关的雷同代码并继续重用
Q:如何捕获异常,常用的异常机制
如果我们没有对异常进行任何预防,那么在程序执行的过程中发生异常,就会中断程序,调用python默认的异常处理器,并在终端输出异常信息。
Try…except…finally语句:当try语句执行时发生异常,回到try语句层,寻找后面是否有except语句。找到except语句后,会调用这个自定义的异常处理器。except将异常处理完毕后,程序继续往下执行。finally语句表示,无论异常发生与否,finally中的语句都要执行。
Assert语句:判断assert后面紧跟的语句是True还是False,如果是True则继续执行print,如果是False则中断程序,调用默认的异常处理器,同时输出assert语句逗号后面的提示信息。
With语句:如果with语句或语句块中发生异常,会调用默认的异常处理器处理,但文件还是会正常关闭。
Q:Python的作用域以及Python搜索变量的顺序
Python作用域简单说就是一个变量的命名空间,代码中变量被赋值的位置,就决定了哪些范围的对象可以访问这个变量,这个范围就是变量的作用域。
在python中,只有模块,类,函数才会引入新的作用域。
Python的变量名解析机制也称为LEGB法则:本地作用域->全局/模块作用域->内置作用域
Q:Python 变量的创建与消亡过程,垃圾回收机制。
https://blog.csdn.net/reasonyuanrobot/article/details/83793511
python内部使用引用计数,来保持追踪内存中的对象。
python内部记录了对象有多少引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不在需要时,这个对象的引用计数为0时,它被垃圾回收,然后清除其在内存的空间。当然除了引用计数为0的会被清除,还有一种情况也会被垃圾收集器清掉:当两个对象相互引用时,他们本身其他的引用已经为0了.
垃圾回收机制还有一个 循环垃圾回收器 ,确保释放循环引用对象。
在python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象一级的内存池机制。
这就意味着python在运行期间会大量的执行malloc(动态内存分配)和free(释放内存)的操作,频繁的在用户态和核心态之间进行切换,这将严重影响python的执行效率。为了加速python的执行效率,python引入一个内存池机制,用于管理对小块内存的申请和释放。
Q:Python如何进行内存管理
1)对象的引用计数机制
Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
引用计数增加的情况:
一个对象分配一个新名称
将其放入一个容器中(如列表、元组或字典)
引用计数减少的情况:
使用del语句对对象别名显示的销毁
引用超出作用域或被重新赋值
2)垃圾回收
当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
3)内存池机制
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
Pymalloc机制:为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
Q:为什么会出现死锁?
所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。
产生死锁的原因可归结为如下两点:
- a. 竞争资源
- b. 进程间推进顺序非法
Q:多线程的实现方式?线程和进程的区别?
线程是指进程内的一个执行单元,也是进程内的可调度实体.
进程是资源分配的最小单位,线程是程序执行的最小单位.
与进程的区别:
(1) 地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;
(2) 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
(3) 线程是处理器调度的基本单位,但进程不是
(4) 二者均可并发执行
python主要是通过thread和threading这两个模块来实现多线程支持。python的thread模块是比较底层的模块,python的threading模块是对thread做了一些封装,可以更加方便的被使用。
threading.Thread(Target=executable Method)
Q:如何结束一个进程?
(1)调用terminate方法。
(2)使用subProcess模块的Popen方法。
Q:什么是虚拟内存?
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存(例如RAM)的使用也更有效率。
Q:多态怎么体现的
多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。综上可以说,多态性是 : 一个接口,多种实现
多态性的好处:
增加了程序的灵活性,以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(obj)
增加了程序额可扩展性,通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(obj)去调用
Q:面向对象里面重写和重载的区别
多态:允许不同类的对象对同一消息做出响应。即同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。这也意味着一个对象有着多重特征,可以在特定的情况下,表现不同的状态,从而对应着不同的属性和方法。
多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
方法重载(Overloading):一个类中有多个方法(函数),它们具有相同的名字,但方法传递的参数或参数的个数不同,返回类型可以相同。
方法重写(Override): 子类对父类的方法做一定的修改,返回值和形参都不能改变。又称方法覆盖。
虚拟内存有以下两个优点:
1.虚拟内存地址空间是连续的,没有碎片
2.虚拟内存的最大空间就是cup的最大寻址空间,不受内存大小的限制,能提供比内存更大的地址空间
Q:找到100亿个URL中重复的URL?
由于数据量很大,16*100亿B = 1600亿Byte,约等于160G。10亿Byte约等于1G大小。这种题目都是有数据资源限制的。如果说机器内存只有16G,那我们可以通过Hash算法,把原始大文件,hash分成10个小文件。或者hash成更多更小的文件,以满足机器资源限制。因为通过hash,我们可以保证相同的URL一定可以被分配到相同的小文件上。然后从每个文件里统计计算每个URL出现就可以了,可以使用hashMap存放统计结果。
Q:python第三方的库有哪些
Faker: 创建伪数据
Pandas: Python数据分析高层次应用库
Pytest: 单元测试框架
Flask: web微框架
PyYAML:解析yaml文件
Simplejson:解析json文件
Requests:Apache2 Licensed开源协议的HTTP库
Beautiful Soup: HTML和XML的解析库
Re: 正则表达式解析和处理功能库
Q:HashMap和HashTable,以及ConCurrentHashMap,区别原理?
HashTable
底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
初始size为11,扩容:newsize = olesize2+1
计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length
HashMap
底层数组+链表实现,可以存储null键和null值,线程不安全
初始size为16,扩容:newsize = oldsize2,size一定为2的n次幂
扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入.
插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
计算index方法:index = hash & (tab.length – 1)
ConcurrentHashMap
底层采用分段的数组+链表实现,线程安全
通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容
ConcurrentHashMap提供了与Hashtable和SynchronizedMap不同的锁机制。Hashtable中采用的锁机制是一次锁住整个hash表,从而在同一时刻只能由一个线程对其进行操作;而ConcurrentHashMap中则是一次锁住一个桶。
ConcurrentHashMap默认将hash表分为16个桶,诸如get、put、remove等常用操作只锁住当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。