[英]Python - bound variable scope to closure
我有一些使用外部变量的 function。 一个(基本上)简化的例子:
a = 2
b = 3
def f(x):
return x * a + b
虽然我需要f
中a
和b
,但我在其他任何地方都不需要它们。 特别是,可以写a = 5
,这将改变f
的行为。 我应该如何使a
和b
对外部不可见?
其他语言允许我大致编写以下代码:
let f =
a = 2
b = 3
lambda x: x * a + b
我想要的是:
f
必须按预期工作并具有相同的签名a
和b
必须只计算一次a
和b
不得存在于f
之外的 scope 中a =...
和b =...
不影响f
g
然后将其删除,这是我不喜欢的(例如,存在覆盖现有g
的风险,我认为它简直丑陋):def g():
a = 2
b = 3
return lambda x: x * a + b
f = g()
del g
一种方法是简单地使用 class。 这允许您将a
和b
放置在 class 的 scope 中,而f
仍然可以访问它们。
class F:
def __init__(self):
self.a = 2
self.b = 3
def __call__(self, x):
return x * self.a + self.b
f = F()
f(1)
# returns:
5
如果您不喜欢调用 class 构造函数,则可以覆盖__new__
以实质上创建一个带有内部存储变量的可调用对象。 虽然这是一个反模式,但不是很pythonic。
class f:
a = 2
b = 3
def __new__(cls, x):
return x * cls.a + cls.b
f(1)
# returns:
5
此方法基于此线程中提供的答案,但仅限于上述特定问题。 您可以使用装饰器来更新 function 可用的全局变量,同时还可以将a
和b
存储在闭包中。
from functools import wraps
def dec_ab(fn):
a = 2
b = 3
@wraps(fn)
def wrapper(*args, **kwargs):
# get global scope
global_scope = f.__globals__
# copy current values of variables
var_list = ['a', 'b']
current_vars = {}
for var in var_list:
if var in global_scope:
current_vars[var] = global_scope.get(var)
# update global scope
global_scope.update({'a': a, 'b': b})
try:
out = fn(*args, **kwargs)
finally:
# undo the changes to the global scope
for var in var_list:
global_scope.pop(var)
global_scope.update(current_vars)
return out
return wrapper
@dec_ab
def f(x):
"""hello world"""
return x * a + b
这保留了函数签名并防止a
和b
被更改
f(1)
# returns:
5
a
# raises:
NameError: name 'a' is not defined
您可以使用默认的 arguments 来完成此操作。 默认 arguments 仅在创建闭包时计算一次(这就是为什么如果您将可变对象作为默认 arguments,state 在调用之间保留)。
def f(x, a=2, b=3):
return x * a + b
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.