题目001: 在Python中如何实现单例模式。
题目002:不使用中间变量,交换两个变量`a`和`b`的值。
题目003:写一个删除列表中重复元素的函数,要求去重后元素相对位置保持不变。
题目004:假设你使用的是官方的CPython,说出下面代码的运行结果。
题目005:Lambda函数是什么,举例说明的它的应用场景。
题目006:说说Python中的浅拷贝和深拷贝。
题目007:Python是如何实现内存管理的?
题目008:说一下你对Python中迭代器和生成器的理解。
题目009:正则表达式的match方法和search方法有什么区别?
题目010:下面这段代码的执行结果是什么。
题目011:Python中为什么没有函数重载?
题目012:用Python代码实现Python内置函数max。
题目013:写一个函数统计传入的列表中每个数字出现的次数并返回对应的字典。
题目014:使用Python代码实现遍历一个文件夹的操作。
题目015:现有2元、3元、5元共三种面额的货币,如果需要找零99元,一共有多少种找零的方式?
题目016:写一个函数,给定矩阵的阶数`n`,输出一个螺旋式数字矩阵。
题目017:阅读下面的代码,写出程序的运行结果。
题目018:说出下面代码的运行结果。
题目19:说说你用过Python标准库中的哪些模块。
题目19:说说你用过Python标准库中的哪些模块。
题目20:`init__`和`__new`方法有什么区别?
题目21:输入年月日,判断这个日期是这一年的第几天。
题目22:平常工作中用什么工具进行静态代码分析。
题目23:说一下你知道的Python中的魔术方法。
题目24:函数参数`arg`和`*kwargs`分别代表什么?
题目25:写一个记录函数执行时间的装饰器。
题目26:什么是鸭子类型(duck typing)?
题目27:说一下Python中变量的作用域。
题目28:说一下你对闭包的理解。
题目29:说一下Python中的多线程和多进程的应用场景和优缺点。
题目30:说一下Python 2和Python 3的区别。
题目31:谈谈你对“猴子补丁”(monkey patching)的理解。
题目32:阅读下面的代码说出运行结果。
题目33:编写一个函数实现对逆波兰表达式求值,不能使用Python的内置函数。
题目34:Python中如何实现字符串替换操作?
题目35:如何剖析Python代码的执行性能?
题目36:如何使用`random`模块生成随机数、实现随机乱序和随机抽样?
题目37:解释一下线程池的工作原理。
题目38:举例说明什么情况下会出现`KeyError`、`TypeError`、`ValueError`。
题目39:说出下面代码的运行结果。
题目40:如何读取大文件,例如内存只有4G,如何读取一个大小为8G的文件?
题目41:说一下你对Python中模块和包的理解。
题目42:说一下你知道的Python编码规范。
题目43:运行下面的代码是否会报错,如果报错请说明哪里有什么样的错,如果不报错请说出代码的执行结果。
题目44:对下面给出的字典按值从大到小对键进行排序。
题目45:说一下`namedtuple`的用法和作用。
题目46:按照题目要求写出对应的函数。
题目47:按照题目要求写出对应的函数。
题目48:按照题目要求写出对应的装饰器。
题目49:写一个函数实现字符串反转,尽可能写出你知道的所有方法。
题目50:按照题目要求写出对应的函数。
正文:
题目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
对象来提供锁,可以使用锁对象的acquire
和release
方法来实现加锁和解锁的操作。当然,更为简便的做法是使用锁对象的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中的集合底层使用哈希存储,所以集合的
in
和not in
成