随着 Python 最近变得越来越流行,你们中的许多人可能正在接受与 Python 打交道的技术面试。在这篇文章中,我将列出十个高级 Python 面试问题和答案。
这些内容可能会令人困惑,并且针对的是中级开发人员,他们需要对 Python 作为一种语言及其背后的工作原理有很好的理解。
1、Nolocal 和 Global 关键字的用途是什么?
这两个关键字用于更改先前声明的变量的范围。nolocal当您需要访问嵌套函数中的变量时经常使用,nolocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量。
def func1():
x = 5
def func2():
nolocal x
print(x)
func2()
global是一个更直接的指令。它使先前声明的变量成为全局变量。例如,考虑这段代码:
x = 5
def func1():
print(x)
func1()
>>>5
由于x在函数调用之前声明,因此func1可以访问它。但是,如果您尝试更改它:
x = 5
def func2():
x += 3
func2()
>>>UnboundLocalError: 赋值前引用了局部变量“c”
为了让它工作,我们需要指出x我们指的是全局变量x:
x = 5
def func2():
global x
x += 3
func2()
2、class方法和静态方法有什么区别?
它们都定义了一个class方法,可以在不实例化class的对象的情况下调用该方法。唯一的区别在于他们的签名:
A class:
@staticmethod
def func1():
pass
@classmethod
def func2(cls):
pass
如您所见,classmethod接受一个隐式参数cls,该参数将被设置为classA本身。一个常见的用例classmethod是创建替代的可继承构造函数。
3、什么是 GIL 以及绕过它的一些方法是什么?
GIL 代表全局解释器锁,它是 Python 用于并发的一种机制。它内置于 Python 系统的深处,目前无法摆脱它。GIL 的主要缺点是它使线程不是真正的并发。它锁定了解释器,即使看起来你正在使用线程,但它们并不是同时执行的,从而导致性能损失。这里有一些绕过它的方法:
- multiprocessing模块。它允许您生成新的 Python 进程并以与管理线程相同的方式管理它们。
- asyncio模块。它有效地启用了异步编程并添加了async/await语法。虽然它没有解决 GIL 问题,但它会使代码方式更易读和更清晰。
- Stackless_Python。这是一个没有 GIL 的 Python 分支。它最显着的用途是作为 EVE Online 游戏的后端。
3、什么是metaclass以及何时使用它们?
metaclass是class的class。当继承过于混乱时,元class可以指定许多class共有的某些行为。一种常见的元class是ABCMeta,用于创建抽象class。
Python 中的元class和元编程是一个很大的话题。如果您对此感兴趣,请务必相关信息。
4、什么是class型注解?什么是通用class型注释?
虽然 Python 是一种动态class型语言,但为了清晰起见,有一种方法可以对class型进行注释。这些是内置class型:
- int
- float
- bool
- str
- bytes
该typing模块提供了复杂class型:
- List
- Set
- Dict
- Tuple
- Optional
- ETC。
以下是如何使用class型注释定义函数:
def func1(x: int, y: str) -> bool:
return False
泛型class型注解是将另一种class型作为参数的注解,允许你指定复杂的逻辑:
- List[int]
- Optional[List[int]]
- Tuple[bool]
请注意,这些仅用于警告和静态class型检查。您将无法在运行时保证这些class型。
5、什么是生成器函数?编写您自己的范围版本
生成器函数是可以在return值后暂停执行的函数,以便稍后恢复执行并return另一个值。这是pass关键字实现的yield,您使用它代替 return。您使用过的最常见的生成器函数是range. 这是实现它的一种方法(仅适用于积极的步骤,我将把它留作练习以制作支持消极步骤的方法):
def range(start, end, step):
cur = start
while cur > end:
yield cur
cur += step
6、什么是 Python 中的装饰器?
Python 中的装饰器用于修改函数的行为。例如,如果您想记录对一组特定函数的所有调用、缓存其参数和return值、执行基准测试等。
装饰器以符号为前缀@,并放置在函数声明之前:
@my_decorator
def func1():
pass
7、什么是 Python 中的 Pickling 和 Unpickling?
序列化的 Python 方式. Pickling 允许您将对象序列化为字符串(或您选择的任何其他内容),以便持久存储或pass网络发送。Unpickling 是从字符串中恢复原始对象的过程。Pickling 是不安全的。只从受信任的来源中提取对象。
下面是你将如何 pickle 一个基本的数据结构:
import pickle
cars = {"Subaru": "best car", "Toyota": "no i am the best car"} cars_serialized = pickle.dumps(cars)
# cars_serialized 是一个字节串new_cars = pickle.loads(cars_serialized)
8、什么是*argsPython**kwargs函数?
这些与拆包密切相关。如果你放入*args函数的参数列表,所有未命名的参数都将存储在args数组中。**kwargs工作方式相同,但对于命名参数:
def func1(*args, **kwargs):
print(args)
print(kwargs)
func1(1, 'abc', lol='lmao')
> [1, 'abc']
> {"lol": "lmao" }
9、文件有什么.pyc用?
.pyc.class文件包含 Python 字节码,与Java 中的文件相同。不过,Python 仍然被认为是一种解释型语言,因为这个编译阶段发生在您运行程序时,而在 Java 中,它们是明确分开的。
10、你如何在 Python 中定义抽象class?
ABC您从模块继承类来定义抽象类 abc:
from abc import ABC,abstractmethod
class AbstractCar(ABC):
@abstractmethod
def drive(self):
pass
要实现该class,只需继承它:
class 红旗汽车(AbstractCar):
def drive(self):
print('go go go')
if __name__ == '__main__':
a = 红旗汽车()
a.drive()