以下为译文:
本文列出53个Python面试问题,并且提供了答案,供数科学家和软件工程师们参考。
不久前,我作为“数据科学家”开始担任一个新的角色,实际上就是一位“Python工程师”。
如果我在面试前提前了解一下Python的线程生命周期,而不是它的Recommender System(推荐系统)的话,我可能会在面试中表现得更好。
为了帮助大家通过面试,下面我整理了我为Python面试/工作准备的问题,并提供了答案。大多数数据科学家都会编写大量的代码,所以这些问题/答案对科学家和工程师都同样适用。
无论你是一位面试官、还是准备应聘一份工作、或者只是想提高你的Python技能,这份清单对你来说都将是无价之宝。
问题是无序的。让我们开始吧。
目录:
1. 列表(list)和元组(tuple)有什么区别?
2. 如何进行字符串插值?
3. “is”和“==”有什么区别?
4. 什么是装饰器(decorator)?
5. 解释Range函数
6. 定义一个名为car的类,它有两个属性:“color”和“speed”。然后创建一个实例并返回“speed”。
7. Python中的实例方法、静态方法和类方法有什么区别?
8. “func”和“ func()”有什么区别?
9. 解释map函数的工作原理。
10. 解释reduce函数的工作原理。
11.解释filter函数的工作原理
12. Python是按引用调用还是按值调用?
13. 如何使用reverse函数反转一个列表?
14. 字符串乘法是如何工作的?
15. 列表乘法是如何工作的?
16. 类中的“self”指的是什么?
17. 如何在Python中连接列表?
18. 浅拷贝和深拷贝之间有什么区别?
19. 列表和数组有什么区别?
20. 如何连接两个数组?
21. 你喜欢Python的什么?
22. 你最喜欢Python的哪个库?
23. 举出几个可变和不可变对象的例子?
24. 如何将一个数字四舍五入到小数点后三位?
25. 如何分割一个列表?
26. 什么是pickling?
27. 字典和JSON有什么区别?
28. 你在Python中使用了哪些ORM?
29. any()和all()如何工作?
30. 字典和列表的查找速度哪个更快?
31. 模块(module)和包(package)有什么区别?
32. 如何在Python中递增和递减一个整数?
33. 如何返回一个整数的二进制值?
34. 如何从列表中删除重复的元素?
35. 如何检查一个值是不是在列表中存在?
36. append和extend有什么区别?
37. 如何取一个整数的绝对值?
38. 如何将两个列表组合成一个元组列表?
39. 如何按字母顺序对字典进行排序?
40. 一个类如何继承Python的另一个类?
41. 如何删除字符串中的所有空白?
42. 在迭代序列时,为什么要使用enumerate()?
43. pass、continue和break之间有什么区别?
44. 如何将for循环转换为使用递推式构造列表(list comprehension)?
45. 举一个使用三元运算符的例子。
46. 检查一个字符串是否仅仅包含数字?
47. 检查一个字符串是否仅仅包含字母?
48. 检查字符串是否只包含数字和字母?
49. 从字典返回键列表
50. 如何将一个字符串转化为全大写和全小写?
51. remove、del和pop有什么区别?
52. 举一个递推式构造字典(dictionary comprehension)的例子
53. Python中的异常处理是如何进行的?
正文:
经典面试题与答案
1. 列表(list)和元组(tuple)有什么区别?
在我每一次应聘Python数据科学家的面试中,这个问题都会被问到。所以对这个问题的答案,我可以说是了如指掌。
列表是可变的。创建后可以对其进行修改。
元组是不可变的。元组一旦创建,就不能对其进行更改。
列表表示的是顺序。它们是有序序列,通常是同一类型的对象。比如说按创建日期排序的所有用户名,如["Seth", "Ema", "Eli"]。
元组表示的是结构。可以用来存储不同数据类型的元素。比如内存中的数据库记录,如(2, "Ema", "2020–04–16")(#id, 名称,创建日期)。
2. 如何进行字符串插值?
在不导入Template类的情况下,有3种方法进行字符串插值。
name = 'Chris'# 1. f stringsprint(f'Hello {name}')# 2. % operatorprint('Hey %s %s' % (name, name))# 3. formatprint("My name is {}".format((name)))
3. “is”和“==”有什么区别?
在我的Python职业生涯的早期,我认为它们是相同的,因而制造了一些bug。所以请大家听好了,“is”用来检查对象的标识(id),而“==”用来检查两个对象是否相等。
我们将通过一个例子说明。创建一些列表并将其分配给不同的名字。请注意,下面的b指向与a相同的对象。
a = [1,2,3]b = ac = [1,2,3]
下面来检查是否相等,你会注意到结果显示它们都是相等的。
print(a == b)print(a == c)#=> True#=> True
但是它们具有相同的标识(id)吗?答案是不。
print(a is b)print(a is c)#=> True#=> False
我们可以通过打印他们的对象标识(id)来验证这一点。
print(id(a))print(id(b))print(id(c))#=> 4369567560#=> 4369567560#=> 4369567624
你可以看到:c和a和b具有不同的标识(id)。
4. 什么是装饰器(decorator)?
这是每次面试我都会被问到的另一个问题。它本身就值得写一篇文章。如果你能自己用它编写一个例子,那么说明你已经做好了准备。
装饰器允许通过将现有函数传递给装饰器,从而向现有函数添加一些额外的功能,该装饰器将执行现有函数的功能和添加的额外功能。
我们将编写一个装饰器,该装饰器会在调用另一个函数时记录日志。
编写装饰器函数logging。它接受一个函数func作为参数。它还定义了一个名为log_function_called的函数,它先执行打印出一些“函数func被调用”的信息(print(f'{func} called.')),然后调用函数func()。最后返回定义的函数。
def logging(func): def log_function_called(): print(f'{func} called.') func() return log_function_called
让我们编写其他两个函数,我们最终会将装饰器添加到其中(但还没有)。
def my_name(): print('chris')def friends_name(): print('naruto')my_name()friends_name()#=> chris#=> naruto
现在将装饰器添加到上面编写的两个函数之中。
@loggingdef my_name(): print('chris')@loggingdef friends_name(): print('naruto')my_name()friends_name()#=> <function my_name at 0x10fca5a60> called.#=> chris#=> <function friends_name at 0x10fca5f28> called.#=> naruto
现在,你了解了如何仅仅通过在其上面添加@logging(装饰器),就能够轻松地将日志添加到我们编写的任何函数中。
5. 解释Range函数
Range函数可以用来创建一个整数列表,一般用在for循环中。它有3种使用方法。
Range函数可以接受1到3个参数,参数必须是整数。
请注意:我已经将range的每种用法包装在一个递推式构造列表(list comprehension)中,以便我们可以看到生成的值。
用法1 - range(stop):生成从0到参数“stop”之间的整数。
[i for i in range(10)]#=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
用法2 - range(start, stop) : 生成从参数“start”到“stop”之间的整数
[i for i in range(2,10)]#=> [2, 3, 4, 5, 6, 7, 8, 9]
用法3 - range(start, stop, step):以参数“step”为步长,生成从“start”到“stop”之间的整数。
[i for i in range(2,10,2)]#=> [2, 4, 6, 8]
6. 定义一个名为car的类,它有两个属性:“color”和“speed”。然后创建一个实例并返回“speed”。
class Car : def __init__(self, color, speed): self.color = color self.speed = speedcar = Car('red','100mph')car.speed#=> '100mph'
7. Python中的实例方法、静态方法和类方法有什么区别?
实例方法:接受self参数,并且与类的特定实例相关。
静态方法:使用装饰器 @staticmethod,与特定实例无关,并且是自包含的(不能修改类或实例的属性)。
类方法:接受cls参数,并且可以修改类本身。
我们将通过一个虚构的CoffeeShop类来说明它们之间的区别。
- class CoffeeShop:
- specialty = 'espresso'
-
- def __init__(self, coffee_price):
- self.coffee_price = coffee_price
-
- # instance method
- def make_coffee(self):
- print(f'Making {self.specialty} for ${self.coffee_price}')
-
- # static method
- @staticmethod
- def check_weather():
- print('Its sunny') # class method
- @classmethod
- def change_specialty(cls, specialty):
- cls.specialty = specialty
- print(f'Specialty changed to {specialty}')
CoffeeShop类有一个属性specialty,默认值设为“espresso”。CoffeeShop类的每个实例初始化时都使用了coffee_price这个属性。同时,它还有3个方法,一个实例方法,一个静态方法和一个类方法。
让我们将coffee_price的值设为5,来初始化CoffeeShop的一个实例。然后调用实例方法make_coffee。
coffee_shop = CoffeeShop('5')coffee_shop.make_coffee()#=> Making espresso for $5
现在我们来调用静态方法。静态方法无法修改类或实例状态,因此通常用于工具函数,例如,把2个数字相加。我们这里用它来检查天气。天气晴朗。太好了!
coffee_shop.check_weather()#=> Its sunny
现在让我们使用类方法修改CoffeeShop的属性specialty,然后调用make_coffee()方法来制作咖啡。
coffee_shop.change_specialty('drip coffee')#=> Specialty changed to drip coffeecoffee_shop.make_coffee()#=> Making drip coffee for $5
注意,make_coffee过去是用来做意式浓缩咖啡(espresso)的,但现在用来做滴滤咖啡(drip coffee)了!
8. “func”和“ func()”有什么区别?
这个问题的目的是想看看你是否理解所有函数也是Python中的对象。
- def func():
- print('Im a function')
-
- func
- #=> function __main__.func>func()
- #=> Im a function
func是表示函数的对象,它可以被分配给变量或传递给另一个函数。带圆括号的func()调用该函数并返回其输出。
9. 解释map函数的工作原理。
Map函数返回一个列表,该列表由对序列中的每个元素应用一个函数时返回的值组成。
def add_three(x): return x + 3li = [1,2,3][i for i in map(add_three, li)]#=> [4, 5, 6]
上面,我对列表中的每个元素的值加了3。
10. 解释reduce函数的工作原理。
这个问题很棘手,在你使用过它几次之前,你得努力尝试自己能够理解它。
reduce接受一个函数和一个序列,然后对序列进行迭代。在每次迭代中,当前元素和前一个元素的输出都传递给函数。最后,返回一个值。
from functools import reducedef add_three(x,y): return x + y li = [1,2,3,5] reduce(add_three, li)#=> 11
返回11,它是1 + 2 + 3 + 5的总和。
11.解释filter函数的工作原理
Filter函数顾名思义,是用来按顺序过滤元素。
每个元素都被传递给一个函数,如果函数返回True,则在输出序列中返回该元素;如果函数返回False,则将其丢弃。
def add_three(x): if x % 2 == 0: return True else: return Falseli = [1,2,3,4,5,6,7,8][i for i in filter(add_three, li)]#=> [2, 4, 6, 8]
注意上面所有不能被2整除的元素如何被删除的。
12. Python是按引用调用还是按值调用?
如果你在谷歌上搜索这个问题并阅读前几页,你就要准备好进入语义的迷宫了。你最好只是了解它的工作原理。
不可变对象(如字符串、数字和元组等)是按值调用的。请注意下面的例子,当在函数内部修改时,name的值在函数外部不会发生变化。name的值已分配给内存中该函数作用域的新块。
name = 'chr'def add_chars(s): s += 'is' print(s)add_chars(name) print(name)#=> chris#=> chr
可变对象(如列表等)是通过引用调用的。注意下面的例子中,函数外部定义的列表在函数内部的修改是如何影响到函数外部的。函数中的参数指向内存中存储li值的原始块。
li = [1,2]def add_element(seq): seq.append(3) print(seq)add_element(li) print(li)#=> [1, 2, 3]#=> [1, 2, 3]
13. 如何使用reverse函数反转一个列表?
下面的代码对一个列表调用reverse()函数,对其进行修改。该方法没有返回值,但是会对列表的元素进行反向排序。
li = ['a','b','c']print(li)li.reverse()print(li)#=> ['a', 'b', 'c']#=> ['c', 'b', 'a']
14. 字符串乘法是如何工作的?
让我们看看将字符串" cat"乘以3的结果。
'cat' * 3#=> 'catcatcat'
该字符串将自身连接3次。
15. 列表乘法是如何工作的?
我们来看看将列表[1,2,3]乘以2的结果。
[1,2,3] * 2#=> [1, 2, 3, 1, 2, 3]
输出的列表包含了重复两次的列表[1,2,3]的内容。
16. 类中的“self”指的是什么?
“self”引用类本身的实例。这就是我们赋予方法访问权限并且能够更新方法所属对象的能力。
下面,将self传递给__init__(),使我们能够在初始化时设置实例的颜色。
- class Shirt:
- def __init__(self, color):
- self.color = color
-
- s = Shirt('yellow')
- s.color
- #=> 'yellow'
17. 如何在Python中连接列表?
将2个列表相加,就是将它们连接在一起。但请注意,数组的工作方式不是这样的。
- a = [1,2]
- b = [3,4,5]
-
- a + b
- #=> [1, 2, 3, 4, 5]
18. 浅拷贝和深拷贝之间有什么区别?
我们将在一个可变对象(列表)的上下文中讨论这个问题,对于不可变的对象,浅拷贝和深拷贝的区别并不重要。
我们将介绍三种情况。
1. 引用原始对象。这将新对象li2指向li1所指向的内存中的同一位置。因此,我们对li1所做的任何更改也会在li2中发生。
li1 = [['a'],['b'],['c']]li2 = li1li1.append(['d'])print(li2)#=> [['a'], ['b'], ['c'], ['d']]
2. 创建原始对象的浅拷贝副本。我们可以使用list()构造函数来实现这一点。浅拷贝创建一个新对象,但是用对原始对象的引用填充它。因此,向原始列表li3中添加新对象不会传播到li4中,但是修改li3中的一个对象将传播到li4中。
li3 = [['a'],['b'],['c']]li4 = list(li3)li3.append([4])print(li4)#=> [['a'], ['b'], ['c']]li3[0][0] = ['X']print(li4)#=> [[['X']], ['b'], ['c']]
3. 创建一个深拷贝副本。这是用copy.deepcopy()完成的。现在,这两个对象是完全独立的,并且对其中一个对象所做的更改不会对另外一个对象产生影响。
import copyli5 = [['a'],['b'],['c']]li6 = copy.deepcopy(li5)li5.append([4])li5[0][0] = ['X']print(li6)#=> [['a'], ['b'], ['c']]
19. 列表和数组有什么区别?
注意:Python的标准库有一个array(数组)对象,但在这里,我特指常用的Numpy数组。
列表存在于python的标准库中。数组由Numpy定义。
列表可以在每个索引处填充不同类型的数据。数组需要同构元素。
列表上的算术运算可从列表中添加或删除元素。数组上的算术运算按照线性代数方式工作。
列表还使用更少的内存,并显著具有更多的功能。
20. 如何连接两个数组?
记住,数组不是列表。数组来自Numpy和算术函数,例如线性代数。
我们需要使用Numpy的连接函数concatenate()来实现。
import numpy as npa = np.array([1,2,3])b = np.array([4,5,6])np.concatenate((a,b))#=> array([1, 2, 3, 4, 5, 6])
21. 你喜欢Python的什么?
Python可读性很强,并且有一种Python方式可以处理几乎所有事情,这意味着它有一种简洁明了的首选方法。
我将Python与Ruby进行对比,Ruby通常有很多种方法来做某事,但是没有指南说哪种方法是首选。
22. 你最喜欢Python的哪个库?
在处理大量数据时,没有什么比Pandas(熊猫)更有帮助了,因为Pandas让操作和可视化数据变得轻而易举。
23. 举出几个可变和不可变对象的例子?
不可变意味着创建后不能修改状态。例如:int、float、bool、string和tuple。
可变意味着可以在创建后修改状态。例如列表(list)、字典(dict)和集合(set)。
24. 如何将一个数字四舍五入到小数点后三位?
使用round(value, decimal_places)函数。
a = 5.12345round(a,3)#=> 5.123
25. 如何分割一个列表?
分割语法使用3个参数,list[start:stop:step],其中step是返回元素的间隔。
a = [0,1,2,3,4,5,6,7,8,9]print(a[:2])#=> [0, 1]print(a[8:])#=> [8, 9]print(a[2:8])#=> [2, 3, 4, 5, 6, 7]print(a[2:8:2])#=> [2, 4, 6]
....博主太懒了字数太多了,不想写了....文章已经做成PDF,有需要的朋友可以私信我免费获取!