python基础面试题1
Python面试重点(基础篇)
注意:只有必答题部分计算分值,补充题不计算分值。
第一部分 必答题(每题2分)
简述列举了解的编程语言及语言间的区别?
c语言是编译型语言,运行速度快,但翻译时间长python是解释性语言,开发效率高,但运行速度慢java必须声明变量,python并不需要声明变量
编译型语言:一次性全部编译成二进制码,再去运行解释型语言:编译一行,运行一行python 解释型 简洁高效 容易上手java 混合型 (JVM,JIT编译器) 学习成本高,开发周期慢,web方向c 编译型 底层语言,只有面向过程,没有面向对象c++ 编译型 底层语言,面向过程,面向过程都有go 编译型 应用在区块链 高并发高可用 游戏方向
列举Python2和Python3的区别?
python2:1.源码不统一,源码重复,有整型int和长整形long,使用asii编码,print后不用加括号 2.range不是可迭代对象 返回list 3.2种类 经典类和新式类 class Car():pass 经典类(多继承当中的搜索原则深度优先) class Car(object):pass 新式类(多继承当中的搜索原则广度优先) 4.除法:结果是整型 5.input raw_input => 等价于python input
python3:1.源码统一,源码不重复,全都是整型,使用utf-8编码,print‘后必须加括号 2.range 返回的 可迭代对象 3.都是新式类 4.除法:结果是小数
看代码写结果
v1 = 1 or 2 1v2 = 3 and 7 or 9 and 0 7?and 全真则真 一假则假or 一真则真 全假则假逻辑运算符优先级 () >not > and > orTrue or 表达式 => TrueFalse and 表达式 => False
比较以下值有什么不同?
v1 = [1,2,3] [int,int,int]v2 = [(1),(2),(3)] [int,int,int]v3 = [(1,),(2,),(3,)] [tuple,tuple,tuple]
用一行代码实现数值交换。
a = 1 b = 2a,b = b,a
Python中单引号、双引号、三引号的区别?
单双引号都可以在括号内使用(" ‘内容‘ ")三引号可以显示多行,注释
单双引号没有区别,三引号可以支持跨行
is和==的区别?
is判断两边的内存地址是否相等==判断等号两边的值是否相等
python里如何实现tuple和list的转化?
list=[1,2,3,4,5,6]x=tuple(list)print(type(x),x)??tup=(1,2,3,4,5,6)y=list(tup)print(type(y),y)
如何实现字符串
name=‘老男孩‘
的反转?使用字符串切片 name1=name[::-1]
两个set如何获取交集、并集、差集?
a=set(‘asdfg‘)b=set(‘qwert‘)交集:print(x&y)并集:print(x|y)差集:print(x-y)
那些情况下, y != x - (x-y)会成立?
x和y是两个不相等的非空集合的情况下
Python中如何拷贝一个对象?
可以使用浅拷贝拷贝父对象,也可以copy模块的deepcopy完全拷贝父对象和子对象?import copy针对于列表的拷贝,还可以使用[:], [::],浅拷贝的一种方式list1=[1,2,3]list2=list1[:]list1.append(4)print(list2)
简述 赋值、浅拷贝、深拷贝的区别?
赋值是将多个变量指向同一个内存地址浅拷贝是只拷贝第一层元素的地址深拷贝是完全拷贝原来的对象,拷贝后的对象是新的对象??赋值:将变量和值在内存中形成映射指向关系浅拷贝是只拷贝第一层元素的地址copy.copy深拷贝是为所有层级的元素都单独开启新空间 copy.deepcopy() 地址:原不可变数据只是暂时的指向,可变的数据独立开辟新空间
pass的作用?
占位定义一个空类保证程序结构的完整
阅读代码写结果。
import copya = [1,2,4,5,[‘b‘,‘c‘]]b = ac = copy.copy(a) 浅拷贝d = copy.deepcopy(a) 深拷贝?a.append(5)a[4].append(‘d‘)?print(b)print(c)print(a)a = b [1,2,4,5,[‘b‘,‘c‘,‘d‘],5]c [1,2,4,5,[‘b‘,‘c‘,‘d‘]]
用Python实现9 * 9 乘法表。
l=1i=0while l<10: i=1 while i<=l: if i==l: print(i,‘*‘,l,‘=‘,l*i) else: print(i,‘*‘,l,‘=‘,l*i,end=‘ ‘)? i += 1 l += 1
用Python显示一个斐波那契数列。
a,b = 0, 1 while b<100: print (b), a, b = b, a+b
1.list = [1,1]for i in range(10): list.append(list[-1] + list[-2])print(list)2.a,b = 0,1for i in range(10): print(b)a,b = b, a+b3.def fib(n): if n <=2: return 1 return fib(n-1) fib(n-2)print(fib(5))
如何删除列表中重复的值?
list1=["1","1","2","3list1"]list1=list(set(list1))list1.remove("1")print(list1)print(list(set(list1)))print(sorted(list(set(list1))))在列表中元素值少的情况下,可以直接用索引删除指定重复的值
一个大小为100G的文件etl_log.txt, 要读取文件中的内容, 写出具体过程代码?
def read_line(path): with open(path, ‘r‘, encoding=‘utf-8‘) as f: line = f.readline() while line: line = f.readline() print(line)
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"],sart = 10))print(a)
lambda关键字的作用?
lambda 匿名函数:用一句话表达只有返回值的无名函数lambda 参数: 返回值
*arg
和**kwarg
作用?在定义函数时,允许我们传入多个实参*args 普通收集参数 :收集多余的没人要的普通实参**kwargs 关键字收集参数: 收集所欲的没人要的关键字实参
如何在函数中设置一个全局变量 ?
def func(): global a a = 90func()print(a)
filter、map、reduce的作用?
filter => 过滤数据iterable: 可迭代对象(range,容器类型数据,迭代器)filter(func,iterzble) =>返回迭代器?map => 处理(映射)数据map(func,iterable) =>返回迭代器list1 = [1,2,3]it = map(lambda x : x*3,list1)print(list(it))?reduce => 计算数据from functools import reducereduce(func,iterable) =>最后计算的值list2=[1,2,3,4]res = reduce(lambda x, y : x*10 +y ,list2)print(res,type(res))
什么是匿名函数?匿名函数有什么作用?
用一句话表达只有返回值的无名函数配合高阶函数使用
Python递归的最大层数?
官方说法1000,实际测试994~1000
什么是迭代器?什么是可迭代对象?
迭代器是一个对象且迭代器只能使用一次迭代器生辰后的对象就是迭代器对象?具有__iter__()和__next__()这两个方法的就是迭代器具有__iter__()方法的就是可迭代对象dir(数据) 可以查看该数据的内部系统成员可迭代对象=>迭代器 把不能直接别next获取 => 可直接获取到该数据的一个过程
什么是生成器?
生成器是一次生成一个值的特殊类型函数,生成器的本质就是迭代器?生成器的本质就是迭代器,可以自定义迭代的逻辑创建方式两种: 1.生成器表达式(推导式) (i for i in range(3)) 2.生成器函数 (含有yield关键字)
什么是装饰器及应用场景?
装饰器本质上是闭包,它可以在让其他函数在不需要做任何代码的变动的前提下增加额外的功能;应用场景:计算函数运行次数;插入日志,作为函数的运行日志;缓存,实现缓存处理;
什么是反射及应用场景?
通过字符串操作类对象或者模块中的属性和方法应用: 可以配合用户的操作或者输入,调用其中的成员,api接口
写一个普通的装饰器。
闭包:内函数使用了外函数的局部变量,外函数把内函数返回出来的过程叫做闭包这个内函数叫做闭包函数特点:如果内函数使用了外函数的局部变量,那么该变量于内函数发生绑定,延长该变量的生命周期def warpper(f): def inner(*args,**kwargs): print("被装饰函数执行前") ret = f(*args,**kwargs) print("被装饰函数执行后") return ret return innerdef func(*args,**kwargs): print(f"被装饰的{args,kwargs}") return "这是func函数"func = warpper(func)print(func(1,2,3,a=1))
写一个带参数的装饰器。
def auth(argv):--接收参数 def warpper(func): def inner(*args,**kwargs): if argv == ‘博客园‘: print(‘欢迎登陆博客园‘) user = input(userse) pwd = input(‘pwd‘) if user ==‘alex‘ and pwd ==‘ds12‘: func(*args,**kwargs) elif argv == ‘码云‘: print(‘欢迎登陆码云‘) user = input(userse) pwd = input(‘pwd‘) if user ==‘ale‘ and pwd ==‘ds23‘: func(*args,**kwargs) return inner return warpper?def foo(): print(‘被装饰的函数‘)a = auth("111")foo = a(foo)foo()
求结果
def num(): return [lambda x:i*x for i in range(4)]print([m(2) for m in num()])[6,6,6,6]
def(a, b=[])这种写法有什么陷阱?
当第一次执行的时候实例化了一个list,第二次执行还是用第一次执行的时候实例化的地址存储,所以三次执行的结果就是 [1, 1, 1] 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,3]
请编写一个函数实现将IP地址转换成一个整数。
如 10.3.9.12 转换规则为: 10 00001010 3 00000011 9 00001001 12 00001100 再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ?1.ljust 原字符串居左,填充符号rjust 原字符串居右,填充符号ip="10.3.9.12"strvar = ""for i in ip.split("."): bin_str = str(bin(int(i)))[2:] strvar += bin_str.rjust(8,"0") print(strvar)# 把二进制 字符串转换成十进制,默认转换时,是十进制print(int(strvar,2))?2.ip = "10.3.9.12"strvar = ""for i in ip.split("."): strvar +=format(int(i),"08b")print(int(strvar,2))
请查找一个目录下的所有文件(可能存在文件嵌套)。
1.递归import osdef 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 ?pathvar = r"路径"res = getallsize(pathvar)# print(res)?2.import os # os.walk() => 生成器pathvar = r"路径"gen = os.walk(pathvar)?for root,dirs,files in gen: for name in files: pathvar = os.path.join(root,name) print(pathvar)
求结果
import mathprint (math.floor(5.5))结果:5
是否使用过functools中的函数?其作用是什么?
生成一个固定参数的新函数?from functools import reduce# 在装饰器中使用,如果想要保留原来函数的属性,加上wrapsfrom functools import wraps?def wrapper(func): @wraps(func) def inner(*args,**kwargs): res = func(*args,**kwargs) print("and you") return res return inner?@wrapperdef func(): print("i am fine 3q")?func()print(func)
re的match和search区别?
match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回nonesearch()会扫描整个字符串并返回第一个成功的匹配:?match : 必须从字符串的开头进行匹配search: 从任意位置开始匹配,匹配到就返回只匹配一个
用Python匹配HTML tag的时候,<.>和<.?>有什么区别?
<.*>尽可能多的匹配,就是匹配到的字符串尽量长,<.*?>是尽可能少的匹配,就是匹配到的字符串尽量短。?. 除了\n的任意字符* 量词,代表匹配0次或者多次,任意个.* 贪婪匹配.*? 非贪婪匹配
如何生成一个随机数?
import randomprint(random.randint(0,9))?import randomrandom.random 随机获取 0<= x < 1random.randrange 随机获取指定范围中的整数,用法上同rangerandom.uniform 随机获取指定范围中的小数
super的作用?
可以在子类中调用父类的方法或属性?# 用来解决多继承之间复杂的调用关系使用super在多继承中,如果出现了多个同名方法super在调用的时候,会按照mro列表的继承顺序依次调用类.mro() = > lst
双下划线和单下划线的区别?
__name是私有变量,只有内部可以访问,外部访问不了_name是"可以被访问,但是是私有变量"?class MyClass(): __abc = 90 _ppp = 100?封装: 公有public 私有private 受保护的protected私有: 只能在当前这个类里面使用,不能再子类或者在类外使用受保护的: 可以在当前这个类或者子类里使用,不能再类外使用约定俗成在该变量前面加上一个下划线_ , 就表示受保护了?
@staticmethod和@classmethod的区别?
@staticmethod不需要表示自身对象的self和自身类的参数而@classmethod也不需要self参数,但第一个参数需要是表示自身类的参数?一个静态方法,一个类方法一个静态方法:(无论是对象还是类,都可以调用,不会默认传递任何参数)一个类方法 :(无论是对象还是类,都可以调用,会默认传递类这个参数)
实现一个单例模式(加锁)。
# 单例模式:这个类无论实例化多少次,都有且只有一个对象from threading import Lockclass 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.__objobj1 = MyClass()obj2 = MyClass()print(obj1,obj2)
栈和队列的区别?
队列先进先出栈后进先出
以下代码输出是什么? 请给出答案并解释。
class Parent(object): x = 1?class Child1(Parent): pass?class Child2(Parent): pass?print Parent.x, Child1.x, Child2.x1 1 1Child1.x = 2print Parent.x, Child1.x, Child2.x1 2 1Parent.x = 3print Parent.x, Child1.x, Child2.x3 2 3
参考下面代码片段
class Context: pass?with Content() as ctx: ctx.do_something()请在Context类下添加代码完成该类的实现class Sample: def __enter__(self): return self? def __exit__(self, type, value, trace): print("type:", type) print("value:", value) print("trace:", trace) print(sample)?? def do_something(self): bar = 1 return bar + 10?with Sample() as sample: sample.do_something()
# 面向对象的上下文管理是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()
第二部分 可选题
如何获取列表中第二大的值
?list1 = [ 1, 13, 5, 6, 11, 12, 7, 8, 13]list1.sort() count = list1.count(list1[len(list1) - 1] ) c = 0while c < count: list1.pop() c += 1print(list1[len(list1) - 1]) ?
简述Python内存管理机制。
Python有两种共存的内存管理机制: 引用计数和垃圾回收当一个Python对象被引 用时其引用计数增加1, 当其不再被一个变量引用时则计数减1. 当引用计数等于0时对象被删除.
简述Python的垃圾回收机制。
当Python的某个对象的引用计数降为0时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾。垃圾回收机制: 引用计数 引用为0的时候会自动清除 标记清除 交叉引用不变的时候自动清除 分袋回收
请用两个队列来实现一个栈
栈 : 先进后出,后进先出队列 : 先进先出,后进后出?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()) # cprint(obj.pop()) # bprint(obj.pop()) # aprint(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实现链表的逆转。
链表的逆转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)