机器学习面试题汇总与解析——Python



  • 本专栏适合于Python已经入门的学生或人士,有一定的编程基础。

  • 本专栏适合于算法工程师、机器学习、图像处理求职的学生或人士。

  • 本专栏针对面试题答案进行了优化,尽量做到好记、言简意赅。这才是一份面试题总结的正确打开方式。这样才方便背诵

  • 如专栏内容有错漏,欢迎在评论区指出或私聊我更改,一起学习,共同进步。

  • 相信大家都有着高尚的灵魂,请尊重我的知识产权,未经允许严禁各类机构和个人转载、传阅本专栏的内容。


  • 关于机器学习算法书籍,我强烈推荐一本《百面机器学习算法工程师带你面试》,这个就很类似面经,还有讲解,写得比较好。

  • 关于深度学习算法书籍,我强烈推荐一本《解析神经网络——深度学习实践手册》,简称 CNN book,通俗易懂。

  • 关于Python的知识点,推荐一个网址:https://github.com/hantmac/Python-Interview-Customs-Collection



1. python 深拷贝与浅拷贝⭐⭐⭐⭐⭐

参考回答

浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。

深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。

答案解析

图片说明

图片说明

2. python 多线程能用多个 cpu 么?⭐⭐⭐⭐⭐

参考回答

python 的多线程不能利用多核 CPU

原因是 python 的解释器使用了GIL(Global Interpreter Lock),在任意时刻中只允许单个python线程运行。无论系统有多少个 CPU 核心,python 程序都只能在一个 CPU 上运行。

答案解析

GIL 中文译为全局解释器锁,其本质上类似操作系统的 Mutex。GIL 的功能是:在 CPython 解释器中执行的每一个 Python 线程,都会先锁住自己,以阻止别的线程执行。

因为 python 的多线程本身不能利用多核 CPU,但 Python 中还有其他的多进程编程模块,例如 multiprocessing,它可以在多个 CPU 上并行执行任务。使用多进程可以充分利用多个 CPU 运行不同的进程,从而提高并行计算的性能。在多进程编程中,每个进程都有自己独立的 Python 解释器和内存空间,因此不存在 GIL 的限制。

3. python 垃圾回收机制⭐⭐⭐⭐⭐

参考回答

Python的垃圾回收机制是以:引用计数器为主,标记清除分代回收为辅。

方式1引用计数:每个对象内部都维护了一个值,该值记录这此对象被引用的次数,如果次数为 0,则 Python 垃圾回收机制会自动清除此对象。

方式2标记-清除(Mark—Sweep):被分配对象的计数值与被释放对象的计数值之间的差异累计超过某个阈值,则 Python 的收集机制就启动

方式3:当代码中主动执行 gc.collect() 命令时,Python 解释器就会进行垃圾回收。

4. python 里的生成器是什么⭐⭐⭐⭐⭐

在 Python 中,生成器(Generator)是一种特殊的迭代器,它是一种用于创建迭代器的函数。生成器函数可以通过 yield 语句来产生一个值,并且在产生值之后可以暂停执行,保存当前的状态。当再次请求下一个值时,生成器会从上次暂停的位置继续执行,生成下一个值。这种方式可以有效地节省内存空间,因为它不需要一次性生成所有的值,而是按需生成。

生成器的工作方式与普通函数不同。普通函数在调用时会执行完所有的代码并返回结果,而生成器函数在每次调用时只会执行到 yield 语句处,并返回一个值。生成器函数的执行过程可以被暂停和恢复,从而实现了按需生成数据的效果。

答案解析

以下是一个简单的生成器函数的示例:

def countdown(n):
    while n > 0:
        yield n
        n -= 1

# 使用生成器函数创建生成器对象
generator = countdown(5)

# 通过迭代生成器对象获取值
for value in generator:
    print(value)

输出结果为:

5
4
3
2
1

5. 迭代器和生成器的区别⭐⭐⭐⭐⭐

迭代器是一种对象,它实现了迭代协议,即具有 __iter____next__ 方法。迭代器可以用于遍历可迭代对象(如列表、元组、字典等),每次调用 __next__ 方法都返回可迭代对象中的下一个元素,当没有更多元素可返回时,会引发 StopIteration 异常。

生成器是一种特殊的迭代器,它是通过生成器函数或生成器表达式创建的。生成器函数是使用 def 关键字定义的函数,其中包含 yield 语句。生成器表达式则类似于列表推导式,但使用圆括号括起来。生成器函数可以通过 yield 语句来产生一个值,并且在产生值之后可以暂停执行,保存当前的状态。当再次请求下一个值时,生成器会从上次暂停的位置继续执行,生成下一个值。避免一次性生成所有数据,从而节省内存空间。

区别

  • 定义方式:迭代器可以通过实现迭代协议来创建,而生成器可以通过生成器函数或生成器表达式来创建。

  • 返回值:迭代器的 __next__ 方法返回下一个元素,而生成器函数中的 yield 语句用于产生值,并且在生成值后可以暂停执行,保存当前状态。生成器表达式直接返回生成器对象。

  • 状态保存:迭代器在迭代过程中不会保存状态,每次调用 __next__ 方法都是从头开始计算下一个值。而生成器函数和生成器表达式可以保存状态,在下次调用时从上次暂停的位置继续执行。

  • 内存占用:迭代器需要保存完整的迭代对象,占用内存较大。生成器采用按需生成的方式,只在需要时生成数据,节省内存空间。

  • 使用方式:迭代器可以通过 iter() 函数进行转换,并使用 next() 函数获取下一个元素。生成器可以直接使用,也可以通过迭代来获取值。

6. 装饰器⭐⭐⭐⭐⭐

参考回答

装饰器(Decorator)是 Python 中一种特殊的语法构造,用于修改或扩展函数(或类)的功能。装饰器本质上是一个函数,它接受一个函数作为输入,并返回一个新的函数作为输出,这个新函数通常会在原函数的基础上添加一些额外的功能或行为。

装饰器的作用是实现代码的重用和功能的动态扩展,它可以在不修改原函数代码的情况下,对函数进行功能增强、日志记录、性能统计等操作。通过装饰器,我们可以将通用的功能逻辑与具体函数的实现分离,提高代码的可读性和可维护性。

答案解析

下面是一个简单的装饰器示例,用于记录函数的执行时间:

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        execution_time = end_time - start_time
        print(f"函数 {func.__name__} 执行时间:{execution_time} 秒")
        return result
    return wrapper

@timer
def my_function():
    time.sleep(2)
    print("执行完成")

my_function()

在上面的示例中,timer 函数是一个装饰器,它接受一个函数作为参数,并返回一个新的函数 wrapper。新函数 wrapper 在执行被装饰的函数之前和之后,添加了计时的逻辑。通过在 my_function 函数上添加 @timer 装饰器,实际上调用的是 timer(my_function),从而将 my_function 函数传递给 timer 装饰器进行装饰。

执行结果会输出函数的执行时间,如:

执行完成
函数 my_function 执行时间:2.0017595291137695 秒

这样,我们通过装饰器实现了对函数执行时间的统计,而不需要修改原函数的代码。

7. python 有哪些数据类型⭐⭐⭐⭐⭐

  • 数字类型(Numeric Types):整数(int)、浮点数(float)、复数(complex)等。

  • 字符串类型(String Type):由字符组成的序列,用于表示文本信息。

  • 列表类型(List Type):有序可变的集合,可以包含任意类型的元素,使用方括号 [] 表示。

  • 元组类型(Tuple Type):有序不可变的集合,可以包含任意类型的元素,使用圆括号 () 表示。

  • 集合类型(Set Type):无序的可变集合,不允许重复元素,使用花括号 {} 表示。

  • 字典类型(Dictionary Type):无序的键值对集合,用于存储具有唯一键的值,使用花括号 {} 表示。

  • 布尔类型(Boolean Type):表示真或假的值,包括 True 和 False 两个取值。

  • 空值类型(None Type):表示空对象或缺失值的特殊类型,只有一个取值 None。

8. Python 中列表( List )中的 del,remove,和 pop 等的用法和区别⭐⭐⭐⭐⭐

1.del:del 是一个关键字,用于删除列表中指定位置的元素或删除整个列表。它有以下两种用法:

  • 删除指定位置的元素:使用 del 关键字加上列表名和索引,例如:del my_list[index],将删除列表 my_list 中索引为 index 的元素。
  • 删除整个列表:使用 del 关键字加上列表名,例如:del my_list,将删除整个列表 my_list。

2.remove:remove 是列表的方法,用于删除列表中第一个匹配的指定元素。它的用法是:

  • 使用列表名后跟点操作符(.)和 remove 方