作为程序员,你可能或多或少经历过一些技术面试,有的是编程语言本身的问题,有的是工程相关的问题。作者曾接受过采访或接受过他人采访。今天我们就总结一下面试Python程序员时经常被问到的9个问题。收藏供大家参考。1:Python列表、元组和字典有什么区别?这个问题应该经常被问到,我们在这里详细解释一下。列表(List),Python的列表其实是一个动态数组,存储在一个连续的内存块中,随机访问的复杂度是O(1),当插入和删除元素时会引起内存块的移动,时间复杂度是O(n).同时,它是一个可变对象。当我们为列表赋值时,我们只得到它的内存地址。如果我们需要将列表的所有内容复制到另一个变量中,就需要使用copy(浅拷贝)和deepcopy(深度拷贝)。元组(Tuple),Python的元组是一种不可变的数据结构,本质上是一个数组。因为它是一个不可变对象,所以Tuple在创建的时候长度是恒定的,所以我们不能向它添加和删除元素。但是,元组中包含的对象是可变的。当我们将一个包含元组的变量赋值给另一个变量时,实际上是在内存中重新申请了一块内存空间,用于创建一个新的元组。字典(Dict),Python的字典是一个哈希表,一种根据键值对(Key,Value)直接访问的数据结构。哈希函数这里就不多分析了,大家可以自行理解。如果字典产生哈希冲突,也就是Key遇到重复的时候。Python会通过开放寻址的方式计算出下一个候选位置,反复测试保证生成的哈希值不会冲突。字典和列表一样,也是可变对象。Copy(浅拷贝)和deepcopy(深拷贝)也需要复制内容。2:如何倒序输出一个字符串或数字?字符串倒序,我们可以使用Python切片来倒序字符串,参考如下代码:str1="风吹万里,吹过玉门关"print(str1[::-1])slice的参数格式:[start_index:stop_index:step]如果我们不填写slice的起始和结束位置参数,默认是取字符串的全部内容。当step参数(stepsize)为负数时,字符串会自动从右往左取值,-1表示按顺序取值,那么自然是倒序了。我们也可以通过切片的原理,倒序输出数字。对于正整数number=10002new_number=int(str(number)[::-1])对于负整数number=-10002new_number=int('-{0}'.format(str(abs(number))[::-1]))3:谈谈Python的内存管理机制Python有一个内置的垃圾回收机制,而引用计数就是这个机制的一部分。在Pyhton源码中,Py_INCREF(op)和Py_DECREF(op)这两个宏实际上是用来增减引用计数的。当一个对象被创建、赋值、传参,以及函数返回前,它的引用计数值(ob_refcnt)可能会加1(INC),一直累加。当对象变量失去作用域时,引用计数的值减1(DEC)。当对象的引用计数减少到0(ob_refcnt为0)时,Py_DECREF(op)调用对象“析构函数”(del)将其从内存中释放。4:什么是Session、Cookie、Token?Session是一个概念,信息保存在服务器端。Cookie是Session的一种实现,信息保存在客户端(浏览器)。由于HTTP协议的无状态特性,我们需要在浏览器和服务器之间建立一个凭证来识别用户的身份和详细信息。此凭据可以是Cookie或Token。当用户登录成功后,我们可以用他们的身份凭证在服务器端生成一个Session信息,保存在文件、数据库或内存中。通常,Session会有一个Sessionid。因为在服务器端访问session信息需要sessionid,所以一般情况下,我们将sessionid存储在cookie中。Cookie信息其实就是在用户登录生成Session信息后,将Sessionid或其他附加信息返回给客户端,客户端将其保存在本地文件中。当浏览器向服务器发起请求时,会通过cookie中的Sessionid访问服务器,服务器根据Sessionid查找存储的Session信息。如果能够查到信息且内容正确,则认为访问有效。除了存储SessionID,cookies还可以存储其他非敏感信息(如用户昵称、头像等),提供给浏览器直接使用,而不是每次都从服务器获取。关于Token,其实更多的是在基于RESTAPI的服务中使用。它的认证机制是当用户登录时,服务端计算出一个Token信息,存储在服务端,返回给客户端。内容通常包括用户id、当前时间戳、签名等信息。Token一般保存在客户端的localStorage、cookie或者sessionStorage中。它通常存储在服务器上的数据库中。当client再次请求server时,会在本地获取Token信息,放在headers中。当服务端收到请求后,会自动去headers中获取Token进行分析,以识别用户。5:GET和POST的区别和作用是什么?GET和POST在本质上没有区别,HTTP协议也没有规定GET和POST传输数据长度的限制。服务器端可能存在的唯一限制是服务器程序和浏览器。通常在Nginx或者各种WebServer服务程序中,对GET和POST传输的最大长度都有限制。GET提交的数据长度限制通常取决于浏览器,每个浏览器的限制是不同的。在HTTP协议中,在大多数WebServer中,使用的方法和数据如何传输实际上没有关系。GET和POST提交的数据其实都在BODY区。我们可以通过GET或POST传输文件。之所以通常定义GET获取数据,POST提交数据,是因为GET请求是幂等的,而POST请求不是。幂等性意味着对资源的一个和多个请求应该具有相同的副作用。简单来说,这意味着对同一个URL的多个请求应该返回相同的结果。基于幂等性原则,当我们使用GET方式对数据进行增删改查时,会产生副作用,因为GET会在网络不好的时候自动尝试重试,增加了重复数据操作的风险。用它来获取数据就没有这样的风险,因为即使我们请求一个资源100万次,它仍然不会改变。这个问题要看面试官的技术水平。如果面试官愿意和你深入交谈,那么你可以这样回答。如果面试官自己心里有一些标准答案,建议只回答GET获取数据,POST提交数据。此外,DELETE方法实际上是幂等的。即使删除100万次,数据也只会被删除一次。6:什么是Python装饰器。Python的装饰器本质上也是一个函数。它的目的是让其他函数可以添加与装饰器函数相关的功能,而不用做太多的代码改动。我们先来看看装饰器的实现和应用。打开UC浏览器查看更多精彩图片上面我们实现了一个极简的Python装饰器,在fun1函数启动和结束时打印日志。通过这个例子,我们可以发现,其实Python装饰器简化了调用代码,如果不使用装饰器,上面的代码可以这样写。上面的代码会通过log函数显式调用func1函数,不易理解,而且还破坏了代码调用的顺序,不够优雅。如果我需要在fun1前面加10多个装饰器,那么这个调用关系就要写十多次,这在阅读理解上基本上是一场灾难。Python装饰器通常用于但不限于以下场合。日志打印、性能测试、数据库事务处理、权限校验、缓存处理。总结一下,Pyhton装饰器的用处就是让我们能够更好的复用代码,在实现相同功能的代码时,采用更符合人类理解的代码结构。Python的装饰器其实就是JAVA语言的AOP编程(面向切片)。7:Python的全局锁、进程、线程、协程的概念Python的全局锁是保证线程安全的一种折衷。简单的说,无论CPU有多少核,同一时间都只能运行一个线程。对于IO密集型计算,多线程勉强可以用。如果是CPU密集型,那么Python的多线程就几乎没用了。如果你想利用多核CPU,你可以使用进程。Pyhton中的multiprocessing模块处理了这个问题。每个计算任务都会有一个独立的Python进程,让任务运行在独立的解释器环境中,提高计算效率。协程的概念是线程和进程在CPU用户态和内核态之间切换时会产生大量的性能开销。在这种情况下,协程或者微线程的概念应运而生。Python3.5之后,使用async/await关键字来处理协程。它的优点是:没有线程间切换的开销。没有线程锁机制,因为只有一个线程,没有共享变量的锁,进一步提高了效率。8:列表理解和字典理解listcomprehensionlist1=[iforiinrange(5)]字典理解dict1={k:vfork,vindict.items()}setcomprehensionset1={x*2forxin[1,2]}列表推导、字典推导、集合推导都是Python的特性,而字典推导是Python2.7之后才有的。这三种推导方式的作用是通过已有的数据序列构造出另一种新的数据序列结构,从代码可读性和收敛性的角度来说是必要的,避免代码写法复杂繁琐。9:生成器构造Generatorx=(iforiinrange(10))Outputx
