来源商业新知,原文标题:如何在一场面试中展现你对Python的coding能力?
如果你已经通过了招聘人员的电话面试,那么下面正是该展现你代码能力的时候了。无论是练习,作业,还是现场白板面试,这都是你证明自己的代码技巧的时刻。
我们知道面试官常常会出一些题让你来解决,作为一名程序员,除了需要具备解决问题的思路以外,代码的质量和简洁性也很关键。因为从一个人的代码可以直接看出你的基本功。对于Python而言,这就意味着你需要对Python的内置功能和库有很深入的了解。
本篇给大家介绍一些很强大的功能,它们能让面试官眼前一亮,觉得你很高级,这可以很大程度上给你加分。对于这些功能, 我们从Python内置函数开始,然后是Python对数据结构的天然支持,最后是Python强大的标准库。
选择正确的内置功能
Python有一个大型标准库,但只有一个内置函数的小型库,这些函数总是可用的,不需要导入。它们每一个都值得我们仔细研究,但是在研究前,我还是给大家一些小的提示,尤其是在其中一些函数的情况下,可以用什么替代更好。
1. 使用enumerate()而不是range()进行迭代
在面试中,这种情况可能比任何其他情况都要多:您有一个元素列表,您需要遍历列表,同时访问索引和值。
有一个名为FizzBuzz的经典编码面试问题可以通过迭代索引和值来解决。在FizzBuzz中,你将获得一个整数列表,任务是执行以下操作:
-
用“fizz”替换所有可被3整除的整数
-
用“buzz”替换所有可被5整除的整数
-
将所有可被3和5整除的整数替换为“fizzbuzz”
通常,开发人员将使用range()解决此问题:
>>> numbers = [45, 22, 14, 65, 97, 72]
>>> for i in range(len(numbers)):... if numbers[i] % 3 == 0 and numbers[i] % 5 == 0:... numbers[i] = 'fizzbuzz'... elif numbers[i] % 3 == 0:... numbers[i] = 'fizz'... elif numbers[i] % 5 == 0:... numbers[i] = 'buzz'...>>> numbers['fizzbuzz', 22, 14, 'buzz', 97, 'fizz']
Range允许你通过索引访问数字元素,并且对于某些特殊情况也是一个很有用的工具。但在这种情况下,我们希望同时获取每个元素的索引和值,更优雅的解决方案使用enumerate():
>>> numbers = [45, 22, 14, 65, 97, 72]
>>> for i, num in enumerate(numbers):... if num % 3 == 0 and num % 5 == 0:... numbers[i] = 'fizzbuzz'... elif num % 3 == 0:... numbers[i] = 'fizz'... elif num % 5 == 0:... numbers[i] = 'buzz'...>>> numbers['fizzbuzz', 22, 14, 'buzz', 97, 'fizz']
对于每个元素,enumerate()返回一个计数器和元素值。计数器默认为0,也是元素的索引。 不想在0开始你的计数?只需使用可选的start参数来设置偏移量:
>>> numbers = [45, 22, 14, 65, 97, 72]
>>> for i, num in enumerate(numbers, start=52):... print(i, num)...52 4553 2254 1455 6556 9757 72
通过使用start参数,我们访问所有相同的元素,从第一个索引开始,但现在我们的计数从指定的整数值开始。
2. 使用递推式构造列表而不是map()和filter()
“我认为删除filter()和map()是非常有争议的。”
- Guido van Rossum,Python的创造者
一般使用者可能错误地认为它没有争议,但Guido有充分的理由想要从Python中删除map()和filter()。一个原因是Python支持递推式构造列表,它通常更容易阅读并支持与map()和filter()相同的功能。
让我们首先看看我们如何构造对map()的调用以及等效的递推构造列表:
>>> numbers = [4, 2, 1, 6, 9, 7]
>>> def square(x):... return x*x...>>> list(map(square, numbers))[16, 4, 1, 36, 81, 49]>>> [square(x) for x in numbers][16, 4, 1, 36, 81, 49]
使用map()和列表推导的两种方法都返回相同的值,但列表推导更容易阅读和理解。下面我们可以对filter()及其等效的列表推导做同样的事情:
>>> def is_odd(x):
... return bool(x % 2)...>>> list(filter(is_odd, numbers))[1, 9, 7]>>> [x for x in numbers if is_odd(x)][1, 9, 7]
就像我们在map中看到的那样,filter和列表推导方法返回相同的值,但列表推导更容易理解。
来自其他语言的开发人员可能不同意构造列表比map和filter更容易阅读,但根据我的经验,初学者能够更直观地写出列表推导。但无论哪种方式,在编码面试中使用列表推导很少会出错,因为它会让你知道Python中最常见的是什么。
3. 使用断点breakpoint()调试而不是print()
你可能通过在代码中添加print并查看打印出的内容来调试一个小问题。这种方法起初效果很好,但很快变得很麻烦。另外,在编码面试设置中,你几乎不希望在整个代码中调用print()。
相反,你应该使用调试器。对于不是很琐碎的错误,它几乎总是比使用print()更快,并且鉴于调试是编写软件的重要部分,它表明你知道如何使用可以在工作中快速开发的工具。
如果你使用的是Python 3.7,则无需导入任何内容,只需在代码中要放入调试器的位置调用breakpoint():
# Some complicated code with bugs
breakpoint()
调用breakpoint()会将你带入pdb,这是默认的Python调试器。在Python 3.6及更早版本中,你可以通过显式导入pdb来执行相同的操作:
import pdb; pdb.set_trace()
像breakpoint()一样,pdb.set_trace()会将你带入pdb调试器。它不是那么简洁,而且需要记住的多一点。你可能想要尝试其他调试器,但pdb是标准库的一部分,因此它始终可用。无论你喜欢哪种调试器,在进行编码面试设置之前,都值得尝试使用它们来适应工作流程。
4. 使用f-Strings格式化字符串
Python有很多不同的方法来处理字符串格式化,有时候不知道使用哪个。在coding的面试中,如果使用Python 3.6+,建议的格式化方法是Python的f-strings。
f-strings支持使用字符串格式化迷你语言,以及强大的字符串插值。这些功能允许你添加变量甚至有效的Python表达式,并在添加到字符串之前在运行时对它们进行评估:
>>> def get_name_and_decades(name, age):
... return f"My name is {name} and I'm {age / 10:.5f} decades old."...>>> get_name_and_decades("Maria", 31)My name is Maria and I'm 3.10000 decades old.
f-string允许你将Maria放入字符串中,并在一个简洁的操作中添加具有所需格式的年龄。需要注意的一个风险是,如果你输出用户生成的值,那么可能会带来安全风险,在这种情况下,模板字符串可能是更安全的选择。
5. 使用sorted()对复杂列表进行排序
大量的编码面试问题需要进行某种排序,并且有多种有效的方法可以进行排序。除非面试官希望你实现自己的排序算法,否则通常最好使用sorted()。你可能已经看到了排序的最简单用法,例如按升序或降序排序数字或字符串列表:
>>> sorted([6,5,3,7,2,4,1])
[1, 2, 3, 4, 5, 6, 7]>>> sorted(['cat', 'dog', 'cheetah', 'rhino', 'bear'], reverse=True)['rhino', 'dog', 'cheetah', 'cat', 'bear]
默认情况下,sorted()已按升序对输入进行排序,而reverse关键字参数则按降序排序。
值得了解的是可选关键字key,它允许你在排序之前指定将在每个元素上调用的函数。添加函数允许自定义排序规则,如果要对更复杂的数据类型进行排序,这些规则特别有用:
>>> animals = [
... {'type': 'penguin', 'name': 'Stephanie', 'age': 8},... {'type': 'elephant', 'name': 'Devon', 'age': 3},... {'type': 'puma', 'name':