美文网首页
测试工程师面试题-Python基础面试题

测试工程师面试题-Python基础面试题

作者: 小喜_ww | 来源:发表于2023-12-12 15:20 被阅读0次

    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:newinit的区别

    创建一个新实例时调用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 = oldsize
    2,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个写线程执行,并发性能的提升是显而易见的。

    相关文章

      网友评论

          本文标题:测试工程师面试题-Python基础面试题

          本文链接:https://www.haomeiwen.com/subject/vrqybktx.html