2020面试篇:python面试题库(基础篇)附详细答案

https://shimo.im/docs/CdDxcHctyWwDJTYt/read
https://www.jianshu.com/p/c44e48b42fce
https://www.cnblogs.com/clement-jiao/p/8719323.html#_label0

面试篇:python面试题库(基础篇)

1.为什么学习Python?
Python 是一种面向对象的、解释型的、通用的、开源的脚本编程语言。
应用:Web应用开发、自动化运维、人工智能领域、网路爬虫、科学计算、游戏开发
优点:
(1)简单易用,学习成本低,看起来非常优雅干净;
(2)标准库和第三库众多,功能强大,既可以开发小工具,也可以开发企业级应用;
(3)站在了人工智能和大数据的风口上,站在风口上,猪都能飞起来。
缺点:
(1)运行慢(解释型语言,边运行边翻译;高级语言,屏蔽了很多底层细节)
(2)代码加密困难(解释型语言,源代码直接运行)
参考链接:Python的特点(优点和缺点)
2. 通过什么途径学习的Python?
大牛公众号+python书籍《python宝典》+教程视频+项目经验+请教同事、QQ交流群
3. Python和Java、PHP、C、C#、C++等其他语言的对比?
C、C++、Python和Java四种是通用编程语言,JavaScript和PHP算是Web环境的专用编程语言。
C语言由于其底层操作特性和历史的积累,在嵌入式领域是当之无愧的王者;
C++是一种支持最广泛编程范式的复杂语言,这些年来发展不太好,目前在服务器后台和游戏领域还有其一席之地;
Python作为一种灵活的轻便的通用型脚本语言,使用范围比较广,从应用软件到Web开发都有它的身影,由于其解释语言的特点,比较适合轻量级或原型开发;
Java由于其跨平台可移植性,在Web开发领域大放异彩,特别是在企业级Web开发,同时由于Android系统采用Java来开发应用程序,所以也随着Android的发展而应用越发广泛;
JavaScript语言由于其是浏览器内置的脚本语言,是Web前端开发的主流,近年来由于google的V8引擎开源,出现了Node.js之类JavaScript后台开发框架,把JavaScript的应用领域扩展到了Web后台;
PHP作为一种简单的Web服务器后台脚本语言,在全世界范围内的网站上有最大的使用率。

详细链接:Python和Java、PHP、C、C#、C++等其他语言的对比?
参考链接:六种主流编程语言(C、C++、Python、JavaScript、PHP、Java)特性对比

4. 简述解释型和编译型编程语言?
编译型的语言包括:C、C++、Delphi、Pascal、Fortran
解释型的语言包括:Java、Basic、javascript、python
差异总结:
编译型语言:
原理:通过专门的编译器,将所有源代码一次性转换成特定平台(Windows、Linux 等)执行的机器码(以可执行文件的形式存在)。
优点:编译一次后,脱离了编译器也可以运行,并且运行效率高。
缺点:可移植性差,不够灵活。
解释型语言:
原理:由专门的解释器,根据需要将部分源代码临时转换成特定平台的机器码。
优点:跨平台性好,通过不同的解释器,将相同的源代码解释成不同平台下的机器码。
缺点:一边执行一边转换,效率很低。

详细链接:简述解释型和编译型编程语言?

5. Python解释器种类以及特点?
CPython:c语言开发的使用最广的解释器
IPython:基于cpython之上的一个交互式解释器,交互方式增强,功能和cpython一样
PyPy:目标是执行效率 采用JIT技术 对python代码进行动态编译,提高执行效率
JPython:运行在Java上的解释器 直接把python代码编译成Java字节码执行
IronPython:运行在微软 .NET 平台上的解释器,把python编译成. NET 的字节码
6. 位和字节的关系?
位bit:计算机的最小数据单位;
字节byte:存储空间的基本计量单位。
一般一个汉字占2byte,一个英文字母占1byte
1byte=8bit
7. b、B、KB、MB、GB 的关系?
GB=1024 MB=1024 KB= 1024 B= 8b
8. 请至少列举5个 PEP8 规范
一、代码编排:
(1)缩进:每级缩进使用四个空格
(2)换行:限制每行的最大长度为79个字符,换行用()或者
(3)空行:类和顶层函数之间使用两个空行;方法之间用一个空行;函数内逻辑无关段落之间空一行;文件最后留一个空行
二、文档编排:
(4) 导入模块:
导入优先级:标准(python自带的库)、第3方(pip安装的库)、自己编写的,之间空一行
一行导入一个库
三、空行空格:
总体原则,避免不必要的空格
(1)各种右括号前不要加空格。
(2)逗号、冒号、分号前不要加空格。
(3)函数的左括号前不要加空格。如Func(1)。
(4)序列的左括号前不要加空格。如list[2]。
(5)操作符左右各加一个空格,不要为了对齐增加空格。
(6)函数默认参数使用的赋值符左右省略空格。
(7)不要将多句语句写在同一行,尽管使用‘;’允许。
(8)if/for/while语句中,即使执行语句只有一句,也必须另起一行。
四、注释
句子+两个空格#一个空格+英文(首字母大写)
五、命名规范
(1)模块名:小写,不要下划线
(2)类名:首字母大写,驼峰式
(2)函数名、变量名:小写,下划线分割
(3)常量:大写,下划线分割
官方文档英文版链接:PEP 8 – Style Guide for Python Code
官方文档中文版链接:link

9. 通过代码实现如下转换:
题目:
(1)二进制转换成十进制:v = “0b1111011”
(2)十进制转换成二进制:v = 18
(3)八进制转换成十进制:v = “011”
(4)十进制转换成八进制:v = 30
(5)十六进制转换成十进制:v = “0x12”
(6)十进制转换成十六进制:v = 87
答案:
(1)二转十:int(v, 2)
(2)十转二:bin(v)
(3)八转十:int(v, 8)
(4)十转八:oct(v)
(5)十六转十:int(v,16)
(6)十转十六:hex(v)

转换规则:
其他进制转二进制----bin(var)
其他进制转八进制----oct(var)
其他进制转十进制----int(var)
其他进制转十六进制----hex(var)
字符串转byte----str_var.encode()
byte转字符串----byte_var.decode()

10. 请编写一个函数实现将IP地址转换成一个整数。

如 10.3.9.12 转换规则为:
10 00001010
3 00000011
9 00001001
12 00001100
再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ?

ip = "10.3.9.12"
ip_2b = [bin(int(i)) for i in ip.split(".")] # ['0b1010', '0b11', '0b1001', '0b1100']
ip_2 = [j.replace("0b", "") for j in ip_2b] #去掉b符号['1010', '11', '1001', '1100']
ip_2_0 = [("0" * (8-len(j)) +j) for j in ip_2] # 补全0,['00001010', '00000011', '00001001', '00001100']
ip_2_all = "".join(ip_2_0) # 00001010000000110000100100001100
print(int(ip_2_all,2)) # 转换成2进制,167971084

11. python递归的最大层数?
python3.7中为996,可以在os模块中设置次数

def print(code):
    print(code)
print('python')
# [Previous line repeated 996 more times]
# RecursionError: maximum recursion depth exceeded

# 设置sys最大递归次数
import sys
sys.setrecursionlimit(4000)

def print(code):
    print(code)
print('python')

11.1 求结果:
v1 = 1 or 3
v2 = 1 and 3
v3 = 0 and 2 and 1
v4 = 0 and 2 or 1
v5 = 0 and 2 or 1 or 4
v6 = 0 or False and 1

答案:
1, 3, 0, 1, 1,False
规则:
x and y:当x为True时是y,x为False 时是x
x or y:当x为True时是x,x为False 时是y
not x:如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。
在没有其他限定时,and的优先级大于or。

12. ascii、gbk、unicode、utf-8 区别?
(1)ASCII码:一个字符=1个字节,最多只能用8位来表示,即:2**8 = 256,可以最多表示 256 个字符。
(2)Unicode编码:万国码,世界上所有的符号都给予独一无二的编码,解决乱码问题。一个字符=2个字节
(3)utf-8:万国码的升级版,一种针对Unicode的可变长度字符编码,UTF8是互联网中使用最多的对Unicode的实现方式。一个中文字符是三个字节;英文是一个字节;欧洲是2个字节。
背景:有些符号需要1个字节,有些需要2或3个字节更多。如果Unicode统一规定,每个符号用3个字节表示,但是某些字母显然不需要3个,那么就浪费了空间,文本文件大小超出了很多,这显然是不合理的。直到UTF8字符编码出现。
(4)gbk:非ASCII码,只用来编码汉字,一个汉字 = 两个字节,一个英文字母 = 一个字节,可以最多组合256*256=65536个符号,共收录汉字和图形符号21886个。

注1:gbk 转 utf-8 需通过媒介 unicode
encode编码成bytes,将str转为bytes:str.encede(‘utf-8’)
decode解码成str,将bytes转为str:bytes.decede(‘utf-8’)
注2:python2对内容进行编码(默认ascii),而python3对内容进行编码的默认为utf-8(首行:# -- coding: utf-8 --)。

13. 字节码和机器码的区别?
(1)机器码(machine code):学名机器语言指令,也被称为原生码(Native Code),是电脑的CPU可直接解读的数据
机器码是电脑CPU直接读取运行的机器指令,运行速度最快,但是非常晦涩、较难编写。
(2)字节码(Bytecode):一种包含执行程序、由一序列 op 代码/数据对 组成的二进制文件。
字节码是一种中间状态(中间码)的二进制代码(文件)。需要解释器转译后才能成为机器码。
如Java,先通过编译器转化为字节码的*.class文件,运行时再通过平台的JVM(JAVA虚拟机)将字节码转为机器码。

14. 三元运算规则以及应用场景
三元运算符就是在赋值变量的时候,可以直接加判断,然后赋值格式。
[on_true] if [expression] else [on_false]
举例:small = x if x < y else y.

15. 列举 Python2和Python3的区别?

1.核心类差异 python2 python3 备注
字符编码 ascii unicode(utf-8)
import 相对路径 绝对路径
缩进 允许tab和space共存 tab和space共存会报错
2.废弃类类差异 python2 python3 备注
废弃 print语句 print函数
不等于 <>或!= !=
废弃 long整数型 统一使用int
废弃 生成器xrange() 生成器range()
dictionary关联的keys()、values()、items(),和高阶函数zip(),map(),filter() list对象 可迭代对象,可以通过list强行转换
3.修改类差异 python2 python3 备注
除法操作符 /是整数除法,//是小数除法 /是小数除法,//是整数除法
比较操作符 任意两个对象都可以比较 只有同一数据类型的对象可以比较
for循环 会修改外部相同名称变量的值 不会修改外部相同名称变量的值
打开文件 file( … ) 或 open(…) 只能用 open(…)
input input的到的为int型,raw_input得到的为str型 仅input,得到的为str型

详细链接:Python 2.x与Python 3​​.x版本区别

16. 用一行代码实现数值交换
a,b=b,a

17. Python3和Python2中 int 和 long的区别?
python3取消了long,只有int类型

18. xrange和range的区别?
python2中xrange返回的是迭代器,range返回的是列表
python3中不支持xrange,range返回的是迭代器。

19. 文件操作时:xreadlines和readlines的区别?
python2中xreadlines返回的是迭代器,readlines返回的是列表
python3中不支持xreadlines,readlines返回的是列表

20. 列举布尔值为False的常见值?
[] (空列表)、{}(空集合)、""(空字符串)、{} 空字典,None空值、0和0.0数值、False

21. 字符串、列表、元组、字典每个常用的5个方法?
str: split(),join(),find(),index(),lower(),strip(),upper(),replace()
list: append(),count(),extend(),pop(),sort()
tuple: count(),index(),contains(),sizeof(),len()
dict: clear(),copy(),get(),items(),keys(),values(),pop()

22. lambda表达式格式以及应用场景?
(1)公式:函数名 = lambda 参数 :返回值
举例:

add = lambda x, y : x+y
print(add(1,2))  # 3

(2)应用场景:为了解决那些功能很简单的需求而设计的一句话函数,即匿名函数。如:map(function, iterable, …)
应用场景:函数式编程,闭包

#参数可以有多个,用逗号隔开
#匿名函数不管逻辑多复杂,只能写一行,且逻辑执行结束后的内容就是返回值
#返回值和正常的函数一样可以是任意数据类型

map(lambda x: x ** 2, [1, 2, 3, 4, 5])  # 使用 lambda 匿名函数
[1, 4, 9, 16, 25]

(3)优点:简洁;缺点:难理解

23. pass的作用?
pass 是空语句,不做任何事情。一般用做占位语句,保持程序结构的完整性。

24. *arg和kwarg作用?**

def foo(x,*args,**kwargs):
	print(x);print(args);print(kwarg);

foo(1,2,3,4,y=1,a=2,b=3,c=4)
#结果为1 (2,3,4) {‘y’:1,‘a’:2,‘b’:3,‘c’:4}
#x:位置参数,x与*arg与**kwarg的顺序必须是这样的,不能变。
#*arg:任意多个无名参数,可变参数,会把多出来的位置参数转化为tuple,长度不定;
#**kwarg:关键字参数,键值对参数,会把关键字参数转化为dict,长度不定,且kwarg中的key必须与需要的形参名对应,不多也不少且对应。
#注:单独使用一个*作为特殊分隔符号,可以控制关键字参数,如def person(required_arg, *, keyword1, keyword2):,只能传入1个位置参数,2个关键字参数,否则报错

参考链接:Python中的*arg和**kwarg

25. is和= =的区别?
对象包含的三个基本要素:id(身份标识)、type(数据类型)和value(值)
is比较的是对象id,也就是内存地址;==比较的是对象的value。

26. 简述Python的深浅拷贝以及应用场景?
浅拷贝只是增加了一个指针指向一个存在的内存地址;
深拷贝是增加一个指针并且开辟了新的内存,这个增加的指针指向这个新的内存地址。
采用浅拷贝的情况,释放内存,会释放同一内存,深拷贝就不会出现释放同一内存的错误。

27. Python垃圾回收机制(GC)?
引用计数(reference counting),标记清除(mark and sweep),分代回收(generation collection)

引用计数–跟踪和回收垃圾
标记-清除–解决容器对象可能产生的循环引用的问题
分代回收–以空间换取时间来进一步提高垃圾回收的效率

详细链接:Python垃圾回收机制(GC,Garbage collection)总结
参考链接:Python垃圾回收机制详解

28. Python的可变类型和不可变类型?
不可变类型:int, str, tuple不可变对象。——值变,内存地址变
可变类型:列表list,字典dic,可变对象。——值变,内存地址不变
可变:指的是内存地址变化

29. 求结果:
v = dict.fromkeys([‘k1’,‘k2’],[])
print(v)
v[‘k1’].append(666)
print(v)
v[‘k1’] = 777
print(v)

求结果:
{‘k1’: [], ‘k2’: []}
{‘k1’: [666], ‘k2’: [666]}
{‘k1’: 777, ‘k2’: [666]}
分析:
dict.fromkeys(seq[, value]):fromkeys() 函数用于创建一个新字典,以序列 seq 中元素做字典的键,value 为字典所有键对应的初始值。
append() 方法用于在列表末尾添加新的对象。此处是对对象“v[‘k1’]=[]”进行添加对象“666”,所以字典v中的每个值都是[],相当于都加了一个666.
注:如果字典v的值是不同的对象(对应不同的内存地址),则针对该对象改变

30.求结果
def num():
return [lambda x : i * x for i in range(4)]

print([m(2) for m in num()])
结果:
[6,6,6,6]

分析:
(1)lambda argument_list: expression,lambda返回值是一个函数的地址,也就是函数对象;
(2)待补
(3)函数、类、模块会产生作用域,代码块不会产生作用域。作用域按照变量的定义位置可以划分为4类:
Local:(函数内部)局部作用域
Enclosing:(嵌套函数的外层函数内部)嵌套作用域(闭包)
Global:(模块全局)全局作用域
Built-in:(内建)内建作用域

python解释器查找变量时,会按照顺序依次查找局部作用域—>嵌套作用域—>全局作用域—>内建作用域,在任意一个作用域中找到变量则停止查找,所有作用域查找完成没有找到对应的变量,则抛出 NameError: name ‘xxxx’ is not defined的异常。
(4)最普遍的解决方案是创建一个闭包,通过使用默认参数立即绑定它的参数,即变闭包作用域为局部作用域。例如:
def num():
return [lambda x, i=i : i * x for i in range(4)]

参考链接:fun = [lambda x: x*i for i in range(4)] 本质解析/原理,LEGB规则 闭包原理

31. 列举常见的内置函数?
id(),type(),value(),int(),str(),list(),set(),tuple()
参考链接:python3中内置函数
参考链接:Python 内置函数

32. filter、map、reduce的作用?
(1)filter(function, iterable)函数:用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。
接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判定,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
举例:
def is_odd(n):
return n % 2 == 1

tmplist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
newlist = list(tmplist)
print(newlist)
(2)map(function, iterable, …)函数:是对一个可迭代对象里面的每一个对象执行同一个操作(函数)并且返回一个可迭代对象。
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
举例:
map(square, [1,2,3,4,5]) # 计算列表各个元素的平方
[1, 4, 9, 16, 25]
(3)reduce(function, iterable[, initializer])函数:会对参数序列中元素进行累积。
函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
举例:
from functools import reduce
def add(x,y):
return x + y
print (reduce(add, range(1, 101))) # 505

33. 一行代码实现9*9乘法表?
print(’\n’.join(["".join(["{}*{}={} ".format(x, y, x * y) for y in range(1,x+1)]) for x in range (1,10)]))

34. 如何安装第三方模块?以及用过哪些第三方模块?
安装模块包:(python3 -m) pip install SomePackage
已安装包列表:pip3 list(包如:requests,xlrd,xlwt,pymysql,urllib3)

35. 至少列举8个常用模块都有那些?
sys:工具脚本经常调用的命令行参数。比如:返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
os:o提供了许多与操作系统相关联的函数,比如:os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
time:比如:time.strftime("%Y-%m-%d %X")返回格式化的日期
datetime:比如:datetime.datetime.now()返回当前日期
re:正则
requests:Requests可以轻而易举的完成浏览器可有的任何操作
random:提供了生成随机数的工具
math:为浮点运算提供了对底层C函数库的访问

36. re的match和search区别?
(1)re.match(pattern, string[, flags]) :
从首字母开始开始匹配,string如果包含pattern子串,则匹配成功,返回Match对象,失败则返回None;
(2)re.search(pattern, string[, flags]) :
若string中包含pattern子串,则返回Match对象,否则返回None,如果string中存在多个pattern子串,只返回第一个。
(3)re.findall(pattern, string[, flags]) :
返回string中所有与pattern相匹配的全部字串,返回形式为数组。

37. 什么是正则的贪婪匹配?
贪婪匹配:总是尝试匹配尽可能多的字符;
非贪婪匹配:是尝试匹配尽可能少的字符,匹配规则前加?
注:
.表示任意字符;
*表示任意次,+表示 >=1次,?表示0或1次

38.求结果
a. [ i % 2 for i in range(10) ]
b. ( i % 2 for i in range(10) )

a. [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
b.

39.求结果
a. 1 or 2
b. 1 and 2
c. 1 < (2==2)
d. 1 < 2 == 2

a.1
b.2
c.False
d.True # 1<2 and 2==2

40. def func(a,b=[]) 这种写法有什么坑?
因为b是可变类型,每次调用这个方法b不会每次都初始化[],而是调用相同的[],多次调用这个函数的会输出错误的值。
def func(a,b=[]) 这种写法有什么坑?

41. 如何实现 “1,2,3” 变成 [‘1’,’2’,’3’] ?
“1,2,3”.split(",")

42. 如何实现[‘1’,’2’,’3’]变成[1,2,3] ?
print(list(map(lambda x:int(x),[“1”, “2”, “3”])))

43. 比较:a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 c = [(1,),(2,),(3,) ] 的区别?
a = [1,2,3] # 元素是整数
b = [1,2,3] # 元素是整数
c = [(1,),(2,),(3,) ] # 元素是元祖
补:

print(f'他们分别都是列表:{a},{b},{c}')
print(f'他们的类型都是:{type(a)},{type(b)},{type(c)}')
print(f'其中元素类型为:{[type(x) for x in a]},{[type(x) for x in b]},{[type(x) for x in c]}')
# 他们分别都是列表:[1, 2, 3],[1, 2, 3],[(1,), (2,), (3,)]
# 他们的类型都是:,,
# 其中元素类型为:[, , ],[, , ],[, , ]

44. 如何用一行代码生成[1,4,9,16,25,36,49,64,81,100] ?

[i*i for i in range(1, 11)] # [pow(i, 2) for i in range(1, 11)]
list(map(lambda x: x*x, range(1, 11)))

45. 一行代码实现删除列表中重复的值 ?
list0 = [‘b’, ‘c’, ‘d’, ‘b’, ‘c’, ‘a’, ‘a’]

list0 = sorted(list(set(list0)), key=list0.index) # 不改变顺序

46. 如何在函数中设置一个全局变量 ?
在函数的内部,通过global声明,使在函数内部中设置一个全局变量,这个全局变量可以在任意的函数中进行调用
举例:global nums

47.logging模块的作用?以及应用场景?
(1)背景:在我们平时编写的程序,基本上都会有记录日志的需求,并且日志当中包含的内容既有正常的程序访问,又有错误,警告等信息输出,在python的logging模块当中就提供了标准的日志接口,可以通过它来存储各种格式的日志。
(2)logging日志模块:用来记录用户的行为 或者 代码执行的过程。
logging模块也分为五个等级:
debug() # 最详细的日志信息,典型应用场景是 问题诊断
info(),
warning(),
error(),
critical()
其中默认级别为warning,默认打印到终端
(3)作用:可以了解程序的运行情况是否正常,在程序出现故障快速定位出错地方以及故障分析
(4)使用场景:
开发应用程序或部署开发环境时,可以使用DEBUG或INFO级别的日志获取尽可能详细的日志信息来进行开发或部署调试;应用上线或部署生产环境时,应该使用WARNING或ERROR或CRITICAL级别的日志来降低机器的I/O压力和提高获取错误日志信息的效率。

参考链接:logging模块的作用以及应用场景

48. 请用代码简答实现stack 。
Stack():创建一个新的空栈
push(item):添加一个新的元素item到栈顶
pop():弹出栈顶元素
peek():返回栈顶元素,且不从栈中删除
is_empty():判断栈是否为空
size():返回栈的元素个数

# Stack():创建一个新的空栈
class Stack():
    def __init__(self):
        self.items = []

    # 判断栈是否为空
    def is_empty(self):
        return self.items == []

    # 添加一个新的元素,item到栈顶
    def push(self, item):
        self.items.append(item)

    # 弹出栈顶元素
    def pop(self):
        return self.items.pop()

    # 返回栈顶元素
    def peek(self):
        return self.items[len(self.items) - 1]

    # 返回栈的元素个数
    def size(self):
        return len(self.items)

栈stack:先进后出,添加、删除为O(1)
队列quene:先进先出,添加、删除为O(1),查询为O(n)
双端队列deque(double-end quene):= 栈 + 队列,添加、删除为O(1),查询为O(n)

49. 常用字符串格式化哪几种?
f-string模式:f"my name is {name}"
.format形式:“my name is {}”.format(name)
%形式:“my name is %s, age is %d” % (name,age)

50. 简述 生成器、迭代器、可迭代对象 以及应用场景?(待完善)
(1)迭代器(Iterator):内置函数iter(),next()。如list、tuple等
(2)生成器(generator):自己实现的迭代器,一边循环一边计算的机制,保存的是算法。
通过next()取值,两种表现形式:将列表生成式的[]改为();含有yield关键字的函数。
如:[pow(i,2) for i in range(1,11)]是列表,(pow(i,2) for i in range(1,11))是生成器
(3)可迭代对象(iterable):可以直接作用于for循环的叫可迭代对象,可迭代对象包括以下2种:1) list、tuple、set、dict、str等集合数据类型;2) 生成器
iter(iterable) # 将一个可迭代对象转换为迭代器

关系:可迭代对象(迭代器(生成器))
应用场景 : 处理大量数据时逐个取值
注1:问:
生成器都是迭代器,但是为什么集合数据类型不是迭代器呢?
因为生成器代表长度未知的数据流,而list等集合数据类型的长度是确定的。

注2:
凡是可以用作for循环的对象都是可迭代对象,都遵循了可迭代协议;
凡是可以用next()取出下一个元素,使用iter()返回自身的的迭代器类型;
可迭代数据类型如list,dict,str等都是Iteralbe但不是迭代器Iterator,不过可以通过iter(list)函数获取一个迭代器对象。

51. 用Python实现一个二分查找的函数。

def binary_search(li, val):
    left, right = 0, len(li) - 1
    
    while left <= right:
        mid = (left + right) // 2
        if li[mid] < val:
            left = mid + 1
        elif li[mid] > val:
            right = mid - 1
        else:
            return li[mid]

   return None

52. 谈谈你对闭包的理解?(待完善)
(1)理解1:
闭包作用,保证数据安全;
内层函数对外层函数非全局变量的引用就会形成闭包;
被引用的非全局变量也称自由变量,这个自由变量会与内层函数产生一个绑定关系;
自由变量不会在内存中消失。
(2)创建一个闭包必须满足以下几点:
1)必须有一个内嵌函数;
2)内嵌函数必须引用外部函数中的变量;
3)外部函数的返回值必须是内嵌函数
(3)理解3:
闭包其实就是将函数内部的局部变量包装起来,当函数调用完毕之后,函数返回对象的__closure__属性中任然存在这原函数的局部变量,而且可以用。__closure__返回的是一个tuple,tuple中每一个元素是cell对象。

def func1(x):
    def func2(y):
        return x+y
    return func2

for cell in fisrt.__closure__:
    print(cell.cell_contents)

通俗的理解闭包 闭包能帮我们做什么?

53. os和sys模块的作用?
os:系统有关。这个模块提供了一种方便的使用操作系统函数的方法。
sys:解释器有关。这个模块可供访问由解释器使用或维护的变量和与解释器进行交互的函数。

import os

os.getcwd() # 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  # 改变当前脚本工作目录;相当于shell下cd
os.curdir  # 返回当前目录: ('.')
os.pardir  # 获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2')    # 可生成多层递归目录
os.removedirs('dirname1')    # 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    # 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')    # 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    # 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove()  # 删除一个文件
os.rename("oldname","newname")  # 重命名文件/目录
os.stat('path/filename')  # 获取文件/目录信息
os.sep    # 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep    # 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep    # 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name    # 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command")  # 运行shell命令,直接显示
os.environ  # 获取系统环境变量
os.path.abspath(path)  # 返回path规范化的绝对路径
os.path.split(path)  # 将path分割成目录和文件名二元组返回
os.path.dirname(path)  # 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path)  # 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path)  # 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  # 如果path是绝对路径,返回True
os.path.isfile(path)  # 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path)  # 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]])  # 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path)  # 返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path)  # 返回path所指向的文件或者目录的最后修改时间

import sys

sys.argv           命令行参数List,第一个元素是程序本身路径
sys.exit(n)        退出程序,正常退出时exit(0)
sys.version        获取Python解释程序的版本信息
sys.maxint         最大的Int值
sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform       返回操作系统平台名称

54. 如何生成一个随机数?

import random
random.random():生成一个[0,1.0)之间的随机小数。
random.uniform(a,b):生成一个a到b之间的随机小数。
random.randint(a,b):生成一个a到b之间的随机整数。
random.randrange(a,b,c):随机生成一个从a到b以c递增的数。

55. 如何使用python删除一个文件?

import os
os.remove(path) # 删除文件path。如果path是一个目录,抛出osError错误。
os.rmdir("dir") # 只能删除空目录

56. 谈谈你对面向对象的理解?
体现在三个方面: 封装、继承、多态
(1)封装有两种方式:
1)将同一类的方法封装到类中
2)将数据封装到对象中
(2)继承:子类拥有父类的所有方法和属性,
好处:抽取重复代码,减少代码冗余。
坏处:耦合性太强。
(3)多态:同一个方法在不同的类中最终呈现出不同的效果,即为多态。
简单一句说多态:求面积方法,三角形是ab/2,矩形是ab.

57. Python面向对象中的继承有什么特点?(待完善)
1、在继承中基类的构造(init()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。super().init()

2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数

3、Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)

继承的优点:
(1)建造系统中的类,避免重复操作。
(2)新类经常是基于已经存在的类,这样就可以提升代码的复用程度。

58. 面向对象深度优先和广度优先是什么?(待完善)
(1)定义
深度优先:不全部保留节点,占用空间小,有回溯操作(即有入栈/出栈操作),运行速度慢。
广度优先:保留全部节点,占用空间大;无回溯操作(既无入栈、出栈操作)、运行速度快。
(2)执行方法的查找顺序:
在经典类中,是深度优先,先把一条线查完(栈,)
在新式类中,广度优先(顺着一条线查,如果还有别的路可以查到一个类,这条路就终止了,换一条线查)
(3)继承用到
python2中的没有继承object的类都是经典类,经典类都是深度优先。
python3中都是继承object的新式类,新式类都是广度优先;如果你创建了一个类,并且该类没有继承任意类,那么他就是一个经典类

59.super函数的作用是什么?(待学习)
super()函数是用于调用父类的一个方法,实例化父类。用来解决多重继承问题的。

# python3的示例:
class A:
     def add(self, x):
         y = x+1
         print(y)
class B(A):
    def add(self, x):
        super().add(x)
b = B()
b.add(2)  # 3

# python2的示例:
class A(object):   # Python2.x 记得继承 object
    def add(self, x):
         y = x+1
         print(y)
class B(A):
    def add(self, x):
        super(B, self).add(x)
b = B()
b.add(2)  # 3

60. 是否使用过functools中的函数?其作用是什么?(待学习)
作用:把一个函数的某些参数给固定住,返回一个新的函数,调用这个新函数会更简单。
他的装饰器修复的函数functool.wraps,还有偏函数functools.partial

functools中很多函数,搞明白需要一定的时间。可以参考http://c.biancheng.net/view/2443.html

61. 列举面向对象中带爽下划线的特殊方法,如:newinit(待学习)
62. 列举面向对象中的特殊成员以及应用场景? (类似问题)name,module,dict,__doc__等等
str :call :getattr :setattr :enter :exit :getitem :setitem :iter :

__new__:可以调用其它类的构造方法或者直接返回别的对象来作为本类的实例。
__init__: 负责类的实例化
__call__:对象后边加括号,出发执行
__str__:print打印一个对象时。
__doc__:类的注释,该属性是无法继承的。
__getattr__:在使用调用属性(方式、属性)不存在的时候触发
__setattr__:添加/修改属性会触发它的执行
__dellattr__:删除属性的时候会触发
__delete__:采用del删除属性时,触发

63. 如何判断是函数还是方法?
(1)定义:
函数:是封装了一些独立的功能。可以直接调用,python内置了许多函数,同时可以自建函数来使用。
方法:和函数类似,同样封装了独立的功能,但是方法是需要通过对象来调用的,表示针对这个对象要做的操作。
(2)判断
print(isinstance(obj.func, FunctionType)) # False
print(isinstance(obj.func, MethodType)) # True
注:
isinstance(object, classinfo)函数:判断一个对象是否是一个已知的类型,类似 type()。

  • object – 实例对象。
  • classinfo – 可以是直接或间接类名、基本类型或者由它们组成的元组。
  • 如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False。

64. 静态方法和类方法区别?
静态方法:相当于普通函数
类方法:通过类调用,第一个参数默认是类本身。

  • 实例方法只能由实例调用,并且一般使用self作为实例本身在类实例化的时候进行传参;
  • 普通方法只能由类调用,不能由实例调用,可以在类内部被其他函数调用;
  • 静态方法和类方法都可以由类和实例调用。
class Classname:
    @staticmethod # 用 @staticmethod 装饰的不带 self 参数的方法叫做静态方法,类的静态方法可以没有参数,可以直接使用类名调用。
    def fun():
        print('静态方法')

    @classmethod # 加上 @classmethod 装饰器,默认有个 cls 参数,可以被类和对象调用。
    def a(cls):
        print('类方法')

    # 普通方法 # 默认有个self参数,且只能被对象调用。
    def b(self):
        print('普通方法')

Classname.fun() # 类调用
Classname.a() # 类调用

C = Classname() # 对象调用
C.fun()
C.a()
C.b()

65. 1、2、3、4、5 能组成多少个互不相同且无重复的三位数?
60个,数学公式就是C53*3!

li = [1,2,3,4,5]
li_str = []
for i in li:
    for j in li:
        for k in li:
            if i != j and j != k and k != i:
                li_str.append(f"{i}{j}{k}")

print(len(li_str))

66. 什么是反射?以及应用场景?
python的四个重要内置函数:getattr、hasattr、delattr和setattr较为全面的实现了基于字符串的反射机制。通过getattr()内值函数将一个指定的字符串映射到一个接口或者函数,他们都是对内存内的模块进行操作,并不会对源文件进行修改。主要的应用场景是:在web后端根据不同入参值走不同的接口。
67. metaclass作用?以及应用场景?
68. 用尽量多的方法实现单例模式。new, 装饰器。创建对象的过程:调类的__new__()方法实例化对象,然后在调用__init__()方法初始化对象。我们实现单例模式的话就直接重写__new__方法:

class Singleton(object):
    def __new__(cls,a):
        if not hasattr(cls, '_instance'):
            cls._instance = object.__new__(cls)
        return cls._instance

    def __init__(self,a):
        self.a = a

    def aa(self):
        print(self.a)

69. 装饰器的写法以及应用场景。
装饰器本质上是个python函数,目的是在不影响其他函数功能的情况下通过注解语法糖,给函数添加新增新的功能。

应用场景:
1,引入日志
2,函数执行时间统计
3,执行函数前预备处理–测试
4,执行函数后清理功能–测试
5,权限校验
6,函数或者接口QPS获取
补充链接如何理解Python装饰器?

70. 异常处理写法以及如何主动抛出异常(应用场景)?

(1)

try:
    """执行语句"""
except: #异常类型
    """触发异常后执行的语句"""
finally:
    """有没有异常都执行的语句"""

(2)主动抛出异常
raise #异常类实例
自定义异常之后,在try语句中raise这个自定义Exception。

71. 什么是面向对象的MRO?
Method Resoluthion Order. 继承场景下方法解析顺序问题,多重继承的情况下,寻找目标方法的算法。在Python2中基类的MRO是采用深度遍历优先。新式类的MRO算法是广度优先。在python3中MRO采用叫C3的算法,代码试了一下还是不太明白既不是深度遍历也不是广度遍历。感觉是个结合体。

72. isinstance作用以及应用场景?
判断对象是不是某个类的实例
isinstance(object, classinfo),如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False。
注:
isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。

73. 写代码并实现:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1]

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        if len(nums) == 2:
                return [0, 1]
        else:
            for i in range(len(nums)):
                for j in range(i+1, len(nums)):
                    if nums[i]+ nums[j] == target:
                        return [i, j]

74.json序列化时,可以处理的数据类型有哪些?如何定制支持datetime类型?
对于python而言有dict、list、string、int、float、long、bool、None。

75.json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?
dumps时指定ensure_ascii=False

76.什么是断言?应用场景?
assert 主要用于单元测试
断言条件为真时代码继续执行,否则抛出异常,这个异常通常不会去捕获他.我们设置一个断言目的就是要求必须实现某个条件

77. 有用过with statement吗?
背景:file = open(“text.txt”,“r”)
这样直接打开文件,如果出现异常(如,读取文件过程中文件不存在),则直接出现错误,close命令无法执行,文件无法关闭。
with open() as file:
用with语句的好处就是到达语句末尾时会自动关闭文件,即使出现异常。作用效果相当于try-except-finally
应用:文件操作时使用过
补充链接:open()与with open()

78.使用代码实现查看列举目录下的所有文件?
[ele for ele in os.listdir(os.path.curdir) if os.path.isfile(ele)]

79.简述 yield和yield from关键字?
yield : 生成器函数关键字,yield 后面接的对象会一个一个地往生成器中添加进去,访问生成器用的内建函数next()。
yield from : 相当于for i in obj : yield i

你可能感兴趣的:(2020面试篇:python面试题库(基础篇)附详细答案)