11个Python面试必备问题 *

最好的Python开发人员和工程师可以回答的全面来源的基本问题. 在我们社区的推动下,我们鼓励专家提交问题并提供反馈.

现在就聘请一名顶级Python开发人员
Toptal标志是顶级自由软件开发人员的专属网络吗, designers, 金融专家, 产品经理, 和世界上的项目经理. 顶级公司雇佣Toptal自由职业者来完成他们最重要的项目.

面试问题

1.

下面代码的输出是什么? 解释你的答案.

def extendList(val, list=[]):
    list.追加(val)
    返回列表

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

打印“list1 = %s”% list1
打印“list2 = %s”% list2
打印“list3 = %s”% list3

你会如何修改定义 extendList 产生预期的行为?

查看答案

以上代码的输出将是:

List1 = [10, 'a']
List2 = [123]
List3 = [10, 'a']

许多人会错误地认为 list1 等于 [10] and list3 等于 ['a'],认为 list 参数将被设置为其默认值 [] 每一次 extendList is called.

然而,实际发生的是创建新的默认列表 only once 当函数为 defined,然后在随后的任何时候使用相同的列表 extendList 在没有 list 指定参数. 这是因为默认参数中的表达式是在定义函数时计算的, 当它被召唤的时候就不会.

list1 and list3 因此在操作 same 默认列表,而 list2 在它创建的单独列表上操作(通过传递它自己的空列表作为 list 参数).

的定义 extendList 函数可以修改如下不过,对…… always 如果没有,开始一个新的列表 list 参数,这更可能是期望的行为:

def extendList(val, list=None):
  如果list为None:
    list = []
  list.追加(val)
  返回列表

使用这个修订后的实现,输出将是:

List1 = [10]
List2 = [123]
List3 = ['a']
2.

下面代码的输出是什么? 解释你的答案.

def乘数():
  返回[lambda x: I * x for I in range(4)]
    
Print [m(2) for m in 乘数()]

你会如何修改定义 乘数 产生预期的行为?

查看答案

上面代码的输出将是 [6, 6, 6, 6] (not [0, 2, 4, 6]).

这是因为Python的闭包是 后期绑定. 这意味着在调用内部函数时查找闭包中使用的变量的值. 因此,当 any 返回的函数 乘数() 都叫,值 i 是否在周围的范围内查找 当时. 到那时,无论调用返回的函数中的哪个 for 循环已经完成 i 最后的值是3. Therefore, 每个返回的函数都将传递给它的值乘以3, 因此,由于在上面的代码中传递了一个值2, 它们都返回值6 (i).e., 3 x 2).

(顺便说一句,正如在 Python漫游指南, 有一种普遍的误解,认为这与lambda有关, 哪一个不是这样. 类创建的函数 lambda 表达式没有任何特殊之处,使用普通类型创建的函数也会显示相同的行为 def.)

下面是一些绕过这个问题的例子.

一种方法是用a Python发电机 如下:

def乘数():
  对于范围(4)中的I: yield lambda x: I * x 

另一种解决方案是创建一个闭包,通过使用默认参数立即绑定到它的参数. 例如:

def乘数():
  返回[lambda x, i=i: i * x for i in range(4)]

或者,也可以使用 functools.partial 功能:

从functools导入partial
从操作符导入mul

def乘数():
  返回[partial(mul, i) for i in range(4)]

最后,最简单的修复方法可能是简单地替换返回值 [] with ():

def乘数():
  返回(lambda x: I * x for I in range(4))
3.

下面代码的输出是什么? 解释你的答案.

类的父(对象):
    x = 1

类Child1(父):
    pass

类Child2(父):
    pass

印父.x, Child1.x, Child2.x
Child1.x = 2
印父.x, Child1.x, Child2.x
Parent.x = 3
印父.x, Child1.x, Child2.x
查看答案

以上代码的输出将是:

1 1 1
1 2 1
3 2 3

让许多人感到困惑或惊讶的是,最后一行输出是 3 2 3 而不是 3 2 1. 为什么改变的值 Parent.x 的值也可以改变 Child2.x,但同时不改变的值 Child1.x?

答案的关键在于,在Python中,类变量在内部被作为字典处理. 如果在当前类的字典中没有找到变量名,则类层次结构(i.e., 它的父类)被搜索,直到找到被引用的变量名(如果被引用的变量名在类本身或其层次结构中的任何地方都找不到), an AttributeError occurs).

因此,设置 x = 1 in the Parent 类使类成为变量 x (值为1)在该类中可引用 and 它的任何子节点. 这就是为什么第一个 print 语句输出 1 1 1.

随后, 如果它的任何子类重写了该值(例如, 当我们执行语句时 Child1.x = 2),则在该子节点中更改该值 only. 这就是为什么第二个 print 语句输出 1 2 1.

最后,如果在父类中更改了该值(例如,在执行语句时) Parent.x = 3), 该更改也反映在尚未覆盖该值的任何子节点上(在这种情况下将是) Child2). 这就是为什么第三个 print 语句输出 3 2 3.

申请加入Toptal的发展网络

并享受可靠、稳定、远程 Python自由开发者职位

申请成为自由职业者
4.

下面的代码在Python 2中的输出是什么? 解释你的答案.

def div1 (x, y):
    打印"%s/%s = %s" % (x, y, x/y)
    
def div2 (x, y):
    打印"%s//%s = %s" % (x, y, x//y)

div1(5,2)
div1(5.,2)
div2(5,2)
div2(5.,2.)

同样,在Python 3中答案会有什么不同(当然,假设上面的 print 语句被转换为Python 3语法)?

查看答案

In Python 2,上述代码的输出将是:

5/2 = 2
5.0/2 = 2.5
5//2 = 2
5.0//2.0 = 2.0

默认情况下,如果两个操作数都是整数,Python 2会自动执行整数运算. 因此, 5/2 yields 2, while 5./2 yields 2.5.

注意,你可以在Python 2中通过添加以下import来覆盖此行为:

从__future__导入分区

还要注意,“双斜杠”(//)操作员将 always 执行整数除法,无论操作数类型如何. 这就是为什么 5.0//2.0 yields 2.0 即使在Python 2中.

Python 3, however, does not have this behavior; i.e., it does not 如果两个操作数都是整数,则执行整数运算. 因此,在Python 3中,输出将如下:

5/2 = 2.5
5.0/2 = 2.5
5//2 = 2
5.0//2.0 = 2.0
5.

下面代码的输出是什么?

List = ['a', 'b', 'c', 'd', 'e']
打印列表(10:)
查看答案

上面的代码将输出 [],并将 not 导致… IndexError.

正如人们所预料的那样, 试图使用超过成员数的索引访问列表的成员(例如.g.,试图访问 list[10] 在上面的列表中)的结果为 IndexError. However, 尝试访问位于起始索引处的列表切片,如果超出列表中成员的数量,将会导致错误 not 导致… IndexError 并且将简单地返回一个空列表.

这是一个特别棘手的问题,因为它会导致难以追踪的bug,因为在运行时不会引发错误.

6.

考虑下面的代码片段:

1. List = [[]] * 5
2. 列表#输出?
3. list[0].追加(10)
4. 列表#输出?
5. list[1].追加(20)
6. 列表#输出?
7. list.追加(30)
8. 列表#输出?

第2、4、6和8行输出是什么? 解释你的答案.

查看答案

输出如下所示:

[[], [], [], [], []]
[[10], [10], [10], [10], [10]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]

原因如下:

The first line of output is presumably intuitive and easy to understand; i.e., List = [[]] * 5 简单地创建一个5个列表的列表.

However,这里要理解的关键是这个表述 List = [[]] * 5 does NOT 创建一个包含5的列表 distinct lists; rather, it creates a a list of 对同一列表的5个引用. 有了这样的理解,我们就可以更好地理解输出的其余部分.

list[0].追加(10) 向第一个列表追加10. 但由于所有5个列表都指向同一个列表,因此输出为: [[10], [10], [10], [10], [10]].

同样的, list[1].追加(20) 向第二个列表追加20. 但是,由于所有5个列表都指向同一个列表,所以现在的输出是: [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]].

相比之下, list.追加(30) 追加一个完全 new 元素到" outer "列表,因此会产生输出: [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30].

7.

给定一个N个数的列表, 使用单个列表推导式生成一个只包含以下值的新列表:
(a)偶数
(b)从原列表中具有偶数索引的元素

例如,如果 list[2] 包含一个偶数的值 should 被包含在新列表中,因为它也是偶数索引(i.e., 2)在原列表中. 然而,如果 list[3] 包含一个偶数,这个数应该 not 被包含在新列表中,因为它位于奇数索引(i.e., 3)在原列表中.

查看答案

解决这个问题的简单方法如下

[x for x in list[::2] if x%2 == 0]

例如,给定以下列表:

#        0   1   2   3    4    5    6    7    8
List = [1,3,5,8,10,13,18,36,78]

列表推导 [x for x in list[::2] if x%2 == 0] 将计算为:

[10, 18, 78]

这个表达式首先取偶数下标的数, 然后过滤掉所有的奇数.

8.

给定字典的以下子类:

类DefaultDict (dict类型):
  Def __missing__(self, key):
    return []

下面的代码可以工作吗? 为什么或为什么不?

d = default ()
D ['florp'] = 127
查看答案

Actually, 所示的代码将与python 2或3中的标准字典对象一起工作——这是正常的行为. 子类化dict是不必要的. 但是,这个子类仍然不能与所示的代码一起工作,因为 __missing__ 返回一个值,但不改变字典本身:

d = default ()
print d
{}
打印d(“foo”)
[]
print d
{}

所以它会“奏效”,,也就是说它不会产生任何误差, 但并没有达到预期的效果.

Here is a __missing__方法,该方法将更新字典,并返回一个值:

类DefaultDict (dict类型):
    Def __missing__(self, key):
        Newval = []
        Self [key] = newval
        返回newval

但是从版本2开始.在collections模块(在标准库中)中已经提供了一个defaultdict对象.)

9.

如何对下面的代码进行单元测试呢?

Async def logs(cont, name):
    Conn = aiohttp.UnixConnector(路径= " / var /运行/码头工人.sock")
    与aiohttp异步.ClientSession(connector=conn)作为session:
        带会话的异步.get (f“http://xx/containers/ {cont} /日志?follow=1&Stdout =1")
            Async for line in resp.content:
                打印(名称、线)
查看答案

一个好的答案是建议使用特定的异步模拟库和异步测试用例方法, 包括一个短暂的事件循环,保证终止(i.e. 超时前的最大步数.)

一个很好的答案是,同步和异步代码中的同步问题基本上是一样的, 区别在于抢占粒度.

一个漂亮的答案是考虑到上面的代码只有一个流(简单),而其他一些代码的流是混合的(e.g. 将两个流合并为一个流,排序等). 例如,考虑以下对给定代码的升级:

keep_running = True

Async def logs(cont, name):
    Conn = aiohttp.UnixConnector(路径= " / var /运行/码头工人.sock")
    与aiohttp异步.ClientSession(connector=conn)作为session:
        带会话的异步.get (f“http://xx/containers/ {cont} /日志?follow=1&Stdout =1")
            Async for line in resp.content:
                如果不是,keep_running:
                    break
                打印(名称、线)

在这里,任何异步语句都可能产生改变全局变量的副作用 keep_running.

10.

如何列出模块中的功能?

查看答案

Use the dir() 方法列出模块中的函数.

例如:

进口some_module
打印dir (some_module)
11.

编写一个函数,输出给定列表中不存在且不能用列表子元素的和表示的最小整数.

E.g. For a = [1,2,5,7] 不是由列表或列表的切片表示的最小整数是4,如果 a = [1,2,2,5,7] 最小的不可表示整数是18.

查看答案
出现进口itertools
Sum_list = []
Stuff = [1,2,5,7]
for L in range(0, len(stuff)+1):
    用于itertools中的子集.组合(东西,L):
        sum_list.追加(sum(子集))

New_list = list(set(sum_list))
new_list.sort()
对于range(0,new_list[-1]+2)中的每一个:
    如果每个不在new_list中:
        打印(每个)
        break

面试不仅仅是棘手的技术问题, 所以这些只是作为一个指南. 并不是每一个值得雇佣的“A”候选人都能回答所有的问题, 回答所有问题也不能保证成为A级考生. 一天结束的时候, 招聘仍然是一门艺术,一门科学,需要大量的工作.

为什么Toptal

厌倦了面试候选人? 不知道该问什么才能让你得到一份好工作?

让Toptal为你找到最合适的人.

现在就聘请一名顶级Python开发人员

我们的Python开发者专属网络

希望找到一份Python开发人员的工作?

让Toptal为你找到合适的工作.

申请成为Python开发人员

工作机会从我们的网络

提出面试问题

提交的问题和答案将被审查和编辑, 并可能会或可能不会选择张贴, 由Toptal全权决定, LLC.

*所有字段均为必填项

寻找Python开发人员?

寻找 Python开发人员? 查看Toptal的Python开发人员.

Chris Lee

自由Python开发人员

美国Toptal的自由Python开发人员 Since 二零一七年十月三日

Chris在开发API服务方面有多年的经验. 他最喜欢使用aiohttp包, SQLAlchemy(蒸馏器), 和PostgreSQL栈, 但他也熟悉弗拉斯克, MongoDB, Redis, and more. 他是Indico Data solutions后端团队的一员,Indico Data solutions是一家机器学习API和工具提供商,负责开发处理大数据处理和分析的后端服务. Chris在AWS、GCE和Azure云方面也有出色的技能.

Show More

汉娜Herbig

自由Python开发人员

美国Toptal的自由Python开发人员 Since 2022年6月22日

汉娜是一名自学成才的软件工程师,她已经写了十多年的代码. 她的大部分经验都是在Python上, 包括FastAPI和Flask, 但她也有使用Ruby的经验, c++ + Qt, 和JavaScript, 包括节点.js、Vue、jQuery和Socket.IO. Hannah在这些项目中从事后端api和图形用户界面(gui)的工作.

Show More

马克西米利安霍普夫

自由Python开发人员

联合王国Toptal的自由Python开发人员 Since 2019年6月4日

Max是一位数据科学和机器学习专家,专门研究深度学习和自然语言处理. 他帮助建立了德国资金最雄厚的金融科技公司之一,并在伦敦成功创立了自己的人工智能公司. 马克斯的研究成果发表了一篇科学论文, 通过高级分析提高营销准确性, 并为体育赛事和客户行为的预测建立了可靠的模型.

Show More

Toptal连接 Top 3% 世界各地的自由职业人才.

加入Toptal社区.

了解更多