[PYTHON] Closure implementation

Let's take a look at the implementation of closures based on the content of the previous article (I investigated how the scope looks).

def counter(x):
	pprint(locals())
	def count():
		pprint(locals())
		y = x
		x += 1
		return y
	return count
c = counter(10)
print c()
print c()
print c() 

Looks like it works, but when I do, I get the following error:

Execution result


{'x': 10}
{}
Traceback (most recent call last):
  File "tes004.py", line 12, in <module>
    print c()
  File "tes004.py", line 7, in count
    y = x
UnboundLocalError: local variable 'x' referenced before assignment

The argument x of the function counter () appears as a local variable of counter (). If you just refer to the variable x from the internal function count (), you can refer to the variable x as a local variable of count (), but the assignment code ( x + = 1 ⇒ This is also the reference code. ), So it works as a variable defined in the count () function block, but an error occurs because the reference is executed before the assignment. Variables defined in the outer function can be referenced, but cannot be assigned (rewritten).

Next is a pattern that can be executed well.

def counter(x):
	pprint(locals())
	y = [x]
	def count():
		pprint(locals())
		z = y[0]
		y[0] += 1
		return z
	return count
c = counter(10)
print c()
print c()
print c() 

Execution result


{'x': 10}
{'y': [10]}
10
{'y': [11]}
11
{'y': [12]}
12

This code also seems to rewrite the variable y with the internal function count (), but it works fine because it only rewrites the contents of the list that can be referenced by the variable y. For example, changing y [0] + = 1 to y = [y [0] + 1] will result in an error. This is because we are trying to rewrite the variable y. Therefore, even if the reference destination is not a list but a class, the reference destination can be updated.

The following is an example implemented in a class.

class tcls():
	def __init__(self, x):
		self.x = x

def counter(x):
	pprint(locals())
	y = tcls(x)
	def count():
		pprint(locals())
		z = y.x
		y.x += 1
		return z
	return count
c = counter(10)
print c()
print c()
print c() 

Execution result


{'x': 10}
{'y': <__main__.tcls instance at 0x0222F788>}
10
{'y': <__main__.tcls instance at 0x0222F788>}
11
{'y': <__main__.tcls instance at 0x0222F788>}
12

Recommended Posts

Closure implementation
closure
Python closure sample
Python> function> Closure
Shakedrop's Keras implementation
Insertion sort implementation
Gradient method implementation 1
Image of closure