均从网上搜集而来,非本人面经,这里做简单整理,这里侧重于机器学Python
Python迭代器,生成器
实现了iter和next方法的对象都称为迭代器。迭代器是一个有状态的对象,在调用next() 的时候返回下一个值,
迭代器的目的是为了节省内存,只有调用next方法时才返回该元素。
迭代器是一种Lasy Load的模式,只有在调用时才生成值,没有调用的时候就等待下一次调用。
生成器本质上还是一个迭代器,也是用在迭代操作中,因此它有和迭代器一样的特性,唯一的区别在于实现方式上不一样,后者更加简洁,不需要像迭代器一样实现iter和next方法,只需要使用关键字yield就可以。
实现生成器的方式:
第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator,其实就是一个tuple。
如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值
另一种实现generator的方式是。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
参考:https://www.zhihu.com/question/20829330
区别:生成器能做到迭代器能做的所有事,而且因为自动创建了iter()和next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保持程序状态的自动生成,当发生器终结时,还会自动跑出StopIterration异常。
简单谈下GIL
Python代码的执行由python虚拟机(也叫解释器主循环,CPython版本)来控制,Python在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即任意时刻,只有一个线程在解释器中运行。对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。再调用外部代码(如C/C++扩展函数)的时候,GIL讲会被锁定,直到这个函数结束为止(由于在这期间没有Python的字节码被运行,所以不会做线程切换)。
所以,虽然CPython的线程库直接封装了系统的原生线程,但CPython整体作为一个进程,同一时间只会有一个获得GIL的线程在跑,其他线程则处于等待状态。这就造成了即使在多核CPU中,多线程也只是做着分时切换而已。不过muiltprocessing的出现,已经可以让多进程的python代码编写简化到了类似多线程的程度了。
怎么解决GIL:
1、能用进程(可以并行)不用线程。
2、高效的代码(多线程执行的任务,想并行的)使用c,c++来编写
3、只要在进行耗时的IO操作的时候,能释放GIL,所以只要在IO密集型的代码里,用多线程就很合适
参考:https://blog.csdn.net/wem603947175/article/details/81742718
Python多进程实现方式与通信
方式一: os.fork()
方式二: 使用multiprocessing模块: 创建Process的实例,传入任务执行函数作为参数
方式三: 使用进程池Pool
通信实现:
Python multiprocessing 模块下的 Queue 类,提供了多个进程之间实现通信的诸多方法;
Pipe,又被称为“管道”,常用于实现 2 个进程之间的通信,这 2 个进程分别位于管道的两端。
Python内存管理机制
(1)垃圾回收
python不像C++,Java等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值。对Python语言来讲,对象的类型和内存都是在运行时确定的。这也是为什么我们称Python语言为动态类型的原因(这里我们把动态类型可以简单的归结为对变量内存地址的分配是在运行时自动判断变量类型并对变量进行赋值)。
包括标记清除,分代回收
(2)引用计数
每一个对象,都维护这一个对指向该对对象的引用的计数。而当引用计数变为0的时候就会被回收掉
(3)内存池机制
Python的内存池分为大内存和小内存:(256K为界限分大小内存)
1、大内存使用malloc进行分配 2、小内存使用内存池进行分配 3、Python的内存池(金字塔)
None False 0的区别与联系
None和False它们的主要区别是在语义上:False和True对应,它作为布尔类型用来描述逻辑中“假”这个概念;None和“存在元素”相对应,“存在元素”反过来为“不存在元素”,也就是None。这两个对象在实际使用中也应该遵守这个规则。
0仅在数字型表示中表示为False
with函数
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭/线程中锁的自动获取和释放等。
python的name和对象的blinding机制
python将赋值语句认为是一个命名操作
绑定就是将一个对象与一个名字联系起来。更确切地讲,就是增加该对象的引用计数。众所周知,C++中一大问题就是内存泄漏 — 即动态分配的内存没有能够回收,而解决这一问题的利器之一就是引用计数。python就采用了这一技术实现其垃圾回收机制。
python深浅拷贝
浅拷贝就是对引用的拷贝,深拷贝就是对对象的资源的拷贝。
浅拷贝仅仅复制了容器中元素的地址,浅拷贝是在另一块地址中创建一个新的变量或容器,但是容器内的元素的地址均是源对象的元素的地址的拷贝。也就是说新的容器中指向了旧的元素。(注意:对源对象的不可变元素进行修改,会开辟新的内存,就有新的引用,而浅拷贝是指向的修改前的引用,所以浅拷贝不变。)
深拷贝是在另一块地址中创建一个新的变量或容器,同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本
多进程和多线程
https://zhuanlan.zhihu.com/p/46368084
线程之间通过互斥锁进行通信,进程之间通过队列和管道进行通信
Python Set Dict相关
Python new init区别
new在创建对象时被调用,任务是创建对象并返回该实例对象,是一个静态方法
init是初始化对象时被调用,此时对象创建已完成,是一个实例方法
python单下划线和双下划线有什么区别
前置单下划线表示表面上私有,最好只在内部使用;后置单下划线和Python关键字区分;前置双下划线表示真正的的私有;双侧双下划线表示在类或对象某些事件触发后执行,如初始化。