In JavaScript I might write a function like this:
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()
I want to try to achieve a similar function using python. Particularly how I can access both inner functions via the outer function's return.
Here is a working, but funny looking, version in 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']()
Is there some sort of more elegant or 'pythonic' way of writing a closure like this?
Python is not as strong as other languages in closures. First, it supports only reading the "closed" variables, and second, the return
statement makes it a bit more awkward.
On the other hand, it is very concise with classes, so if you want a data member with two functions, I would do it with a class:
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())
I dare say that in this case, this would be the pythonic way.
EDIT
After seeing your comment about tracking function calls, I add this. You can make it by a closure, like this:
# 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
But this is not idiomatic in Python. Also keeping count
inside the function object is a nice trick, but that's what it is. A trick. In LISP or Scala on the other hand a closure would be more natural, but then, I don't think it would be possible to keep count
as a field, but, rather, return it together with the result.
I would say that in this case, again, the idiomatic Python code would be via classes, it is more comprehensible IMO and is of the same length of code:
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)
And the output would be the same. The purpose of __call__
is to allow treating the object as a function by means of calling with parenthesis.
Simply implement __getitem__
class Foo:
class_attributes = {'a': 3,
'b': 5}
def __getitem__(self, name):
return Foo.class_attributes[name]
f = Foo()
print f['a']
output:
3
I think that what you want to achieve is something like the following example :
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
You want the pythonic way of creating closures. So the above example demonstrate how to do that.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.