Python练习题:为下一次面试做好准备

2020-09-22 02:56:04

您是Python开发人员吗?在面试前温习您的技能吗?如果是这样的话,本教程将引导您完成一系列旨在模拟常见编码测试场景的Python实践问题。在您开发了自己的解决方案之后,您将浏览Real Python团队的答案,这样您就可以优化您的代码,给您的面试官留下深刻印象,并获得您梦想的工作!

本教程面向中级Python开发人员。它假定具备Python的基本知识和解决Python问题的能力。通过单击下面的链接,您可以获得针对本教程中将看到的每个问题的单元测试失败的框架代码:

下载示例代码:单击此处获取您将用来解决本教程中的Python练习问题的代码。

下面的每个问题都显示了此框架代码中描述问题需求的文件头。因此,下载代码,启动您最喜欢的编辑器,让我们深入研究一些Python实践问题!

让我们从一个热身问题开始。在第一个练习题中,您将编写代码对整数列表求和。每个练习问题都包括一个问题描述。此描述直接从存储库中的框架文件中提取,以便您在处理解决方案时更容易记住。

您还将看到每个问题的解决方案部分。大部分讨论将在下面的折叠部分进行。如果您尚未复制该存储库,请针对以下问题制定解决方案,然后展开解决方案框以检查您的工作。

#Integrgersums.py";";";最多n的整数总和编写一个函数add_it_up(),该函数接受单个整数作为输入,并将从零到输入参数的整数总和返回给输入参数。如果传入非整数,则函数应返回0。";";";

注意:请记住,在您准备好查看此Python练习问题的答案之前,不要打开下面折叠的部分!

对于这个问题,您将看到几种不同的解决方案。第一个不太好:

#Integrgersums.py def first(N):num=1sum=0而num<;n+1:sum=sum+num num=num+1返回和。

在这个解决方案中,您将手动构建一个While循环来遍历数字1到n。您保留一个运行和,然后在完成循环后返回它。

它不会显示您对Python的了解,也不会显示该语言如何简化这样的任务。

它不符合问题描述中的错误条件。传入字符串将导致函数抛出异常,而它应该只返回0。

您将在下面的最终答案中处理错误条件,但首先让我们改进核心解决方案,使其更具Python风格。

首先要考虑的是While循环。Python具有强大的遍历列表和范围的机制。创建您自己的通常是不必要的,这里肯定就是这种情况。您可以将WHILE循环替换为在范围()上迭代的循环:

#Integrgersums.py def Better(N):Num in Range(n+1)的sum=0:sum+=num return sum

您可以看到,for...range()构造已经替换了While循环并缩短了代码。需要注意的一件事是,range()直到但不包括给定的数字,因此您需要在这里使用n+1。

这是很好的一步!它删除了在范围内循环的一些样板代码,使您的意图更加清晰。但你在这里还能做更多的事。

哇!。通过使用内置sum(),您只需一行代码!虽然代码高尔夫通常不会生成可读性最好的代码,但在这种情况下,您可以获得双赢:代码更短、可读性更强。

然而,还有一个问题仍然存在。此代码仍然不能正确处理错误条件。要解决这个问题,您可以将前面的代码包装在try...Except块中:

#Integrgersums.py def add_it_up(N):try:result=sum(range(n+1))Expect TypeError:Result=0返回结果。

有时,面试官会问这个有固定限制的问题,比如“打印前九个整数的总和。”当问题以这种方式表述时,一个正确的解决方案将是打印(45)。

但是,如果您给出了这个答案,那么您应该使用能够逐步解决问题的代码进行后续工作。诡计答案是开始回答的好地方,但不是结束的好地方。

如果您想扩展这个问题,请尝试向add_it_up()添加一个可选的下限,以使其更灵活!

下一个问题由两部分组成。您将编写一个函数来计算文本输入上的凯撒密码。对于这个问题,您可以自由使用Python标准库的任何部分来执行转换。

提示:字符串库中有一个函数可以使这项任务变得更容易!

#caesar.py";";";凯撒密码凯撒密码是一种简单的替换密码,在该密码中,明文的每个字母都被一个通过向下移动字母表n位找到的字母替换。例如,假设输入的纯文本如下:zucd xyz如果移位值n为4,则加密文本将如下所示:EFGH BCD您要编写一个函数,该函数接受两个参数、一个纯文本消息和要在密码中进行移位的字母数。该函数将返回一个加密字符串,其中所有字母都已转换,所有标点符号和空格保持不变。注意:您可以假设纯文本除了空格和标点符号之外都是小写的ASCII。";";";

请记住,这部分问题实际上是关于您在标准库中能做得多好。如果您发现自己正在计算如何在没有库的情况下进行转换,那么就省省吧!你以后会用到的!

注意:请记住,在您准备好查看此Python练习问题的答案之前,不要打开下面折叠的部分!

此解决方案使用标准库中字符串模块中的.late()。如果您在这个问题上苦苦挣扎,那么您可能需要暂停片刻,并考虑如何在解决方案中使用.late()。

1#caesar.py 2导入字符串3 4 def Caesar(PLAN_TEXT,SHIFT_NUM=1):5个字母=字符串。ASCII_LOWERCASE 6掩码=字母[Shift_Num:]+字母[:Shift_Num]7 trantab=str。Maketrans(字母,掩码)8返回纯文本。翻译(Trantab)。

您可以看到,该函数使用了字符串模块中的三项内容:

在前两行中,您使用字母表的所有小写字母创建一个变量(此程序仅使用ASCII),然后创建一个掩码,它是相同的一组字母,只是移位了。切片语法并不总是显而易见的,所以让我们通过一个真实的示例来介绍一下:

您可以看到x[3:]是第三个字母之后的所有字母,而x[:3]只是前三个字母。

解决方案中的第6行,Letters[Shift_Num:]+Letters[:Shift_Num]创建了一个由Shift_Num字母移位的字母列表,末尾的字母环绕到前面。一旦有了要映射到的字母列表和字母掩码,就可以调用.maketrans()来创建转换表。

接下来,将转换表传递给字符串方法.late()。它将字母中的所有字符映射到掩码中的相应字母,而保留所有其他字符。

这个问题是了解和使用标准库的练习。在面试过程中的某个时候,你可能会被问到这样的问题。如果这种情况发生在你身上,花点时间思考可能的答案是很好的。如果您还记得这个方法--本例中的.Translate()--那么您就一切都准备好了。

你完全可以一片空白。在这种情况下,您可能会用解决下一个问题的方法来解决这个问题,这是一个可以接受的答案。

您可能还记得标准库有一个函数可以做您想做的事情,但是不记得细节。

如果你正在做正常的工作,遇到了这两种情况中的任何一种,那么你只需要做一些搜索,然后就可以上路了。但是在面试的情况下,大声说出问题会对你的事业有帮助。

向面试官寻求具体的帮助要比直接忽视要好得多。尝试类似于“我认为有一个函数可以将一组字符映射到另一组字符。你能帮我记住它叫什么吗?“。

在面试中,承认自己不知道往往比虚张声势要好。

现在您已经看到了使用Python标准库的解决方案,让我们再次尝试同样的问题,但是没有帮助!

对于第三个练习题,您将再次解出Caesar密码,但这一次您将不使用.late()。

此问题的描述与上一个问题相同。在深入研究解决方案之前,您可能想知道为什么在没有.late()的帮助下要重复相同的练习。

这是个很好的问题。在正常生活中,当您的目标是获得一个工作的、可维护的程序时,重写标准库的部分内容不是一个好的选择。Python标准库中充斥着针对大大小小问题的有效、经过良好测试的快速解决方案。充分利用它是优秀程序员的标志。

也就是说,这不是一个工作项目,也不是你为了满足需求而建立的计划。这是一个学习练习,也是面试中可能会问到的问题。两者的目标都是看看如何解决问题,以及在这样做的同时进行哪些有趣的设计权衡。

因此,本着学习的精神,让我们尝试在不使用.late()的情况下解析凯撒密码。

对于这个问题,当您准备好展开下面的部分时,您将有两种不同的解决方案可供查看。

注意:请记住,在您准备好查看此Python练习问题的答案之前,不要打开下面折叠的部分!

针对这一问题,提出了两种不同的解决方案。两个都检查一下,看看你更喜欢哪一个!

对于第一个解决方案,您需要紧跟问题描述,向每个字符添加金额,并在超出z时将其翻回到字母表的开头:

1#caesar.py 2导入字符串3 4 def Shift_n(字母,金额):如果字母不在字符串中,则为5。ASCII_LOWERCASE:6返回字母7 NEW_Letter=order(Letter)+金额8 WHILE NEW_Letter&>order(";z";):9 NEW_Letter-=26 10 WHILE NEW_Letter<;Order(";a";):11 new_Letter+=26 12 Return chr(New_Letter)13 14 def Caesar(消息,金额):15 enc_list=[消息中的字母的Shift_n(字母,金额)]16 return";";。JOIN(Enc_List)。

从第14行开始,您可以看到Caesar()执行列表理解,为message中的每个字母调用一个助手函数。然后,它执行.join()来创建新的编码字符串。这很简短,您将在第二个解决方案中看到类似的结构。有趣的部分发生在Shift_n()中。

在这里,您可以看到string.asciilowercase的另一个用法,这一次会过滤掉不在该组中的任何字母。一旦您确定已经过滤掉了任何非字母,您就可以继续编码了。在此版本的编码中,您将使用Python标准库中的两个函数:

同样,我们鼓励你不仅要学习这些功能,而且要考虑如果你记不起他们的名字,你在面试时会如何应对。

Ord()执行将字母转换为数字的工作,而chr()将其转换回字母。这很方便,因为它允许您对字母进行算术运算,这正是您想要解决此问题的原因。

第7行编码的第一步是使用order()获取原始字母的数值,从而获得编码字母的数值。Ord()返回字符的Unicode代码点,结果是ASCII值。

对于许多具有小移位值的字母,您可以将字母转换回字符,这样就完成了。但考虑一下开头的字母z。

一个字符的移动应该会产生字母a。要实现这个环回,您可以找到从编码的字母到字母z的差异。如果该差异是正数,那么您需要返回到开头。

在第8行到第11行中,通过向字符重复加26或从字符中减去它,直到它在ASCII字符范围内,就可以做到这一点。请注意,这是解决此问题的一种相当低效的方法。您将在下一个答案中看到更好的解决方案。

最后,在第12行,转换移位函数获取新字母的数字值,并将其转换回字母以返回它。

虽然此解决方案采用字面上的方法来解决Caesar密码问题,但是您也可以在实际问题2中使用另一种模仿.late()解决方案的方法。

此问题的第二个解决方案模仿了Python的内置方法.Translate()的行为。它不是将每个字母移动给定的量,而是创建一个转换映射并使用它对每个字母进行编码:

1#caesar.py 2导入字符串3 4 def Shift_n(字母,表):5尝试:6索引=字符串。ASCII_小写。Index(Letter)7返回表[index]8除ValueError:9 Return Letter 10 11 def Caesar(Message,Amount):12 Amount=Amount%26 13 TABLE=STRING。ASCII_LOWERCASE[金额:]+字符串。ASCII_LOWERCASE[:Amount]14 enc_list=[用于消息中的字母的Shift_n(Letter,TABLE)]15 RETURN";";。JOIN(Enc_List)。

从第11行的Caesar()开始,首先修复数量大于26的问题。在前面的解决方案中,您反复循环,直到结果在正确的范围内。在这里,您可以使用mod操作符(%)采取更直接、更有效的方法。

Mod运算符从整数除法中产生余数。在本例中,您将除以26,这意味着保证结果介于0和25之间(包括0和25)。

接下来,创建转换表。这与以前的解决方案有所不同,值得关注。您将在本节末尾看到有关这方面的更多信息。

创建表之后,Caesar()的其余部分与前面的解决方案相同:列表理解用于加密每个字母,.join()用于创建字符串。

Shift_n()在字母表中查找给定字母的索引,然后使用该索引从表中提取一个字母。Try...Except块捕获在小写字母列表中找不到的那些大小写。

现在让我们讨论一下表创建问题。对于这个玩具示例,它可能不太重要,但它说明了日常开发中经常出现的一种情况:平衡代码的清晰度和已知的性能瓶颈。

如果再次检查代码,您会发现表仅在Shift_n()中使用。这表明,在正常情况下,它应该是在Shift_n()中创建的,因此其范围被限制在Shift_n()中:

#caesar.py导入字符串def low_Shift_n(字母,金额):table=string。ASCII_LOWERCASE[金额:]+字符串。ASCII_LOWERCASE[:Amount]TRY:INDEX=STRING。ASCII_小写。Index(Letter)返回表[index]除ValueError:Return Letter def low_Caesar(Message,Amount):Amount=Amount%26 enc_list=[Message中Letter的Shift_n(Letter,Amount)]return";";。JOIN(Enc_List)。

这种方法的问题是,它会花费时间为消息的每个字母计算相同的表。对于较小的消息,此时间可以忽略不计,但对于较大的消息,此时间可能会累积起来。

避免这种性能损失的另一种可能方法是将TABLE设置为全局变量。虽然这也降低了建筑业的处罚,但使表格的范围更大了。这似乎并不比上面显示的方法更好。

归根结底,是预先创建表一次,还是给它一个更大的范围,还是只为每个字母创建表,这就是所谓的设计决定。您需要根据您对您试图解决的实际问题的了解来选择设计。

如果这是一个小项目,并且您知道它将用于对大消息进行编码,那么只创建表一次可能是正确的决定。如果这只是一个较大项目的一部分,这意味着可维护性是关键,那么也许每次都创建表是更好的选择。

既然您已经了解了两种解决方案,那么花点时间来讨论它们的异同是值得的。

你已经在凯撒密码的这一部分看到了两种解决方案,它们在很多方面都非常相似。它们的行数大致相同。这两个主要例程除了限量和创建表之外都是相同的。只有当您查看帮助器函数的两个版本Shift_n()时,才会发现不同之处。

第一个Shift_n()几乎是问题要求的直译:“将字母向下移动,并在z处换行。”这显然与问题陈述相对应,但它也有一些缺点。

虽然它与第二个版本的长度大致相同,但第一个版本的Shift_n()要复杂得多。这种复杂性来自于进行翻译所需的字母转换和数学运算。其中涉及的细节-转换为数字、减法和换行-掩盖了您正在执行的操作。第二个Shift_n()对其细节的涉及要少得多。

该函数的第一个版本也特定于解决此特定问题。Shift_n()的第二个版本,与标准库的.Translate()类似,它也是仿照它的,它更通用,可以用来解决更大的一组问题。请注意,这不一定是一个好的设计目标。

极限编程运动产生的口头禅之一是“你不会需要它的”(YAGNI)。通常,软件开发人员在查看Shift_n()这样的函数时会认为,如果他们使其更加灵活(可能是通过传递参数而不是使用string.ascii_lowercase),那么它会更好、更具通用性。

虽然这确实会使功能更具通用性,但也会使其更加复杂。YAGNI咒语是为了提醒你,在你没有一个具体的用例之前,不要增加复杂性。

总结一下您的Caesar密码节,这两个解决方案之间有明显的取舍,但是第二个Shift_n()看起来稍微更好一些,更像是Python函数。

既然您已经以三种不同的方式编写了凯撒密码,让我们转到一个新问题。

日志解析器问题是软件开发中经常出现的问题。许多系统在正常操作期间生成日志文件,有时您需要解析这些文件以查找运行系统的异常或一般信息。

对于此问题,您需要解析指定格式的日志文件并生成报告:

#logparse.py";";";日志解析器接受命令行上的文件名。该文件是来自您正在调试的系统的类似Linux的日志文件。在各种语句中混杂着指示设备状态的消息。它们如下所示:Jul1116:11:51:490[139681125603136]dut:device state:on the device state消息有许多可能的值,但此程序只关心三个值:ON、OFF和ERR。您的程序将解析给定的日志文件,并打印出一份报告,给出设备开机时间和任何错误情况的时间戳。";";";

请注意,提供的框架代码不包括uni。

.