天天看点

【Python面试题】【基础篇】持续更新中...

1、不错的面试题网站

<a href="http://www.codingonway.com/">http://www.codingonway.com/</a>

<a href="https://github.com/revotu/python-interviews">https://github.com/revotu/python-interviews</a>

<a href="https://github.com/taizilongxu/interview_python">https://github.com/taizilongxu/interview_python</a>

2、Python是如何进行内存管理的?

Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。

3、垃圾回收机制

当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。

当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。

4、引用计数机制

PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除、引用超出作用域或被重新赋值,它的ob_refcnt就会减少.引用计数为0时,该对象生命就结束了。

优点:

1. 简单

2. 实时性

缺点:

1. 维护引用计数消耗资源

2. 循环引用

5、标记-清除

基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。

6、分代回收

分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。

Python默认定义了三代对象集合,索引数越大,对象存活时间越长。

举例:

当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。

7、内存池机制

Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。

Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。

Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。

对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。

8、函数参数

普通参数

即在调用函数时必须按照准确的顺序来进行参数传递。

默认参数

即参数含有默认值,在调用函数时可以进行参数传递,若没有进行参数传递则使用默认值,要注意,默认参数必须在普通参数的右侧(否则解释器无法解析)

元组参数,即 *args

参数格式化存储在一个元组中,长度没有限制,必须位于普通参数和默认参数之后

字典参数,即 **kwargs

参数格式化存储在一个字典中,必须位于参数列表的最后面

9、Python里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)

赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。

浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变){1,完全切片方法;2,工厂函数,如list();3,copy模块的copy()函数}

深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变){copy模块的deep.deepcopy()函数}

copy 仅拷贝对象本身,而不拷贝对象中引用的其它对象。

deepcopy 除拷贝对象本身,而且拷贝对象中引用的其它对象。

10、Python中重载

函数重载主要是为了解决两个问题:

1. 可变参数类型

2. 可变参数个数

解释一:

那么对于情况 1 ,函数功能相同,但是参数类型不同,python 如何处理?答案是根本不需要处理,因为 python 可以接受任何类型的参数,如果函数的功能相同,那么不同的参数类型在 python 中很可能是相同的代码,没有必要做成两个不同函数。

那么对于情况 2 ,函数功能相同,但参数个数不同,python 如何处理?大家知道,答案就是缺省参数。对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。

鉴于情况 1 跟 情况 2 都有了解决方案,python 自然就不需要函数重载了。

解释二:

简单来说,Python中为什么不需要重载,重载要解决的是参数类型和参数个数的问题,对于类型,python不像是c语言整型要写int,字符串要写str,,,这些python都不需要。

那么需要解决的就是传递参数个数问题,此时python可以传递列表呀,字典呀,可以使用*arg和**args呀,所以python根本不需要重载。

11、Python中单下划线和双下划线

__foo__:一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突.

_foo:一种约定,用来指定变量私有.程序员用来指定私有变量的一种方式.

__foo:这个有真正的意义:解析器用_classname__foo来代替这个名字,以区别和其他类相同的命名.

12、 __new__和__init__的区别

1. __new__是一个静态方法,而__init__是一个实例方法.

2. __new__方法会返回一个创建的实例,而__init__什么都不返回.

3. 只有在__new__返回一个cls的实例时,后面的__init__才能被调用.

4. 当创建一个新实例时调用__new__,初始化一个实例时用__init__.

13、单例模式

该模式的主要目的是确保某一个类只有一个实例存在

使用模块

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

将上面的代码保存在文件 mysingleton.py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象

使用类

基于__new__方法实现(推荐使用,方便)

当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.__new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式

当我们实现单例时,为了保证线程安全需要在内部加入锁,未加锁部分并发执行,加锁部分串行执行,速度降低,但是保证了数据安全

14、创建字典的方法

直接创建

dict = {'name':'earth', 'port':'80'}

工厂方法

items=[('name','earth'),('port','80')]

dict2=dict(items)

fromkeys()方法

dict1={}.fromkeys(('x','y'),-1)

dict={'x':-1,'y':-1}

dict2={}.fromkeys(('x','y'))

dict2={'x':None, 'y':None}

15、数组和元组之间的区别是什么?

相同点

首先,列表与元组都是容器,是一系列的对象;

其次,二者都可以包含任意类型的元素甚至可以是一个序列。

不同点

列表和元组的“技术差异”是,列表是可变的,而元组是不可变的。

16、Python都有那些自带的数据结构?

Python自带的数据结构分为可变的和不可变的。

可变的有:

集合

字典

不可变的有:

字符串

元组

数字

数组

17、推导式

列表(list)推导式

功能:是提供一种方便的列表创建方法,所以,列表解析式返回的是一个列表

例子:

&gt;&gt;&gt; li=[i*2 for i in range(10) if i % 2 == 0]

&gt;&gt;&gt; print li

[0, 4, 8, 12, 16]

列表解析式最擅长的方式就是对整个列表分别做相同的操作,并且返回得到一个新的列表

字典(dict)推导式

集合(set)推导式

功能:集合推导式跟列表推导式差不多,都是对一个列表的元素全部执行相同的操作,但集合是一种无重复无序的序列

区别:跟列表推到式的区别在于:1.不使用中括号,使用大括号;2.结果中无重复;3.结果是一个set()集合,集合里面是一个序列

&gt;&gt;&gt; squared={i*2 for i in [1,1,2]}

&gt;&gt;&gt; print squared

set([2, 4])

18、Python是如何进行类型转换的?

Python提供了将变量或值从一种类型转换成另一种类型的内置函数。比如int函数能够将符合数学格式数字型字符串转换成整数。否则,返回错误信息。

19、Python是如何被解释的?

Python是一种解释性语言,Python解释器会将源代码转换成中间语言,之后再翻译成机器码再执行。

20、.Python中的负索引是什么?

Python中的序列索引可以是正也可以是负。如果是正索引,0是序列中的第一个索引,1是第二个索引。如果是负索引,(-1)是最后一个索引而(-2)是倒数第二个索引。

21、Python的参数传递是值传递还是引用传递

1).Python的参数传递有:

位置参数

默认参数,

可变参数,

关键字参数

2).函数的传值到底是值传递还是引用传递,要分情况

a.不可变参数用值传递:

像整数和字符串这样的不可变对象,是通过拷贝进行传递的,因为你无论如何都不可能在原处改变不可变对象

b.可变参数是用引用传递的

比如像列表,字典这样的对象是通过引用传递,和C语言里面的用指针传递数组很相似,可变对象能在函数内部改变.

22、Xrange和range的区别是什么?

xrange 函数说明:用法与range完全相同,所不同的是生成的不是一个数组,而是一个生成器。

&gt;&gt;&gt; range(5)

[0, 1, 2, 3, 4]

&gt;&gt;&gt; xrange(5)

xrange(5)

&gt;&gt;&gt; list(xrange(5))

23、单引号,双引号,三引号的区别

1),单引号和双引号主要用来表示字符串

区别:

若你的字符串里面本身包含单引号,必须用双引号

比如:"can't find the log\n"

2).三引号

三单引号:'''python ''',也可以表示字符串一般用来输入多行文本,或者用于大段的注释

三双引号:"""python""",一般用在类里面,用来注释类

24、类和实例

<a href="https://www.cnblogs.com/crazyrunning/p/6945183.html">https://www.cnblogs.com/crazyrunning/p/6945183.html</a>

25、类变量和实例变量

实例变量是对于每个实例都独有的数据,而类变量是该类所有实例共享的属性和方法。

class Dog:

kind = 'canine' # class variable shared by all instances

def __init__(self, name):

self.name = name # instance variable unique to each instance

类Dog中,类属性kind为所有实例所共享;

实例属性name为每个Dog的实例独有。

26、类对象和实例对象

类对象

类对象仅支持两个操作:

实例化;使用instance_name = class_name()的方式实例化,实例化操作创建该类的实例。

属性引用;使用class_name.attr_name的方式引用类属性。

实例对象

实例对象是类对象实例化的产物,实例对象仅支持一个操作:

属性引用;与类对象属性引用的方式相同,使用instance_name.attr_name的方式。

27、属性绑定

我们说的属性绑定,首先需要一个可变对象,才能执行绑定操作,使用objname.attr = attr_value的方式,为对象objname绑定属性attr。

这分两种情况:

若属性attr已经存在,绑定操作会将属性名指向新的对象;

若不存在,则为该对象添加新的属性,后面就可以引用新增属性。

类属性绑定

类属性的绑定发生在两个地方:

类定义时;

运行时任意阶段。

在类定义中,类属性的绑定并没有使用objname.attr = attr_value的方式,这是一个特例,其实是等同于后面使用类名绑定属性的方式。

因为是动态语言,所以可以在运行时增加属性,删除属性。

实例属性绑定

与类属性绑定相同,实例属性绑定也发生在两个地方:

类实例有两个特殊之处:

__init__在实例化时执行

Python实例调用方法时,会将实例对象作为第一个参数传递

因此,__init__方法中的self就是实例对象本身

28、属性引用

类属性引用

类属性的引用,肯定是需要类对象的,属性分为两种:

数据属性

函数属性

实例属性引用

使用实例对象引用属性稍微复杂一些,因为实例对象可引用类属性以及实例属性。但是实例对象引用属性时遵循以下规则:

总是先到实例对象中查找属性,再到类属性中查找属性;

属性绑定语句总是为实例对象创建新属性,属性存在时,更新属性指向的对象。

29、Python 中的 is 和 ==

is is the identity comparison. #比较引用是否相同

== is the equality comparison. #比较内容是否相同

python中新建变量时,并不需要指定类型,因为每个变量实际上存储的是一个引用,就是指向一个对象实体的指针。

is 判断的就是这个指针的值是否相同,如果相同则表示两个变量指向同一个对象实体。

而==则比较它们的内容是否相同

30、isinstance 和 type 的区别

class A:

pass

class B(A):

isinstance(A(), A) # returns True

type(A()) == A # returns True

isinstance(B(), A) # returns True

type(B()) == A # returns False

区别就是:

type()不会认为子类是一种父类类型。

isinstance()会认为子类是一种父类类型。

31、