Python基础面试
简述列举了解的编程语言及语言之间的区别.
编译型: 一次性全部编译成二进制码,然后运行
解释型:编译一行,运行一行
1.python 解释型,间接高效,容易上手,各个方向百花齐放
2.java 混合型(JVM,JIT编译器),开发周期慢,web方向
3.c 编译型 属于底层开发,只有面向过程,没有面向对象
4.c++ 编译型 属于底层开发,既有面向过程,还有面向对象
5.go 编译型 应用在区块链,高并发高可用,游戏方向
第二题 列举python2和python3的区别.
python2
1.print "123"
2.range 返回list
3.ascii
4.两种类: 经典类 和 新式类
class Car(): pass 经典类(多继承当中搜索成员时,采用深度优先原则)
class Car(object): pass 新式类(多继承当中搜索成员时,采用广度优先原则)
5.除法 / : 结果是整数
6.int long(长整型)
7.raw_input
python3
1.print("123")
2.range 返回的是可迭代的对象(容器类型数据,range对象,迭代器)
3.默认utf-8
4.都是新式类
5.除法 / :结果是小数
6.int
7.input
第三题 看代码写结果.
逻辑运算符优先级: () > not > and > or
逻辑短路
""" True or 表达式 False and 表达式 True or True => True True or False = True False and False => False False and True => False """
and 全真则真,一假则假 or 一真则真,全假则假
布尔值为假的十种情况:
0,0.0,False,'',(),[],set(),{},0j,None
v1 = 1 or 2
v2 = 3 and 7 or 9 and 0 v2 = 7 or 0
print(v1) 为1
print(v2) 为7
""" Number ( int , float , bool , complex )
复数 : 用在数据分析,人工智能
complexvar = 3 + 4j 实数: 3 虚数: 4j j : 如果有一个数,他的平方等于-1,那么这个数就是j,表达高精度的类型,科学家认为有. """
第四题 比较一下值有什么不同?
元组:逗号是区分元组的标识符
a = 1,2,3
print(a, type(a))
a = () # 空元组
a = (1) # 整型
a = ("abc") # 字符串
v1 = [1,2,3] # 列表
v2 = [(1),(2),(3)] # [int, int,int]
v3 = [(1,),(2,),(3,)] # [tuple,tuple,tuple]
a = 1 # 整型
a = 1,# 元组
print(a,type(a))
第五题 用一行代码实现数值转换.
a = 1 b = 2
1.一行代码
a,b = b,a
2.通过临时变量
a = 1 b = 2
tmp = a a = b b = tmp print(a,b)
第六题 python单引号、双引号、三引号的区别.
单双引号没有区别,三引号支持跨行
互相嵌套的情况下,不要使用相同的引号
"aa"a"a"
'bbb'b'b'
"""
aaa
'''
bbb
'''
"""
第七题 is和==的区别.
is 是判断两边内存地址是否相同 == 判断两边的值是否相同
第八题 python里面如何实现tuple和list的转化.
int float complex bool str list tuple set dict
list(数据) tuple(数据)
第九题 如何实现字符串name=’老男孩‘的反转?
切片 name[start🔚step] 字符串,列表,元组
name[1:5]
第十题 俩个set如何实现交集、并集、差集?
& 交集 intersection
-
差集
-
difference
-
| 并集 union
-
^ 对称差集 (抛出交集之外的部分,合在一起组成集合)
-
symmetric_difference
4 & 5
100
101
100
True and False => False <=> 0
set1 = {"赵忠祥","倪萍","赵丽蓉","王文"}
set2 = {"赵忠祥","倪萍","掏粪男孩","蔡徐坤"}
res = set1 ^ set2
print(res)
"""
要求数据是等长的二级容器,并且元素个数2个
lst = [("a",1),["b",2],{"c",3}] print(dict(lst)) """
第11题 那些情况下,y!=x-(x-y)回成立?
y != x - (x-y)
y != y
非空且不为子父关系的两个集合
x = {"a","b","c"} y = {"b","d"}
{"a","b","c"} - {"a","c"} = {"b"}
{"b","d"} != {"b"}
两个集合 , 互为子集父集时,不符合条件
x = {"a","b","c"} y = {"b","c"}
{"b","c"} != {"a","b","c"} - ( {"a","b","c"} - {"b","c"}) "} !={"b","c"} != {"a","b","c"} - {"a"} {"b","c {"b","c"}
两个空集合, 不符合条件
x = set() y = set() set() != set() - (set()-set()) set() != set()
不能确保每次都成功,存在精度损耗
""" x = 5.829999999999999999 y = 3.318888888888888888 print(y != x - (x-y)) print(0.3 == 0.1+0.2) print(1.5 == 0.3+1.2) """
第12题 python如何拷贝一个对象?
import copy
lst1 = [1,2,3]
1.copy.copy 2.lst.copy 3.切片[:] [::]
lst2 = lst1[:]
lst2 = lst1
lst1.append(4) print(lst2) # [1,2,3]
第13题 简述赋值 浅拷贝 深拷贝的区别?
赋值 : 从右向左看,将变量和值在内存中形成映射指向关系
浅拷贝: 只拷贝第一级容器中的所有元素 copy.copy()
深拷贝: 为所有层级元素都单独开辟空间,进行拷贝 copy.deepcopy()
(地址: 原不可变数据只是暂时指向原来的空间,可变的数据一开始就单独开辟新空间)
""" 可变数据: list set dict 不可变数据: int float bool complex str tuple """
import copy lst1 = [1,2,3,4,[5,6,7,8]] lst2 = copy.deepcopy(lst1) lst1[0] = 100 print(lst1) print(lst2)
print(id(lst1[-1] )) print(id(lst2[-1] ))
第14题 pass的作用
占位
if 表达式: 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')
b [1,2,4,5,["b","c","d"],5]
c [1,2,4,5,["b","c","d"]]
a [1,2,4,5,["b","c","d"],5]
第16题 用python实现9*9乘法表
i = 1 while i <= 9 :
# 打印表达式
j = 1
while j<=i:
# %2d 原字符串默认居右 %-2d 原字符串默认居左
print("%d*%d=%2d " % (j,i,i*j) , end="")
j+=1
# 打印换行
print()
i+=1
i = 9 while i >= 1:
# 打印表达式
j = 1
while j<=i:
# %2d 原字符串默认居右 %-2d 原字符串默认居左
print("%d*%d=%2d " % (j,i,i*j) , end="")
j+=1
# 打印换行
print()
i-=1
第17题 用python实现一个斐波那契数列。
1 1 2 3 5 8 13 21 ....
方法一
a = b = 1 for i in range(10): print(a) a, b = b, a+b print(a,b)
a,b = 0,1 for i in range(10): print(b) a, b = b, a+b
方法二
lst = [1,1] for i in range(10): lst.append( lst[-1] + lst[-2] ) print(lst)
方法三
def fib(n): if n <= 2: return 1 # 现在值 = 上一个值 + 上上个值 return fib(n-1) + fib(n-2)
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144
print(fib(5))
""" return s5 return fib(4) [3] + fib(3) [2] fib(3)[2] + fib(2)[1] fib(2) [1] + fib(1) [1] fib(2)[1] + fib(1)[1] """
第18题 如何删除列表中重复的值
list(set(lst))
第19题 一个大小为100G的文件etl_log.TXT,要读取文件中的内容,写出具体过程代码?
第一种
f = open(文件,mode="r",encoding="utf-8") for line in f: # f是迭代器,遍历时,默认按照一行一行进行读取 print(line)
第二种
r => read的单位是字符 rb => read的单位是字节
with open("文件",mode = "r",encoding="utf-8") as fp: # 一次最多读取100个字符 res = fp.read(100) while res: print(res) res = fp.read(100)
第20题 a = dict(zip(('a','b','c','d','e'),(1,2,3,4,5))) 请问a是什么?
'''zip和enumerate返回的是迭代器''' a = dict(zip(("a","b","c","d","e"),(1,2,3,4,5))) print(a)
zip 拉链函数
Iterator 迭代器 Iterable 可迭代对象
from collections import Iterator,Iterable it = zip(("a","b") , [1,2] ) print(it) for i in it: print(i)
res = isinstance(it , Iterator) print(res)
enumerate 枚举函数
it = enumerate(["a","b"])
start 关键字可以指定开始值;
it = enumerate(["a","b"] , start=10)
for i in it:
# print(i)
res = dict(it) print(res)
issubclass 用来判断子父关系,如果是返回True ,否则返回False;
print(issubclass(Iterator,Iterable))
第21题 lambda 关键字的作用?
lambda 匿名函数 : 用一句话来表达只有返回值的函数 lambda 参数 : 返回值
第22题 *arg和**kwarg的作用?
arg 普通收集参数 : 收集多余的没人要的普通实参 **kwarg 关键字收集参数: 收集多余的没人要的关键字实参 位置参数 -> 形参 def func(arg): pass func(1,2,3) func(a=1,b=2,c=3)
第23题 如何在函数中设置一个全局变量?
"""global关键字可以在函数内定义或者修改全局变量""" def func(): global abc abc = 100 func() print(abc)
第24题 filter、map、reduce的作用?
filter -> 过滤数据
三目(元)运算符 : 真值 if 条件表达式 else 假值 lst = [1,2,3,43,5,6]
过滤所有的奇数 [一次计算1个]
filter(lambda x : True if x % 2 == 0 else False , lst) filter 会根据return 返回的True 与 False 判定是保留或者舍弃 True => 保留该数据 False => 舍弃该数据,最后返回迭代器
map -> 处理计算数据[一次计算1个]
lst = [1,2,3] it = map(lambda x : x*3 , lst) print(list(it))
from functools import reduce
reduce -> 计算数据[一次计算2个]
lst = [5,6,7,8] => int 5678 res = reduce(lambda x,y : x*10 + y , lst) print(res) """ 5 * 10 + 5 = 56 56 * 10 + 7 = 567 567 * 10 + 8 = 5678 """
第25题 什么是匿名函数?匿名函数有什么作用?
lambda 匿名函数 : 用一句话来表达只有返回值的函数 lambda 参数 : 返回值
第26题 python递归的最大层数?
官方说法1000层: 实测 994 ~ 1000 import sys sys.setrecursionlimit(9999999) # 修改递归最大深度
第27题 什么是迭代器?什么是可迭代对象?
可迭代对象 -> 迭代器 把不能够直接被next获取 -> 可以被next直接获取的过程
for循环底层用的就是迭代器.
next 获取数据时,是单向不可逆过程;
具有iter 和 next 是迭代器
具有iter方法的是可迭代对象
dir(数据) -> 查看该数据对象的内部成员
第28题 什么是生成器?
生成器是特殊的迭代器,可以自定义迭代的逻辑 不是一股脑把数据一次性拿出,而是通过调用,一次只获取一个 创建生成器两种: (1) 生成器表达式 (推导式) gen = ( i for i in range(3) ) (2) 生成器函数 (含有yield关键字) def func(): for i in range(10): yield i
mygen = func()
print(next(mygen))
第29题 什么是装饰器及应用场景?
在不修改源代码的情况下,为原函数扩展新功能->装饰器
装饰器的本质实际上就是闭包
应用: 登录认证,property类,框架(django , flask @app.route("/",methods=["GET","POST"]))
第30题 什么是反射及应用场景?
通过字符串操作类对象 或者 模块中的成员(属性,方法)
hasattr , getattr , setattr ,delattr 应用: 可以配合用户的操作或者输入,调用其中的成员,完成功能;api接口;
第31题 写一个普通装饰器
@符功能: (1) 自动把要扩展功能的函数当成参数传递给装饰器 (2) 把装饰器中的新函数拿出来替换旧函数,以完成功能的拓展;
闭包: 内函数使用了外函数的局部变量,外函数把内函数返回出来的过程叫做闭包 里面的内函数叫做闭包函数; 特点: 闭包情况下,内函数使用了外函数的局部变量,延长该部变量的生命周期
def wrapper(func): # 定义处 * 和* 打包变成元组和 字典 def inner(args,kwargs): # 调用处 * 和 解包成函数中的一个个参数,实现调用; res = func(*args,**kwargs) print("okkkkk@") return res
return inner
@wrapper def func(): print("i am fine and you")
func()
第32题 写一个带参数的装饰器
outer 只是单纯的保留参数
def outer(n): # wrapper是装饰器 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 == 1:
return inner1
else:
return inner2
return wrapper
@outer(1) # outer(1) => wrapper 相当于@wrapper def func(): print(" i am a boy ") func()
第33题 求结果
def num():
return [lambda x:i*x for i in range(4)]
print([m(2) for m in num()])
def num(): return [ lambda x:i*x for i in range(4) ] print([m(2) for m in num()])
[ lambda x : i*x for i in range(4) ]
[ func ]
lambda 参数 : 返回值
i*x for i in range(4)
不是函数,因为返回值错了;
func = lambda x : i*x for i in range(4)
种类三种: 列表推导式 集合推导式 字典推导式
推导式
[ lambda x:i*x for i in range(4) ]
原型
def num(): lst = [] for i in range(4): def func(x): # i => 0 1 2 3 return i * x lst.append(func) return lst lst = num() print(lst) """ [ <function num.<locals>.func at 0x000001ED3201D1E0>, <function num.<locals>.func at 0x000001ED3201D268>, <function num.<locals>.func at 0x000001ED3201D2F0>, <function num.<locals>.func at 0x000001ED3201D378> ] """
原型
for m in num(): # 调用函数 , 参数为2 # return i * x => return i * 2 => i是几? m(2) # 6,6,6,6
for i in range(4): pass print(i) # 3 """ 定义函数时,不会执行其中的代码 只有在调用函数时,才会参与执行和运算; """
定义
def func(x) print(x)
调用
func(3)
""" 刚开始定义的时候,没有去执行函数内部的内容,不存在i变量的赋值. 只有在调用的时候,才会去获取此时的i值 而调用时,此时的i值是3,由于遍历已经结束,而i的值处在闭包中,延长该变量的生命周期,可以获取到 return i * x => return 3 * 2 => 6 由于是4个函数,所以是4个6; """
第34题 def(a,b=[])这种写法有什么陷阱?
b参数(默认参数)等于列表,提前在内存中开辟好空间,进行数据的存储 如果用户传递实参,那么使用用户自己的实参值 如果用户没有传递实参,那么使用默认值(提前开辟好空间的列表) def(a, b=3): pass
第35题 看代码写结果
def func(a,b=[]):
b.append(a)
return b
v1 = func(1)
v2 = func(2,[10,20])
v3 = func(3)
def func(a,b=[]): b.append(a) return b
使用默认在内存中开辟好的列表
v1 = func(1) # [1]
[10,20] 一个列表 默认参数[1]也是一个列表
v2 = func(2,[10,20]) # [10,20,2]
v3 = func(3) # [1,3]
v1,v3 指向同一个列表
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)
v2 = func(2,[10,20])
print(v2)
v3 = func(3)
print(v3)
v1 = [1]
v2 = [10, 20, 2]
v3 = [1, 3]
第37题 请编写一个函数思想将ip地址转换成一个整数。
方法一
ip = "10.3.9.12" strvar = '' for i in ip.split("."): # print(i) bin_str = str(bin(int(i)))[2:] strvar += bin_str.rjust(8,"0") print(strvar)
把二进制字符串转换成十进制
print(int(strvar,2))
方法二
ip = "10.3.9.12" strvar = "" for i in ip.split("."): # print(format(int(i),"08b")) # 8总长度 0用来补齐8位的 b代表二进制; strvar += format(int(i),"08b") print(strvar) # 00001010000000110000100100001100 print(int(strvar,2)) # 167971084
第38题 请查找一个目录下的所有文件(可能存在文件嵌套)。
方法一
import os def getallsize(pathvar): size = 0 lst = os.listdir(pathvar) # print(lst) for i in lst: # 拼接完整的路径 pathvar2 = os.path.join(pathvar,i) # 判断是否是文件 if os.path.isfile(pathvar2): print(pathvar2,"文件") # 累加文件的大小 size+= os.path.getsize(pathvar2) # 判断是否是文件夹 elif os.path.isdir(pathvar2): print(i,"文件夹") size += getallsize(pathvar2)
return size
pathvar = r"E:\串讲python28\day2\ceshi100" print( getallsize(pathvar) ) # 24674
方法二
import os pathvar = r"E:\串讲python28\day2\ceshi100"
gen = os.walk(pathvar) print(gen) size = 0 for root , dirs , files in gen: # print(root) # print(dirs) # print(files) for name in files: pathvar = os.path.join(root,name) size += os.path.getsize(pathvar) print(size) # 24674
第39题 求结果
import math
print (math.floor(5.5))
floor 地板 向下取整
ceil 天花板 向上取整
import math print(math.floor(5.5)) print(math.ceil(5.1))
第40题 是否使用过dunctools中的函数?其作用是什么?
from functools import reduce
在装饰器中使用,保留原函数的属性,避免暴露装饰器的名字;
from functools import wraps
def wrapper(func): @wraps(func) def inner(args,**kwargs): res = func(args,**kwargs) print("雷霆嘎巴,无情哈拉少") return res
return inner
@wrapper def func(): print(1111) return 123
print(func)
<function func at 0x000001F5EA8F5B70>
<function wrapper.<locals>.inner at 0x0000019DCB645BF8>
<function func at 0x00000210C7575BF8>
第41题 re的match和search区别?
match : 必须从字符串的开头进行匹配 (默认加了^)
search: 从左到右任意位置开始找,找到就返回;
第42题 用python匹配HTML tag的时候,<.>和<.?>有什么区别?
<.> . 除了\n的任意字符
-
? + {3,10} 都是量词
-
.? 除了\n的任意字符 匹配到0个或者1个
-
.* 贪婪匹配 默认向更多次匹配
-
.*? 非贪婪匹配 默认向更少次匹配
-
.?? 非贪婪匹配 默认向更少次匹配
<.> 除了\n的任意字符 , 个数必须是一个
<.?> 除了\n的任意字符 , 个数必须是一个 或者 0个
<.*?>
第43题 如何生成一个随机数?
import random
random.randrange 随机获取范围内的整数 用法range相同
random.uniform 随机获取范围内的小数
res = random.uniform(1,5)
第44题 super的作用?
super 用来调用父类的相关成员属性和方法,用来解决多继承之间复杂的调用关系
类.mro() => 调用顺序列表(继承关系) super调用父类相关成员时,参照mro列表中的继承顺序依次调用
第45题 双下滑线和单下划线的区别?
封装: 公有public 私有private 受保护的protected
私有:__ 2个下划线来表达 __sex
受保护:在python 中有约定俗成的写法,在成员的前面加上一个下划线 (可以在继承时使用该成员,无法在类外使用;) _sex
魔术方法/属性: doc init ...
第46题 @staticmethod和@classmethod的区别?
@staticmethod 静态方法
无论是类还是对象,都可以调用,不会默认传递任何参数
@classmethod 类方法
无论是类还是对象,都可以调用,默认传递类这个参数
class Ceshi():
@staticmethod
def func1(): # self
print(111)
@classmethod
def func2(cls):
print(cls)
print(222)
obj = Ceshi()
obj.func1()
Ceshi.func1()
obj.func2()
Ceshi.func2()
第47题 实现一个单例模式(加锁)。
单态(例)模式 : 这个类无论实例化多少次,都有且只有一个对象
目的: 节省内存空间,提高运行效率,应用在多人使用同一个操作类的场景
每生成一个对象,都在内存中占用空间,尤其在执行mysql操作类时
因为多人的使用,创建出多个对象,而对象本身不会额外增加新成员,只做单纯的成员调用
那么就可以使用单态模式;
from threading import Lock
class SingleTon():
# 防止类外直接调用obj成员,对他进行保护,所以用私有
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 = SingleTon()
obj2 = SingleTon()
obj3 = SingleTon()
print( id(obj1) , id(obj2) , id(obj3) )
第48题 栈和队列的区别?
栈: 先进后出 或 后进先出
队列: 先进先出 或 后进后出
第49题 一下代码输出是什么?请给出打哪并解释。
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x) # 1 1 1
Child1.x = 2
print(Parent.x, Child1.x, Child2.x) # 1 2 1
Parent.x = 3
print(Parent.x, Child1.x, Child2.x) # 3 2 3
第50题 一下代码输出是什么?请给出打哪并解释。
面向对象的上下文管理, with语法的具体实现
class Context: # 在使用with语法时,自动触发,功能返回对象
def enter(self):
return self
# 在执行完with语法之后,自动触发,用来做收尾操作
def __exit__(self, exc_type, exc_val, exc_tb):
print("关闭文件 f.close() ")
def do_something(self):
print("我是做点什么~")
with Context() as ctx:
ctx.do_something()
附加题:
(1) 如何获取列表中第二大的值
lst = [1,2,3,4,5,5,5,5,5,5,5,5] setvar = set(lst)
列表.sort 类型有局限性,只能是列表,基于原有列表进行修改
sorted 容器类型数据皆可以,返回新列表
lst = sorted(setvar) print(lst) # [1, 2, 3, 4, 5]
res = lst[-2] print(res)
print(sorted("abzzcdefg"))
(2) 简述python内存管理机制。
(3) 简述python的垃圾回收机制。
计数器,垃圾回收,缓存池
1.计数器
a = 100 (100这个值计数为1,被引用过1次) b = a (100这个值计数为2,被引用过2次) del b (100这个值计数为1,被引用过1次,100本身不会被删掉) del a (100这个值计数为0,被引用过0次,100本身被删掉)
2.标记清除 (用来辅助计数) 分带回收
标记清除 :应对解决循环引用的情况,避免删不掉 第0代 新生代 第1代 老年代 第2代 永久代
分代回收 import gc print(gc.get_threshold()) (700, 10, 10)
# 700 新增的对象-消亡对象 == 700 触发分代回收,检测垃圾数据
# 10 当第0代对象检测的次数达到10次,会触发第0代和第1代数据的检测和回收
# 10 当第1代对象检测的次数达到10次,会触发第0代和第1代,2代所有数据的检测和回收
3.缓存池
"""避免频繁的创建或者销毁变量影响效率,提前缓存一些数据在内存中提升速度;"""
1.小数据池-5 ~256,常驻内存 (多个文件之间的)
2.共用数据,常驻内存 (一个文件之内的)
3.使用intern,指定驻留内存
from sys import intern
a = intern("你好sfsdf" * 5)
b = intern("你好sfsdf" * 5)
print(a is b)
浙公网安备 33010602011771号