Python总结面试题
- 一、50 道重要的 Python 面试题问答题 编程题】
-
- 1. 说说你用过Python标准库中的模块是什么?
- 2. `init__`和`__new`方法有什么区别?
- 3. 静态代码分析在正常工作中使用什么工具。
- 4. 函数参数`arg`和`*kwargs`分别代表什么?
- 5. 鸭子的类型是什么?(duck typing)?
- 6. 说一下Python中变量的作用域。
- 8. 说一下Python 2和Python 3的区别。
- 9. 解释线程池的工作原理。
- 10. 例子说明什么情况会发生`KeyError`、`TypeError`、`ValueError`。
- 11. 说一下你对Python中模块和包的理解。
- 12. 说说你知道的Python编码规范。
- 13. 说说Python浅拷贝和深拷贝。
- 14. 正则表达式的match方法和search方法有什么区别?
- 15. Python为什么没有函数重载?
- 16. 在Python如何实现单例模式?
- 17. 交换两个变量而不使用中间变量`a`和`b`的值。
- 18. 以下代码的执行结果是什么。
- 19. 用Python代码实现Python内置函数max。
- 20. 有三种货币:2元、3元和5元。如果你需要找零99元,有多少种方法可以找到零?
- 21. 编写函数统计传入列表中每个数字的次数,并返回相应的字典。
- 22. 使用Python通过文件夹实现代码操作。
- 22. 写一个函数,给定矩阵的阶数`n`,输出螺旋数字矩阵。
- 23. 阅读下面的代码,写下程序的操作结果。
- 24. 输入年月日,判断这个日期是今年的第几天。
- 25. 写一个装饰器,记录函数执行时间。
- 25. 说一下Python多线程和多过程的应用场景和优缺点。
- 26. 阅读下面的代码说出运行结果。
- 27. 编写函数以实现对逆波兰的表达式求值,不能使用Python内置函数。
- 28. Python如何实现字符串替换操作?
- 29. 如何剖析Python代码执行性能?
- 30. 如何使用`random`模块生成随机数,实现随机乱序和抽样?
- 31. 例子说明什么情况会发生`KeyError`、`TypeError`、`ValueError`。
- 32. 说说下面代码的操作结果。
- 33. 例如,如何读取大文件只有4个内存G,如何读一个大小8G的文件?
- 34. 操作下面的代码是否会报错,如果报错,请说明哪里有错误,如果不报错,请说明代码的执行结果。
- 35. 从大到小对键排序下面给出的字典按值。
- 36. 说一下`namedtuple`用法和作用。
- 37. 根据主题要求写出相应的函数。
- 38. 根据主题要求写出相应的函数。
- 39. 根据题目要求写相应的装饰器。
- 40. 写一个函数来实现字符串的反转,尽可能多地写下你知道的所有方法。
- 结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结结结结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结结结结结结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结结结结结结结结结结结结结结结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结尾结结
?大家好,我是编程师ID ??个人主页:编程ID的csdn博客 系列专栏:Python ??推荐编程刷题神器,点击跳转进入网站
一、50 道重要的 Python 面试题【问答题 编程题】
1. 说说你用过Python标准库中的模块是什么?
:Python标准数据库中有许多模块。建议您根据您过去的项目经验介绍您使用的标准数据库和三方数据库,因为这些是您最熟悉的,官的深入挖掘。
2. init__
和__new
方法有什么区别?
Python中调用结构器创建对象属于两阶段结构过程,首先执行__new__该方法获得保存对象所需的内存空间,然后通过__init__填写内存空间数据(对象属性的初始化)。__new__创建了方法的返回值Python对象(引用),而__init__该方法的第一个参数是该对象(引用),因此在__init__对象的初始化操作可以在中间完成。__new__它的第一个参数是类,__init__它的第一个参数是对象法。
3. 静态代码分析在正常工作中使用什么工具。
:静态代码分析工具可以从代码中提取各种静态属性,使开发者能够更好地理解代码的复杂性、可维护性和可读性。这里提到的静态属性包括: 如:PEP-8。 代码中的潜在问题包括语法错误、缩进、导入缺失、变量覆盖等。 代码中的坏味道。 代码的复杂性。 代码的逻辑问题。
静态代码分析主要用于工作Pylint和Flake8。Pylint更新版本还提供了代码复杂性统计数据,可以检查代码错误、味道不好、代码不规范等问题,可以生成检查报告。Flake8封装了Pyflakes(检查代码逻辑错误),McCabe(检查代码复杂性)和Pycodestyle(检查代码是否符合要求PEP-8规范)工具,可进行三种工具提供的检查。
4. 函数参数arg
和*kwargs
分别代表什么?
Python函数参数分为位置参数、可变参数、关键字参数和命名关键字参数。args代表可变参数,可接收0个或任何多个参数。当不确定调用器将传输多少位置参数时,可使用可变参数,并将传输参数包装成一个元组。**kwargs可以接收代表关键字参数的参数名称=以参数值的方式输入的参数将被包装成字典。定义函数时,如果同时使用args和**kwargs,然后函数可以接收任何参数。
5. 鸭子的类型是什么?(duck typing)?
鸭子类型是判断一个对象是否是某种类型时使用的动态语言的一种方法,也称为鸭子判断法。简单地说,鸭子类型是指判断一只鸟是否是鸭子。我们只关心它是否像鸭子一样游泳,它是否像鸭子一样吠叫,它是否像鸭子一样行走。换句话说,如果对象的行为与我们的预期一致(我们可以接受一些信息),我们将确定它是某种类型的对象。
在Python有很多语言bytes-like对象(如:bytes、bytearray、array.array、memoryview)、file-like对象(如:StringIO、BytesIO、GzipFile、socket)、path-like对象(如:str、bytes),其中file-like对象可以支持read和write操作,可以像文件一样读写,即所谓对象有鸭子的行为可以判断为鸭子的判断方法。再比如Python中列表的extend方法,它所需的参数不一定是列表,只要是可迭代的对象。
注:动态语言的鸭型大大简化了设计模式的应用。
6. 说一下Python中变量的作用域。
Python局部作用域有四个作用域(Local)、嵌套作用域(Embedded)、全局作用域(Global)、内置作用域(Built-in),搜索标识符时,会遵循LEGB搜索的顺序,如果所有的功能域都找不到这个标识符,就会导致NameError异常。
谈谈你对闭包的理解。 闭包是支持一流函数的编程语言(Python、JavaScript等)实现词法绑定的技术。当捕获封闭时,它的自由变量(定义在函数外但在函数内使用的变量)将在捕获时确定,这样即使它与捕获时的上下文分离,它也可以像往常一样运行。简单地说,闭包可以理解为能够读取其他函数内部变量的函数。在这种情况下,函数调用结束后,函数的局部变量结束了生命周期,但闭包延长了局部变量的生命周期使用闭包的时候需要注意,闭包会使得函数中创建的对象不会被垃圾回收,可能会导致很大的内存开销,所以闭包一定不能滥用。
题目29:说一下Python中的多线程和多进程的应用场景和优缺点。 线程是操作系统分配CPU的基本单位,进程是操作系统分配内存的基本单位。通常我们运行的程序会包含一个或多个进程,而每个进程中又包含一个或多个线程。多线程的优点在于多个线程可以共享进程的内存空间,所以进程间的通信非常容易实现;但是如果使用官方的CPython解释器,多线程受制于GIL(全局解释器锁),并不能利用CPU的多核特性,这是一个很大的问题。使用多进程可以充分利用CPU的多核特性,但是进程间通信相对比较麻烦,需要使用IPC机制(管道、套接字等)。
多线程适合那些会花费大量时间在I/O操作上,但没有太多并行计算需求且不需占用太多内存的I/O密集型应用。多进程适合执行计算密集型任务(如:视频编码解码、数据处理、科学计算等)、可以分解为多个并行子任务并能合并子任务执行结果的任务以及在内存使用方面没有任何限制且不强依赖于I/O操作的任务。
扩展:Python中实现并发编程通常有多线程、多进程和异步编程三种选择。异步编程实现了协作式并发,通过多个相互协作的子程序的用户态切换,实现对CPU的高效利用,这种方式也是非常适合I/O密集型应用的。
8. 说一下Python 2和Python 3的区别。
:这种问题千万不要背所谓的参考答案,说一些自己最熟悉的就足够了。
- Python 2中的print和exec都是关键字,在Python 3中变成了函数。
- Python 3中没有long类型,整数都是int类型。
- Python 2中的不等号<>在Python 3中被废弃,统一使用!=。
- Python 2中的xrange函数在Python 3中被range函数取代。
- Python 3对Python 2中不安全的input函数做出了改进,废弃了raw_input函数。
- Python 2中的file函数被Python 3中的open函数取代。
- Python 2中的/运算对于int类型是整除,在Python 3中要用//来做整除除法。
- Python 3中改进了Python 2捕获异常的代码,很明显Python 3的写法更合理。
- Python 3生成式中循环变量的作用域得到了更好的控制,不会影响到生成式之外的同名变量。
- Python 3中的round函数可以返回int或float类型,Python 2中的round函数返回float类型。
- Python 3的str类型是Unicode字符串,Python 2的str类型是字节串,相当于Python 3中的bytes。
- Python 3中的比较运算符必须比较同类对象。
- Python 3中定义类的都是新式类,Python 2中定义的类有新式类(显式继承自object的类)和旧式类(经典类)之分,新式类和旧式类在MRO问题上有非常显著的区别,新式类可以使用class__
属性获取自身类型,新式类可以使用
__slots魔法。 - Python 3对代码缩进的要求更加严格,如果混用空格和制表键会引发TabError。
- Python 3中字典的keys、values、items方法都不再返回list对象,而是返回view object,内置的map、filter等函数也不再返回list对象,而是返回迭代器对象。
- Python 3标准库中某些模块的名字跟Python 2是有区别的;而在三方库方面,有些三方库只支持Python 2,有些只能支持Python 3。
9. 解释一下线程池的工作原理。
:池化技术就是一种典型空间换时间的策略,我们使用的数据库连接池、线程池等都是池化技术的应用,Python标准库currrent.futures模块的ThreadPoolExecutor就是线程池的实现,如果要弄清楚它的工作原理,可以参考下面的内容。
线程池是一种用于减少线程本身创建和销毁造成的开销的技术,属于典型的空间换时间操作。如果应用程序需要频繁的将任务派发到线程中执行,线程池就是必选项,因为创建和释放线程涉及到大量的系统底层操作,开销较大,如果能够在应用程序工作期间,将创建和释放线程的操作变成预创建和借还操作,将大大减少底层开销。线程池在应用程序启动后,立即创建一定数量的线程,放入空闲队列中。这些线程最开始都处于阻塞状态,不会消耗CPU资源,但会占用少量的内存空间。当任务到来后,从队列中取出一个空闲线程,把任务派发到这个线程中运行,并将该线程标记为已占用。当线程池中所有的线程都被占用后,可以选择自动创建一定数量的新线程,用于处理更多的任务,也可以选择让任务排队等待直到有空闲的线程可用。在任务执行完毕后,线程并不退出结束,而是继续保持在池中等待下一次的任务。当系统比较空闲时,大部分线程长时间处于闲置状态时,线程池可以自动销毁一部分线程,回收系统资源。基于这种预创建技术,线程池将线程创建和销毁本身所带来的开销分摊到了各个具体的任务上,执行次数越多,每个任务所分担到的线程本身开销则越小。
一般线程池都必须具备下面几个组成部分:
- 线程池管理器:用于创建并管理线程池。
- 工作线程和线程队列:线程池中实际执行的线程以及保存这些线程的容器。
- 任务接口:将线程执行的任务抽象出来,形成任务接口,确保线程池与具体的任务无关。
- 任务队列:线程池中保存等待被执行的任务的容器。
10. 举例说明什么情况下会出现KeyError
、TypeError
、ValueError
。
举一个简单的例子,变量a是一个字典,执行int(a[‘x’])这个操作就有可能引发上述三种类型的异常。如果字典中没有键x,会引发KeyError;如果键x对应的值不是str、float、int、bool以及bytes-like类型,在调用int函数构造int类型的对象时,会引发TypeError;如果a[x]是一个字符串或者字节串,而对应的内容又无法处理成int时,将引发ValueError。
11. 说一下你对Python中模块和包的理解。
每个Python文件就是一个模块,而保存这些文件的文件夹就是一个包,但是这个作为Python包的文件夹必须要有一个名为__init__.py的文件,否则无法导入这个包。通常一个文件夹下还可以有子文件夹,这也就意味着一个包下还可以有子包,子包中的__init__.py并不是必须的。模块和包解决了Python中命名冲突的问题,不同的包下可以有同名的模块,不同的模块下可以有同名的变量、函数或类。在Python中可以使用import或from … import …来导入包和模块,在导入的时候还可以使用as关键字对包、模块、类、函数、变量等进行别名,从而彻底解决编程中尤其是多人协作团队开发时的命名冲突问题。
12. 说一下你知道的Python编码规范。
:企业的Python编码规范基本上是参照PEP-8或谷歌开源项目风格指南来制定的,后者还提到了可以使用Lint工具来检查代码的规范程度,面试的时候遇到这类问题,可以先说下这两个参照标准,然后挑重点说一下Python编码的注意事项。
使用空格来表示缩进而不要用制表符(Tab)。
和语法相关的每一层缩进都用4个空格来表示。
每行的字符数不要超过79个字符,如果表达式因太长而占据了多行,除了首行之外的其余各行都应该在正常的缩进宽度上再加上4个空格。
函数和类的定义,代码前后都要用两个空行进行分隔。
在同一个类中,各个方法之间应该用一个空行进行分隔。
二元运算符的左右两侧应该保留一个空格,而且只要一个空格就好。
变量、函数和属性应该使用小写字母来拼写,如果有多个单词就使用下划线进行连接。
类中受保护的实例属性,应该以一个下划线开头。
类中私有的实例属性,应该以两个下划线开头。
类和异常的命名,应该每个单词首字母大写。
模块级别的常量,应该采用全大写字母,如果有多个单词就用下划线进行连接。
类的实例方法,应该把第一个参数命名为self以表示对象自身。
类的类方法,应该把第一个参数命名为cls以表示该类自身。
采用内联形式的否定词,而不要把否定词放在整个表达式的前面。例如:if a is not b就比if not a is b更容易让人理解。
不要用检查长度的方式来判断字符串、列表等是否为None或者没有元素,应该用if not x这样的写法来检查它。
就算if分支、for循环、except异常捕获等中只有一行代码,也不要将代码和if、for、except等写在一起,分开写才会让代码更清晰。
import语句总是放在文件开头的地方。
引入模块的时候,from math import sqrt比import math更好。
如果有多个import语句,应该将其分为三部分,从上到下分别是Python标准模块、第三方模块和自定义模块,每个部分内部应该按照模块名称的字母表顺序来排列。
13. 说说Python中的浅拷贝和深拷贝。
思路:这个题目本身出现的频率非常高,但是就题论题而言没有什么技术含量。对于这种面试题,在回答的时候一定要让你的答案能够超出面试官的预期,这样才能获得更好的印象分。所以回答这个题目的要点不仅仅是能够说出浅拷贝和深拷贝的区别,深拷贝的时候可能遇到的两大问题,还要说出Python标准库对浅拷贝和深拷贝的支持,然后可以说说列表、字典如何实现拷贝操作以及如何通过序列化和反序列的方式实现深拷贝,最后还可以提到设计模式中的原型模式以及它在项目中的应用。
通常只复制对象本身,而不仅会复制对象,还会递归的复制对象所关联的对象。深拷贝可能会遇到两个问题:一是一个对象如果直接或间接的引用了自身,会导致无休止的递归拷贝;二是深拷贝可能对原本设计为多个对象共享的数据也进行拷贝。Python通过copy模块中的copy和deepcopy函数来实现浅拷贝和深拷贝操作,其中deepcopy可以通过memo字典来保存已经拷贝过的对象,从而避免刚才所说的自引用递归问题;此外,可以通过copyreg模块的pickle函数来定制指定类型对象的拷贝行为。
deepcopy函数的本质其实就是对象的一次序列化和一次返回序列化,面试题中还考过用自定义函数实现对象的深拷贝操作,显然我们可以使用pickle模块的dumps和loads来做到,代码如下所示。
import pickle
my_deep_copy = lambda obj: pickle.loads(pickle.dumps(obj))
列表的切片操作[:]相当于实现了列表对象的浅拷贝,而字典的copy方法可以实现字典对象的浅拷贝。对象拷贝其实是更为快捷的创建对象的方式。在Python中,通过构造器创建对象属于两阶段构造,首先是分配内存空间,然后是初始化。在创建对象时,我们也可以基于“原型”对象来创建新对象,通过对原型对象的拷贝(复制内存)就完成了对象的创建和初始化,这种做法更加高效,这也就是设计模式中的原型模式。在Python中,我们可以通过元类的方式来实现原型模式,代码如下所示。
import copy
class PrototypeMeta(type):
"""实现原型模式的元类"""
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
# 为对象绑定clone方法来实现对象拷贝
cls.clone = lambda self, is_deep=True: \
copy.deepcopy(self) if is_deep else copy.copy(self)
class Person(metaclass=PrototypeMeta):
pass
p1 = Person()
p2 = p1.clone() # 深拷贝
p3 = p1.clone(is_deep=False) # 浅拷贝
14. 正则表达式的match方法和search方法有什么区别?
思路:正则表达式是字符串处理的重要工具,所以也是面试中经常考察的知识点。在Python中,使用正则表达式有两种方式,一种是直接调用re模块中的函数,传入正则表达式和需要处理的字符串;一种是先通过re模块的compile函数创建正则表达式对象,然后再通过对象调用方法并传入需要处理的字符串。如果一个正则表达式被频繁的使用,我们推荐用re.compile函数创建正则表达式对象,这样会减少频繁编译同一个正则表达式所造成的开销。
match方法是从字符串的起始位置进行正则表达式匹配,返回Match对象或None。search方法会扫描整个字符串来找寻匹配的模式,同样也是返回Match对象或None。
15. Python中为什么没有函数重载?
:C++、Java、C#等诸多编程语言都支持函数重载,所谓函数重载指的是在同一个作用域中有多个同名函数,它们拥有不同的参数列表(参数个数不同或参数类型不同或二者皆不同),可以相互区分。重载也是一种多态性,因为通常是在编译时通过参数的个数和类型来确定到底调用哪个重载函数,所以也被称为编译时多态性或者叫前绑定。这个问题的潜台词其实是问面试者是否有其他编程语言的经验,是否理解Python是动态类型语言,是否知道Python中函数的可变参数、关键字参数这些概念。
首先Python是解释型语言,函数重载现象通常出现在编译型语言中。其次Python是动态类型语言,函数的参数没有类型约束,也就无法根据参数类型来区分重载。再者Python中函数的参数可以有默认值,可以使用可变参数和关键字参数,因此即便没有函数重载,也要可以让一个函数根据调用者传入的参数产生不同的行为。
✅作者简介:大家好我是编程ID 📃个人主页:编程ID的csdn博客 系列专栏:Python 💬推荐一款编程题刷题神器👉点击跳转进入网站
16. 在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
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
17. 不使用中间变量,交换两个变量a
和b
的值。
思路:典型的送人头的题目,通常交换两个变量需要借助一个中间变量,如果不允许使用中间变量,在其他编程语言中可以使用异或运算的方式来实现交换两个变量的值,但是Python中有更为简单明了的做法。
a = a ^ b
b = a ^ b
a = a ^ b
a, b = b, a
18. 下面这段代码的执行结果是什么。
def multiply():
return [lambda x: i * x for i in range(4)]
print([m(100) for m in multiply()])
运行结果:
[300, 300, 300, 300]
:上面代码的运行结果很容易被误判为[0, 100, 200, 300]。首先需要注意的是multiply函数用生成式语法返回了一个列表,列表中保存了4个Lambda函数,这4个Lambda函数会返回传入的参数乘以i的结果。需要注意的是这里有闭包(closure)现象,multiply函数中的局部变量i的生命周期被延展了,由于i最终的值是3,所以通过m(100)调列表中的Lambda函数时会返回300,而且4个调用都是如此。
如果想得到[0, 100, 200, 300]这个结果,可以按照下面几种方式来修改multiply函数。
:使用生成器,让函数获得i的当前值。
def multiply():
return (lambda x: i * x for i in range(4))
print([m(100) for m in multiply()])
或者
def multiply():
for i in range(4):
yield lambda x: x * i
print([m(100) for m in multiply()])
:使用偏函数,彻底避开闭包。
from functools import partial
from operator import __mul__
def multiply():
return [partial(__mul__, i) for i in range(4)]
print([m(100) for m in multiply()])
19. 用Python代码实现Python内置函数max。
:这个题目看似简单,但实际上还是比较考察面试者的功底。因为Python内置的max函数既可以传入可迭代对象找出最大,又可以传入两个或多个参数找出最大;最为关键的是还可以通过命名关键字参数key来指定一个用于元素比较的函数,还可以通过default命名关键字参数来指定当可迭代对象为空时返回的默认值。
下面的代码仅供参考:
def my_max(*args, key=None, default=None):
""" 获取可迭代对象中最大的元素或两个及以上实参中最大的元素 :param args: 一个可迭代对象或多个元素 :param key: 提取用于元素比较的特征值的函数,默认为None :param default: 如果可迭代对象为空则返回该默认值,如果没有给默认值则引发ValueError异常 :return: 返回可迭代对象或多个元素中的最大元素 """
if len(args) == 1 and len(args[0]) == 0:
if default:
return default
else:
raise ValueError('max() arg is an empty sequence')
items = args[0] if len(args) == 1 else args
max_elem, max_value = items[0], items[0]
if key:
max_value = key(max_value)
for item in items:
value = item
if key:
value = key(item)
if value > max_value:
max_elem, max_value = item, value
return max_elem
20. 现有2元、3元、5元共三种面额的货币,如果需要找零99元,一共有多少种找零的方式?
:还有一个非常类似的题目:“一个小朋友走楼梯,一次可以走1个台阶、2个台阶或3个台阶,问走完10个台阶一共有多少种走法?”,这两个题目的思路是一样,如果用递归函数来写的话非常简单。
from functools import lru_cache
@lru_cache()
def change_money(total):
if total == 0:
return 1
if total < 0:
return 0
return change_money(total - 2) + change_money(total - 3) + \
change_money(total - 5)
21. 写一个函数统计传入的列表中每个数字出现的次数并返回对应的字典。
:送人头的题目,不解释。
def count_letters(items):
result = {
}
for item in items:
if isinstance(item, (int, float)):
result[item] = result.get(item, 0) + 1
return result
也可以直接使用Python标准库中collections模块的Counter类来解决这个问题,Counter是dict的子类,它会将传入的序列中的每个元素作为键,元素出现的次数作为值来构造字典。
from collections import Counter
def count_letters(items):
counter = Counter(items)
return {
key: value for key, value in counter.items() \
if isinstance(key, (int, float))}
22. 使用Python代码实现遍历一个文件夹的操作。
:基本也是送人头的题目,只要用过os模块就应该知道怎么做。
Python标准库os模块的walk函数提供了遍历一个文件夹的功能,它返回一个生成器。
import os
g = os.walk('/Users/Hao/Downloads/')
for path, dir_list, file_list in g:
for dir_name in dir_list:
print(os.path.join(path, dir_name))
for file_name in file_list:
print(os.path.join(path, file_name))
说明:os.path模块提供了很多进行路径操作的工具函数,在项目开发中也是经常会用到的。如果题目明确要求不能使用os.walk函数,那么可以使用os.listdir函数来获取指定目录下的文件和文件夹,然后再通过循环遍历用os.isdir函数判断哪些是文件夹,对于文件夹可以通过递归调用进行遍历,这样也可以实现遍历一个文件夹的操作。
22. 写一个函数,给定矩阵的阶数n
,输出一个螺旋式数字矩阵。
例如:n = 2, 返回:1 2 4 3 例如:n = 3, 返回:1 2 3 8 9 4 7 6 5 这个题目本身并不复杂,下面的代码仅供参考。
def show_spiral_matrix(n):
matrix = [[0] * n for _ in range(n)]
row, col = 0, 0
num, direction = 1, 0
while num <= n ** 2:
if matrix[row][col] == 0:
matrix[row][col] = num
num += 1
if direction == 0:
if col < n - 1 and matrix[row][col + 1] == 0:
col += 1
else:
direction += 1
elif direction == 1:
if row < n - 1 and matrix[row + 1][col] == 0:
row += 1
else:
direction += 1
elif direction == 2:
if col > 0 and matrix[row][col - 1] == 0:
col -= 1
else:
direction += 1
else:
if row > 0 and matrix[row - 1][col] == 0:
row -= 1
else:
direction += 1
direction %= 4
for x in matrix:
for y in x:
print(y, end='\t')
print()
23. 阅读下面的代码,写出程序的运行结果。
items = [1, 2, 3, 4] print([i for i in items if i > 2]) print([i for i in items if i % 2]) print([(x, y) for x, y in zip('abcd', (1, 2, 3 标签:
02重载连接器he