A Closure in Python is a function object that remembers values in enclosing scopes even if they are not present in memory.
- It is a record that stores a function together with an environment: a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.
- A Closure—unlike a plain function—allows the function to access those captured variables through the Closure’s copies of their values or references, even when the function is invoked outside their scope.
This post will demonstrate how to run another Python feature in Python4Delphi with RAD Studio: Closure in Python GUI apps and gets the output.
Prerequisites: Before we begin to work, download and install the latest Python for your platform. Follow the Python4Delphi installation instructions mentioned here. Alternatively, you can check out the easy instructions found in this video Getting started with Python4Delphi.
First, open and run our Python GUI using project Demo1 from Python4Delphi with RAD Studio. Then insert the script into the lower Memo, click the Execute button, and get the result in the upper Memo. You can find the Demo1 source on GitHub. The behind the scene details of how Delphi manages to run your Python code in this amazing Python GUI can be found at this link.
Table of Contents
1. Non-Local Variable in a Nested Function
Before reviewing deeper into what a Python Closure is, we need to understand what is a nested function and nonlocal variable first.
A function defined inside another function is called a nested function. Nested functions can access variables of the enclosing scope.
In Python, these non-local variables are read-only by default and we must declare them explicitly as non-local (using nonlocal keyword) in order to modify them.
Following is an example of a nested function accessing a non-local variable in Python GUI:
1 2 3 4 5 6 7 8 9 10 11 12 |
def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) printer() # We execute the function # Output: Hello print_msg("Hello") |
Output in Python GUI:
2. Python Closures
Closures in Python are created by function calls. Here is the example:
1 2 3 4 5 6 7 8 9 10 11 |
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) print(incOne(5)) # Prints 6 print(incFive(5)) # Prints 10 |
The call to makeInc creates a binding for x that is referenced inside the function inc. Each call to makeInc creates a new instance of this function, but each instance has a link to a different binding of x. See the output in the Python GUI below:
Notice that while in a regular closure the enclosed function fully inherits all variables from its enclosing environment, in this construct the enclosed function has only read access to the inherited variables but cannot make assignments to them:
1 2 3 4 5 6 7 8 9 10 |
def makeInc(x): def inc(y): # Incrementing x is not allowed x += y return x return inc incOne = makeInc(1) incOne(5) # UnboundLocalError: local variable 'x' referenced before assignment |
Output in Python GUI:
3. When do we have Closures in Python?
As seen from the above example, we have a closure in Python when a nested function references a value in its enclosing scope.
The criteria that must be met to create closure in Python are summarized in the following points.
- We must have a nested function (function inside a function).
- The nested function must refer to a value defined in the enclosing function.
- The enclosing function must return the nested function.
4. When to use Closures in Python?
So what are closures good for?
Closures can avoid the use of global values and provides some form of data hiding. It can also provide an object oriented solution to the problem.
When there are few methods (one method in most cases) to be implemented in a class, closures can provide an alternate and more elegant solution. But when the number of attributes and methods get larger, it’s better to implement a class.
Check out Python4Delphi which easily allows you to build Python GUIs for Windows using Delphi.