Python重点基础总结-面试知识点总结2

提示:作者将用一个系列的博客,总结机器/深度学习算法工程师岗位面试中常见的一些知识点,以帮助小伙伴们更好的应对面试。本系列的内容包括如下:
系列一:机器学习相关基础知识小Tip
系列二:Python基础总结
系列三:CNN相关知识
系列四:Transformer相关知识总结
系列五:经典/热门模型介绍,及深度学习常用知识点
系列六:PyTorch相关知识点及端侧部署基础知识
注:以防再也找不到我,可以收藏博客、关注作者,查看最新内容哦(持续更新中…)

文章目录

  • 系列二:Python基础总结
    • 1. Python的垃圾回收机制?
    • 2. 线程、协程、GIL锁相关知识
    • 3. 浅拷贝和深拷贝
    • 4. Python是解释语言还是编译语言?
    • 5. Python中列表和元组的区别?
    • 6. Python中迭代器的概念?
    • 7. Python中dict(字典)的底层结构?
    • 8. 常用的深度学习框架有哪些,都是哪家公司开发的?
    • 9. Python中生成器的相关知识?
    • 10. Python中装饰器的相关知识?
    • 11. 面向对象程序设计
    • 12.链表数组的区别?
    • 13. 闭包:
    • 14. 单下划线和双下划线的区别?
    • 15. 什么是序列化(pickling)和反序列化(unpickling)?
    • 16. Python是如何进行内存管理的?
    • 17. 能够找到程序中的bug进行静态分析的工具有哪些?
    • 18. 参数是如何进行值传递或引用传递的?


系列二:Python基础总结

1. Python的垃圾回收机制?

在Python中,使用引用计数进行垃圾回收(当某对象的引用计数值为0,那么它的内存就会被立即释放掉);同时通过标记-清除算法解决容器对象可能产生的循环引用问题(标记阶段,遍历所有的对象,如果还有对象引用它,那么就标记该对象为可达;清除阶段,再次遍历对象,如果发现某个对象没有标记为可达,则就将其回收);最后,在循环引用对象的回收中,整个应用程序会被暂停,为了减少应用程序暂停的时间,Python 通过“分代回收”以空间换时间的方法提高垃圾回收效率(对象存在时间越长,越可能不是垃圾,应该越少去收集。这样在执行标记-清除算法时可以有效减小遍历的对象数,从而提高垃圾回收的速度)。

2. 线程、协程、GIL锁相关知识

1)CPU密集型也叫计算密集型,是指I/O在很短时间就可以完成,但CPU需要大量的计算和处理,特点:CPU占用率相当高。如:压缩解压缩,加密解密,正则表达式搜索。
2)I/O密集型指的是系统运作大部分的状况是CPU在等I/O(硬盘/内存)的读/写操作,CPU占用率仍然较低。如:文件处理程序,网络爬虫程序,读写数据程序。
3)多进程Process(可用multiprocessing实现)。优点:同一时刻,可以利用多核CPU并行运算(并行执行)。缺点:占用资源最多,可启动数目比线程少。适用于CPU密集型计算。一个进程可启动N个线程。
4)多线程Thread(threading模块)。优点:相比于进程,更轻量级、占用资源少。缺点:相比于进程,多线程只能并发执行(指一个时间段内,在一个CPU能运行多个程序),不能利用多个CPU(GIL);相比于协程,启动数目有限制,占用内存资源,有线程切换开销。适用于I/O密集型计算,同时运行的任务数目要求不多。一个线程可以启动N个协程。
5)多协程。优点:内存开销最少,启动协程数量最多。缺点:支持的库有限制、代码实现复杂。适用于I/O密集型计算,需要超多任务运行,但用于有库支持的场景。
补充:进程:多进程利用多核CPU完成任务,是操作系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,进程之间的通信由操作系统传递,导致通讯效率低,创建或销毁进程时系统开销大;线程:是CPU调度的最小单位,所有线程共享进程的内存空间,通讯效率高,切换开销小,但共享意味着竞争 (CPython全局解释器锁,同时只能运行一个线程,无法利用多核 CPU),在I/O阻塞的时候,解释器会释放GIL;协程:一个可以挂起的函数,协程的调度完全由用户控制,用函数切换,开销极小。
6)Python里有多线程吗?Python里的多线程是假的多线程。Python速度慢的两大原因:python属于动态类型语言边解释边执行;GIL锁无法利用多核CPU并行执行。
7)GIL(全局解释器锁):是计算机程序设计语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行。即使在多核处理器上,使用GIL的解释器也只允许同一时间执行一个线程。GIL的存在是为了解决多线程之间数据完整性和状态同步的问题,简化了python对共享资源的管理。
8)怎么规避GIL带来的限制?多线程Threading机制仍然是有用的,用于I/O密集型计算。因为在I/O期间,线程会释放GIL,实现GPU和I/O的并行,因此多线程用于I/O密集型计算依然可以大幅度提升速度。但多线程用于CPU密集型计算时,只会更加拖慢速度;使用multiprocessing的多进程机制实现并行计算,利用多核CPU优势。
9)使用线程池的优点:提升性能,因为减去了大量新建和终止线程的开销,重用了线程资源;使用场景,适合于处理突发性大量请求或需要大量线程完成任务;防御功能,能有效避免系统因创建线程过多而导致系统负荷过大相应变慢等问题;代码优势,使用线程池的语法比自己新建线程、执行线程更加简洁。

3. 浅拷贝和深拷贝

在Python中,用一个变量给另一个变量赋值,其实就是给当前内存中的对象增加一个“标签”而已。
浅拷贝是指创建一个新的对象,其内容是原对象中元素的引用(新对象与原对象共享内存中的子对象)。
深拷贝是指创建一个新的对象,然后递归的拷贝原对象所包含的子对象。深拷贝出来的对象与原对象没有任何关联。
注:浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其他对象的对象,如列表,类实例等。而对于数字、字符串等类型,没有拷贝一说,产生的都是原对象的引用。
常见的浅拷贝有:切片操作、工厂函数、对象的copy()方法,copy模块中的copy函数。深拷贝只有一种方式:copy模块中的deepcopy函数。
dict,list是可变对象。允许值发生变化,如果对变量进行append操作后, 只是改变了变量值,不会新建一个对象,变量引用的对象的地址不会变化。
str,int,tuple,float是不可变对象。不允许值发生变化,若改变了变量的值,相当于新建了一个对象,对于相同值的对象,内存中只有一个对象。

4. Python是解释语言还是编译语言?

Python是解释语言。解释语言的优点是可移植性好,缺点是运行需要解释环境,运行起来比编译语言要慢,占用的资源也要多一些,代码效率低。编译语言的优点是运行速度快,代码效率高,编译后程序不可以修改,保密性好。缺点是可移植性较差,只能在兼容的操作系统上运行。

5. Python中列表和元组的区别?

1)列表是可变的,在创建之后可以对其进行任意的修改。2)元组是不可变的,元组一旦创建,便不能对其进行更改,可以把元组当作一个只读版本的列表。3)元组无法复制。4)Python将较大的内存块分配给元组,较小内存块分配给列表。与列表相比,元组占用的内存更小。当拥有大量元素时,元组比列表快。

6. Python中迭代器的概念?

可迭代对象是迭代器、生成器和装饰器的基础。简单来说,可以使用for来循环遍历的对象就是可迭代对象(比如常见的list、set和dict)。所有实现了__iter__和__next__两个方法的对象,都是迭代器。可以通过 iter(object) 来返回一个迭代器。迭代器是带状态的对象,它会记录当前迭代所在的位置,以方便下次迭代的时候获取正确的元素。__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出Stop Iteration异常。
Python的for循环本质上就是通过将可迭代对象转换为迭代器,然后不断调用next()函数实现的。这样可以节省内存,因为迭代器只有在我们调用 next() 才会实际计算下一个值。

7. Python中dict(字典)的底层结构?

Python中的dict(字典)为了支持快速查找使用了哈希表作为底层结构,哈希表平均查找时间复杂度为O(1)。 CPython解释器使用二次探查解决哈希冲突问题。

8. 常用的深度学习框架有哪些,都是哪家公司开发的?

1)PyTorch:Facebook 2)TensorFlow:Google 3)Keras:Google 4)Caffe:UC Berkeley 6)PaddlePaddle:百度

9. Python中生成器的相关知识?

我们创建列表的时候,受到内存限制,不可能全部给它一次枚举出来。Python常用的列表生成式有一个致命的缺点就是定义即生成,非常的浪费空间和效率。如果列表元素可以按照某种算法推算出来,那我们可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器,可以像使用迭代器一样使用。要创建一个生成器,最简单的方法是改造列表生成式(将列表生成式中的[]改成(),列表就变为了)。还有一个方法是生成器函数,通过def定义,然后使用yield来支持迭代器协议,比迭代器写起来更简单。python是支持协程的,也就是微线程,就是通过生成器来实现的。配合生成器我们可以自定义函数的调用层次关系从而自己来调度线程。

10. Python中装饰器的相关知识?

装饰器允许通过将现有函数传递给装饰器,从而向现有函数添加一些额外的功能,该装饰器将执行现有函数的功能和添加的额外功能。装饰器本质上还是一个函数,它可以让已有的函数不做任何改动的情况下增加功能。
python的@property是python的一种装饰器,是用来修饰方法的。
作用:可以使用@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性;可以与所定义的属性配合使用,这样可以防止属性被修改。

11. 面向对象程序设计

面向对象程序设计(Object-oriented programming,OOP)有三大特征 ——封装、继承、多态。
封装:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或对象操作,对不可信的进行信息隐藏。
继承:基类(父类)—> 派生类(子类);继承允许子类使用父类的所有方法和属性。
多态:不同的对象调用同一个接口,表现出不同的状态,称为多态。多态是以封装和继承为基础的。
在类括号里写多个父类名,为多继承。但要注意继承顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左到右搜索,即方法在子类中未找到,从左到右查找父类中是否包含方法;若父类方法功能不能满足要求,可以在子类中写父类方法。使用super(子类名,子类对象).func()调用父类方法;类内属性加两个下划线开头,表示属性私有,不能在类外被直接使用或者访问。

12.链表数组的区别?

数组:(1)数组在内存中连续,数组增删时需要移动其它元素,数组在内存中顺序存储,可通过下标访问,访问效率高,但增删效率低。 (2)使用数组之前,必须事先固定数组长度,不支持动态改变数组大小;(3) 数组元素增加时,有可能会数组越界;数组元素减少时,会造成内存浪费;(4)数组从栈上分配内存。 链表:1)链表采用动态内存分配的方式,在内存中不连续 (2)支持动态增加或者删除元素 (3)链表从堆上分配内存,链表访问效率低,如果想要访问某个元素,需要从头遍历,增删效率高。(4)只要可以申请得到链表空间,链表就无越界风险

13. 闭包:

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。闭包具有提高代码复用性的作用。

14. 单下划线和双下划线的区别?

单下划线:用来指定变量私有,只有类对象和子类对象能够访问,外部访问需要接口,不能用import 导入。
双下划线:私有成员,只有类对象自己能够访问,子类对象也无法访问。
foo: python内部的名字,用来区别其他用户自定义的命名,以防止冲突
init:构造函数,在生成对象时调用

15. 什么是序列化(pickling)和反序列化(unpickling)?

序列化:将在内存中的变量转为可存储或传输的过程。应用JSON传输,序列化为统一格式json。 反序列化:与序列化的过程相反
Pickle模块允许我们将Python对象转换成一个string表示的信息,并且可以使用dump函数将其保存到一个文件中去,这样的过程称为序列化。而使用文件中保存的对象信息重构Python对象的过程称为反序列化。

16. Python是如何进行内存管理的?

Python内存空间是以Python私有堆的形式进行管理的。所有的Python对象和数据结构都存放在一个私有堆中。解释器可以访问私有堆,而程序员不可以。
将Python堆空间中的内存分配给Python对象的工作是由Python内存管理器完成的。而内核API则会提供给程序员一些相关的工具来完成涉及到内存的编码工作。
Python还内置垃圾回收器,从而进行回收释放内存到堆空间。

17. 能够找到程序中的bug进行静态分析的工具有哪些?

PyChecker是一种能够发现Python源代码中的bug并对其中的代码风格和复杂度进行警告的静态分析工具。另外一种工具是Pylint,它能够验证模块是否满足编码标准。

18. 参数是如何进行值传递或引用传递的?

python中一切皆对象,参数皆引用;如果函数收到的是一个可变对象(比如列表、字典)的引用,则可修改对象的原始值(相当于“引用传递”方式);如果函数收到的是一个不可变对象(比如数字、字符、元组),就不能直接修改原始对象指向的值(相当于“值传递”方式)。


注:这些知识点是作者在备战秋招的时候,根据一些零碎的博客做的总结(写作目的:主要用于各位小伙伴们的知识交流,如若侵权,则会及时删除)。

*以防再也找不到我,可以收藏博客、关注作者,查看后续系列内容哦(持续更新中…)

你可能感兴趣的:(python,面试,开发语言)