11个Python面试必备问题 *

Toptal sourced essential questions that the best Python developers and engineers can answer. Driven from our community, we encourage experts to submit questions and offer feedback.

现在就聘请一名顶级Python开发人员
Toptal标志是顶级自由软件开发人员的专属网络吗, 设计师, 金融专家, 产品经理, 和世界上的项目经理. Top companies hire Toptal freelancers for their most important projects.

面试问题

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 参数将被设置为其默认值 [] each time extendList is called.

However, what actually happens is that the new default list is created only once 当函数为 defined,然后在随后的任何时候使用相同的列表 extendList 在没有 list 指定参数. This is because expressions in default arguments are calculated 当函数为 defined, 当它被召唤的时候就不会.

list1 and list3 因此在操作 same 默认列表,而 list2 is operating on a separate list that it created (by passing its own empty list as the value for the list 参数).

的定义 extendList 函数可以修改如下不过,对…… always 如果没有,开始一个新的列表 list argument is specified, which is more likely to have been the desired behavior:

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的闭包是 后期绑定. This means that the values of variables used in closures are looked up at the time the inner function is called. 因此,当 any 返回的函数 乘数() 都叫,值 i 是否在周围的范围内查找 当时. By then, regardless of which of the returned functions is called, the for 循环已经完成 i 最后的值是3. 因此, 每个返回的函数都将传递给它的值乘以3, 因此,由于在上面的代码中传递了一个值2, 它们都返回值6 (i).e., 3 x 2).

(顺便说一句,正如在 Python漫游指南, there is a somewhat widespread misconception that this has something to do with lambdas, 哪一个不是这样. 类创建的函数 lambda expression are in no way special and the same behavior is exhibited by functions created using an ordinary def.)

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

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

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

Another solution is to create a closure that binds immediately to its arguments by using a default argument. 例如:

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

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

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

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

Finally, the easiest fix may be to simply replace the return value’s [] 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

What confuses or surprises many about this is that the last line of output is 3 2 3 而不是 3 2 1. 为什么改变的值 Parent.x 的值也可以改变 Child2.x,但同时不改变的值 Child1.x?

The key to the answer is that, in Python, class variables are internally handled as dictionaries. If a variable name is not found in the dictionary of the current class, the class hierarchy (i.e., its parent classes) are searched until the referenced variable name is found (if the referenced variable name is not found in the class itself or anywhere in its hierarchy, an AttributeError occurs).

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

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

Finally, if the value is then changed in the Parent (for example, 当我们执行语句时 Parent.x = 3), that change is reflected also by any children that have not yet overridden the value (which in this case would be 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.)

Also, how would the answer differ in Python 3 (assuming, of course, that the above print 语句被转换为Python 3语法)?

查看答案

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

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

By default, Python 2 automatically performs integer arithmetic if both operands are integers. 因此, 5/2 yields 2, while 5./2 yields 2.5.

Note that you can override this behavior in Python 2 by adding the following 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.

正如人们所预料的那样,试图访问 a member of a list using an index that exceeds the number of members (e.g.,试图访问 list[10] 在上面的列表中)的结果为 IndexError. However,试图访问 a slice of a list at a starting index that exceeds the number of members in the list will not 导致… IndexError 并且将简单地返回一个空列表.

What makes this a particularly nasty gotcha is that it can lead to bugs that are really hard to track down since no error is raised at runtime.

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个引用. With this understanding, we can better understand the rest of the output.

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

同样的, list[1].追加(20) 向第二个列表追加20. But again, since all 5 lists refer to the same list, the output is now: [[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个数的列表, use a single list comprehension to produce a new list that only contains those values that are:
(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]

The expression works by first taking the numbers that are at the even indices, 然后过滤掉所有的奇数.

8.

给定字典的以下子类:

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

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

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

Actually, the code shown will work with the standard dictionary object in python 2 or 3—that is normal behavior. 子类化dict是不必要的. 但是,这个子类仍然不能与所示的代码一起工作,因为 __missing__ 返回一个值,但不改变字典本身:

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

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

这是一个 __missing__-based method that will update the dictionary, as well as return a value:

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

但是从版本2开始.5, a defaultdict object has been available in the collections module (in the standard library.)

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:
                打印(名称、线)
查看答案

A good answer would suggest a specific async mock library and async test case approach, 包括一个短暂的事件循环,保证终止(i.e. 超时前的最大步数.)

A great answer would point out that synchronisation problems are fundamentally the same in synchronous and asynchronous code, 区别在于抢占粒度.

A beautiful answer would take into account that the above code only has one flow (easy) compared to some other code where flows are mixed (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
                打印(名称、线)

Here, any of the async statements could have a side-effect of changing the global keep_running.

10.

如何列出模块中的功能?

查看答案

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

例如:

进口some_module
打印dir (some_module)
11.

Write a function that prints the least integer that is not present in a given list and cannot be represented by the summation of the sub-elements of the list.

E.g. For a = [1,2,5,7] the least integer not represented by the list or a slice of the list is 4, and if 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. He's been a part of the back-end team at Indico Data Solutions—a machine learning API and tools provider—developing back-end services handling big data processing and analysis. Chris在AWS、GCE和Azure云方面也有出色的技能.

显示更多

汉娜Herbig

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

Hannah is a self-taught software engineer who has been writing code for over ten years. 她的大部分经验都是在Python上, 包括FastAPI和Flask, 但她也有使用Ruby的经验, c++ + Qt, 和JavaScript, 包括节点.js、Vue、jQuery和Socket.IO. Hannah has worked on back-end APIs as well as graphical user interfaces (GUIs) in each of these.

显示更多

马克西米利安霍普夫

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

Max is a data science and machine learning expert specializing in deep learning and natural language processing. 他是金融和医疗保健领域的专家. He helped build one of Germany's most highly funded fintechs and successfully founded his own AI company in London. Max also built and led the data team of Garner Health for one of the most successful US healthtech companies, scaling the team from one to 25 people and more than $100 million in annual revenue.

显示更多

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

加入Toptal社区.

了解更多