Python面试宝典
第二章 Python基础
一、基础语法
1.输入与输出
1.1 代码中要修改不可变数据会出现什么问题? 抛出什么异常?
答:代码不会正常运行,抛出 TypeError 异常。
1.2 不使用中间变量交换a和b的值?
- 相加相减法
- 异或运算
- a,b=b,a
1.3 print 调用 Python 中底层的什么方法?
答:sys.stdout.write()方法
1.4 简述对input()函数的理解?
答:在 Python3 中,input()获取用户输入,不论用户输入的是什么,获取到的都是字符串类型的。
2.条件与循环
2.1 range和xrange的区别?
答:二者用法相同,不同:range返回列表,xrange返回生成器。xrange比range性能更好。
3.文件操作
3.1 4G内存如何读取5G的数据?
- 通过生成器,分多次读取
- 通过linux命令split切割成多个小文件
3.2 现在考虑有一个 jsonline 格式的文件 file.txt 大小约为 10K,之前处理文件的
代码如下所示:
def get_lines():
l = []
with open(‘file.txt’,‘rb’) as f:
for eachline in f:
l.append(eachline)
return l
if __name__ == ‘__main__’:
for e in get_lines():
process(e) #处理每一行数据
现在要处理一个大小为 10G 的文件,但是内存只有 4G,如果在只修改 get_lines 函数而其他代
码保持不变的情况下,应该如何实现?需要考虑的问题都有哪些?
def get_lines():
l = []
with open(‘file.txt’,’rb’) as f:
data = f.readlines(60000)
l.append(data)
yield l
答:要考虑到的问题有:
内存只有 4G 无法一次性读入 10G 的文件,需要分批读入。分批读入数据要记录每次读入数据的位置。分批每次读入数据的大小,太小就会在读取操作上花费过多时间
3.3 read、readline 和 readlines 的区别?
- read读取整个文件
- readline生成器方法
- readlines返回迭代器供我们遍历
4.异常处理
try:
可能触发异常的语句
except 错误类型1 [as 变量1]:
处理语句1
except 错误类型2 [as 变量2]:
处理语句2
except Exception [as 变量3]:
不是以上错误类型的处理语句
else:
未发生异常的语句
finally:
无论是否发生异常的语句
4.1 在 except 中 return 后还会不会执行 finally 中的代码?怎么抛出自定义异常?
答:会继续处理 finally 中的代码;用 raise 方法可以抛出自定义异常。
5.模块和包
5.1 常用的 Python 标准库都有哪些?
-
标准库
-
os 操作系统
-
time 时间模块
-
random 随机
-
pymysql 连接数据库
-
threading 线程
-
multiprocessing 进程
-
queue 队列
-
-
第三方库
- django
- flask
- pytorch和tensorflow
- numpy和pandas
5.2 赋值、浅拷贝和深拷贝的区别?(重点)
- 赋值的本质就是将一个对象的内存空间地址赋值给一个变量,让变量指向该内存空间地址。
- 浅拷贝是拷贝了源对象的引用,并创建了一个新的内存空间地址。但是引用的对象的子对象的地址仍然是源对象的,所以当源对象的子对象发生改变时,拷贝对象内的子对象同时也跟着改变。
- 深拷贝就是彻底的拷贝,完全的拷贝了父对象及子对象,同时指向一个新的内存空间地址。源对象与拷贝对象之间的修改互不影响。
5.3 init 和__new__的区别?
- init 在对象创建之后,对对象进行初始化
- new是在对象创建之前创建一个对象,并将对象返回给init进行初始化
5.4 unittest 是什么?
答:在 Python 中,unittest 是 Python 中的单元测试框架。它拥有支持共享搭建、自动测试、在测试
中暂停代码、将不同测试迭代成一组,等的功能。
5.5 模块和包是什么?
答:在 Python 中,模块是搭建程序的一种方式。每一个 Python 代码文件都是一个模块,并可以引用其他的模块,比如对象和属性。
一个包含许多 Python 代码的文件夹是一个包。一个包可以包含模块和子文件夹。
6.Python特性
6.1Python 是强语言类型还是弱语言类型?
Python是强类型的动态脚本语言。
- 强类型:不允许不同类型相加
- 动态:不使用显示数据类型声明,且确定一个变量的类型是在第一次给它赋值的时候
- 脚本语言:解释性语言,不需要编译。
6.2 谈一下什么是解释性语言,什么是编译性语言?
-
解释性语言:边运行便翻译
-
编译型语言:翻译成机器语言后再执行
6.3 Python 中有日志吗?怎么使用?
答:使用logging模块,调用logging.basicConfig()方法
6.4 关于 Python 程序的运行方面,有什么手段能提升性能?
- 使用多进程、多线程
- 使用C或C++编写性能影响较大的部分代码
- IO阻塞可以使用IO多路复用
- 尽量使用Python内建函数
- 尽量使用局部变量
6.5 Python的作用域?
Local)—>被嵌入函数作用域Enclosing locals—>Global—>内置作用域(Built-in)
6.6 什么是 Python 自省?
答:自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.
简单一句就是运行时能够获得对象的类型.比如 type(),dir(),getattr(),hasattr(),isinstance().
6.7 什么是 Python 的命名空间?
答:在 Python 中,所有的名字都存在于一个空间中,它们在该空间中存在和被操作——这就是命名空间。它就好像一个盒子,每一个变量名字都对应装着一个对象。当查询变量的时候,会从该盒子里面寻找相应的对象。
6.8 你所遵循的代码规范是什么?请举例说明其要求?(重点)
PEP8规范
- 变量
- 函数和方法
- 类
- 模块和包:除特殊模块 init 之外,模块名称都使用不带下划线的小写字母
- 关于参数
- 其他
- 一些数字
- 一个函数不超过30行代码
- 一个类不超过200行代码,不超过10个方法,一个模块不超过500行
- pep8工具验证是否符合规范
7.Linux基础和git
7.1 Linux 的基本命令(怎么区分一个文件还是文件夹)
答:ls -F 在显示名称的时候会在文件夹后添加“/”,在文件后面加“*”
7.2 日志以什么格式,存放在哪里?
答:日志以文本可以存储在“/var/log/”目录下后缀名为.log
7.3 Linux 查看某个服务的端口?
netstat -nlp | grep 80
7.4 在 linux 中 find 和 grep 的区别?
grep 是查找匹配条件的行,find 是搜索匹配条件的文件
7.5 Linux 重定向命令有哪些?有什么区别?
- 重定向> 将命令执行结果重定向到一个文件test.txt(存在则覆盖,不存在则新建)
- 重定向> 将命令执行结果追加到一个文件test.txt(原内容不影响)
7.6 软链接和硬链接的区别?
答:软连接类似 Windows 的快捷方式,当删除源文件时,那么软链接也失效了。硬链接可以理解为源文件的一个别名,多个别名所代表的是同一个文件。当 rm 一个文件的时候,那么此文件的硬链接数减1,当硬链接数为 0 的时候,文件被删除。
7.7 git 合并文件有冲突,如何处理?
答:a)git merge 冲突了,根据提示找到冲突的文件,解决冲突如果文件有冲突,那么会有类似的标记;
b)修改完之后,执行 git add 冲突文件名
c)git commit 注意:没有-m 选项 进去类似于 vim 的操作界面,把 conflict 相关的行删除掉直接 push 就可以了,因为刚刚已经执行过相关 merge 操作了。
二、数据类型
1.字典
2.字符串
3.列表
4.元组
5.集合
第三章 Python高级
一、元类
1.Python 中类方法、类实例方法、静态方法有何区别?
类方法:是类对象的方法,在定义时需要在上方使用“@classmethod”进行装饰,形参为 cls,表示类对象,类对象和实例对象都可调用
类实例方法:是类实例化对象的方法,只有实例对象可以调用,形参为 self,指代对象本身;
静态方法:是一个任意函数,在其上方使用“@staticmethod”进行装饰,可以用对象直接调用,静态方法实际上跟该类没有太大关系。
2.Python中如何动态获取和设置对象的属性?
if hasattr(Parent,'x'):
print(getattr(Parent,'x'))
setattr(Parent,'x',3)
print(getattr(Parent,'x'))
二、内存管理和垃圾回收机制
1.Python的内存管理机制及调优手段?
垃圾回收:
- 引用计数
- 标记清除
- 分代回收
当某些内存块 M 经过了 3 次垃圾收集的清洗之后还存活时,我们就将内存块 M 划到一个集合A 中去,而新分配的内存都划分到集合 B 中去。当垃圾收集开始工作时,大多数情况都只对集合 B 进行垃圾回收,而对集合 A 进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合 B 中的某些内存块由于存活时间长而会被转移到集合 A 中,当然,集合 A 中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。
调优手段:
-
1.手动垃圾回收
-
2.调高垃圾回收阈值
-
3.避免循环引用(手动解循环引用和使用弱引用)
2.内存泄漏是什么?如何避免?
指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。导致程序运行速度减慢甚至系统崩溃等严重后果。
原因:有 del() 函数的对象间的循环引用是导致内存泄漏的主凶。
解决:不使用一个对象时使用:del object 来删除一个对象的引用计数就可以有效防止内存泄漏问题
判断是否内存泄漏:sys.getrefcount(obj),如果返回的引用计数不为 0,说明在此刻对象 obj 是不能被垃圾回收器回收掉的。
三、函数
1. 函数参数
1.1 Python 函数调用的时候参数的传递方式是值传递还是引用传递?
答:Python 的参数传递有:位置参数、默认参数、可变参数、关键字参数。
函数的传值到底是值传递还是引用传递,要分情况:
- 不可变参数用值传递(拷贝)
- 可变参数用引用传递
1.2 对缺省参数的理解 ?
答:缺省参数指在调用函数的时候没有传入参数的情况下,调用默认的参数,在调用函数的同时赋值时,所传入的参数会替代默认参数。
*args 是不定长参数
**kwargs 是关键字参数
1.3 为什么函数名字可以当做参数用?
答:Python 中一切皆对象,函数名是函数在内存中的空间,也是一个对象。
2.内建函数
2.1 map函数和reduce函数?
答:map()方法会将 一个函数 映射到序列的每一个元素上,生成新序列返回。(函数可以传递1或多个参数)
reduce()是将传入的函数作用在序列的第一个元素得到结果后,把这个结果继续与下一个元素作用(累积计算),返回一个数。(函数只能传递两个参数)
2.2 递归函数停止的条件?
递归的终止条件一般定义在递归函数内部,在递归调用前要做一个条件判断,根据判断的结果选择是继续调用自身,还是 return;返回终止递归。
终止的条件:
- 判断递归的次数是否达到某一限定值
- 判断运算的结果是否达到某个范围等,根据设计的目的来选择
2.3 回调函数如何通信的?
答:回调函数是把**函数的指针(地址)**作为参数传递给另一个函数,将整个函数当作一个对象,赋值给调用的函数。
2.4 一句话解决阶乘函数?
reduce(lambda x,y:x*y,range(1,n+1))
3.Lambda
四、设计模式
1.单例
1.1 手写一个单例?
class Singleton:
def __new__(cls,*args,**kwargs):
if not hasattr(cls,"_instance"):
cls._instance =super(Singleton,cls).__new__(cls)
return cls._instance
1.2 单例模式的应用场景?
- 共享资源,避免由于资源操作时导致的性能或损耗等,如日志文件、应用配置
- 控制资源的情况下,方便资源之间的互相通信,如线程池
2.装饰器
2.1对装饰器的理解 ,并写出一个计时器记录方法执行性能的装饰器?
答:装饰器本质上是一个 Python 函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
import time
def timeit(func):
def wrapper():
start = time.clock()
func()
end =time.clock()
print 'used:', end - start
return wrapper
@timeit
def foo():
print 'in foo()'
2.2 什么是闭包三要素?
- 函数嵌套
- 内调用外
- 外返回内
2.3 函数装饰器有什么作用?
答:装饰器本质上是一个 Python 函数,它可以在让其他函数在不需要做任何代码的变动的前提下增加额外的功能。装饰器的返回值也是一个函数的对象,它经常用于有切面需求的场景。 比如:插入日志、性能测试、事务处理、缓存、权限的校验等场景 有了装饰器就可以抽离出大量的与函数功能本身无关的雷同代码并发并继续使用。
3.生成器
3.1生成器、迭代器的区别?
3.2 yield 用法?
五、面向对象
1.类
类是创建对象的模板。
2.对象
2.1 Python 中的可变对象和不可变对象?
2.2 Python 中 is 和==的区别?
答:is是通过id判断,而==是通过值判断。
2.3Python中的魔法方法?
创建对象自动调用
__init__ 构造器,当一个实例被创建的时候初始化的方法。但是它并 不是实例化调用的第一个方法。
__new__才是实例化对象调用的第一个方法,它只取下 cls 参数,并把 其他参数传给 __init__。 __new__很少使用,但是也有它适合的场景,尤其 是当类继承自一个像元组或者字符串这样不经常改变的类型的时候。
__call__ 允许一个类的实例像函数一样被调用 。
__getitem__ 定义获取容器中指定元素的行为,相当于 self[key] 。
__getattr__ 定义当用户试图访问一个不存在属性的时候的行为 。
__setattr__ 定义当一个属性被设置的时候的行为 。
__getattribute__ 定义当一个属性被访问的时候的行为
2.4面向对象中怎么实现只读属性?
2.5谈谈你对面向对象的理解?
答:面向对象是相对于面向过程而言的。面向过程语言是一种基于功能分析的、以算法为中心的程序设计方法;而面向对象是一种基于结构分析的、以数据为中心的程序设计思想。在面向对象语言中有一个有很重要东西,叫做类。
面向对象有三大特性:封装、继承、多态。
六、正则表达式
1. Python 里 match 与 search 的区别?
2. Python 字符串查找和替换?
3.用 Python 匹配 HTML g tag 的时候,<.> 和 <.?> 有什么区别?
答:<.>是贪婪匹配,会从第一个“<”开始匹配,直到最后一个“>”中间所有的字符都会匹配到,中间可能会包含“<>”。
<.?>是非贪婪匹配,从第一个“<”开始往后,遇到第一个“>”结束匹配,这中间的字符串都会匹配到,但是不会有“<>”。
4.正则元字符的含义?
七、系统编程
1.如何实现多进程、多线程?
实现多进程:multiprocessing模块
【1】 将需要新进程执行的事件封装为函数
【2】 通过模块的Process类创建进程对象,关联函数
【3】 通过进程对象调用start启动进程
【4】join()等待子进程结束
实现多线程:threading模块
【1】 将需要新线程执行的事件封装为函数
【2】 通过模块的Thread类创建线程对象,关联函数
【3】 通过线程对象调用start启动线程
【4】join()等待子进程结束
2. 谈谈你对多进程,多线程,以及协程的理解,项目是否用?
答:性能要求特别高的项目,才会用到多进程、多线程,小项目用不到。如多线程写爬虫
进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大。
线程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
3.什么是多线程竞争
线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:
数据几乎同步会被多个线程占用,造成数据混乱 ,即所谓的线程不安全
那么怎么解决多线程竞争问题?-- 锁。
-
锁的好处:
确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下 的原子操作问题。
-
锁的坏处:
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了 锁的致命问题:死锁。
八、网络编程
1.UDP和TCP的实现流程?
2.简述TCP和UDP的区别以及优缺点?
UDP 是面向无连接的通讯协议。
- 优点:速度快、操作简单、要求系统资源比较少,可以实现广播模式。
- 缺点:由于传输数据前不与对方建立连接,不重复发送,不可靠。
TCP 是面向连接的通讯协议,通讯前三次握手建立连接,通讯完成时四次挥手断开连接。
- 优点:保障数据的准确性,较为可靠。
- 速度慢,消耗系统资源较多。
3.请简单说一下三次握手和四次挥手?
三次握手:建立连接
- 客户端向服务器发送消息报文请求连接
- 服务器收到请求后,回复报文确定可以连接
- 客户端收到回复,发送最终报文连接建立
四次挥手:断开连接
- 客户端发送报文请求断开连接
- 服务端收到请求后,立即回复,表示准备断开
- 服务端准备就绪,再次发送报文表示可以断开
- 客户端收到确定,发送最终报文完成断开
4.HTTP 请求方法都有什么?
HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法。
HTTP1.1 新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法
5.七层网络模型?
6.url的形式?
形式: scheme://host[:port#]/path/…/[?query-string][#anchor]
第四章 数据库
一、Mysql
1.Python操作Mysql的步骤?
2.SQL 的 select 语句完整的执行顺序?
(5)SELECT DISTINCT <select_list>
(1)FROM <left_table> <join_type> JOIN <right_table> ON <on_predicate>
(2)WHERE <where_predicate>
(3)GROUP BY <group_by_specification>
(4)HAVING <having_predicate>
(6)ORDER BY <order_by_list>
(7)LIMIT <limit_number> offset number
3.事务的四大特性?
- 原子性
- 一致性
- 隔离性
- 持久性
4.数据库的索引?
索引的实现通常使用B_Tree,加快数据的查询速度。
5.数据库如何优化查询效率?
- 存储引擎,InnoDB实务,MyISAM查询速度更快
- 分表分库
- 对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索
引 - 避免在 where 子句中对字段进行 null 值判断
- 避免在 where 子句中使用 != 或 <> 操作符
- 避免在 where 子句中使用 or 来连接条件
- Update 语句,如果只更改 1、2 个字段,不要 Update 全部字段,否则频繁调用会引起明显的
性能消耗,同时带来大量日志 - 对于多张大数据量(这里几百条就算大了)的表 JOIN,要先分页再 JOIN,否则逻辑读会很高,
性能很差。
6.Mysql集群的优缺点?
优点:
- 高可用
- 快速的自动失效切换
- 灵活的分布式体系结构,没有单点故障
- 高吞吐量和低延迟
- 可扩展性强,支持在线扩容
缺点:
- 存在很多限制,比如:不支持外键
- 部署、管理、配置很复杂
- 占用磁盘空间大、内存大
- 备份和恢复不方便
- 重启的时候,数据节点将数据 load 到内存需要很长的时间
7.你用的 Mysql 是哪个引擎,各引擎之间有什么区别?
主要 MyISAM 与 InnoDB 两个引擎,其主要区别如下:
- InnoDB 支持事务,MyISAM 不支持
- InnoDB 支持外键,MyISAM 不支持
- InnoDB 支持行锁,MyISAM支持表级锁
8.数据库设计范式?
第一范式:列不可拆
第二范式:记录可以唯一区分
第三范式:外键建立在主键上
二、Redis
非关系型数据库
类型 | 特点 | 使用场景 |
---|---|---|
string | 简单key-value类型,value可为字符串和数字 | 常规计数(微博数, 粉丝数等功能) |
hash | 是一个string类型的field和value的映射表,hash特别适合用于存储对象 | 存储部分可能需要变更的数据(比如用户信息) |
list | 有序可重复列表 | 消息队列等 |
set | 无序不可重复集合 | 存储并计算关系(如微博,关注人或粉丝存放在集合,可通过交集、并集、差集等操作实现如共同关注、共同喜好等功能) |
sortedset | 每个元素带有分值的集合 | 各种排行榜 |