基础篇--【python】面试题汇总
1.尽可能多的列举PEP8规范有哪些?
- 不要在行尾加分号,也不要用分号将两条命令放在一行
- 每行不超过80个字符
- 不要使用反斜杠连接行
- 在注释中,如果有必要,将长的url放在一行
- 除非用于实现行连接,否则不要在返回语句或条件语句中使用括号
- 用4个空格代替代码缩进,不要使用TAB
- 顶级定义之间空2行,方法定义之间空1行
2.ascii,unicode,utf-8,gbk的区别
ascii 8位 一个字节
unicode A:32位,四个字节 中文:32位,四个字节
utf-8 A:8位,一个字节 中文:16位,两个字节
gbk A:8位,一个字节 中文:16位,两个字节
区别:
1.各个编码之间的二进制是不能互相识别的
2.文件的存储,传输,不能是unicode,只能是utf-8,gbk,ascii
转换:
encode str > bytes 编码
decode bytes > str 解码
3.python递归的最大层数是多少以及如何修改
python默认递归最大数为1000,用于防止无限递归造成内存溢出奔溃
修改方法:
import sys
sys.setrecursionlimit(1500)
4.字节码和机器码的区别
字节码是一种中间状态的二进制代码,需要直译器转译后才能成为机器码
5.三元运算符是什么
三元运算符就是在赋值变量的时候,可以直接加判断
res = a if a > b else b
6.列举python2和python3的区别
print : 2print语句,3print函数
输入函数:2 input_raw() ,3 input()
super(): 2 必须显示的在参数中写上基类,3直接无参数调用即可
没有了int和long的区别
编码:2 默认ascii,3默认utf-8
字符串:
2.unicode表示字符串序列,str表示字节序列
3.str表示字符串序列,byte类型表示字节序列
true和false:
2.可以赋值和操作
3.不可变
迭代器:
2.当中许多返回列表的方法,如range,字典对象的dict.keys(),dict.values()方法,map,filter,zip:并且迭代器必须实现next方法
3.将返回列表的方法改为了返回迭代器对象,内置了__next__,不用特意去实现next
7.用一行代码实现数值交换
a,b = b,a
8.xrange和range的区别
range和xrange都是在循环中使用,输出结果一样
range返回一个list对象,xrange返回一个生成器对象
xrange每次调用返回其中的一个值,内存占用少,性能好
9.字符串,列表,元组,字典各自常用的方法
string: 去掉空格和特殊符号: name1 = name.strip() #去掉两边空格 name2 = name.lstrip() #去掉左边空格 name3 = name.rstrip() #去掉右边空格 搜索和替换: name.count("e") #查找某个字符在字符串中出现的次数 name.capitalize() #首字母大写 name.center(100,"-") #把字符串放中间,两边用-补齐到100 name.find("a") #找到这个字符返回下标,存在多个返回第一个,不存在返回-1 name.index("a") #找到这个字符返回下标,存在多个返回第一个,不存在报错 print(name.replace(name,"123")) #字符串的替换 name.replace("abc","123") #返回一个替换后的字符串 验证和替换函数: name.startswith("abc") #是否以abc开头 name.endswith("abc") #是否以abc结尾 name.isalnum() #是否全十字母和数字,并且至少包含一个字符 name.isalpha() #是否全是字母,并且至少包含一个字符 name.isdigit() #是否全是数字,并且至少包含一个字符 name.isspace() #是否全是空白字符,并且至少包含一个支付 name.islower() #是否全是小写 name.isupper() #是否全是大写 name.istitle() #是否首字母大写 字符串的分割: name.split('') #默认按照空格进行分割,从前往后 name.rsplit() #从后往前分割 连接字符串: '.'.join(name) #用.号将一个可迭代的序列拼接起来 切片: name1 = name[0:3] #截取第一位到第三位的字符 name2 = name[:] #截取全部字符 name3 = name[6:] #截取第6个字符到结尾 name4 = name[:-3] #截取从开头到最后一个字符之前 name5 = name[-1] #截取最后一个字符 name6 = name[::-1] #创造一个与原字符串顺序相反的字符串 name7 = name[:-5:-1] #逆序截取 列表: 列表的特性: 有序集合,通过偏移来索引,从而读取数据,支持嵌套,可变类型 创建列表: list1 = ["1","2","3","4"] #方法1 list2 = list("1234") #方法2 添加元素: 末尾追加: list1.append(5) 指定位置前面插入: list1.insert(2,6) #下标为2的前面插入6 追加一个列表: list1.extend([7,8,9]) 遍历列表: 直接遍历: for i in list1: print(i) 带索引遍历: for index,i in enumerate(list1): print(i,index) 通过下标取值: print(list1[2]) 删除元素: list1.remove() #参数object,删除靠前的重复元素,无重复返回None list1.pop() #可选参数 index,删除指定位置的元素,默认为最后一个元素 del list1[1] #删除列表或者指定元素或者切片,删除后无法访问 排序和反转代码: list1.reverse() #反转列表 list1.sort() #排序 字典: 字典是无序的可变序列 创建: 空字典: dict1 = {} dict2 = dict() 值为None的字典: dict3 = dict.fromkeys(['a','b','c']) ==> {'a':None,'b':None,'c':None} 通过zip函数构建字典 dict4 = dict(zip(keyslist,valueslist)) 通过赋值表达式元组构造字典 dict5 = dict(name='bob',age=22) ==> {'name':'bob','age':22} 成员关系: 字典的成员关系只判断key,与value无关 列出所有的健,值,键值对: dict6.keys() #键 返回的是可迭代对象 dict7.values() #值 返回的是可迭代对象 dict8.items() #键值对 返回的是可迭代对象 拷贝一个字典的副本: dict9 = dict8.copy() #浅拷贝 dict10 = dict8.deepcopy() #深拷贝 根据键获取值,默认值default dict11 = dict12.get(key,default) 合并更新字典 dict13.updat(dict12) 删除字典 d.pop(key) 新增或者修改键对应的值 D[2] = value #如果存在则修改,不存在则创建 获取字典键的列表,值的列表 list(D.keys()) list(D.values()) 字典推导式 D = [x:x**2 for x in range(10) if x %2 == 0] 字典使用事项 序列运算无效,字典是映射机制 对新索引的赋值会添加新的键值对 键不一定总是字符串,但总是不可变对象 元组: 概述: 任意对象的有序集合,可以通过序列取值 元组不可变的序列的操作类型 固定长度,异构,嵌套(元组里也可以包含元组) 创建: 空元组 t1 = () t2 = tuple() 单个元素要加, x = (40,) ==>一个元组,具有一个元素的值是40 多元素元组的表达方式 t = (1,2,3) t1 = 1,2,3 #括号可以省略 用一个可迭代对象生产元组 t = tuple('abc') 元组的访问 t[i] t[i][j] 合并和重复 t1 + t2 t1 * 3 迭代和成员关系 for x in T: print(x) 'spam' in T 对元组进行排序 对元组排序,通常先得将它转换为列表并使得它成为一个可变对象,或者使用sorted方法,它接收任何序列对象 T = ('c','a','b','d') tmp = list(T) tmp.sort() ==> ['a','b','c','d'] T = tunple(tmp) sorted(T) 为何有了列表还要用元组 元组可以看成是简单得对象组合,而列表是随着时间而改变得数据集合 元组得不可变性提供了某种完整性,这样可以确保元组不会被另外一个引用来修改 元组类似其他语言中的常数声明 集合 创建: a = set() b = set(iterable) #用可迭代对象创建一个集合 集合的运算: & 生成两个集合的交集 s3 = s1 & s2 | 生成两个集合的并集 s3 = s1 | s2 - 生成两个集合的补集 s3 = s1 - s2 ^ 对称补集 s3 = s1 ^ s2 (只能属于s1或者s2,也就是去除掉s1和s2重合的部分)
10.lambda表达式格式以及应用场景?
举例:
from functools import reduce
add = lambda x,y:x+y
print(add(1,2)) # 输出3
与map和用,遍历序列,对序列中每个元素进行操作,获取最终的新序列
x = [11,22,33]
print(list(map(lambda x:x=100,x))) #[111,122,133]
与filter和用,对序列中的元素进行筛选,最终获取符合条件的序列
x2 = [11,22,33]
print(list(filter(lambda x:x>20,x)))
与reduce和用,对序列内所有元素进行累计操作
x3 = [1,2,3,4]
print(reduce(lambda x1,x2:x1+x2,x3))
11.*arg和**kwarg作用?
*arg和**kwarg都是用来传不固定个数的参数到函数中的
*arg :可以理解为只有一列的元组,长度不固定
**kwarg:可以理解为字典,长度不固定。
二者可以单独使用,或者组合使用,一起使用的时候,*arg要放在**kwarg之前。
12.is和==的区别
python中对象包含的三个基本要素,分别是:
id(身份标识)
type(数据类型)
value(值)
对象之间判断是否相等就需要用到is 或者 ==:
is 判断两个对象的id值是否相等,即两个对象是否指向同一个内存地址
== 判断两个对象的值是否相等
13.Python的赋值,深浅拷贝以及应用场景?
import copy
浅拷贝:copy.copy()
深拷贝:copy.deepcopy()
对于数字和字符串而言,赋值,深拷贝和浅拷贝无意义,因为其始终指向同一个内存地址。
赋值:简单的拷贝对象的引用,两个对象的id相同
浅拷贝指的是创建一个新的对象,仅仅拷贝数据集合的第一层数据,在内存中共享子对象
深拷贝指的是创建一个新的组合对象,与原对象完全无关,真正独立。
14.Python垃圾回收机制?
python垃圾回收算法GC算法,分为以下三点:
引用计数/标记-清除/分代回收
引用计数
对象在被方法引用的时候会自动计数加1,当引用该对象的对象被删除的时候,那么该对象的引用计数就会减少,一直到它的引用计数变为0,垃圾回收机制就会自动回收。
优点:
简单实用
缺点:
维护性高,需要占用额外的资源
不能解决循环引用的问题
循环引用:两个列表相互引用
标记-清除
标记-清除就是用来解决循环引用的问题的。
未来追踪容器对象,需要每个容器对象维护两个额外的指针,root链表和unreachable链表。
因为unreachable可能存在被root链表引用的可能,所以要在标记过程中发现并将其从unreachable链表中转移到root链表中,然后剩下的才做真正的回收。
分代回收
理论上讲,创建量应该与释放数量相等,但是如果存在循环引用,创建量就会大于释放量,如果这个差值超出了GC的阈值,那么分代回收机制就会启动。
分代回收将对象分为三代:
0代表幼年对象
1代表青年对象
2代表老年对象
如果在第0代的gc垃圾回收中存活下来,就会进入第1代,第2代同理;
然后如果在上一次检查之后,第N代垃圾回收次数大于第N+1代,那么第N+1代就会做垃圾回收检查。
15.一行代码实现9*9乘法表
print ('\n'.join([' '.join(['%s*%s=%-2s' % (y,x,x*y) for y in range(1,x+1)]) for x in range(1,10)]))
16.列举常见的内置函数?
反射相关,总共4个
hasattr 根据字符串的形式 , 去判断对象中是否有成员
getattr 根据字符串的形式,去对象中找成员
setattr 根据字符串的形式 , 动态的设置一个成员(在内存中)
delattr 用于删除属性
delattr(x, 'foobar') 相等于 del x.foobar
基础数据类型相关,总共38个
bool,int,float,complex(复数),bin(整型转换为二进制),oct(整型转换为八进制),hex(整型转换为十六进制),abs(求绝对值),divmod(除,余数),round(值,小数后几位),pow(幂运算),sum,max,min,list,tuple,reversed,slice,str,format,bytes,bytearry,memoryview,ord,chr,ascill,repr,dict,set(),frozenset,len,sorted,enumerate,all,any,zip,filter,map
作用域相关
locals 获取执行本方法所在命名空间内的局部变量的字典
globals 获取全局变量的字典
面向对象相关
type 元类,类的最高层
object
classmethod 类方法,用来修改类变量
staticmethod 类方法,用来处理一些和操作类无关的事
propery 可以像调用一个变量一样调用一个方法
vars
super 在多继承中,可以保证顶层父类只被调用一次 ,用 _ _mro_ _ 查看多继承规律时,遵循深度优先原则
issubclass 检查第一个参数是否是第二个参数的子子孙孙类
isinstance 检查第一个参数(对象) 是否是第二个参数(类及父类)的实例.
迭代/生成器相关
next
iter
range range 是一个生成器,他只用来存储数据的生成方式,而不直接存储数据
其他
eval 将字符串类型的代码执行并返回结果
exec 将自字符串类型的代码执行
compile
input
print
id
hash
open
__import__
help
callable 检测一个对象能否被调用
dir 查看内置属性和方法
17.如何安装第三方模块?以及用过哪些第三方模块?
pip install django #通过pip安装
pip install -i https://pypi.douban.com/simple django #通过豆瓣源加速安装
python setup.py build # 源码下载解压
python setup.py install
#常用第三方库
pillow #图像相关的处理库
Scrapy # 一个快速,高级的屏幕抓取以及web爬虫框架
requests #一个关于http请求的优秀开源库
beautifulsoup # xml和html的解析库,比较慢,效率很低
18.re的match和search区别?
match()函数只检测RE是不是在string的开始位置匹配,search()会扫描整个string查找匹配;
19.什么是正则的贪婪匹配?
总是尝试匹配尽可能多的字符,对应格式:xx*xx
20.def func(a,b=[]) 这种写法有什么坑?
函数的第二个默认参数是一个list,当第一次指向的时候实例化了一个list,第二次执行还是用第一次执行的时候实例化的地址存储。,默认参数应该设置为None