【建议收藏】50 道硬核的 Python 面试题!

Python基础---面试题汇总 前言 本文只涉及Python相关的面试题,面向中高级Python开发,太基本的题目不收录。 更希望通过代码演示,原理探究等来深入讲解某一知识点,做到融会贯通。 另外部分演示代码有兴趣的可以找我拿。 语言基础篇 Python的基本数据类型 Python3 中有六个标准的数据类型: Number(数字)(包括整型、浮点型、复数、布尔型等) String(字符串) List(列表) Tuple(元组) Set(集合) Dictionary(字典) Python3 的六个标准数据类型... 阅读详情

题目001: 在Python中如何实现单例模式。

点评:单例模式是指让一个类只能创建出唯一的实例,这个题目在面试中出现的频率极高,因为它考察的不仅仅是单例模式,更是对Python语言到底掌握到何种程度,建议大家用装饰器和元类这两种方式来实现单例模式,因为这两种方式的通用性最强,而且也可以顺便展示自己对装饰器和元类中两个关键知识点的理解。

方法一:使用装饰器实现单例模式。

from functools import wraps


def singleton(cls):
    """单例类装饰器"""
    instances = {}

    @wraps(cls)
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return wrapper


@singleton
class President:
    pass

扩展:装饰器是Python中非常有特色的语法,用一个函数去装饰另一个函数或类,为其添加额外的能力。通常通过装饰来实现的功能都属横切关注功能,也就是跟正常的业务逻辑没有必然联系,可以动态添加或移除的功能。装饰器可以为代码提供缓存、代理、上下文环境等服务,它是对设计模式中代理模式的践行。在写装饰器的时候,带装饰功能的函数(上面代码中的wrapper函数)通常都会用functools模块中的wraps再加以装饰,这个装饰器最重要的作用是给被装饰的类或函数动态添加一个__wrapped__属性,这个属性会将被装饰之前的类或函数保留下来,这样在我们不需要装饰功能的时候,可以通过它来取消装饰器,例如可以使用President = President.__wrapped__来取消对President类做的单例处理。需要提醒大家的是:上面的单例并不是线程安全的,如果要做到线程安全,需要对创建对象的代码进行加锁的处理。在Python中可以使用threading模块的RLock对象来提供锁,可以使用锁对象的acquirerelease方法来实现加锁和解锁的操作。当然,更为简便的做法是使用锁对象的with上下文语法来进行隐式的加锁和解锁操作。

方法二:使用元类实现单例模式。

class SingletonMeta(type):
    """自定义单例元类"""

    def __init__(cls, *args, **kwargs):
        cls.__instance = None
        super().__init__(*args, **kwargs)

    def __call__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__call__(*args, **kwargs)
        return cls.__instance


class President(metaclass=SingletonMeta):
    pass

扩展:Python是面向对象的编程语言,在面向对象的世界中,一切皆为对象。对象是通过类来创建的,而类本身也是对象,类这样的对象是通过元类来创建的。我们在定义类时,如果没有给一个类指定父类,那么默认的父类是object,如果没有给一个类指定元类,那么默认的元类是type。通过自定义的元类,我们可以改变一个类默认的行为,就如同上面的代码中,我们通过元类的__call__魔术方法,改变了President类的构造器那样。

补充:关于单例模式,在面试中还有可能被问到它的应用场景。通常一个对象的状态是被其他对象共享的,就可以将其设计为单例,例如项目中使用的数据库连接池对象和配置对象通常都是单例,这样才能保证所有地方获取到的数据库连接和配置信息是完全一致的;而且由于对象只有唯一的实例,因此从根本上避免了重复创建对象造成的时间和空间上的开销,也避免了对资源的多重占用。再举个例子,项目中的日志操作通常也会使用单例模式,这是因为共享的日志文件一直处于打开状态,只能有一个实例去操作它,否则在写入日志的时候会产生混乱。

题目002:不使用中间变量,交换两个变量`a`和`b`的值。

点评:典型的送人头的题目,通常交换两个变量需要借助一个中间变量,如果不允许使用中间变量,在其他编程语言中可以使用异或运算的方式来实现交换两个变量的值,但是Python中有更为简单明了的做法。

方法一:

a = a ^ b
b = a ^ b
a = a ^ b

方法二:

a, b = b, a

扩展:需要注意,a, b = b, a这种做法其实并不是元组解包,虽然很多人都这样认为。Python字节码指令中有ROT_TWO指令来支持这个操作,类似的还有ROT_THREE,对于3个以上的元素,如a, b, c, d = b, c, d, a,才会用到创建元组和元组解包。想知道你的代码对应的字节码指令,可以使用Python标准库中dis模块的dis函数来反汇编你的Python代码。

题目003:写一个删除列表中重复元素的函数,要求去重后元素相对位置保持不变。

点评:这个题目在初中级Python岗位面试的时候经常出现,题目源于《Python Cookbook》这本书第一章的第10个问题,有很多面试题其实都是这本书上的原题,所以建议大家有时间好好研读一下这本书。

def dedup(items):
    no_dup_items = []
    seen = set()
    for item in items:
        if item not in seen:
            no_dup_items.append(item)
            seen.add(item)
    return no_dup_items

如果愿意也可以把上面的函数改造成一个生成器,代码如下所示。

def dedup(items):
    seen = set()
    for item in items:
        if item not in seen:
            yield item
            seen.add(item)

扩展:由于Python中的集合底层使用哈希存储,所以集合的innot in成员运算在性能上远远优于列表,所以上面的代码我们使用了集合来保存已经出现过的元素。集合中的元素必须是hashable对象,因此上面的代码在列表元素不是hashable对象时会失效,要解决这个问题可以给函数增加一个参数,该参数可以设计为返回哈希码或hashable对象的函数。

题目004:假设你使用的是官方的CPython,说出下面代码的运行结果。

点评:下面的程序对实际开发并没有什么意义,但却是CPython中的一个大坑,这道题旨在考察面试者对官方的Python解释器到底了解到什么程度。

a, b, c, d = 1, 1, 1000, 1000
print(a is b, c is d)

def foo():
    e = 1000
    f = 1000
    print(e is f, e is d)
    g = 1
    print(g is a)

foo()

运行结果:

True False
True False
True

上面代码中a is b的结果是Truec is d的结果是False,这一点的确让人费解。CPython解释器出于性能优化的考虑,把频繁使用的整数对象用一个叫small_ints的对象池缓存起来造成的。small_ints缓存的整数值被设定为[-5, 256]这个区间,也就是说,在任何引用这些整数的地方,都不需要重新创建int对象,而是直接引用缓存池中的对象。如果整数不在该范围内,那么即便两个整数的值相同,它们也是不同的对象。

CPython底层为了进一步提升性能还做了另一个设定,对于同一个代码块中值不在small_ints缓存范围内的整数,如果同一个代码块中已经存在一个值与其相同的整数对象,那么就直接引用该对象,否则创建新的int对象。需要大家注意的是,这条规则对数值型适用,但对字符串则需要考虑字符串的长度,这一点大家可以自行证明。

扩展:如果你用PyPy(另一种Python解释器实现,支持JIT,对CPython的缺点进行了改良,在性能上优于CPython,但对三方库的支持略差)来运行上面的代码,你会发现所有的输出都是True。

题目005:Lambda函数是什么,举例说明的它的应用场景。

点评:这个题目主要想考察的是Lambda函数的应用场景,潜台词是问你在项目中有没有使用过Lambda函数,具体在什么场景下会用到Lambda函数,借此来判断你写代码的能力。因为Lambda函数通常用在高阶函数中,主要的作用是通过向函数传入函数或让函数返回函数最终实现代码的解耦合。

Lambda函数也叫匿名函数,它是功能简单用一行代码就能实现的小型函数。Python中的Lambda函数只能写一个表达式,这个表达式的执行结果就是函数的返回值,不用写return关键字。Lambda函数因为没有名字,所以也不会跟其他函数发生命名冲突的问题。

扩展:面试的时候有可能还会考你用Lambda函数来实现一些功能,也就是用一行代码来实现题目要求的功能,例如:用一行代码实现求阶乘的函数,用一行代码实现求最大公约数的函数等。

fac = lambda x: __import__('functools').reduce(int.__mul__, range(1, x + 1), 1)
gcd = lambda x, y: y % x and gcd(y % x, x) or x

Lambda函数其实最为主要的用途是把一个函数传入另一个高阶函数(如Python内置的filtermap等)中来为函数做解耦合,增强函数的灵活性和通用性。下面的例子通过使用filtermap函数,实现了从列表中筛选出奇数并求平方构成新列表的操作,因为用到了高阶函数,过滤和映射数据的规则都是函数的调用者通过另外一个函数传入的,因此这filtermap函数没有跟特定的过滤和映射数据的规则耦合在一起。

items = [12, 5, 7, 10, 8, 19]
items = list(map(lambda x: x ** 2, filter(lambda x: x % 2, items)))
print(items)    # [25, 49, 361]

扩展:用列表的生成式来实现上面的代码会更加简单明了,代码如下所示。

items = [12, 5, 7, 10, 8, 19]
items = [x ** 2 for x in items if x % 2]
print(items)    # [25, 49, 361]

题目006:说说Python中的浅拷贝和深拷贝。

点评:这个题目本身出现的频率非常高,但是就题论题而言没有什么技术含量。对于这种面试题,在回答的时候一定要让你的答案能够超出面试官的预期,这样才能获得更好的印象分。所以回答这个题目的要点不仅仅是能够说出浅拷贝和深拷贝的区别,深拷贝的时候可能遇到的两大问题,还要说出Python标准库对浅拷贝和深拷贝的支持,然后可以说说列表、字典如何实现拷贝操作以及如何通过序列化和反序列的方式实现深拷贝,最后还可以提到设计模式中的原型模式以及它在项目中的应用。

浅拷贝通常只复制对象本身,而深拷贝不仅会复制对象,还会递归的复制对象所关联的对象。深拷贝可能会遇到两个问题:一是一个对象如果直接或间接的引用了自身,会导致无休止的递归拷贝;二是深拷贝可能对原本设计为多个对象共享的数据也进行拷贝。Python通过copy模块中的copydeepcopy函数来实现浅拷贝和深拷贝操作,其中deepcopy可以通过memo字典来保存已经拷贝过的对象,从而避免刚才所说的自引用递归问题;此外,可以通过copyreg模块的pickle函数来定制指定类型对象的拷贝行为。

deepcopy函数的本质其实就是对象的一次序列化和一次返回序列化,面试题中还考过用自定义函数实现对象的深拷贝操作,显然我们可以使用pickle模块的dumpsloads来做到,代码如下所示。

import pickle

my_deep_copy = lambda obj: pickle.loads(pickle.dumps(obj))

列表的切片操作[:]相当于实现了列表对象的浅拷贝,而字典的copy方法可以实现字典对象的浅拷贝。对象拷贝其实是更为快捷的创建对象的方式。在Python中,通过构造器创建对象属于两阶段构造,首先是分配内存空间,然后是初始化。在创建对象时,我们也可以基于“原型”对象来创建新对象,通过对原型对象的拷贝(复制内存)就完成了对象的创建和初始化,这种做法更加高效,这也就是设计模式中的原型模式。在Python中,我们可以通过元类的方式来实现原型模式,代码如下所示。

import copy


class PrototypeMeta(type):
    """实现原型模式的元类"""

    def __init__(cls, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 为对象绑定clone方法来实现对象拷贝
        cls.clone = lambda self, is_deep=True: \
            copy.deepcopy(self) if is_deep else copy.copy(self)


class Person(metaclass=PrototypeMeta):
    pass


p1 = Person()
p2 = p1.clone()                 # 深拷贝
p3 = p1.clone(is_deep=False)    # 浅拷贝

题目007:Python是如何实现内存管理的?

点评:当面试官问到这个问题的时候,一个展示自己的机会就摆在面前了。你要先反问面试官:“你说的是官方的CPython解释器吗?”。这个反问可以展示出你了解过Python解释器的不同的实现版本,而且你也知道面试官想问的是CPython。当然,很多面试官对不同的Python解释器底层实现到底有什么差别也没有概念。所以,千万不要觉得面试官一定比你强,怀揣着这份自信可以让你更好的完成面试。

Python提供了自动化的内存管理,也就是说内存空间的分配与释放都是由Python解释器在运行时自动进行的,自动管理内存功能极大的减轻程序员的工作负担,也能够帮助程序员在一定程度上解决内存泄露的问题。以CPython解释器为例,它的内存管理有三个关键点:引用计数、标记清理、分代收集。

引用计数:对于CPython解释器来说,Python中的每一个对象其实就是PyObject结构体,它的内部有一个名为ob_refcnt 的引用计数器成员变量。程序在运行的过程中ob_refcnt的值会被更新并藉此来反映引用有多少个变量引用到该对象。当对象的引用计数值为0时,它的内存就会被释放掉。

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

以下情况会导致引用计数加1

  • 对象被创建

  • 对象被引用

  • 对象作为参数传入到一个函数中

  • 对象作为元素存储到一个容器中

以下情况会导致引用计数减1

  • del语句显示删除对象引用

  • 对象引用被重新赋值其他对象

  • 一个对象离开它所在的作用域

  • 持有该对象的容器自身被销毁

  • 持有该对象的容器删除该对象

可以通过sys模块的getrefcount函数来获得对象的引用计数。引用计数的内存管理方式在遇到循环引用的时候就会出现致命伤,因此需要其他的垃圾回收算法对其进行补充。

这里也给大家准备了一套系统学习资源,文中所展示的资料全部都是免费分享,点击下方链接添加微信即可免费获取!

戳这里 👉 【读者福利】Python经典学习资料免费分享,领走不谢! 👈

题目008:说一下你对Python中迭代器和生成器的理解。

点评:很多人面试者都会写迭代器和生成器,但是却无法准确的解释什么是迭代器和生成器。如果你也有同样的困惑,可以参考下面的回答。

迭代器是实现了迭代器协议的对象。跟其他编程语言不通,Python中没有用于定义协议或表示约定的关键字,像interfaceprotocol这些单词并不在Python语言的关键字列表中。Python语言通过魔法方法来表示约定,也就是我们所说的协议,而__next____iter__这两个魔法方法就代表了迭代器协议。可以通过for-in循环从迭代器对象中取出值,也可以使用next函数取出迭代器对象中的下一个值。生成器是迭代器的语法升级版本,可以用更为简单的代码来实现一个迭代器。

扩展:面试中经常让写生成斐波那契数列的迭代器,大家可以参考下面的代码。

class Fib(object):

    def __init__(self, num):
        self.num = num
        self.a, self.b = 0, 1
        self.idx = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.idx < self.num:
            self.a, self.b = self.b, self.a + self.b
            self.idx += 1
            return self.a
        raise StopIteration()
 

如果用生成器的语法来改写上面的代码,代码会简单优雅很多。

def fib(num):
    a, b = 0, 1
    for _ in range(num):
        a, b = b, a + b
        yield a

题目009:正则表达式的match方法和search方法有什么区别?

点评:正则表达式是字符串处理的重要工具,所以也是面试中经常考察的知识点。在Python中,使用正则表达式有两种方式,一种是直接调用re模块中的函数,传入正则表达式和需要处理的字符串;一种是先通过re模块的compile函数创建正则表达式对象,然后再通过对象调用方法并传入需要处理的字符串。如果一个正则表达式被频繁的使用,我们推荐用re.compile函数创建正则表达式对象,这样会减少频繁编译同一个正则表达式所造成的开销

match方法是从字符串的起始位置进行正则表达式匹配,返回Match对象或None。search方法会扫描整个字符串来找寻匹配的模式,同样也是返回Match对象或None。

题目010:下面这段代码的执行结果是什么。

def multiply():
  
Python 常见的 170 面试题全解析:2022 版 阅读详情

相关推荐

建议收藏50 硬核Python 面试题

题目001: 在Python中如何实现单例模式。方法一:使用装饰器实现单例模式。 方法二:使用元类实现单例模式。 题目002:不使用中间变量,交换两个变量`a`和`b`的值。方法一: 方法二: 题目003:写一个删除列表中重复元素的函数,要求去重后元素相对位置保持不变。 如果愿意也可以把上面的函数改造成一个生成器,代码如下所示。 题目004:假设你使用的是官方的CPython,说出下面代码的运行结果。 运行结果: 上面代码中的结果是但的结果是,这一点的确让人费

k15778864599的博客 833

硬核Python 面试题Python经典面试题总结

一、50 重要的 Python 面试题【问答题+编程题】 1. 说说你用过Python标准库中的哪些模块。 2. `init__`和`__new`方法有什么区别? 3. 平常工作中用什么工具进行静态代码分析。 4. 函数参数`arg`和`*kwargs`分别代表什么? 5. 什么是鸭子类型(duck typing)? 6. 说一下Python中变量的作用域。 8. 说一下Python 2和Python 3的区别。 9. 解释一下线程池的工作原理。 10. 举例说明什么情况下会出现`KeyError`、`T

weixin_43474701的博客 4898

12个高级 Python 面试问题与解答

PIP 是 Python Installer Package 的缩写,它提供了安装各种 Python 模块的无缝接口。它是一个命令行工具,可以通过互联网搜索软件包并安装它们,而无需任何用户交互。Python zip() 函数返回一个 zip 对象,该对象映射多个容器的相似索引。它接受一个可迭代对象,将其转换为迭代器,并根据传递的可迭代对象聚合元素。它返回元组的迭代器。

我的博客,不一样的自我表达 708

Python面试基础篇 - 50经典面试题(附答案及多种解答)

整理了这一份Python面试题的基础篇,进阶的先不说我能不能整理出来,估计整出来了不一定能看明白!(篇幅比较长,可以通过目录选择自己想看的~)

五包辣条的博客 2万+

50Python面试题,面试巩固必看,建议收藏

鸭子类型是动态类型语言判断一个对象是不是某种类型时使用的方法,也叫做鸭子判定法。简单的说,鸭子类型是指判断一只鸟是不是鸭子,我们只关心它游泳像不像鸭子、叫起来像不像鸭子、走路像不像鸭子就足够了。换言之,如果对象的行为跟我们的预期是一致的(能够接受某些消息),我们就认定它是某种类型的对象。bytesbytearraymemoryviewStringIOBytesIOGzipFilesocketstrbytes),其中file-like对象都能支持read和write。

m0_62283350的博客 2万+

建议收藏50 硬核Python 面试题..

所以回答这个题目的要点不仅仅是能够说出浅拷贝和深拷贝的区别,深拷贝的时候可能遇到的两大问题,还要说出Python标准库对浅拷贝和深拷贝的支持,然后可以说说列表、字典如何实现拷贝操作以及如何通过序列化和反序列的方式实现深拷贝,最后还可以提到设计模式中的原型模式以及它在项目中的应用。在使用面向对象编程语言的时候,定义类是最常见的一件事情,有的时候,我们会用到只有属性没有方法的类,这种类的对象通常只用于组织数据,并不能接收消息,所以我们把这种类称为数据类或者退化的类,就像C语言中的结构体那样。

测试萌萌 1300

50JAVA基础算法编程题【内含分析、程序答案】【建议收藏

🍅 硬核资料:关注即可领取PPT模板、简历模板、行业经典书籍PDF。🍅 技术互助:技术群大佬指点迷津,你的问题可能不是问题,求资源在群里喊一声。🍅 面试题库:由技术群里的小伙伴们共同投稿,热乎的大厂面试真题,持续更新中。🍅 知识体系:含编程语言、算法、大数据生态圈组件(Mysql、Hive、Spark、Flink)、数据仓库、Python、前端等等。网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

m0_60635001的博客 969

7套干货,Python常用技术学习知识图谱!!(史上最全,建议收藏

给大家推荐几个宝藏级教程,你可以根据自己的自身情况进行选择: 一、Python入门 二、Python数据分析 三、Python爬虫 四、Python学习技术问题汇总 五、数据结构与算法 六、计算机基础 七、MySQL

独木不成林,单弦不成音。 4万+

2024年Python最新2024年50必备python面试题大全(附答案)【建议收藏】(2)

运行错误(需要更多测试,并且错误仅在运行时显示)简单性。

2401_84564025的博客 144

Python程序员必须吃透的100个函数,建议收藏!_pyhon常用函数 anki

新手在做写代码的时候容易卡壳,尤其当接触的函数以及其他知识比较多的时候,经常会看完需求之后不知自己该用什么方法来实现它,实现的逻辑可能你有,但怎么该用什么函数给忘了,这其实就是知识的储备不够,你记不住哪个函数有什么作用,自然一头雾水。这几天我专门整理了Python常用的一些函数,从最基础的输入输出函数到正则等12个板块的,总共100多个常用函数,方便小伙伴们进行快速地记忆,每天快速过一遍,用的时候再加深一下,慢慢地你就会摆脱写代码卡壳的状况。案例:修改元组 #取元组下标在1~4之间的3个数,转换成列表。

485

建议收藏!2026 SQLite + Python 3.10 + FastAPI 全栈实战指南:从零基础到企业级落地,一文讲透异步数据库开发

SQLite + Python 3.10 + FastAPI全栈实战指南(2026) 摘要:本文针对中小型应用开发中的"过度工程化"问题,提出基于SQLite、Python 3.10和FastAPI的轻量级全栈解决方案。文章首先分析四种典型开发痛点场景,包括基础设施过载、异步并发阻塞等问题。随后详细介绍这一技术组合的核心优势,重点解析SQLAlchemy 2.0异步架构、WAL模式并发机制等关键技术原理。通过与传统Django+PostgreSQL方案的对比,展示该组合在开发效率、运维成本和性能表现上的优势

【javatoai17819112191】→Java && python && AI Agent工程师 747

头条二面Kafka面经总结:搞懂Kafka的这个问题,你离大厂就不远了!!(建议收藏

有些读者去头条二面,被面试官问了一个关于Kafka的问题:多个Kafka消费者如何同时消费相同Topic下的相同Partition的数据?看似一个简单的问题,竟然把这位读者问懵了!今天,我们一起来分析下这面试题

冰河的专栏 5707

7套干货,Python常用技术学习知识图谱!!(史上最全,建议收藏

本课程是李宁老师结合十多年Python教学和开发经验的结晶。本系列课程中涉及到的知识点。

imtokenmax众筹 1186

7套干货,Python常用技术学习知识及图谱!!(史上超全,建议收藏

本课程是老师结合十多年Python教学和开发经验的结晶。本系列课程中涉及到的知识点都是在实际工作中遇到的,并且已经解决的各种问题。还有的技术问题是搜集了国内外程序员遇到的各种类型的技术问题,部分和这些程序员直接交流,了解他们的需求以及某些理解上的困难。通过手机和总结这些技术问题,并给出多种可能的解答,将非常有助于Python程序员解决在实际工作中遇到的各种问题。

m0_74942241的博客 515

7套干货,Python常用技术学习知识图谱!!(史上最全,建议收藏(1)

本课程是李宁老师结合十多年Python教学和开发经验的结晶。本系列课程中涉及到的知识点。

2201_75604580的博客 572
上一篇: Python五大就业方向薪资现状,新手要注意,选错你就白学了!
下一篇: 想转行学python?看完这个路线图,平均薪资超2W+
程序员源源
博客等级 码龄4年 75粉丝 140原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值