python面试题库_v1.0
又是一年春节后,又到了程序猿跳槽,入职的季节了,在此分享一些python面试题,以供刚刚入坑的新猴参考。闲话少说,开始刷题。
1.什么是python?(作为自己吃饭的东西,怎么能不知道python是什么呢)
可以尝试从以下几个方面来谈:
(1).Python是一种解释型语言,python代码在运行之前不要编译。Python解释器会将源代码转换成中间语言,之后再翻译成机器码再执行。
(2).Python是动态类型语言,在声明变量时,不需要说明变量的类型。
a = "零_WYF"
b = 1
c = 3.1415926
d = True
(3).Python适合面向对象的编程,因为它支持通过组合与继承的方式定义类。
(4).在Python语言中,函数是第一类对象。
(5).Python代码编写快,但是运行速度比编译语言通常要慢。(这个缺点在当今硬件处理速度越来越快的今天,又算得了什么呢)
(6).Python用途广泛,程序员可以专注于算法和数据结构的设计,而不用处理底层的细节。
2.什么是Python的自省?
python自省是python具有的一种能力,是面向对象的语言所写的程序在运行时,所能知道对象的类型。简单来说就是运行时能够获得对象的类型。比如type(),dir(),getattr(),hasattr(),isinstance()。
3.什么是PEP-8?
PEP-8是一种编程规范。
作为一名python程序员一定要知道这个规范,因为缩进是python的一大特点,对于每一个段落(level)的缩进,pep-8给出的规范是4 spaces。有的编辑器默认是8 spaces的,建议修改一下。
其主要内容包括代码编排、文档编排、空格的使用、注释、文档描述、命名规范、编码建议等。
知道这些便可,有兴趣可以详细了解一下,有助于自己养成良好的编程规范,写出一手漂亮的代码。
4.什么是pickling和unpickling?
在文件中,字符串可以很方便的读取写入,数字可能稍微麻烦一些,因为read()方法只返回字符串,我们还需要将其传给int()这样的函数,使其将如"1994"的字符串转为数字1945.但是,如果要半寸更复杂的数据类型,如列表,字典,或者类的实例,那么就会更复杂了。
为了让用户在平常的编程和测试时保存复杂的数据类型,python提供了标准模块,称为pickle.这个模块可以将几乎任何的python对象(甚至是python的代码),转换为字符串表示,这个过程称为pickling.而要从里面重新构造回原来的对象,则称为unpickling.在pickling和unpicking之间,表示这些对象的字符串表示,可以存于一个文件,也可以通过网络远程机器间传输。
如果你有一个对象friend,和一个已经打开并用于写的文件对象f,pickle这个对象最简单的方式就是使用:
pickle.dunmp(friend,f)
# Pickle模块读入任何Python对象,将它们转换成字符串,然后使用dump函数将其转储到一个文件中——这个过程叫做pickling。
有了pickle这个对象,就能对f以读取的形式打开:
x = pickle.load(f)
#从存储的字符串文件中提取原始Python对象的过程,叫做unpickling。
5.Python是怎么管理内存的?
Python的内存管理是由私有head空间管理的。所有的python对象和数据结构都在一个私有heap中。程序员没有该、访问该heap的权限,只有解释器才能对它进行操作。
为python的heap空间分配内存是由python内存管理模块进行的,其核心API会提供一些访问该模块的方法拱程序员使用。
Python有自带的垃圾回收机制,它回收并释放没有被使用的内存,让它们能够被其他程序使用。
6.Python的垃圾回收机制
Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。
(1).引用计数
PyObject是每个对象必有的内容,其中ob_refcnt就是作为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。引用计数为0时,该对象的生命就结合了。
优点:简单,实时性
缺点:维护引用计数消耗资源,循环引用
(2).标记-清除机制
基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点,以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一边内存空间,把所有没有标记的对象释放。
(3).分代技术
分代回收的整体思想是:将系统中的所有内存根据其存活时间划分不同的集合,每个集合就成为一个“代”,垃圾收集频率随着代的存活时间的增大而减小,存活时间通常利用几次垃圾回收来度量。
python默认定义了三代对象集合,索引数越大,对象存活时间越长。
举例:
当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。
7.有没有一个工具可以帮助查找python的bug和进行静态的代码分析?
PyChecker是一个静态分析工具,它不仅能报告源代码中的错误,并且会报告错误类型和复杂度。
Pylint是检验模块是否达到代码标准的另一个工具。
8.什么是python装饰器?
Python装饰器是python中特有变动,可以使修改函数变得更容易。
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,比较经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。
概括的讲,装饰器的作用就是为了已经存在的对象添加额外的功能。
9.数组和元组之间的区别是什么,如何相互转换?
区别:
数组内容是可以被修改的,而元组内容是只读的。另外,元组可以被哈希,比如作为字典的关键字。
数组在python中叫做列表。列表可以修改,如果元组中仅有一个元素,则要在元素后加上逗号。元组和列表的查询方式一样。元组只可读不可修改,如果程序中的数据不允许修改可用元组。
转换:
>>> zero = [1,2,3,4,5,6]
>>> zero
[1, 2, 3, 4, 5, 6]
>>> zero_t = tuple(zero)
>>> zero_t
(1, 2, 3, 4, 5, 6)
>>> zero_l = list(zero_t)
>>> zero_l
[1, 2, 3, 4, 5, 6]
>>>
>>> a = [1]
>>> tuple(a)
(1,)
>>>
10.什么是Python的命名空间?
在Python中,所有的名字都存在一个空间中,它们在该空间中存在和被操作——这就是命名空间。它就像一个盒子,每一个变量名字都对应装着一个对象。当查询变量的时候,会从该盒子里面找到相应的对象。
11.列表推导式和字典推导式是什么?
它们是可以轻松创建字典和列表的语法结构。
由输出项,列表项,过滤项组成,过滤项为bool值可省略
[expr for itm in collection if condition] 列表常规推导
(expr for itm in collection if condition) 列表迭代推导
{expr for itm in collection if condition} 字典/集合推导
{key: value for (key, value) in iterable}字典推导
举例:
列表推导式
>>> zero = [0,-1,5,3,-9,-3,6,2]
>>> zero_list = [x**2 for x in zero if x >0]
>>> print(zero_list)
[25, 9, 36, 4]
>>>
字典推导式
>>> zero = [5,3,2,8,5,2,0]
>>> zero_dict = {i:i*i for i in zero}
>>> print(zero_dict)
{5: 25, 3: 9, 2: 4, 8: 64, 0: 0}
>>>
12.Python都有哪些自带的数据结构?
Python自带的数据结构可分为可变和不可变的。
可变的有:数组、集合、字典;
不可变的有:字符串、元组、数。
13.Python中的lambda是什么?
这是一个被用于代码中的单个表达式的匿名函数。
14.为什么lambda没有语句?
匿名函数lambda没有语句的原因是它被用于在代码执行的时候构建新的函数对象并且返回。
15.参数按值传递和引用传递是怎么实现的?
Python中的一切都是类,所有的变量都是一个对象的引用。引用的值是由函数确定的,因此无法改变。但是如果一个对象是可以被修改的,你可以改动对象。
传值:
简单来说,你在内存中有一个地址,我也有一个地址,我把我的地址里面的内容复制给你,以后你做什么就跟我没关系,不会改变原来的参数的内容。
传引用:
所谓传引用是有一个参数在内存有个地址,地址里面放了一堆东西,在调用函数时,把实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。也就是说最后函数运行完之后会改变原来参数的内容。
16. * args, ** kwargs?参数是什么?
如果我们不确定要往函数中传入多少个参数,或者我们想往函数中以列表和元组的形式传递参数时要用 * args;如果我们不知道要往函数中传入多少个关键词参数,或者想传入字典的值作为关键词参数时,那就要使用 ** kwargs。
注意: * args和 ** kwargs可以同时在函数的定义中,但是 * args必须在 * *kwargs前面。
17.Python中pass是什么?
pass是一个在Python中不会被执行的语句。在复杂语句中,如果一个地方需要暂时被留白,它常常被用于占位符。
>>> if zero == 'wyf':
... pass # 这个if语句不会被执行
...
>>>
18.unittest是什么?
在Python中,unittest是Python的单元测试框架。它拥有支持共享搭建、自动测试、在测试中暂停代码、将不同测试迭代成一组,等功能。
19.构造器是什么?
构造器是实现迭代的一种机制。它功能的实现依赖于yield表达式,除此之外它跟普通的函数没有什么两样。
20.在Python中什么是slicing?
Slicing是一种在有序的对象类型中(数组,元组,字符串)节选某一段的语法。
21.doc string是什么?
Python中文档字符串被称为docstring,它在Python中的作用是为函数、模块和类注释生成文档。
22.如何在Python中老被对象?
如果在python中拷贝对象,大多数时候你可以用copy.copy()或者copy.deepcopy()。但是并不是所有的对象都可以被拷贝。
23.Python中的负索引是什么?
Python中的序列索引可以是正也可以是负。如果是正索引,0是序列中的第一个索引,1是第二个索引。如果是负索引,-1是最后一个索引,-2是倒数第二个索引。
24.Python中如何将一个数字转换成一个字符串?
可以使用自带函数str()将一个数字转换成字符串。如果想要八进制或者十六进制数,可以使用oct()或hex()。
>>> zero = 24
>>> str(zero)
'24'
>>> oct(zero)
'0o30'
>>> hex(zero)
'0x18'
>>>
25.xrange和range的区别是什么?
xrange用于返回xrange对象,而range用于返回一个数组。不管那个范围多大,xrange都使用同样的内存。
注意:python3中没有xrange。
>>> a = xrange(10)
>>> a
xrange(10)
>>> b = range(10)
>>> b
[0, 1
26.Python中模块和包是什么?
在Python中,模块是搭建程序的一种方式。每一个Python代码文件都是一个模块,并可引用其他的模块,比如对象和属性。
一个包包含许多Python代码的文件夹是一个包。一个包可以包含模块和子文件夹。
27.CSRF是什么?
CSRF是伪造客户端请求的一种攻击,CSRF的英文全称是Cross Site Request Forgery,字面意思是跨站点伪造请求。
28.如何用Python删除一个文件?
使用函数os.remove("file")
29.Python中如何生成随机数?
在Python中用于生成随机数的模块是random,在使用前需要import。
举例:
random.random():生成一个0-1之间的随机浮点数
random.randint(a,b):生成[a,b]之间的整数
random,uniform(a,b):生成[a,b]之间的浮点数
random.randrange(a,b,step):在指定的集合[a,b)中,以step为基数随机取一个数
random.choice(sequence):从特定序列的中随机取一个元素,这里的序列可以是字符列表,元组等。
>>> random.random()
0.40081603972810886
>>> random.randint(1,6)
1
>>> random.uniform(1,6)
5.154534728596936
>>> random.randrange(1,6,3)
4
>>> a = [34,66,88,123,1994]
>>> random.choice(a)
123
>>>
30.如何在一个function里面设置一个全局变量
如果要给全局变量在一个函数里赋值,必须使用global语句。global VarName的表达式会告诉Python,VarName是一个全局变量,这样Python就不会在局部命名空间里寻找这个变量了。
31.Python如何实现单例模式?其他23中设计模式python如何实现?
单例模式主要有四种方法:new、共享属性、装饰器、import。
__ new__方法:
class Singleton(object):
def __new__(cls, *args, **kw):
if not hasattr(cls, '_instance'):
orig = super(Singleton, cls)
cls._instance = orig.__new__(cls, *args, **kw)
return cls._instance
class MyClass(Singleton):
a = 1
共享属性:
创建实例时把所有实例的__ dict__指向同一个字典,这样它们就具有了相同的属性和方法。
class Borg(object):
_state = {}
def __new__(cls, *args, **kw):
ob = super(Borg, cls).__new__(cls, *args, **kw)
ob.__dict__ = cls._state
return ob
class MyClass2(Borg):
a = 1
装饰器版本
def singleton(cls, *args, **kw):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return getinstance
@singleton
class MyClass:
import方法
作为python的模块是天然的单例模式
# mysingleton.py
class My_Singleton(object):
def foo(self):
pass
my_singleton = My_Singleton()
# to use
from mysingleton import my_singleton
my_singleton.foo()
其他23中设计模式基本分为创建型、结构型和行为型模式。
创建模式,提供实例化的方法,为适合的状况提供相应的对象创建方法。
结构化模式,通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。
行为模式,用于在不同的实体间建立通信,为实体之间的通信提供更容易,更灵活的通信方法。
各模式的实现可根据其特点编写代码。
32.Python中的作用域
Python中,一个变量的作用域总是由代码中被赋值的地方决定的。
当Python遇到一个变量的话他会按照这样的顺序搜索:
本地作用域(Local)→当前作用域被嵌入的本地作用域(Enclosing locals)→全局/模块作用域(Global)→内置作用域(Built-in)
33.GIL线程全局锁
线程全局锁(Global Interperter Lock),即Python为了保证线程安全而采用的独立线程运行的限制,说白了就是一个核只能在同一时刻运行一个线程。
解决办法就是多进程和协程(协程也只是单CPU,但是能减小切换代价提升性能)。
34.什么是协程?
简单点说协程是进程和线程的升级版,进程和线程都面临着内核态和用户态的切换问题而耗费许多切换时间,而协程就是用户自己控制切换的时机,不需要再陷入系统的内核态。
35.什么是进程?
进程:能够完成多个任务,一般而言,一个进程就是一个独立的软件,如我们在电脑上运行了多个QQ。
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
36.什么是线程?
线程:能够完成多个任务,一半而言,一个进程至少存在一个线程或多个线程,如打开网页,启动多个页面选项卡。
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
36.进程和线程的区别?优缺点
1、 一个程序中至少有一个进程,一个进程中至少有一个线程;
2、 线程的划分尺度小于进程(占有资源),使得多线程程序的并发性高;
3、 进程运行过程中拥有独立的内存空间,而线程之间共享内存,从而极大的提高了程序的运行效率
4、 线程不能独立运行,必须存在于进程中
优缺点:
线程开销小,但是不利于资源的管理和保护,而进程反之。
37.Python中的多线程--threading
Python2中支持多线程编程的模块有两个thread、threading,但是官方已经不建议使用thread模块。
Python3中取消了thread模块,只有threading模块,所以我们使用threading模块来学习多线程编程。
heike_cover.png