Python - 基础阶段(面试题)
Python面试重点(基础篇)
第一部分 必答题(每题2分)
-
简述列举了解的编程语言及语言间的区别?
C语言:Java,Python,底层均是有C语言开发完成 Java:用户量最高的语言. PHP:网站的快速开发 Python:语言简洁,代码流畅,第三方库比较多
-
列举Python2和Python3的区别?
python2: range xrange python3: range python2中有两种数据类型:unicode str python3中有两种数据类型:str bytes python2: 经典类、新式类(直接或间接继承object) python3: 新式类
-
看代码写结果
v1 = 1 or 2 1 v2 = 3 and 7 or 9 and 0 7
-
比较以下值有什么不同?
# 逗号才是区分是否是元组的标识符 v1 = [1,2,3] # 列表[int , int , int] v2 = [(89),(2.12),("abc")] # [int , float , str] v3 = [(1,),(2,),(3,)] # [tuple,tuple,tuple,tuple] res = () # 表达空元组
-
用一行代码实现数值交换。
a = 1 b = 2 a,b = b,a
-
Python中单引号、双引号、三引号的区别?
单双引号没有区别,三引号可以支持跨行 在互相嵌套时需注意:里外不能使用相同的引号 三引号是注释
-
is和==的区别?
is 判断两边的内存地址id是否一致 == 判断等号两边的值是否相等
-
python里如何实现tuple和list的转化?
Tuple是元组的意思,元组是不能修改的;list是列表的意思,列表是可以修改的;在Python中实现Tuple和list的转换可以通过两个函数list()、Tuple()实现转换。举例如下:将元组a转换为列表b,b=list(a)将列表b转换为元组a,a=Tuple(b) 老师解答; int float complex bool str list tuple set dict list(数据) tuple(数据)
-
如何实现字符串
name='老男孩'
的反转?1.切片 name = name[::-1] 2.列表的reverse方法 name = list(name) name.reverse() name = ''.join(name) #name = ''.join(name[::-1])
-
两个set如何获取交集、并集、差集?
# 第10题 交集 & intersection 差集 - difference 并集 | union 对称差集 ^ symmetric_difference
-
那些情况下, y != x - (x-y)会成立?
两个不相等的非空集合 """ 非空集合且不为子父关系的两个集合 """ y != x-(x-y) x = {"a","b","c"} y = {"b","d"} if y != x-(x-y): print("ok
-
Python中如何拷贝一个对象?
copy模块 copy.copy() copy.deepcopy() #第12题解答2 # import copy # 针对于列表的拷贝,还可以使用[:] , [::],浅拷贝的一种方式 lst1 = [1,2,3] lst2 = lst1[:] lst1.append(4) print(lst2)
-
简述 赋值、浅拷贝、深拷贝的区别?
赋值:让多个变量同时指向一个对象的内存地址。不可变对象在赋值时会开辟新空间。可变对象在赋值时,修改一个的值,另一个也会发生改变。 浅拷贝:(copy模块的copy.copy()函数),浅拷贝在拷贝时,只拷贝第一层中的引用,如果元素是可变对象,并且被修改,那么拷贝的对象也会发生变化。####拷贝第一层元素内存地址 深拷贝:完全拷贝了父对象及其子对象。深拷贝就是将顶级对象以及子对象的值同时复制给新对象,此时修改任何一个都不会影响另一个。{copy模块的 copy.deepcopy()函数}####不管多少层,不可变共有,可变开辟新空间 老师答案; #第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]))
-
pass的作用?
占位符
-
阅读代码写结果。
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(b) print(c) print(a) b = ['1','2','4','5',['b','c','d'],'5'] c = ['1','2','4','5',['b','c','d']] d = ['1','2','4','5',['b','c','d'],'5']
-
用Python实现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()
-
用Python显示一个斐波那契数列。
lst = [1,1] for i in range(10): lst.append() # 第17题 # 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))
-
如何删除列表中重复的值?
set list(set(list))
-
一个大小为100G的文件etl_log.txt, 要读取文件中的内容, 写出具体过程代码?
for i in 文件句柄 # 第19题 fp = open("文件名","模式","编码集") """ fp 是迭代器 from collections import Iterator,Iterable # 在遍历fp时,文件按照一行一行进行读取; for i in fp: code ...
-
a = dict(zip(("a","b","c","d","e"),(1,2,3,4,5))) 请问a是什么?
字典 ------------------------ # 第20题 强转字典的条件:等长的二级容器,配合强转字典的两个函数 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)
-
lambda关键字的作用?
匿名函数 ---------------------------------- lambda 匿名函数 : 用一句话表达只有返回值的无名函数 lambda 参数 : 返回值
-
*arg
和**kwarg
作用?接收多余的位置参数 接收对于的关键字参数
-
如何在函数中设置一个全局变量 ?
global name ----------------------------- """ global 有该全局变量,修改当前变量,没有改全局变量,定义一个全局变量; """ def func(): global a a = 90 func() print(a)
-
filter、map、reduce的作用?
过滤 映射 累计算 ------------------------------------------------------ # 第24题 """ 三目(元)运算符 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))
-
什么是匿名函数?匿名函数有什么作用?
lambda 匿名函数,俗称一行函数 lambda 参数 : 返回值 配合高阶函数使用
-
Python递归的最大层数?
官方说明是1000 实际是994-998
-
什么是迭代器?什么是可迭代对象?
__iter__()和__next__() __iter__() ---------------------------------------------- # 具有__iter__() 和 __next__()这两个方法的是迭代器 # 具有__iter__()方法就是可迭代对象 # dir(数据) 可以查看该数据的内部系统成员 # 可迭代对象 => 迭代器 把不能直接被next获取 => 可直接获取到该数据的一个过程
-
什么是生成器?
生成器的本质就是一个迭代器 具有yield关键字就是生成器 ------------------------------------------------------------- # 第28题 生成器的本质就是迭代器,可以自定义迭代的逻辑 创建方式两种: (1)生成器表达式 (推导式) (i for i in range(3)) (2)生成器函数 (含有yield关键字)
-
什么是装饰器及应用场景?
装饰器的本质就是闭包 在不修改源代码,以及调用方式的情况下,额外的增加新功能 类 登录验证 ------------------------------------------------------- # 第29题 # 装饰器的本质就是闭包 # 在不修改原有代码的前提下,额外增加新功能就是装饰器 # 应用:登录认证,property类,框架(django,flask,@app.route("/",methdos=["GET","POST"]))
-
什么是反射及应用场景?
通过字符串操作对象的方法及属性 场景 CBV 用户输入 ------------------------------------------------------- # 第30题 # 通过字符串去操作类对象 或者 模块中的属性方法 hasattr getattr setattr delattr 应用: 可以配合用户的操作或者输入,调用其中的成员,api接口中
-
写一个普通的装饰器。
def func(a): def foo(*args,**kwargs) ret = a("*args,**kwargs") return ret return foo @func def f1(*args,**kwargs): print(f"这是一个{args}") return "我可以返回了" f1(1,2,3,34,4,5) ------------------------------------------------------------ # 第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()
-
写一个带参数的装饰器。
def startEnd(fun): def wraper(name): print("!!!!!!!!!!!!start!!!!!!!!!") fun(name) print("!!!!!!!!!!!!!end!!!!!!!!!") return wraper hello() @startEnd def hello(name): print("hello {0}".format(name)) hello("boy") ----------------------------------------------------------------- # 第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()
-
求结果
def num(): return [lambda x:i*x for i in range(4)] print([m(2) for m in num()]) [6,6,6,6] ----------------------------------------------------------------------------- # 第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) """
-
def(a, b=[])这种写法有什么陷阱?
默认参数是可变类型 闭包 --------------------------------------------------------------------- # 第34题 def func(a,b=[]) b身上的默认值是列表,如果使用原来默认的参数,调用func函数 会把几次调用的值都存放在同一个默认列表里 """ 默认参数: 如果调用时,用户给实参了,那么使用用户的 如果调用时,用户没给实参,那么使用默认的(早已存在内存中的这个列表) 默认值会提前在内存中驻留,在使用时,才能调取,在定义函数的时候就提前开辟了空间 """
-
看代码写结果
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]
-
看代码写结果
def func(a,b=[]): b.append(a) return b v1 = func(1) print(v1) v2 = func(2,[10,20]) print(v2) v3 = func(3) print(v3) [1] [10, 20, 2] [1,3]
-
请编写一个函数实现将IP地址转换成一个整数。
如 10.3.9.12 转换规则为: 10 00001010 3 00000011 9 00001001 12 00001100 再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ? ------------------------------------------------------------------------------ # 第37题 # 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))
-
请查找一个目录下的所有文件(可能存在文件嵌套)。
os.walk() -------------------------------------------------------------------------------- # 第38题 # 方法一 (递归写法) 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)
-
求结果
import math print (math.floor(5.5)) 5 ---------------------------------------------------------------------------- # 第39题 # 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))
-
是否使用过functools中的函数?其作用是什么?
# 第40题 from functools import reduce # 在装饰器中使用,如果想要保留原来函数的属性,加上wraps from functools import wraps def wrapper(func): @wraps(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() print(func) # def abc(): # pass # print(abc)
-
re的match和search区别?
match 从开头进行匹配,匹配一个就停止 search 从任意位置进行匹配 匹配一个就停止
-
用Python匹配HTML tag的时候,<.>和<.?>有什么区别?
# 第42题 . 除了\n的任意字符 * 量词,代表匹配0次或者多次,任意个 .* 贪婪匹配 .*? 非贪婪匹配
-
如何生成一个随机数?
import random random.random 随机获取 0<= x < 1 random.randrange 随机获取指定范围中的整数,用法上同range random.uniform 随机获取指定范围中的小数
-
super的作用?
按照mro的顺序进行继承 # 用来解决多继承之间复杂的调用关系使用super 在多继承中,如果出现了多个同名方法 super在调用的时候,会按照mro列表的继承顺序依次调用 类.mro() = > lst
-
双下划线和单下划线的区别?
class MyClass(): __abc = 90 _ppp = 100 """ 封装: 公有public 私有private 受保护的protected 私有: 只能在当前这个类里面使用,不能再子类或者在类外使用 受保护的: 可以在当前这个类或者子类里使用,不能再类外使用 约定俗成在该变量前面加上一个下划线_ , 就表示受保护了 """
-
@staticmethod和@classmethod的区别?
一个静态方法,一个类方法 一个静态方法:(无论是对象还是类,都可以调用,不会默认传递任何参数) 一个类方法 :(无论是对象还是类,都可以调用,会默认传递类这个参数)
-
实现一个单例模式(加锁)。
import threading import time class Singleton: instance = None lock = threading.RLock() def __init__(self, name): self.name = name def __new__(cls, *args, **kwargs): if cls.instance: return cls.instance with cls.lock: if cls.instance: return cls.instance time.sleep(0.1) cls.instance = object.__new__(cls) return cls.instance def task(): obj = Singleton('x') print(obj) for i in range(10): t = threading.Thread(target=task) t.start() data = Singleton('asdfasdf') print(data ------------------------------------------王闻------------------------------ # 单态模式:这个类无论实例化多少次,都有且只有一个对象 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)
-
栈和队列的区别?
栈 : 先进后出,或者 后进先出 队列: 先进先出
-
以下代码输出是什么? 请给出答案并解释。
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)
-
参考下面代码片段
class Context: pass with Content() as ctx: ctx.do_something() 请在Context类下添加代码完成该类的实现 ----------------------------------------------------------------------------------- # 第50题 # 面向对象的上下文管理是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 print(obj.pop()) # a print(obj.pop()) # a [a,b,c] [a,b] [a] []
-
请用Python实现一个链表。
# 线性表: 相当于一条直线,没有分支 # ### (1) 创建链表 class Node(): def __init__(self, value, next): self.value = value self.next = next head = Node("头", None) last = head for i in range(5): # v0 v1 v2 v3 v4 node = Node("v%s" % i, None) last.next = node last = node # 查看链表的关系 print(head.value) print(head.next.value) print(head.next.next.value) print(head.next.next.next.value) print(head.next.next.next.next.value) print(head.next.next.next.next.next.value) # print(head.next) print("<========>")
-
请用Python实现链表的逆转。
# 2.链表的逆转 def reverse_link_list(head): # 要是空的,或者None,直接返回head if not head or not head.next: return head # 获取上一个节点对象 prev_node = None # 获取下一个节点对象 next_node = head.next # 获取当前节点对象 current_node = head while True: # 修改next,所指向的对象 current_node.next = prev_node # 如果下一个阶段对象是None if not next_node: # not None break # 重新获取上一个对象,即把当前丢向单独存一份,以准备第二次循环时插进next属性中 prev_node = current_node # 重新获取当前对象 , 即把下一个对象单独存储起来(下个) current_node = next_node # 重新获取下一个对象,即把下一个对象单独存储起来,所指向的下个新对象赋值给next_node(下下个) next_node = current_node.next return current_node head = reverse_link_list(head) print(head.value) print(head.next.value) print(head.next.next.value) print(head.next.next.next.value) print(head.next.next.next.next.value) print(head.next.next.next.next.next.value)