仅记录本人某次面试所经历的问题,而且我的解答也并非完全正确,欢迎提出问题。
0x00 Python的可变对象与不可变对象
- 不可变对象:该对象所指向的内存中的值不能被改变。在某变量已经指向不可变对象的情况下,去改变该变量所指向的内容,实际是将原内容复制一份,放在一个新地址中,最终该变量指向这个新内容。比如int,float,str,tuple
- 可变对象:该对象所指向的内存中的值可以被改变。在某变量已经指向可变对象的情况下,去改变该变量所指向的值,实际是直接改变原内容,没有复制行为,同样没有开辟新地址。比如list,dict,set
- 注意3点:
- a.tuple虽然是不可变对象,但有点特殊。以下截图参考了该文中的https://blog.youkuaiyun.com/liuweiyuxiang/article/details/89349862
- b.可变对象:如果都是通过赋值来引用,哪怕内容一样,地址也不一样;如果变量是通过另一变量的引用传递来引用的,那它们的地址就是一样的。
a = [1, 2] b = [1, 3] print(id(a), id(b)) # 地址不一样,一个改动,另一个自然也就不受影响
a = [1, 2] b = a print(id(a), id(b)) # 地址一样,一个改动,另一个会受影响
- c.list通过= + 和 + = 来更新内容,产生的效果不一样。
a = [1, 2, 3] print(id(a)) a += [4] print(id(a)) # 两次id一致
a = [1, 2, 3] print(id(a)) a = a + [4] print(id(a)) # 两次id不一致
a = [1, 2, 3] b = a print(id(a), id(b)) # id一致,因为是传递引用,而不是赋值引用 a = a + [4] # 等号左边产生了新内容,a也就指向了新内容 print(id(a), id(b)) # id不一致,很好理解:先前a,b共同'追求'[1,2,3],现在a转为'追求'[1,2,3,4] print(b) # 打印[1,2,3],b的内容不受影响
a = [1, 2, 3] b = a print(id(a), id(b)) # id一致 a += [4] # 未产生新内容,属于'原地改变',所以a的指向也没变 print(id(a), id(b)) # id一致,因为上一步未改变指向 print(b) # 通过a改变了指向内容,而a,b指向一样,所以b也就受到了影响
0x01 深拷贝与浅拷贝
- 我在这里归纳一下:深拷贝就是将对象的所有层次都拷贝,而浅拷贝是只拷贝最外层,内层不拷贝
0x02 迭代器与生成器
- 迭代器是什么(如何构造迭代器)
迭代器是实现迭代器协议的对象,该对象必须实现__iter__()和__next__()方法,_ iter_()方法必须始终返回迭代器对象本身,_next _()方法必须返回序列中的下一项 - 迭代器有几种
一种是生成器,它是惰性计算的,边循环边计算;另一种是用iter()函数处理过的基本数据类型,例如列表,元组,集合等等 - 生成器与迭代器的关系。见上图。
- 构造生成器的方式
一是生成器表达式(由列表推导式改中括号为小括号);二是实现了yield关键字的函数
0x03 with关键字
- with关键字一般用在什么场景
with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等 - 能够使用with关键字的对象有哪些特点
该对象必须实现__enter__()和__exit__()方法,例如下面实现一个文件类
注意: 假如程序都没进入__enter__()方法就异常了,也会直接终止程序。比如把11行改为File(‘demo.txt’, ‘r’),就会报错,因为__init__()方法就直接异常了(文件不存在,自然也就无法read)class File(object): def __init__(self, file_name, method): self.file_obj = open(file_name, method) def __enter__(self): return self.file_obj def __exit__(self, type, value, traceback): print("Exception has been handled") self.file_obj.close() return True # 此处若是不返回True,在资源使用期间出现的异常会直接导致程序终止 with File('demo.txt', 'w') as opened_file: opened_file.func() # output # Exception has been handled
- 这种对象还有什么实现方式
使用生成器与装饰器来实现,装饰器就是contextlib模块的contextmanager装饰器。
0x04 有一个大CSV文件,需要转储至另一个CSV文件
import pandas as pd
import numpy as np
import time
df = pd.DataFrame(np.random.randn(1000000, 14), index=pd.date_range('20180101 01', periods=1000000, freq='H'), columns=list('ABCDEFGHIJKLMN'))
df.to_csv('tst.csv')
s_time = time.time()
reader = pd.read_csv('tst.csv', chunksize=1000) # 每次读取1000行
for chunk in reader:
chunk.to_csv('tst_bak.csv', mode='a') # 向目标文件追加
print('costs time ', time.time() - s_time)
0x05 算法题
1.求字符串列表的最大公共子串
>>> ['gajsdlk', 'gasd', 'gae']
Out: ga
>>> ['gajsdlk', 'hasd', 'fae']
Out: 没有最大公共子串
我的解决方法
def func(str_arrays):
loop_count = min([len(s) for s in str_arrays])
common_str = ''
for i in range(loop_count):
for j, s in enumerate(str_arrays):
if s[:i+1] != str_arrays[0][:i+1]:
break
else:
common_str = str_arrays[0][:i+1]
if common_str == '':
return '没有最大公共子串'
return common_str
if __name__ == '__main__':
s_arrays = []
print(func(s_arrays))
缺点:第六行有一次多余比较(自己与自己比较);必定要循环最短字符串长度的次数,浪费时间,没有加标识来跳出循环