函数相关面试题精讲

函数机制是 Python 虚拟机的核心组成部分, 作用域名字空间闭包装饰器 等基本概念均与函数机制紧密联系。

正因如此,函数机制也成为 Python 工程师技术面重点讨论的内容。面试不仅考察后续人对相关知识点的理解,而且可通过类似 装饰器设计 这样的编码环节,考察候选人的程序设计能力。

真题讲解

Python 中有几个名字空间,分别是什么?Python 变量以什么顺序进行查找?

Python 总共有 4 个名字空间:

  • 局部名字空间 ( locals )
  • 闭包名字空间 ( closures )
  • 全局名字空间 ( globals )
  • 内建名字空间 ( builtin )

Python 查找变量时,依次检查 局部闭包全局内建 这几个名字空间,直到变量被找到为止。更多详情,请参考虚拟机部分 作用域名字空间 以及函数机制部分 函数调用 相关章节。

如何在一个函数内部修改全局变量?

在函数内部用 global 关键字将变量声明为全局,然后再进行修改:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
>>> a = 1
>>> def func():
...     global a
...     a = 2
...
>>> print(a)
1
>>> func()
>>> print(a)
2

不使用 def 关键字的话,还有什么办法可以创建函数对象?

根据 Python 对象模型,实例对象可以通过调用类型对象来创建。而函数类型对象,理论上可以通过函数对象找到:

1
2
3
4
5
6
>>> def a():
...     pass
...
>>> function = a.__class__
>>> function
<class 'function'>

实际上,Python 将函数类型对象暴露在 types 模块中,可通过模块属性 FunctionType 访问到:

1
2
3
>>> from types import FunctionType
>>> FunctionType is function
True

函数对象包含以下要素,只要将这些要素备齐,即可调用函数类型对象创建新函数:

  • code ,代码对象;
  • globals ,全局名字空间;
  • name ,函数名;
  • argdefs ,默认参数值;
  • closure ,闭包变量;

我们定义一个函数用于试验,它设置全局变量 value

1
2
3
4
>>> def set_global_value(v):
...     global value
...     value = v
...

一开始全局名字空间并没有变量 value ,经过 set_global_value 函数设置后便可找到:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
>>> value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'value' is not defined
>>> set_global_value(10)
>>> value
10
>>> set_global_value(20)
>>> value
20

接下来,我们借助函数类型对象,创建一个与 set_global_value 类似的新函数 sgv ,只不过全局名字空间与我们指定的字典对象 g 绑定:

1
2
>>> g = {}
>>> sgv = FunctionType(set_global_value.__code__, g, 'sgv')

这样一来,调用 sgv 函数设置的全局变量,将保存在指定的全局名字空间,即字典 g 中:

1
2
3
4
5
6
7
8
>>> g
{}
>>> sgv(10)
>>> g
{'value': 10}
>>> sgv(20)
>>> g
{'value': 20}

这个例子纯粹为了演示如何通过函数类型对象创建新函数,虽不具备实际项目用途,但对理解函数运行机制很有帮助。

更多面试真题

请介绍装饰器的运行原理,并说说你对 @xxxx 这种写法的理解?

请设计一个装饰器,在函数执行时间超过指定值时输出日志

Python中的闭包变量可以被内部函数修改吗?

请描述执行以下程序将输出什么内容?并试着解释其中的原因。

上述的问题,你是否都能对答如流呢?点击 阅读原文,获取详细题解!

【Python源码剖析】系列文章首发于公众号【小菜学编程】,敬请关注:

【Python源码剖析】系列文章首发于公众号【小菜学编程】,敬请关注:

【Python源码剖析】系列文章首发于公众号【小菜学编程】,敬请关注: