python面试题

1、 栈:编译器自动分配释放,存放函数的参数值,局部变量的值。函数每次每次调用,都会新建栈帧,用于局部变量和执行过程存储,等执行结束,栈帧内存被回收,同时释放相关对象。栈一般放当前所需要的数据。
2、 堆:是程序在运行时,而不是在编译时,申请一定大小的内存空间,即是动态分配内存,对其访问和一般访问没有区别(堆本质是在运行时请求操作系统动态分配给自己的内存)。一般由程序员分配释放,若程序员不放,程序结束时,可能由系统释放。
3、 在python3中列表和字典都是有序的,而在python2中,字典是无序的,如果要设置成有序的,用OrderedDict()构造一个字典。
4、 Nginx:Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。
5、 Wsgi协议:PythonWeb服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是Python应用程序或框架和Web服务器之间的一种接口,已经被广泛接受, 它已基本达成它的可移植性方面的目标。
6、 SQL性能优化的一些方法:在where和order by 条件字段使用索引,尽量不要使用or,in,not in,!=(<>)等进行查询,否则会放弃索引,另外索引不是越多越好,索引对查询效率提高的同时会降低插入和更新的效率,还有就是尽量限制查询条件来避免全表扫描,数据库字段类型越小越好,默认值不能使用NULL,数据库数据量过大时应分库分表。
7、 MySQL数据库索引原理:B+树的索引结构。
8、 B树和B+树:B+Tree有以下不同点:
每个结点的指针上限为2d而不是2d+1。
B+树的非叶子节点只包含导航信息,不包含实际的值,所有的叶子节点和相连的节点使用链表相连,便于区分查找和遍历。
B+树的内部节点不包含数据信息,因此在内存页能够存储更多的Key,B+树的叶子节点是相链的,对整个树的遍历只需遍历一次叶子节点即可。
9、 为什么使用B树(B+树):一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数
https://blog.csdn.net/waeceo/article/details/78702584
10、 MySQL索引实现:在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的。
11、 Myisam索引和Innodb存储引擎:MyISAM引擎使用B+Tree作为索引结构,叶结点的data域存放的是数据记录的地址。MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶结点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。InnoDB的辅助索引data域存储相应记录主键的值而不是地址。
12、 全局锁,乐观锁,悲观锁:
典型的冲突:
脏读:当一个事务读取其它完成一半事务的记录时,就会发生脏读取。
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。即每次拿数据的时候都认为别人会修改。
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。乐观锁不能解决脏读的问题。
乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
实现乐观锁的方式:1.使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。2.乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。
13、 Python中的全局解释器锁GIL:Python代码的执行由Python 虚拟机(也叫解释器主循环,CPython版本)来控制,Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即在任意时刻,只有一个线程在解释器中运行。对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。对于单核环境来说,全局锁机制简单,高效。容易实现对象安全访问,便于进行内存管理和编写扩展。但是同样会导致多核环境下无法实现并行,这对于多线程为基础的并发应用是一个灾难。常见的解决方案是用多进程加协程来充分发挥多核环境计算能力但并不意味着多进程是Cpython的禁区,对于IO密集型任务,线程会在发生堵塞时主动释放GIL,以便其他线程得以执行。对于计算密集型任务则采用超时处理。
如何降低GIL影响:(1)、用multiprocess替代Thread,multiprocess库的出现很大程度上是为了弥补thread库因为GIL而低效的缺陷。它完整的复制了一套thread所提供的接口方便迁移。唯一的不同就是它使用了多进程而不是多线程。每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢。它的引入会增加程序实现时线程间数据通讯和同步的困难。(2)、用其他解释器(3)用C来编写多线程扩展,以绕开解释器的限制。
14、 python中内存管理:主要有以下两个方面要讲,引用计数以及垃圾回收,Python内存池机制。
变量和对象:变量,通过变量指针引用对象,变量指针指向具体对象的内存空间,取对象的值。对象,类型已知,每个对象都包含一个头部信息(头部信息:类型标识符和引用计数器)
引用计数:在Python中,每个对象都有指向该对象的引用总数—引用计数。
垃圾回收:当Python的某个对象的引用计数降为0时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾。比如某个新建对象,被分配给某个引用,对象的引用计数变为1。如果引用被删除,对象的引用计数为0,那么该对象就可以被垃圾回收。
注意:1、垃圾回收时,Python不能进行其它的任务,频繁的垃圾回收将大大降低Python的工作效率;
  2、Python只会在特定条件下,自动启动垃圾回收(垃圾对象少就没必要回收)
   3、当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动。
内存池机制:Python中有分为大内存和小内存:(256K为界限分大小内存)1、大内存使用malloc进行分配2、小内存使用内存池进行分配3、Python的内存池(金字塔): 第3层:最上层,用户对Python对象的直接操作。第1层和第2层:内存池,有Python的接口函数PyMem_Malloc实现-----若请求分配的内存在1~256字节之间就使用内存池管理系统进行分配,调用malloc函数分配内存,但是每次只会分配一块大小为256K的大块内存,不会调用free函数释放内存,将该内存块留在内存池中以便下次使用。第0层:大内存-----若请求分配的内存大于256K,malloc函数分配内存,free函数释放内存。第-1,-2层:操作系统进行操作。
15、 TCP三次握手:1、客户端的TCP首先向服务端的TCP发送一个特殊的即SYN报文段。2、服务器收到TCP SYN报文段之后,为该TCP连接分配TCP缓存和变量,并向该客户发送SYN ACK报文段。3、客户端在收到SYN ACK报文段之后,用ACK报文段回复,可能包含数据。
16、 1、客户端向服务器发送TCP FIN报文段,等待来自服务器带确认的TCP报文段,客户处于FIN_wait1阶段。2、服务器收到FIN后,向客户发送TCP ACK报文段,客户机处于FIN_wait2阶段。服务器这时候关闭连接。3、服务器向客户端发送FIN报文段。4、客户端收到FIN,发ACK给服务器确认,同时进入Time_wait(一般30秒,1,2分钟)状态,假定Ack丢失,time_wait状态使客户重传最后的确认报文。
17、 赋值:=赋值:数据完全共享(=赋值是在内存中指向同一个对象,如果是可变(mutable)类型,比如列表,修改其中一个,另一个必定改变;如果是不可变类型(immutable),比如字符串,修改了其中一个,另一个并不会变)
18、 Python中深拷贝:数据完全不共享(复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享),深拷贝就是完完全全复制了一份,且数据不会互相影响,因为内存不共享。深拷贝是对于一个对象所有层次的拷贝(递归)
19、 浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)数字和字符串在内存当中用的也是同一块地址。字典、列表、元组等类型,它们只拷贝第一层地址。对于深拷贝,字典、列表、元组等类型,它里面嵌套多少层,就会拷贝多少层出来,但是最底层的数字和字符串地址不变。通俗的理解是:拷贝了引用,并没有拷贝内容。
20、 Python多态:是面向对象中的三个基本特征(封装,继承,多态)
封装 根据职责将属性和方法封装到一个抽象的类中
继承 实现代码的重用,相同的代码不需要重复的编写
多态 不同的 子类对象 调用相同的 父类方法,产生不同的执行结果,多态可以增加代码的灵活度,调用方只管调用,不管细节。
21、 进程和线程:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程。当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是一个线程。
进程:进程是指处于运行过程中的程序,并且具有一定的独立功能。进程是系统进行资源分配和调度的一个单位。当程序进入内存运行时,即为进程。直白地讲,进程就是应用程序的启动实例。对操作系统来讲,进程是最小的资源管理单元。
线程:线程是进程的组成部分,一个进程可以拥有多个线程,而一个线程必须拥有一个父进程。线程可以拥有自己的堆栈,自己的程序计数器和自己的局部变量,但不能拥有系统资源。它与父进程的其他线程共享该进程的所有资源。线程是最小的执行单元。
线程的特点:线程可以完成一定任务,可以和其它线程共享父进程的共享变量和部分环境,相互协作来完成任务。线程是独立运行的,其不知道进程中是否还有其他线程存在。线程的执行是抢占式的,也就是说,当前执行的线程随时可能被挂起,以便运行另一个线程。一个线程可以创建或撤销另一个线程,一个进程中的多个线程可以并发执行。线程从属于进程,是程序的实际执行者。一个进程至少包含一个主线程,也可以有更多的子线程。
22、 HTTP中GET和POST的区别:get请求无消息体,只能携带少量数据 post请求有消息体,可以携带大量数据。携带数据的方式:get请求将数据放在url地址中,post请求将数据放在消息体中,GET请求提交的数据放置在HTTP请求协议头中,而POST提交的数据则放在实体数据中; GET方式提交的数据最多只能有1024字节,而POST则没有此限制。
23、 HTTP协议的工作过程:(1)域名解析:分解出协议名、主机名、端口、对象路径等部分,得到IP地址(2)建立TCP连接,三次握手,把以上部分结合本机自己的信息,封装成一个HTTP请求数据包(3)Web浏览器向Web服务端发送HTTP请求报文(4)服务器响应HTTP请求(5)浏览器解析HTML代码,并请求HTML代码中的资源(JS,CSS,图片)(这是自动向服务器请求下载的)(6)浏览器对页面进行渲染呈现给客户(7)断开TCP连接。HTTP 1.1在继承了HTTP 1.0优点的基础上,也克服了HTTP 1.0的性能问题
24、 打开一个url,发生了什么?基本概念:我们想要打开一个网站,首先是需要往浏览器的地址的URL输入框架中输入网地址。当我敲下回车后,通过HTTP协议,将网址传送到域名解析服务器,域名解析服务器根据网址找到对应的IP主机(系统服务器)。这个过程叫request,即请求;当IP主机拿到请求后,将相应的资源返回给用户浏览器。这个过程叫response,即响应。
25、 MVC:软件的设计典范,用一种业务逻辑,数据,界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。 核心思想:解耦,让每一个模块独立的Model(模型):处理应用程序数据逻辑的部分,通常模型对象负责数据库存取数据。 View(视图):是应用程序中处理数据显示的部分,通常视图依据模型数据建立的。Controller(控制器):是应用程序处理用户交互的部分,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
在这里插入图片描述
26、 MVT:本质上与MVC模式没有什么差别,也是各组件为了保持松耦合关系,知识定义上有些许不同。
编程模式:model(模型):负责业务对象与数据库的对象(ORM)
Template(模板):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model
和Template。

在这里插入图片描述
27、 M叉树:每个节点有m个子节点和m-1个键值。每个节点中的键值按升序排列。前i个子节点中的键值都小于第i个键值。后m-1个子节点中的键值都大于第i个键值。
28、 有向图:一种数据结构。一幅有向图是由一组顶点和一组有方向的边组成的,每条有方向的边都连着有序的一对顶点。
29、 二分查找:一种效率较高的查找方法。查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。查找过程:首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。时间复杂度:O(log n)
30、 静态方法和动态方法:静态方法是在构造函数本身上定义的方法,只能通过构造函数本身调用,new出来的对象不能够调用。动态方法,也叫做实例方法,所有的实例对象都能够继承调用
31、 OSI模型:Open System Interconnet开放系统互连参考模型,由ISO定义,是一个灵活的、稳健的和可互操作的模型,不是协议,是用来了解和设计网络体系结构的。OSI模型的目的:规范不同系统的互联标准,使两个不同的系统能够较容易的通信,而不需要改变底层的硬件或软件的逻辑。OSI模型的分层:将网络分为7层,由下至上分别为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。网络双方通信时,发送方会将数据从应用层开始一层一层的封装,接收方会从物理层开始进行解封装
应用层:为应用软件提供接口,使应用程序能够使用网络服务
表示层:数据的解码和编码、数据的加密和解密、数据的压缩和解压缩
会话层:负责建立、管理和终止表示层实体之间的会话连接、在设各或节点之间提供会话控制、提供3种不同的方式来组织它们之间的通信:单工、半双工和全双工
传输层:负责建立端到端的连接,保证报文在端到端之间的传输、服务点编址、分段与重组、连接控制、流量控制、差错控制。
网络层:为网络设备提供逻辑地址(三层地址)、进行路由选择、维护路由表、负责将分组数据从源端传输到目的端
数据链路层:在不可靠的物理链路上,提供可靠的数据传输服务,把帧从一跳(结点)移动到另一跳(结点)、组帧、物理编址、流量控制、差错控制、接入控制
物理层:负责把逐个的比特从一跳(结点)移动到另一跳(结点)。
应用层:数据报文 传输层:数据段/数据报 网络层:数据包 数据链路层:数据帧 物理层:比特流
32、 MySQL中的事务:是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。一个数据库事务通常包含了一个序列的对数据库的读/写操作。数据库事务拥有以下四个特性,习惯上被称之为ACID特性。
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中
33、 线程的同步方法:1. 锁机制threading的Lock类,用该类的acquire函数进行加锁,用realease函数进行解锁,当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“同步阻塞”, 直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。2. 信号量:信号量也提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器大于0,则将其减1,如果内部计数器等于0,则会阻塞该线程,知道有线程调用了release方法将内部计数器更新到大于1位置。3. 条件判断:所谓条件变量,即这种机制是在满足了特定的条件后,线程才可以访问相关的数据。它使用Condition类来完成,由于它也可以像锁机制那样用,所以它也有acquire方法和release方法,而且它还有wait,notify,notifyAll方法。4. 同步队列:put方法和task_done方法,queue有一个未完成任务数量num,put依次num+1,task依次num-1.任务都完成时任务结束。
34、 协程:协程,又称微线程。是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。线程是系统级别的它们由操作系统调度,而协程则是程序级别的由程序根据需要自己调度。协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。在一个线程中会有很多函数,我们把这些函数称为子程序,在子程序执行过程中可以中断去执行别的子程序,而别的子程序也可以中断回来继续执行之前的子程序,这个过程就称为协程。也就是说在同一线程内一段代码在执行过程中会中断然后跳转执行别的代码,接着在之前中断的地方继续开始执行,类似与yield操作。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。协程的暂停完全由程序控制,线程的阻塞状态是由操作系统内核来进行切换。
协程的优点:
  (1)无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力)
  (2)无需原子操作锁定及同步的开销
  (3)方便切换控制流,简化编程模型
  (4)高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
协程的缺点:
  (1)无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  (2)进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值