python面试题
1.简述列举了解的编程语言及语言间的区别? 编译型语言:一次性全部编译成二进制码,再去运行 解释型语言:编译一句,运行一句 一、python 解释型 简洁高效,容易上手 二、 java 混合型 (JVM、JIT编译器)学习成本,开发周期慢,web方向偏重 三、 c 编译型 属于底层语言,只有面向过程,没有面向对象 四、c++ 编译型 属于底层语言,既有面向过程,也有面向对象 五、go 编译型 应用在区块链,高并发高可用,游戏方向 2.列举Python2和Python3的区别? python2: 一、print “123” 二、range 返回 list 三、默认编码 --ascii码(无中文) 四、两种类 经典类 和新式类 class Car() : pass 经典类(多继承当中搜索原则以深度优先) class Car(object) : pass 新式类(多继承当中搜索原则以广度优先) 类.mro() => 继承顺序列表 五、除法:结果是整型 六、int,long(长整型) 七、raw_input => 等价于 python3 input,如光写input 就得输入数字 python3: 一、print() 二、range 返回的是可迭代对象 三、默认编码 --utf-8 四、都是新式类 五、除法:结果是小数(无论整数相除还是浮点数相除) 六、int 七、input 3.看代码写结果 v1 = 1 or 2 输出: 1 v2 = 3 and 7 or 9 and 0 输出: 7 # 逻辑运算符优先级 () > not > and > or # 逻辑短路 and 全真则真,一假则假 or 一真则真,全假则假 True or 表达式 => True (单个运算符和多个运算符的情况,都可以直接判定结果) False and 表达式 => False(单个运算符的时候可以) # 布尔值为假的十种情况: bool() => False 0,0.0,False,0j,'',[],(),set(),{},None v1 = 1 or 2 print(v1) # 1 v2 = 3 and 7 or 9 and 0 # v2 = 7 or 0 # v2 = 7 print(v2) """ 数据类型: Number(int , float , complex , bool) 容器:str list tuple set dict # 复数 : 用在数据分析,人工智能中 complexvar = 3 + 4j 3 : 实数 4j: 虚数 j: 如果有一个数,他的平方等于-1 ,那么这个数就是j,科学家认为有,表达高精度类型 """ 4.比较以下值有什么不同? v1 = [1,2,3] 数字 v2 = [(1),(2),(3)] 数字 括号写些什么类型数据,就是什么数据 v3 = [(1,),(2,),(3,)] 元组 # 逗号才是区分是否是元组的标识符 v1 = [1,2,3] # 列表[int , int , int] v2 = [(89),(2.12),("abc")] # [int , float , str] v3 = [(1,),(2,),(3,)] # [tuple,tuple,tuple,tuple] res = () # 表达空元组 5.用一行代码实现数值交换。 # python 特有 a = 1 b = 2 a,b = b,a # 通用 tmp = a a = b b = tmp 6.Python中单引号、双引号、三引号的区别? 单双引号没有区别,三引号可以支持跨行 在互相嵌套时需注意:里外不能使用相同的引号 7.is和==的区别 is 是判断两边内存地址是否相同 == 判断两边的值是否相同 8.python里如何实现tuple和list的转化? # int float complex bool str list tuple set dict list(数据) tuple(数据) 9.如何实现字符串 name='老男孩'的反转? # name[start:end:step] 语法 name[::-1] 10.两个set如何获取交集、并集、差集? 交集 & intersection 差集 - difference 并集 | union 对称差集 ^ symmetric_difference 11.那些情况下, y != x - (x-y)会成立? """ 非空集合且不为子父关系的两个集合 """ y != x-(x-y) x = {"a","b","c"} y = {"b","d"} if y != x-(x-y): print("ok") 12.Python中如何拷贝一个对象? # import copy # 针对于列表的拷贝,还可以使用[:] , [::],浅拷贝的一种方式 lst1 = [1,2,3] lst2 = lst1[:] lst1.append(4) print(lst2) 13.简述 赋值、浅拷贝、深拷贝的区别? #赋值 : 将变量和值在内存中形成映射指向关系 #浅拷贝 : 只拷贝第一级里所有的元素 copy.copy #深拷贝 : 为所有层级的元素都单独开辟新空间 copy.deepcopy() (地址:原不可变数据只是暂时的指向,可变的数据独立开辟新空间) """ 可变数据: list set dict 不可变数据: int float bool complex str tuple """ import copy lst1 = [1,2,3,[4,5,6]] lst2 = copy.deepcopy(lst1) lst1[0] = 100 print(lst1) print(lst2) print(id(lst1[0])) print(id(lst2[0])) 14.pass的作用? 占位 15.阅读代码写结果。 import copy a = [1,2,4,5,['b','c']] b = a c = copy.copy(a) d = copy.deepcopy(a) a.append(5) a[4].append('d') # print(a) [1,2,4,5,['b','c',"d"],5] # print(b) [1,2,4,5,['b','c',"d"],5] # print(c) [1,2,4,5,['b','c',"d"]] 16.实现9*9乘法表 """ 有行又有列,脑海里瞬间想到两层循环 一层循环控制行 一层循环控制列 """ i = 1 while i<=9: # 这个位置写代码 j = 1 while j<= i: # "谁"*"谁"="谁" print("%d*%d=%2d" % (i,j,i*j),end=" ") j+=1 # 打印换行 print() i+=1 for i in range(1,10): for j in range(1,i+1): print("%d*%d=%2d" % (i,j,i*j),end=" ") print() for i in range(1, 10): for j in range(1, i+1): print(f'{j}x{i}={i*j}',end=' ') print() 1x1=1 1x2=2 2x2=4 1x3=3 2x3=6 3x3=9 1x4=4 2x4=8 3x4=12 4x4=16 1x5=5 2x5=10 3x5=15 4x5=20 5x5=25 1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36 1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49 1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64 1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81 17.用Python显示一个斐波那契数列。 # 1 1 2 3 5 8 13 21 ... # 方法一 lst = [1,1] for i in range(10): lst.append(lst[-1] + lst[-2]) print(lst) # 方法二 a,b = 0,1 for i in range(10): print(b) a,b = b,a+b # 方法三 def fib(n): if n <= 2: return 1 # 上一个值 + 上上个值 return fib(n-1) + fib(n-2) print(fib(6)) 18.如何删除列表中重复的值? list(set(lst)) 19.一个大小为100G的文件etl_log.txt, 要读取文件中的内容, 写出具体过程代码? fp = open("文件名","模式","编码集") """ fp 是迭代器 from collections import Iterator,Iterable # 在遍历fp时,文件按照一行一行进行读取; for i in fp: code ... """ 20.a = dict(zip(("a","b","c","d","e"),(1,2,3,4,5))) 请问a是什么? 强转字典的条件:等长的二级容器,配合强转字典的两个函数 zip , enumerate # zip 拉链 a = dict( zip( ("a","b") , [1,2] ) ) print(a) # enumerate 枚举 a = dict( enumerate( ["a","b"] )) a = dict( enumerate( ["a","b"] ,start = 10 )) print(a) 21.lambda关键字的作用? lambda 匿名函数 : 用一句话表达只有返回值的无名函数 lambda 参数 : 返回值 22.*arg和**kwarg`作用? *arg **kwarg # *arg 普通收集参数 : 收集多余的没人要的普通实参 # **kwarg 关键字收集参数: 收集多余的没人要的关键字实参 23.如何在函数中设置一个全局变量 ? """ global 有该全局变量,修改当前变量,没有改全局变量,定义一个全局变量; """ def func(): global a a = 90 func() print(a) 24.filter、map、reduce的作用? """ 三目(元)运算符 True if 条件表达式 else False filter => 过滤数据 iterable : 可迭代对象(range ,容器类型数据 , 迭代器) filter(func,iterable) => 返回迭代器 lst = [1,2,3,4,5] it = filter(lambda x : True if x % 2 == 0 else False , lst ) print(list(it)) """ # map -> 处理(映射)数据 map(func,iterable) => 返回迭代器 lst = [1,2,3] it = map(lambda x : x*3 , lst) print(list(it)) # reduce -> 计算数据 from functools import reduce # reduce(func,iterable) => 最后计算的值 # [5,4,8,8] => 5488 lst = [5,4,8,8] res = reduce(lambda x,y : x*10 + y ,lst ) print(res , type(res)) 25.什么是匿名函数?匿名函数有什么作用? lambda 匿名函数 : 用一句话表达只有返回值的无名函数 lambda 参数 : 返回值 26.Python递归的最大层数? 官方说法1000 , 实际测试 994 ~ 1000 import sys sys.setrecursionlimit(999999) # 修改递归的最大深度 27.什么是迭代器?什么是可迭代对象? # 具有__iter__() 和 __next__()这两个方法的是迭代器 # 具有__iter__()方法就是可迭代对象 # dir(数据) 可以查看该数据的内部系统成员 # 可迭代对象 => 迭代器 把不能直接被next获取 => 可直接获取到该数据的一个过程 28.什么是生成器? 生成器的本质就是迭代器,可以自定义迭代的逻辑 创建方式两种: (1)生成器表达式 (推导式) (i for i in range(3)) (2)生成器函数 (含有yield关键字) 29.什么是装饰器及应用场景? # 装饰器的本质就是闭包 # 在不修改原有代码的前提下,额外增加新功能就是装饰器 # 应用:登录认证,property类,框架(django,flask,@app.route("/",methdos=["GET","POST"])) 30.什么是反射及应用场景? # 通过字符串去操作类对象 或者 模块中的属性方法 hasattr getattr setattr delattr 应用: 可以配合用户的操作或者输入,调用其中的成员,api接口中 31.写一个普通的装饰器。 闭包:内函数使用了外函数的局部变量,外函数把内函数返回出来的过程叫做闭包 这个内函数叫做闭包函数; 特点:如果内函数使用了外函数的局部变量,那么该变量于内函数发生绑定,延长该变量的生命周期 def wrapper(func): def inner(*args,**kwargs): res = func(*args,**kwargs) print("and you") return res return inner @wrapper def func(): print("i am fine 3q") func() 32.写一个带参数的装饰器。 def outer(n): def wrapper(func): def inner1(*args,**kwargs): res = func(*args,**kwargs) print("我是大王") return res def inner2(*args,**kwargs): res = func(*args,**kwargs) print("大王叫我来巡山") return res if n == "alex": return inner1 else: return inner2 return wrapper @outer("alex123") # outer("alex123") => wrapper =>@wrapper def func(): print("i am fine 3q") func() 33.求结果 def num(): return [lambda x:i*x for i in range(4)] print([m(2) for m in num()]) """ def出现的位置是函数的定义处 函数() 出现的位置是函数的调用处 (1)调用的时候,才会把函数中的代码,从上到下执行一遍,否则不执行 (2)里面的func是一个闭包函数,延长了当前变量i的生命周期,最后一次i的值3,所以再去调用时候拿的3 """ def num(): lst = [] for i in range(4): def func(x): return i*x lst.append(func) return lst lst = num() print(lst) lst = [ m(2) for m in num() ] lst = [ m(2) for m in lst ] lst = [ i*x for m in lst ] lst = [3 * 2 for m in lst] lst = [6,6,6,6] """ [ <function func at 0x000001A02CA642F0>, <function func at 0x000001A02CA64378>, <function func at 0x000001A02CA646A8>, <function func at 0x000001A02CA64730> ] def func(): print(1) for i in range(3): print(i) """ 34.def(a, b=[])这种写法有什么陷阱? b身上的默认值是列表,如果使用原来默认的参数,调用func函数 会把几次调用的值都存放在同一个默认列表里 """ 默认参数: 如果调用时,用户给实参了,那么使用用户的 如果调用时,用户没给实参,那么使用默认的(早已存在内存中的这个列表) 默认值会提前在内存中驻留,在使用时,才能调取,在定义函数的时候就提前开辟了空间 """ 35.看代码写结果 def func(a,b=[]): b.append(a) return b v1 = func(1) v2 = func(2,[10,20]) v3 = func(3) print(v1,v2,v3) # [1,3] [10, 20, 2] [1, 3] 36.看代码写结果 def func(a,b=[]): b.append(a) return b v1 = func(1) print(v1) # [1] v2 = func(2,[10,20]) print(v2) # [10, 20, 2] v3 = func(3) print(v3) # [1, 3] 37.请编写一个函数实现将IP地址转换成一个整数。 # ljust 原字符串居左,填充符号 # rjust 原字符串居右,填充符号 # 方法一 ip = "10.3.9.12" strvar = "" for i in ip.split("."): bin_str = str(bin(int(i)))[2:] # 总长度是8 原字符串居右 strvar += bin_str.rjust(8,"0") print(strvar) # 把二进制字符串转换成十进制,默认转换时,是十进制 print(int(strvar,2)) # 方法二 ip = "10.3.9.12" strvar = "" for i in ip.split("."): # format 将整型转化成二进制,不够8位的拿0补位 strvar += format(int(i) , "08b") print(int(strvar,2))
# 方法一 (递归写法)
import os
def getallsize(pathvar):
size = 0
lst = os.listdir(pathvar)
print(lst)
for i in lst:
pathvar2 = os.path.join(pathvar,i)
print(pathvar2)
# 判断是否是文件
if os.path.isfile(pathvar2):
size += os.path.getsize(pathvar2)
# 判断是否是文件夹
elif os.path.isdir(pathvar2):
size += getallsize(pathvar2)
print(size)
return size
# "E:\串讲基础\day2\test\1.txt"
pathvar = r"E:\串讲基础\day2\test"
res = getallsize(pathvar)
# print(res)
# 方法二
import os
# os.walk() => 生成器
pathvar = r"E:\串讲基础\day2\test"
gen = os.walk(pathvar)
for root,dirs,files in gen:
for name in files:
pathvar = os.path.join(root,name)
print(pathvar)
39.求结果
import math
print (math.floor(5.5))
math.floor就相当于是round,在.前面是奇数就进一位,偶数就不进位
# floor ceil round
import math
print(math.floor(5.5))
# round n.5 奇进偶不进
print(round(4.5))
print(round(5.5))
print(round(4.52))
40.是否使用过functools中的函数?其作用是什么?
from functools import reduce
# 在装饰器中使用,如果想要保留原来函数的属性,加上wraps
from functools import wraps
def wrapper(func):
41.re的match和search区别?
"""
match : 必须从字符串的开头进行匹配
search: 从任意位置开始匹配,匹配到就返回
只匹配一个
"""
42.用Python匹配HTML tag的时候,<.>和<.?>有什么区别?
. 除了\n的任意字符
* 量词,代表匹配0次或者多次,任意个
.* 贪婪匹配
.*? 非贪婪匹配
43.如何生成一个随机数?
import random
random.random 随机获取 0<= x < 1
random.randrange 随机获取指定范围中的整数,用法上同range
random.uniform 随机获取指定范围中的小数
44.super的作用?
# 用来解决多继承之间复杂的调用关系使用super
在多继承中,如果出现了多个同名方法
super在调用的时候,会按照mro列表的继承顺序依次调用
类.mro() = > lst
45.双下划线和单下划线的区别?
class MyClass():
__abc = 90
_ppp = 100
"""
封装: 公有public 私有private 受保护的protected
私有: 只能在当前这个类里面使用,不能再子类或者在类外使用
受保护的: 可以在当前这个类或者子类里使用,不能再类外使用
约定俗成在该变量前面加上一个下划线_ , 就表示受保护了
"""
46.@staticmethod和@classmethod的区别?
一个静态方法,一个类方法
一个静态方法:(无论是对象还是类,都可以调用,不会默认传递任何参数)
一个类方法 :(无论是对象还是类,都可以调用,会默认传递类这个参数)
47.实现一个单例模式(加锁)。
# 单态模式:这个类无论实例化多少次,都有且只有一个对象
from threading import Lock
class MyClass(object):
__obj = None
lock = Lock()
def __new__(cls,*args,**kwargs):
with cls.lock:
if not cls.__obj:
cls.__obj = object.__new__(cls)
return cls.__obj
obj1 = MyClass()
obj2 = MyClass()
print(obj1,obj2)
48.栈和队列的区别?
栈 : 先进后出,或者 后进先出
队列: 先进先出
49.以下代码输出是什么? 请给出答案并解释。
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
# 1 1 1
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
# 1 2 1
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
# 3 2 3
print(Parent.x, Child1.x, Child2.x)
50.参考下面代码片段
#代码片段:
class Context:
pass
with Content() as ctx:
ctx.do_something()
请在Context类下添加代码完成该类的实现
# 面向对象的上下文管理是with语法的具体实现
class Context():
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# 相当于在最后,执行了文件的关闭操作,fp.close()
print("abc123")
def do_something(self):
print(1111)
with Context() as ctx:
ctx.do_something()
print(ctx)
# 自动实现了关闭操作
# with open("文件") as fp:
# res = fp.read()
第二部分 可选题
-
如何获取列表中第二大的值?
# (1) 所有的容器类型数据都可以通过 sorted (sort只局限于列表进行排序)
# 去重
lst = set([98,1,100,3,-100,50,100,100])
res = sorted(lst)
res_new = res[-2]
print(res_new) -
简述Python内存管理机制。
# (2) 内存管理机制
计数器,垃圾回收,内存池
# 一.计数器
特点:引用技术如果是0,把这个值从内存中释放掉
a = 100
b = a
print(b)
del b
缺点:在维护引用计数时,又可能数据产生循环引用,造成数据不能删除,造成内存泄漏
lst1 = [1,2]
lst2 = [5,6]
lst1.append(lst2)
lst2.append(lst1)
del lst1
print(lst1)
print(lst2)
# print(lst1)
# print(lst2) -
简述Python的垃圾回收机制。
# 二.垃圾回收:引用计数为主,标记清除和分带回收为辅
标记清除 : 检测标记该对象,避免出现循环引用不能删除的现象
分带回收 :
把内存中的数据分成三个区域: 新生代0,老年代1,永久代2
新生代0数据超过700 , 或者老年代1,永久代2数据超过10,自动触发内存中的垃圾回收机制
新生代0触发将清除所有三代的区域
老年代1触发会清理1,2代
永久代2触发只会清理自己
# 三.内存池
# 在同一个文件当中 (python3.6)
# -->Number 部分
1.对于整型而言,-5~正无穷范围内的相同值 id一致
2.对于浮点数而言,非负数范围内的相同值 id一致
3.布尔值而言,值相同情况下,id一致
4.复数在 实数+虚数 这样的结构中永不相同(只有虚数的情况例外)
# -->容器类型部分
5.字符串 和 空元组 相同的情况下,地址相同
6.列表,元组,字典,集合无论什么情况 id标识都不同 [空元组例外]
# 在不同的文件当中
小数据池 ; 比如整型默认开辟 -5~256 这么多数据提前在内存中驻留 -
请用两个队列来实现一个栈。
"""
栈 : 先进后出,后进先出
队列 : 先进先出,后进后出
"""
from queue import Queue
class Stack():
def __init__(self):
self.master_queue = Queue()
self.minor_queue = Queue()
def push(self,val):
# 入栈
self.master_queue.put(val)
def pop(self):
# 出栈
# 如果队列中没有任何值,直接返回None
if self.master_queue.qsize() == 0 :
return None
while True:
# 当队列总长度为1的时候,循环终止,把最后一个元素拿出来,为了满足栈后进先出的特点
if self.master_queue.qsize() == 1:
value = self.master_queue.get()
break
# 剩下还没有拿出来的元素,暂时放在2号队列中存储
self.minor_queue.put(self.master_queue.get())
"""
minor_queue(1)
master_queue(2 3 4)
minor_queue(2)
master_queue(3 4)
minor_queue(3)
master_queue(4)
"""
# 交换队列,重新循环,继续去最后一个值,如法炮制
self.master_queue,self.minor_queue = self.minor_queue,self.master_queue
return value
obj = Stack()
obj.push("a")
obj.push("b")
obj.push("c")
print(obj.pop()) # c
print(obj.pop()) # b
