【问题标题】:Faking LISP-like closures in Python? [closed]在 Python 中伪造类似 LISP 的闭包? [关闭]
【发布时间】:2018-03-20 02:27:38
【问题描述】:

为这个无益的标题道歉,但我不知道如何用朗朗上口的单行话来表达我的问题。因此,让我解释一下。

在像 Common Lisp 这样的语言中,您可以使用闭包来“隐藏全局变量”,如

(let ((my-global-variable '(foo bar))))
   (defun f (x) (append my-global-variable x)))

这样做的预期效果是

  1. 您会在函数中获得一个可访问的变量,该变量在函数调用之间持续存在
  2. 这是在您的功能范围之外不可见

应该对“不可见”持保留态度,因为仍然可以使用依赖于实现的检查工具从外部访问变量。因此,让我们同意“不可见”的意思是“不影响变量的全局命名空间”。

在 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 版本相比,它不正确

  1. 变量在函数内是可变/可重新绑定

取决于您使用的是 Python

更准确地说,我问是否有另一种解决方案

  1. 不那么冗长
  2. 并且不会使用辅助对象污染名称空间(上例中为helper_function

?

以下是答案列表,由来自user2357112CircArgsStefan 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 不是一种试图隐藏数据和结构的语言。

标签: python closures lisp


【解决方案1】:

也许您正在寻找类似的东西。我认为这比试图与 Python 搏斗以获得纯粹的功能行为更具 Pythonic:

class Helper:

    __hidden_var=5

    def __init__(self):
        pass

    def __call__(self, x):
        self.__hidden_var=x

我有点武断,因为我不完全确定你想要什么,但我已经按照你的要求演示了一个可调用对象。请注意,一旦实例化实例,__ 使该属性在实例外部不可访问(尽管这不是完全正确,因为您仍然可以使用 instance._Helper__hidden_​​var 获得它)。您可能会选择使用类似辅助函数的东西来真正隐藏这样的变量。您可以轻松实现另一种方法来编辑隐藏变量encapsulation

【讨论】:

  • 如果他们不喜欢helper_function,我想他们会讨厌Helper。它有什么优势吗?对我来说,这似乎更糟
  • @StefanPochmann 我想在某种意义上他要求演示如何使用可调用对象来模拟词法闭包。我认为这更清洁。发生的事情一目了然。
猜你喜欢
  • 2015-02-13
  • 2012-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
  • 1970-01-01
相关资源
最近更新 更多