Python常见问题

Python-面试考点

  • 运行可视化网站: https://pythontutor.com/
  • 吐血总结!40道Python面试题集锦(附答案) - 幽默的程序猿日常的文章 - 知乎 https://zhuanlan.zhihu.com/p/366679675

1.基础知识

a.基础要求

  • 参数中的 * 和 的作用(要求:基础知识)**

    python 从参数定位到仅限关键字参数:https://blog.csdn.net/littleRpl/article/details/89457557

    参数中*以及**的作用:https://blog.csdn.net/weixin_41978699/article/details/121008512

    *参数:将任何剩余的参数都以元组的方式传入这个可变参数。允许省略可变参数的函数名

    **参数:会将所有参数放入一个dict供函数使用

  • 选代器(iterator)和生成器(generator) (要求:基础知识)

  • str和unicode的区别(python2下)(要求:基础知识)

  • 装饰器用途(要求:基础知识)

  • is和==的区别(要求:基础知识)

    • == 符号比较的是两个对象的值,is 比较的是两个的对象的标识【id()函数 , Cpython中内存地址】
    • x is None
    • is 符号比 == 运算快【不能重载】,== 是语法糖,【a.__ eq __(b)】
  • **双下划线开头的魔法方法,比如_add__(至少知道一个,以及其作用)**

  • 字符串编码:ascii/unicode/utf-8 分别是什么,以及三者的区别(要求:要求至少能回答一个)

  • 内置数据结构

    • dict (要求:至少知道底层实现是基于hash表,可以扩展提问)

    • list (要求:至少知道底层实现类似链表,可以扩展提问)

    • tuple(要求:知道其与list(异同)

      • 元组的相对不可变形:标识不变,值可变
    • set(要求:知道使用场景)

b.进阶要求

  • yield / yield from的区别(要求:可选)

yield只是将普通函数变成生成器,yield一个值,迭代时可以得到一个值;而yield from是将后面的值变成一个可迭代对象。

  • python 性能优化(要求:基础知识)

    • python为什么慢?

      • python是动态语言

      • python是解释执行

      • python中一切都是对象

      • python GIL

      • 垃圾回收

  • python 模块查找顺序(要求:发挥空间比较大,junior岗位至少知道基本知识)

  • python 字符串编码问题为什么这么复杂(要求:非必须,发挥空间较大,可以引导被面者深入牌答,以及与其他语言的对比)

2 正则表达式

a.基础要求

能够根据实际需求,实现中等难度的正则表达式

b.进阶要求

贪婪与非贫要模式(要求:非junior岗位需要掌握) 捕获与命名捕获(要求:非junior岗位需要掌握)

3 常见模块使用(待补充完善)

a.基础要求:

能够熟练应用基础python模块,如string,logging,json,collections(熟悉其中一个)

b.进阶要求:

1requests,itertools,multiprocessing等

==4.垃圾回收==

a.基础要求:

垃圾回收过程(要求:必须目产出引用计数,其他非必须,发挥里间级大,可以引导面试者深 入回答) 引用计数的缺点(要求:必須掌握)

b.进阶要求:

分线回收


PythonQ&A

https://blog.csdn.net/u013486414/article/details/119701505

代码效率优化?

  • 尽量使用python内置函数
  • 字符串拼接使用python的标准式
  • 需要单次遍历的迭代的数组采用生成器替代【惰性计算】
  • if x代替if x==True

什么是duck type?

鸭子类型更关注对象的行为,只要实现了某种接口方法就行,而不在乎是什么类型(比如说定义了 __iter__魔法方法的类实例对象都可以用for来迭代)

py3和py2的区别

  • print在py3里是一个函数,在py2里只是一个关键字
  • py3文件的默认编码是utf8,py2文件的默认编码是ascii
  • py3的str是unicode字符串,而py2的str是bytes
  • py3的range()返回一个可迭代对象,py2的 range()返回一个列表,xrange()返回一个可迭代对象,
  • py3的除法返回float,py2的除法返回int

可变对象与不可变对象

  • 可变对象: list,dict,set
  • 不可变对象: bool,int,float,tuple,str, frozenset

可哈希和不可哈希对象

什么时候需要捕获异常?

  • Django的ORM框架操作数据库时,获取数据,更新数据等都有可能会异常
  • socket通信时,recv()方法可能会因为对方突然中断连接导致异常

什么是CPython GIL?

GIL,Global Interpreter Lock,即全局解释器锁,引入GIL是因为CPython的内存管理并不是线程安全的,为了保护多线程下对python对象的访问,每个线程在执行过程中都需要先获取GIL,保证同一时刻只有一个线程在执行代码,GIL使得python的多线程不能充分发挥多核CPU的性能,对CPU密集型程序的影响较大。

什么是生成器?

生成器是一种可迭代对象,可以挂起并保持当前的状态

生成器遇到yield处会停止执行,调用next()或send()才会继续执行

定义一个生成器有两种方式,一种是生成器推导式,一种是在普通函数中添加yield语句并实例化

浅拷贝和深拷贝

浅拷贝出来的是一个独立的对象,但它的子对象还是原对象中的子对象

深拷贝会递归地拷贝原对象中的每一个子对象,因此拷贝后的对象和原对象互不相关。

迭代器与可迭代对象的区别

可迭代对象类,必须自定义__iter__()魔法方法,range,list类的实例化对象都是可迭代对象

迭代器类,必须自定义__iter__()和__next__()魔法方法,用iter()函数可以创建可迭代对象的迭代器

闭包

闭包就是一个嵌套函数,它的内部函数 使用 外部函数的变量或参数,它的外部函数返回了内部函数

可以保存外部函数内的变量,不会随着外部函数调用完而销毁。

python垃圾回收机制

引用计数为主,标记清除分代回收为辅

引用计数机制是这样的:

  • 当对象被创建,被引用,作为参数传递,存储到容器中,引用计数+1

  • 当对象离开作用域,引用指向别的对象,del,从容器中移除,引用计数-1

  • 当引用计数降为0,python就会自动回收该对象所在的内存空间,

  • 但是引用计数无法解决循环引用的问题,所以引入了标记清除分代回收机制

async和await的作用

async: 声明一个函数为异步函数,函数内只要有await就要声明为async

await: 搭配asyncio.sleep()时会切换协程,当切换回来后再继续执行下面的语句

内置的数据结构和算法

  • 内置数据结构: list,dict,tuple,set
  • 内置算法: sorted,max

collections模块

collections模块提供了一些好用的容器数据类型,其中常用的有: namedtuple,dequeCounterOrderedDict,defaultdict

为什么dict查找的时间复杂度是O(1)?

dict底层是哈希表,哈希表类似于C语言的数组,可以实现按索引随机访问

但dict的key不一定是整数,需要先通过哈希函数,再经过取余操作转换为索引

list tuple的底层结构

list和tuple底层都是顺序表结构

list底层是可变数组,数组里存放的是元素对象的指针

set的底层结构

哈希表,key就是元素,value都是空

class方法 和 static方法的区别

class方法的第一个参数是cls,可以访问类属性,类方法

static方法和普通函数一样,只不过是放在类里,要通过类或实例来调用,但是它不能访问类和实例的属性和方法

什么是装饰器?

装饰器是一个接收函数作为参数的闭包函数

它可以在不修改函数内部源代码的情况下,给函数添加额外的功能

1
2
3
4
5
6
7
8
9
import time

def calc_time(func):
def inner():
t1 = time.time()
func()
t2 = time.time()
print('cost time: {}s'.format(t2-t1))
return inner

什么是元类? 使用场景

元类是创建类的类type还有继承自type的类都是元类

作用: 在类定义时(new, init)和 类实例化时(call) 可以添加自定义的功能

使用场景: ORM框架中创建一个类就代表数据库中的一个表,但是定义这个类时为了统一需要把里面的类属性全部改为小写,这个时候就要用元类重写new方法,把attrs字典里的key转为小写

Python局部变量

python中list作为全局变量无需global声明的原因,则不会有歧义。它是“明确的”,因为如果把b当作是局部变量的话,它会报KeyError,所以它只能是引用全局的b,故不需要多此一举显式声明global。

Python 读取大文件?

最近无论是面试还是笔试,有一个高频问题始终阴魂不散,那就是给一个大文件,至少超过10g,在内存有限的情况下(低于2g),该以什么姿势读它?

一般:

  • with 上下文管理器会自动关闭打开的文件描述符
  • 在迭代文件对象时,内容是一行一行返回的,不会占用太多内存
1
2
3
4
5
6
7
8
def retrun_count(fname):
"""计算文件有多少行
"""
count = 0
with open(fname) as file:
for line in file:
count += 1
return count

更底层: fp.read() iter(partial(file.read, block_size), '')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def chunked_file_reader(fp, block_size=1024 * 8):
"""生成器函数:分块读取文件内容
"""
while True:
chunk = fp.read(block_size)
# 当文件没有更多内容时,read 调用将会返回空字符串 ''
if not chunk:
break
yield chunk
# iter()优化
def chunked_file_reader(file, block_size=1024 * 8):
"""生成器函数:分块读取文件内容,使用 iter 函数
"""
# 首先使用 partial(fp.read, block_size) 构造一个新的无需参数的函数
# 循环将不断返回 fp.read(block_size) 调用结果,直到其为 '' 时终止
for chunk in iter(partial(file.read, block_size), ''):
yield chunk

def return_count_v3(fname):
count = 0
with open(fname) as fp:
for chunk in chunked_file_reader(fp):
count += 1
return count

pandas分批读取大数据集?

pandas 的 chunksize 读取

Python可变数据类型 不可变数据类型?

不可变类型:数值型、字符串型string和元组tuple;不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象。

可变数据类型:列表list和字典dict,Set集合