【发布时间】:2018-03-20 02:27:38
【问题描述】:
为这个无益的标题道歉,但我不知道如何用朗朗上口的单行话来表达我的问题。因此,让我解释一下。
在像 Common Lisp 这样的语言中,您可以使用闭包来“隐藏全局变量”,如
(let ((my-global-variable '(foo bar))))
(defun f (x) (append my-global-variable x)))
这样做的预期效果是
- 您会在函数中获得一个可访问的变量,该变量在函数调用之间持续存在
- 这是在您的功能范围之外不可见
应该对“不可见”持保留态度,因为仍然可以使用依赖于实现的检查工具从外部访问变量。因此,让我们同意“不可见”的意思是“不影响变量的全局命名空间”。
在 Python 中实现 1. 和 2. 的一种可能方法是通过:
def helper_function():
my_global_variable = ['foo', 'bar']
def f(x):
return my_global_variable + x
return f
f = helper_function()
评估f(['baz']) 会按预期返回['foo', 'bar', 'baz'],它满足 1. 和 2。但是与 Lisp 版本相比,它不正确
- 变量在函数内是可变/可重新绑定
取决于您使用的是 Python
更准确地说,我问是否有另一种解决方案
- 不那么冗长
- 并且不会使用辅助对象污染名称空间(上例中为
helper_function)
?
以下是答案列表,由来自user2357112、CircArgs 和Stefan Pochmann 的有用 cmets 编译而成。
解决方案 1:可调用对象(满足 1-3)
class helper_class:
my_global_var = ['foo','bar']
def __call__(self, x):
return self.my_global_var + x
f = helper_class()
解决方案 2:可选参数的默认值(满足 1,2,4,5(或 2,3,4,5;见下文))
def f(x, my_global_var=['foo', 'bar']):
return my_global_var+x
注意变量是可变的,但是突变不会在函数调用之间传递,所以它不会同时满足1和3。另请注意,默认参数仅计算一次(在定义函数时),因此对我的目的来说是可以接受的。
方案3:函数属性(满足1-5)
def f(x):
return f.my_global_var + x
f.my_global_var = ['foo', 'bar']
从技术上讲,这是最好的解决方案(满足所有要求),但它比使用默认参数稍微冗长。
解决方案 4:巧妙的命名空间破解(满足 1,2,5)
def f():
my_global_var = ['foo', 'bar']
def f(x):
return my_global_var + x
return f
f = f()
请注意,返回的 f 实际上是内部的,不是外部的。
【问题讨论】:
-
定义一个类,或者也许使用函数属性。尝试为此使用闭包变量在 Python 中很尴尬。
-
在尝试将其转换为 Lisp 之前,您应该真正熟悉 Python 本身的术语。
my_global_variable = []无关紧要,因为my_global_variable = x创建了一个 完全不同的 变量,而不是使用来自外部作用域的变量,而my_global_variable = x也无关紧要,因为无法访问该值这些变量中的任何一个都没有办法让它们的值对任何东西产生任何影响。另外,defun不是 Python 中的东西,所以看起来你实际上并没有运行它。 -
那么可能是
def f(x, prefix=['foo', 'bar']): return prefix + x? -
@BlenderBender 取决于您对“单线”和“工作”的含义:-)。无论如何,再多一个选项:
def f(x): return f.prefix + x后跟f.prefix = ['foo', 'bar']。 -
所有这一切都在编辑,方式太多的cmets,仍然没有明确的问题。 你想解决什么问题,你为什么认为你甚至需要这个? Python 不是一种试图隐藏数据和结构的语言。