20个Python面试题来挑战你的知识
在本文中,我将我的一些笔记变成了 20 个面试问题,涵盖了数据结构、核心编程概念和 Python 最佳实践。
希望你能完成其中的一些并重温你的 Python 技能。
事不宜迟,让我们直接进入。 1. 列表和元组有什么区别?你应该什么时候使用哪一个?
列表是可变数据结构,而元组是不可变数据结构。
Python 中的可变对象具有更改其值的能力。
列表是动态的:你可以向其中添加项目或覆盖和删除现有项目。
元组是固定大小的:它们没有方法 append 或 extend 方法。你也不能从中删除项目。
元组和列表都支持索引并允许使用 in 运算符检查其中的现有元素。
→ 在某些情况下,我认为元组可能有用。 如果你声明一个你知道永远不会更改的项目集合,或者你将只循环而不更改其值,请使用元组。 如果你寻找性能,元组比列表更快,因为它们是只读结构。如果你不需要写操作,请考虑使用元组。 如果你想防止意外写入不需要更改的数据,元组可以使你的代码更安全。
这是一个代码示例,显示了元组与列表的不同之处。 >>> numbers = [1, 2, 3, 4, 5] >>> numbers[1] = 100 >>> print(numbers) [1, 100, 3, 4, 5] >>> names = ("john", "joe", "alice") >>> names[0] = "bob") --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in ----> 1 names[0] = "bob" TypeError: "tuple" object does not support item assignment2 — 多处理和多线程有什么区别?你应该什么时候使用哪个?
多处理和多线程是旨在加快代码速度的编程范例。
当你使用多处理时,你可以在进程上并行计算。进程是独立的,不相互通信:它们不共享相同的内存区域,并且相互之间有严格的隔离。在应用方面,多处理适用于 CPU 密集型工作负载。但是,它确实具有与进程数量成正比的大量内存占用。
另一方面,在多线程应用程序中,线程存在于单个进程中。因此,它们共享相同的内存区域:它们可以修改相同的变量并且可以相互干扰。虽然进程是严格并行执行的,但在 Python 中的给定时间点只执行一个线程,这是由于全局解释器锁 ( GIL )。多线程适用于受 IO 限制的应用程序,例如网页抓取或从数据库中获取数据。
→ 如果你想了解有关多线程和多处理的更多信息,我建议你阅读我之前关于多进程跟线程的文章关于多线程你知道多少呢?,该文章全面介绍了这两个概念。 3 — 模块、包和库之间有什么区别?
模块只是一个 Python 文件,旨在导入脚本或其他模块。它包含函数、类和全局变量。
包是模块的集合,它们在文件夹中组合在一起以提供一致的功能。包可以像模块一样被导入。它们通常有一个 __init__.py 文件告诉 Python 解释器按原样处理它们。
库是包的集合。 4 — python 中的多线程有什么问题?
全局解释器锁(或 GIL)可防止 Python 解释器同时执行多个线程。简而言之,GIL 强制在 Python 中的任何时间点只执行一个线程。
这代表了依赖多线程代码的 CPU 密集型应用程序的一个很大的性能瓶颈。 5 — 什么是装饰器?你能描述一下装饰器值得使用的情况吗?
装饰器是一个接收函数作为输入并返回函数作为输出的函数。装饰器的目标是在不改变其核心机制的情况下扩展输入函数的行为。
使用装饰器还可以防止你重复自己。它迫使你编写一次通用代码,然后将其用于需要它的每个功能。
装饰器大放异彩的典型用例是 日志记录 。
例如,想象一下,你希望将传递给程序中调用的每个函数的所有参数值记录到终端。你可以遍历每个函数定义并将其写下来,或者你可以只编写一个装饰器来执行此日志记录任务并将其应用于所有需要它的函数。
将装饰器应用于函数只需在该函数的定义上方添加一行即可。 #没有装饰器 def my_awesome_function(): # 做一些很棒的事情 # 带有装饰器 @my_awesome_decorator def my_awesome_function(): # 做更棒的事情
下面是一个代码示例,它创建了一个名为的装饰器,该装饰器 log 记录了传递给函数的参数的值。 import logging logging.basicConfig( format="%(asctime)s [%(levelname)s] %(name)s - %(message)s", level=logging.INFO, datefmt="%Y-%m-%d %H:%M:%S", stream=sys.stdout, ) logger = logging.getLogger("notebook") def log(func): def wrapper(*args, **kwargs): output = func(*args, **kwargs) msg = f"{func.__name__} was run with the following args: {args} and the following kwargs {kwargs}" logger.info(msg) return output return wrapper @log def print_args(*args, **kwargs): print(args) print(kwargs) >>> print_args(10, a=2, b="test") (10,) {"a": 2, "b": "test"} 2022-03-06 18:07:05,248 - notebook - INFO - print_args was run with the following args: (10,) and the following kwargs {"a": 2, "b": "test"} >>> print_args(10, 100, a=2, b="test") (10, 100) {"a": 2, "b": "test"} 2022-03-06 18:07:05,562 - notebook - INFO - print_args was run with the following args: (10, 100) and the following kwargs {"a": 2, "b": "test"}
装饰器还可以用于其他目的,例如计时功能、验证输入数据、执行访问控制和身份验证、缓存等。 6 — 如何正确地将数据写入文件?否则会出什么问题?
使用上下文管理器是关键。
当你使用 open 没有上下文管理器的语句并且在关闭文件之前发生一些异常时(关闭文件是你在以这种方式打开文件时必须记住的事情)可能会发生内存问题并且文件可能会在此过程中损坏。
当你 with 用来打开一个文件并且发生异常时,Python 保证该文件是关闭的。 d = {"foo": 1} # bad practice f = open("./data.csv", "wb") f.write("some data") v = d["bar"] # KeyError # f.close() never executes which leads to memory issues f.close() # good practice with open("./data.csv", "wb") as f: f.write("some data") v = d["bar"] # python still executes f.close() even if the KeyError exception occurs7 — 函数参数是按引用传递还是按值传递?
在 Python 中,所有函数参数都是通过引用传递的:这意味着如果将参数传递给函数,则函数将获得对同一对象的引用。
如果对象是可变的并且函数改变了它,则参数将在函数的外部范围内发生变异。让我们看一个例子: >>> def append_number(numbers): numbers.append(5) >>> numbers = [1, 2, 3, 4] >>> print(f"before: {numbers}" [1, 2, 3, 4] >>> append_number(numbers) >>> numbers [1, 2, 3, 4, 5]8 — 如何覆盖对象的打印方式?
使用 the __str__ 和 __repr__ dunder 方法。
这是一个示例,它演示了 Person 类中的实例在打印到控制台时如何被很好地格式化。 class Person: def __init__(self, first_name, last_name, age): self.first_name = first_name self.last_name = last_name self.age = age def __str__(self): return f"{self.first_name} {self.last_name} ({self.age})" def __repr__(self): return f"{self.first_name} {self.last_name} ({self.age})" >>> person = Person("John", "Doe", 30) # thanks to __str__ John Doe (30) >>> person # thanks to __repr__ John Doe (30)9 — 编写一个计算整数 n 阶乘的函数
递归是关键 def factorial(n): if n == 0: return 1 else: return n * factorial(n-1)10 — is 和 == 运算符有什么区别?
== 是一个测试相等性的运算符,而 is 是一个测试身份的运算符。
两个对象可以具有相同的值,但不一定相同(即具有相同的内存地址)。
请记住,这 a is b 是 id(a) == id(b) . 11 — 什么时候不应该使用 assert 语句?
assert 语句对于内部测试和完整性检查很有用。
但是,它不应该用于执行数据验证或错误处理,因为出于性能原因,它通常在生产代码中被禁用。
想象一下,如果你使用断言检查管理员权限:这可能会在生产中引入很大的安全漏洞。
assert 你可以抛出自定义错误,而不是使用该语句。 # Dangerous code! def delete_product(user, product_id): assert user.is_admin() user.delete_product(product_id) # Handle this properly by raising an error def delete_product(user, product_id): if not user.is_admin(): raise AuthError("User must have admin privileges") else: user.delete_product(product_id)12 — 什么是 Python 生成器?
Python 生成器是一个生成一系列项目的函数。
生成器看起来像典型的函数,但它们的行为是不同的。对于初学者,不使用return语句,而是使用 yield 语句。
然后,调用生成器函数不会运行该函数:它只会创建一个生成器对象。生成器的代码仅在 next 函数应用于生成器对象或生成器被迭代时执行(在这种情况下, next 函数被隐式调用)
在生成器对象上调用函数的次数 next 等于 yield 在生成器函数中调用语句的次数。
你可以使用 for 循环或生成器表达式定义生成器。 >>> def repeat(n, message): for _ in range(n): yield message repeat_hello_five_times = repeat(5, hello) >>> for message in repeat_hello_five_times: print(message) "hello" "hello" "hello" "hello" "hello" >>> repeat_hello_five_time = ("hello" for _ in range(5)) >>> repeat_hello_five_times at 0x7fb64f2362d0> >>> for message in repeat_hello_five_times: print(message) "hello" "hello" "hello" "hello" "hello" 13 — 类方法和静态方法有什么区别?什么时候应该使用哪个?
静态方法是一种对调用它的类或实例有任何了解的方法。这是一种逻辑上属于该类但没有隐式参数的方法。
可以在类或其任何实例上调用静态方法。
类方法是传递给调用它的类的方法,就像 self 传递给类中的其他实例方法一样。 类方法的强制参数不是类实例:它实际上是类本身。
类方法的一个典型用例是提供另一种构造实例的方法:执行此操作的类方法称为 类的工厂 。
这是一个使用类方法的 Employee 类,该类方法创建实例的方式与类的主构造函数略有不同。 class Employee(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_nale @classmethod def from_string(cls, name_str): first_name, last_name = map(str, name_str.split(" ")) employee = cls(first_name, last_name) return employee ahmed = Employee.from_string("Ahmed Besbes")14 — 举一个例子说明你如何使用 zip 和枚举
该 zip 函数将多个迭代作为输入并将它们聚合到一个元组中。例如,如果你想同时遍历两个列表,这可能很有用。 >>> names = ["john", "bob", "alice"] >>> ages = [10, 16, 20] >>> for name, age in zip(names, ages): print(name, age) john 10 bob 16 alice 20
该 enumerate 函数允许循环遍历一个可迭代对象并同时访问正在运行的索引和项目。 >>> names = ["john", "bob", "alice"] >>> for index, name in enumerate(names): print(index, name) 0 john 1 bob 2 alice15 — 你会如何在给定的函数中使用 *args 和 **kwargs?
*args 和 **kwargs 通过接受可变数量的参数使 Python 函数更加灵活。 *args 在列表中传递可变数量的非关键字参数 **kwargs 在字典中传递可变数量的关键字参数
这是一个函数示例,该函数采用可变数量的关键字参数,这些参数收集在名为的字典中 data (请注意,它不需要命名 kwargs )
16 — 给出一个使用 map 的函数式编程示例>>> numbers = [1, 2, 3, 4, 5] >>> numbers_times_2 = list(map(lambda n: n * 2, numbers)) >>> numbers_times_2 [2, 4, 6, 8, 10]17 — continue 和 break 语句有什么区别
该 break 语句终止包含它的循环。程序立即移动到循环外部范围内的代码段。
另一方面,该 continue 语句跳过当前迭代的其余代码并移至下一个迭代。
18 - 如何防止函数被调用不必要的时间?
使用缓存。
如果与给定输入关联的输出在一段时间内没有变化,则使用缓存对函数有意义。
一个典型的场景是查询一个 web 服务器:如果你第一次查询一个 URL,并且你知道响应不会改变,你可以缓存结果。 from cachetools import cached, TTLCache cache = TTLCache(maxsize=100, ttl=86400) @cached(cache) def extract_article_content(url): response = requests.get(url) content = response.content return content19 — 给出一些 PEP8 指南每个缩进级别使用 4 个空格。 进口应按以下顺序分组: 标准库导入。 相关第三方进口。 本地应用程序/库特定的导入。 函数名和变量名应为小写并用下划线分隔 类名使用 CapWords 约定。 20 — 如何使用具有 2GB RAM 的计算机在 Python 中读取 8GB 文件?
此解决方案适用于任何大型(甚至更大)文件。
当你打开文件时,你需要做的就是将文件对象用作迭代器:在循环此文件对象时,你将一次获取一行,并且前面的行将从内存中清除(即它们是垃圾收集)。
这样,文件将永远不会完全加载到内存中。 with open("./large_dataset.txt") as input_file: for line in input_file: process_line(line)感谢阅读
这是我在面试中经常看到的一些问题的概述。我希望你从文章中学到了一些东西。20 个 Python 面试题来挑战你的知识
水庆霞发愁了!中国女足挑战西班牙,沈梦雨杨倩跃跃欲试!中国女足正在西班牙的马贝拉训练,而且在西班牙的训练期间会进行四场对抗赛,这第一场对抗赛即将打响,对手就是西班牙女足甲级联赛的职业球队皇家贝蒂斯女足,这场比赛也是一场焦点之战,毕竟球
中国女足球员老家被300人暴力强拆关车厢殴打吕童童(中)控诉老家被300人暴力强拆。来自吕童童微博中国山东女足球员吕童童,昨在微博控诉住家遭到300人强拆,报警后警察也不到场,对方还抢手机拆监视器试图避免留下证据,家人被强行
巴黎洗牌曝梅西决定重回巴萨,姆巴佩变老大,内马尔将遭孤立梅西的未来备受球迷关注,阿根廷球星和巴黎的合同在2023年夏天到期,如今看来,梅西未必续约。西班牙电视六台的嘉宾阿尔瓦雷斯透露,梅西渴望以巴萨球员的身份退役,因此,梅西肯定希望重返
VAR背刺静待周中决战最近一个月破厂可谓是诸事不顺,唯一欣慰的是曼城的麻烦也不小。昨晚的比赛,让我下巴砸地板的事情出现了,VAR裁判忘记划线???跟一句语气助词没事吧于是枪迷们开始翻出高中几何教材开始自
棋手战鹰B站4个月涨粉百万,围棋界整活破圈共同体是中国之声决胜时刻联合体育大生意推出的体育商业主题对话节目,以求同存异,聊聊大家共同关心的体育热点话题为口号,每周一期,逢周五晚上1000于中国之声决胜时刻栏目期间播出。兔年
StussyxNikeAirMaxPenny2发布第四款Fossil配色Stussyx耐克AirMaxPenny2虽然没有在2021年举行25周年庆典,但PennyHardaway的第二款签名耐克运动鞋最终将在2022年推出,并通过特别版合作推出。正如
互联网统一大市场打造顶级企业,消费者是关键!每个人都有自己的梦想,为此每个人都努力奋斗与追求。作为追梦人我们,不仅有梦想,还要找到实现梦想的方案路径。为了实现梦想一路前行,我们经历过了多少心酸,经历过了多少坎坷,受了多少委屈
石狮高新技术企业全面开工复工东南网2月13日讯(福建日报记者何金通讯员王鹏达)元宵节过后,公司的生产线逐步复工复产,目前,我们员工全部到位,全部生产线保持了满负荷运行的状态。2月12日,在位于石狮高新区的芯片
菇说八道(429)以守为攻连续鸽了好几盘河圣的棋了,今天再鸽属实不像话了。说句实话,看到柯洁常规赛这个表演,属实想不到季后赛能四连胜。今天主要是想与大家一起回顾一下对范老板这盘棋,我的评价就是四个字倒退5年
锡伯杜喜欢兰德尔的侵略性他这么打时我们很难被击败直播吧2月12日讯尼克斯队今日背靠背作战,126120力克爵士队。赛后,尼克斯队主帅锡伯杜接受了媒体采访。谈及本队全明星兰德尔的发挥,锡伯杜说道我喜欢他攻击篮筐的方式,他在攻击篮筐
56场打完,他已确定成水货状元,1。7亿薪水篮网成冤大头三巨头打散重建,自然是能卖就卖。篮网队正式开启重建模式,送走了欧文,换回了丁威迪史密斯首轮签。送走了杜兰特,换回了布里奇斯卡梅伦约翰逊克劳德首轮签。两大巨星都换了即战力年轻人,以及