为了防止 Python 函数使用除局部变量以外的任何变量,通过指定空的全局作用域和局部作用域执行代码,强制函数只能使用显式传递的变量。
问题背景
在进行 Python 代码重构时,为了确保不忘记纠正函数中的指令而导致原始代码出现问题,我们需要确保函数在测试时无法访问全局变量。除了将函数复制到单独的模块之外,还有哪些方法可以实现这一目的?
解决方案
- 使用单例模式管理全局变量
一种方法是将所有全局变量都放到一个单例(全局)对象中。这样做的好处是,任何对全局变量的使用都会非常明显,便于我们在日后减少或消除它们。
例如,我们可以在模块中进行如下全局声明:
dir_root = "/example/rootdir"
debug_level = 3
然后将它们包装在一个类中,并声明一个单例实例:
class GLOBALS:
dir_root = ...
debug_level = ...
Globals = GLOBALS()
当然,现有引用变量的地方都需要更新,以使用例如 Globals.dir_root
来代替直接使用 dir_root
。
这样做的好处是,它允许我们突出显示对全局变量的使用,同时保持应用程序逻辑不变。这种方式使我们可以以更加渐进的方式进行重构,从而减少引入新逻辑错误的可能性。根据我们的原始问题,我们可以确信任何不显式引用 Globals
对象的函数都不会使用任何全局变量。
2. 使用 functools.partial
另一种方法是使用 functools.partial
来创建函数对象的局部副本。我们可以使用 partial
来绑定函数的参数,同时还可以绑定函数所使用的全局变量。
例如,我们可以使用如下代码来创建一个局部副本的函数,该副本只能访问有限的全局变量:
from functools import partial
def big_function(args):
def one_small_transformation(args):
# No one else needs to see this transformation outside the function1
def second_small_transformation(args):
...
# Block of instructions chaining small transformations
# Other big functions and code making them work together
# Create a partial copy of `one_small_transformation` that only has access to `args`
one_small_transformation_partial = partial(one_small_transformation, args=args)
# Create a partial copy of `second_small_transformation` that only has access to `args`
second_small_transformation_partial = partial(second_small_transformation, args=args)
# Now, we can call these partial functions without worrying about them accessing any global variables
one_small_transformation_partial()
second_small_transformation_partial()
这种方法的好处是,它允许我们在不修改原始函数的情况下创建函数的局部副本。这使得我们可以轻松地测试函数,而无需担心对全局变量的意外访问。
代码示例
# Example 1: Using a singleton to manage global variables
class GLOBALS:
dir_root = "/example/rootdir"
debug_level = 3
Globals = GLOBALS()
def big_function(args):
# Access the global variables using the Globals object
dir_root = Globals.dir_root
debug_level = Globals.debug_level
# ...
# Example 2: Using functools.partial to create a partial copy of a function
from functools import partial
def big_function(args):
def one_small_transformation(args):
# No one else needs to see this transformation outside the function1
def second_small_transformation(args):
...
# Block of instructions chaining small transformations
# Create a partial copy of `one_small_transformation` that only has access to `args`
one_small_transformation_partial = partial(one_small_transformation, args=args)
# Create a partial copy of `second_small_transformation` that only has access to `args`
second_small_transformation_partial = partial(second_small_transformation, args=args)
# Now, we can call these partial functions without worrying about them accessing any global variables
one_small_transformation_partial()
second_small_transformation_partial()
希望这些解决方案对你有帮助。
总结一下
防止 Python 函数使用非局部变量的几种方法:
- 使用
exec
限制作用域:通过执行代码时控制作用域。 - 闭包定义:将函数限制在封闭的局部作用域中。
- 动态检查:通过
globals()
或字节码分析约束变量访问。 - 参数传递:所有变量显式通过参数传递。
- 自定义环境:用隔离的全局和局部环境执行函数。
根据需求选择适合的解决方案,其中闭包和参数传递是最通用和推荐的方式。