Python开发面试问题

仅记录本人某次面试所经历的问题,而且我的解答也并非完全正确,欢迎提出问题。

目录

      • 0x00 Python的可变对象与不可变对象
      • 0x01 深拷贝与浅拷贝
      • 0x02 迭代器与生成器
      • 0x03 with关键字
      • 0x04 有一个大CSV文件,需要转储至另一个CSV文件
      • 0x05 算法题

0x00 Python的可变对象与不可变对象

  • 不可变对象:该对象所指向的内存中的值不能被改变。在某变量已经指向不可变对象的情况下,去改变该变量所指向的内容,实际是将原内容复制一份,放在一个新地址中,最终该变量指向这个新内容。比如int,float,str,tuple
  • 可变对象:该对象所指向的内存中的值可以被改变。在某变量已经指向可变对象的情况下,去改变该变量所指向的值,实际是直接改变原内容,没有复制行为,同样没有开辟新地址。比如list,dict,set
  • 注意3点
  • a.tuple虽然是不可变对象,但有点特殊。以下截图参考了该文中的https://blog.csdn.net/liuweiyuxiang/article/details/89349862
    Python开发面试问题_第1张图片
  • 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 深拷贝与浅拷贝

  • 我在这里归纳一下:深拷贝就是将对象的所有层次都拷贝,而浅拷贝是只拷贝最外层,内层不拷贝
    Python开发面试问题_第2张图片

0x02 迭代器与生成器

Python开发面试问题_第3张图片

  • 迭代器是什么(如何构造迭代器)
    迭代器是实现迭代器协议的对象,该对象必须实现__iter__()和__next__()方法,_ iter_()方法必须始终返回迭代器对象本身,_next _()方法必须返回序列中的下一项
  • 迭代器有几种
    一种是生成器,它是惰性计算的,边循环边计算;另一种是用iter()函数处理过的基本数据类型,例如列表,元组,集合等等
  • 生成器与迭代器的关系。见上图。
  • 构造生成器的方式
    一是生成器表达式(由列表推导式改中括号为小括号);二是实现了yield关键字的函数

0x03 with关键字

  • with关键字一般用在什么场景
    with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等
  • 能够使用with关键字的对象有哪些特点
    该对象必须实现__enter__()和__exit__()方法,例如下面实现一个文件类
    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
    
    注意: 假如程序都没进入__enter__()方法就异常了,也会直接终止程序。比如把11行改为File(‘demo.txt’, ‘r’),就会报错,因为__init__()方法就直接异常了(文件不存在,自然也就无法read)
  • 这种对象还有什么实现方式
    使用生成器与装饰器来实现,装饰器就是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))

缺点:第六行有一次多余比较(自己与自己比较);必定要循环最短字符串长度的次数,浪费时间,没有加标识来跳出循环

你可能感兴趣的:(pure,python)