在JavaScript中,我可能会写一个这样的函数:
function counter() {
foo = 0;
function increment() {
foo += 1
console.log(foo);
}
function printVal() {
console.log(foo);
}
return {
increment: increment,
printVal: printVal,
}
}
func = counter();
func.increment()
func.increment()
func.printVal()
我想尝试使用python实现类似的功能。特别是我如何通过外部函数的返回来访问两个内部函数。
这是python中一个工作但很有趣的版本:
def counter():
foo = {'bar': 0}
def increment():
foo['bar'] += 1
return foo['bar']
def printVal():
return foo['bar']
return {'increment': increment, 'printVal': printVal}
func = counter()
func['increment']()
func['printVal']()
是否有某种更优雅或“pythonic”的方式来编写这样的闭包?
答案 0 :(得分:3)
Python在闭包中没有其他语言那么强大。首先,它只支持读取“闭合”变量,其次,return
语句使它更加尴尬。
另一方面,它对类非常简洁,所以如果你想要一个有两个函数的数据成员,我会用一个类来做:
class Counter:
def __init__(self, c=0):
self.count = c
def increment(self):
self.count += 1
def printVal(self):
return self.count
c = Counter()
c.increment()
print(c.printVal())
我敢说,在这种情况下,这将是pythonic方式。
修改强>
在看到关于跟踪函数调用的评论后,我添加了这个。你可以通过一个闭包来实现它:
# this is the tracked function
def add2(a, b):
return a + b
# this is the count tracker
def counterize(func):
c = [0]
def counter_func(*args, **kw):
c[0] += 1
counter_func.count = c[0]
return func(*args, **kw)
return counter_func
cadd2 = counterize(add2)
print(cadd2(1, 2))
print(cadd2(3, 4))
print('Called %s times' % cadd2.count)
>>>
3
7
Called 2 times
但这不是Python中的惯用语。将count
保留在函数对象中是一个很好的技巧,但这就是它的本质。一个恶作剧。另一方面,在LISP或Scala中,闭包会更自然,但是,我认为不可能将count
保留为字段,而是将其与结果一起返回。 / p>
我想说的是,在这种情况下,再次,惯用的Python代码将通过类,它是更容易理解的IMO,并且具有相同的代码长度:
class Counterize:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
return self.func(*args, **kwargs)
cadd2 = Counterize(add2)
print(cadd2(1, 2))
print(cadd2(3, 4))
print('Called %s times' % cadd2.count)
输出结果是一样的。 __call__
的目的是允许通过括号调用将对象视为函数。
答案 1 :(得分:1)
只需实施__getitem__
class Foo:
class_attributes = {'a': 3,
'b': 5}
def __getitem__(self, name):
return Foo.class_attributes[name]
f = Foo()
print f['a']
输出:
3
答案 2 :(得分:0)
我认为您想要达到的目标类似于以下示例:
def makeInc(x):
def inc(y):
# x is "attached" in the definition of inc
return y + x
return inc
incOne = makeInc(1)
incFive = makeInc(5)
incOne (5) # returns 6
incFive(5) # returns 10
您需要创建闭包的pythonic方式。所以上面的例子演示了如何做到这一点。