在Python中绑定局部变量

4 投票
4 回答
1605 浏览
提问于 2025-04-15 14:56

我在想,Python里有没有好的方法来绑定本地变量。我大部分的工作都是在拼凑一些短小的数据或文本处理脚本,通常会用到一系列的表达式(当Python允许的时候),所以定义对象类(用作命名空间)并实例化它们似乎有点麻烦。

所以我想到的类似于(常见的)Lisp语言,可以这样做:

(setq data '(1 2 3))
(setq output 
      (let ( (x (nth 2 data)) )
       x + x))

在Python中,我能想到的最好的方法是:

data = [1,2,3]
output = ((lambda x: x + x)
          (data[2]))

这些当然是非常简单的例子,但有没有什么方法能像Lisp中的let或let*那样扩展性强呢?定义类是创建本地命名空间的最佳方式吗?……(但这样感觉互动性稍差)

编辑:为了进一步解释我的意图(抱歉之前说得不够清楚),我想减少全局变量的使用。所以在上面的例子中,我是想用提取操作符作为任何可能不想重复的操作的一般情况。例如,人们可能会写:

output = data[2] + data[2]

或者

x = data[2]
output = x + x
del x

来达到同样的效果。实际上,如果对“数据”的操作比获取第二个项目更复杂,我就不想多次输入同样的内容,或者让计算机多次计算同一个表达式的值。因此,在大多数情况下,人们会把操作的结果,比如data[2]或operator.itemgetter(2)(data),赋值给全局空间中的某个变量,但我不太喜欢在全局空间里留下变量,尤其是那些只用来存储计算中的中间值的变量……所以我会在之后立即使用“del”命令。定义一个本地环境或命名空间,并将中间结果绑定到本地变量,是一个理想的替代方案。

4 个回答

2

你可以把一个函数装饰器和默认参数结合起来,得到类似于 let 和块级作用域变量的效果:

def let(func):
    return func()


data = [1,2,3]
@let
def output(x=data[2]):
    return x + x
print(output) # 6

# or if a single expression is enough:
output = let(lambda x=data[2]: x+x)

不过,这种写法在 Python 中并不常见,所以我建议你还是避免使用它,这样可以让你的代码更容易被别人理解。直接使用普通的局部变量就可以了:

data = [1,2,3]
x = data[2]
output = x + x

如果这个问题变得很严重,那说明你可能在一个函数里做的事情太多了。

2

你问的问题有点不太清楚,不过我还是尽量回答一下:

在Python中,你用“=”来给变量起名字。所以你的 data = [1,2,3] 就是把列表 [1,2,3] 绑定到名字 data 上。

你可以通过类和函数/方法来创建局部命名空间。

最接近于像 let 这样强大的东西的,可能就是 deflambda。虽然有些人可能会告诉你Python像Lisp,但其实Python并不是Lisp,也不是特别注重函数式编程,所以你可能需要调整一下自己的思维方式。

更新:哦,我现在明白你的意思了。

所有变量在Python中基本上都是局部的。最接近全局变量的就是在模块空间中定义的变量,因为你可以通过 from <module> import <variable> 来访问它们。你也可以在模块的任何地方访问这些变量,但不能修改它们(除非你用 global 关键字说明你想修改它们)。在函数/方法或类定义中定义的任何东西,只能在那个命名空间中访问。

所以简单来说:你现在担心的那些事情,其实不用担心。Python会为你处理好这些。 :)

3

我只能赞同Lennart和Daniel的观点——Python不是Lisp,试图把一种语言的特性强行搬到另一种语言上,通常会让人感到效率低下和挫败。

首先,来看你的示例代码:

data = [1,2,3]
output = ((lambda x: x + x)
          (data[2]))

如果改成这样会更容易理解:

data = [1, 2, 3]
output = (lambda x=data[2] : x +x)()

不过在这个具体的例子中,使用lambda表达式实在是太复杂了,效率也不高。一个简单的

output = data[2] + data[2]

就能很好地解决问题!-)

关于局部绑定和命名空间,通常的解决办法是使用……函数,甚至可以是嵌套函数。虽然Python是100%面向对象的(也就是说“一切都是对象”),但它并不是纯粹的面向对象,普通的函数也完全可以用。顺便说一下,即使是写“脚本”,你也应该把逻辑放在一个函数里,然后调用它——函数的局部命名空间访问速度比“全局”(实际上是模块级别)命名空间访问要快。常见的模式是:

import whatever

def some_func(args):
    code_here

def some_other_func(args)
    code_here

def main(args):
    parse_args
    some_func(something)
    some_other_func(something_else)
    return some_exit_code

if __name__ == '__main__'
    import sys
    sys.exit(main(sys.argv))         

另外,嵌套函数也可以访问外层的命名空间,也就是说:

def main():
    data = [1, 2, 3]
    def foo():
       x = data[2]
       return x + x
    print foo()
    data = [4, 5, 6]
    print foo()
    # if you want the nested function to close over its arguments:
    def bar(data=data):
       x = data[2]
       return x + x
    print bar()
    data = [7, 8, 9]
    print bar()

希望这些对你有帮助!

撰写回答