问题列表
- 列表和元组的区别?
- 列表和字典有什么区别?
- 列表去重方法
- 字典的原理?
- 什么是lambda函数?它有什么好处?
- super 是干什么用的?为什么要使用 super?
- *args和**kwargs的区别?
- 对装饰器的了解及应用场景?
- 解释下生成器、迭代器
- Python内存管理?
- 介绍一下Python拷贝?
- 谈下python的GIL
- 你对python面向对象有什么概念?能举一个测试工作中用到的面向对象场景吗?
列表和元组的区别?
- 列表是可变的并且可以重新设定长度
- 元组是不可变的,并且长度也是一旦创建就无法改变
- 元组与列表的声明不同
- 元组比列表的访问和处理速度更快
- 元组可以在映射中当做“键”使用,而列表不行
列表和字典有什么区别?
- 获取元素的方式不同。列表通过索引值获取,字典通过键获取。
- 数据结构和算法不同。字典是 hash 算法,查询的速度特别快。
- 占用的内存不同。
列表去重方法
- 使用内置set方法来去重
my_list = [2, 1, 4, 5, 2, 5, 2] new_list = list(set(my_list)) print(new_list)
- 列表进行遍历的方式
my_list = [2, 1, 4, 5, 2, 5, 2] new_list = list() for ele in my_list: if ele not in new_list: new_list.append(ele)
- 使用keys()方法
my_list = [6, 2, 1, 4, 5, 2, 5, 2] new_list = list({}.fromkeys(my_list).keys())
- 使用sorted函数来去重
my_list = [6, 2, 1, 4, 5, 2, 5, 2] new_list = sorted(set(my_list), key=my_list.index)
字典的原理?
- 字典是使用hash表来实现key-value之间的映射和存储的数据结构,hash函数设计的好坏影响着数据的查找访问效率。
- 字典是通过哈希表实现的,字典也被称为哈希数组。
- 哈希函数的目的是使键均匀地分布在数组中,并且可以在内存中以O(1)的时间复杂度进行寻址,从而实现快速查找和修改。
- 哈希表中哈希函数的设计困难在于将数据均匀分布在哈希表中,从而尽量减少哈希碰撞和冲突。
什么是lambda函数?它有什么好处?
- lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的匿名函数
好处
- Lambda表达式非常好用,可以让代码简单、简洁,很适合需要完成一项功能
- 匿名函数,一般用来给 filter, map 这样的函数式编程使用
- 表达式lambda函数默认返回表达式的值,你也可以将其赋值给一个变量
- lambda函数可以接收任意个参数,包括可选参数,但是表达式只有一个
super 是干什么用的?为什么要使用 super?
- super 用于继承父类的方法、属性
- 使用 super 可以提高代码的复用性、可维护性。修改代码时,只需修改父类即可
*args和**kwargs的区别?
- *args 和 **kwargs 都代表 1个 或 多个 参数的意思
- *args 传入tuple 类型的无名参数
- **kwargs 传入的参数是 dict 类型
- args、**kwargs参数的位置必args在**kwargs之前
对装饰器的了解及应用场景?
- 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象,实现原理使用了闭包。
应用场景
- 插入日志
- 性能测试
- 事务处理
- 缓存
- 权限校验
解释下生成器、迭代器
- 迭代器
迭代器 (iterator): 如果一个对象同时有__iter__()和__next__()魔术方法的话,这个对象就可以称为是迭代器。iter()的作用是可以让for循环遍历。而__next__()方法是让对象可以通过 next(实例对象) 的方式访问下一个元素,通常从序列第一个元素开始访问,直到所有的元素都被访问才结束。- 迭代器是用来访问集合元素的一种方式
- 迭代器对象从集合的第一个元素开始访问,直到结束,迭代器只会前进不会后退
- 迭代器有2个基本方法:iter(),next()
- 字符串,列表,元组都可用于创建迭代器
- 生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator- 使用了yield的函数被称为生成器
- 生成器是一个返回迭代器的函数,只能用于迭代操作。所以调用一个迭代器函数,返回的是一个迭代器对象
- 调用生成器函数时,每次遇到yield时,函数会保存当前运行的参数的信息,并返回yield的值,下一次调用next()方法时从上次保留的位置继续运行
Python内存管理?
-
对象的引用计数机制
Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
引用计数增加的情况:- 一个对象分配一个新名称
- 将其放入一个容器中(如列表、元组或字典)
引用计数减少的情况:
- 使用del语句对对象别名显示的销毁
- 引用超出作用域或被重新赋值
sys.getrefcount( )函数可以获得对象的当前引用计数
多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存 -
垃圾回收
- 当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
- 当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们
-
内存池机制
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。- Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放
- Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。
- 对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数
介绍一下Python拷贝?
- 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。
- 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象
谈下python的GIL
GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。
多进程中因为每个进程都能被系统分配资源,相当于每个进程有了一个python解释器,所以多进程可以实现多个进程的同时运行,缺点是进程系统资源开销大
你对python面向对象有什么概念?能举一个测试工作中用到的面向对象场景吗?
概念:
- 面向对象是一种编程思想
- 面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来
- 面向对象编程可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容
优缺点:主要就是面向对象的优缺点
- 优点:面向对象编程可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容
- 缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果
应用场景
- 因为面向对象主要基于类的实现,所以在程序里面使用了类都是面向对象的应用
- 例子:
- 我们操作数据库,封装的数据库类,包含数据库的增删改查
- UI自动化里面,PO思想也是面向对象的实际应用
以上内容纯属个人理解,如有不足,欢迎各位大神指正,转载请注明出处!
如果觉得文章不错,欢迎关注微信公众号,微信公众号定期推送相关测试技术文章