closures
Published 2025-05-13
Closures are functions that “remember” variables in an enclosing scope/function, even after that function has finished executing.
Example:
def power_factory(exponent): def raise_to_power(base): return base ** exponent return raise_to_power
square = power_factory(2)cube = power_factory(3)
print(square(5)) # Outputs 25print(cube(5)) # Outputs 125The inner function raise_to_power “remembers” the exponent even after power_factory(exponent) has finished executing.
def outer_function(text): # This 'text' variable is part of the enclosing scope message = text
def inner_function(): # inner_function() "closes over" the 'message' variable print(message) return inner_function
my_printer = outer_function("Hello 1")my_printer() # Output: Hello 1
another_printer = outer_function("Hello 2")another_printer() # Output: Hello 2
my_printer() # Output: Hello 1def counter_maker(): count = 0 # This state is "closed over" def incrementer(): nonlocal count # Needed to modify the 'count' from the outer scope count += 1 return count return incrementer
c1 = counter_maker()print(c1()) # Output: 1print(c1()) # Output: 2
c2 = counter_maker() # A new, independent counterprint(c2()) # Output: 1A more practical use case: generating parameter-specific force functions based on the particle type and associated mass, charge, etc. The below code is AI-generated.
def create_force_calculator(particle_specific_params, global_simulation_settings): # particle_specific_params could be a dictionary like {'mass': 10, 'charge': -1} # global_simulation_settings could be {'magnetic_field': 5, 'temperature': 300}
def calculate_force(current_particle_state): # This inner function uses particle_specific_params and global_simulation_settings # along with the particle's current_particle_state (e.g., velocity, position) # to compute the force. # Example: force = 0.0 # ... complex physics calculation using all these remembered parameters ... if 'charge' in particle_specific_params: force += particle_specific_params['charge'] * global_simulation_settings['magnetic_field'] * current_particle_state['velocity'] force -= 0.1 * current_particle_state['velocity'] * (global_simulation_settings['temperature']/100) # A made-up drag return force
return calculate_force
# Now you can create specialized force calculators:electron_params = {'mass': 0.1, 'charge': -1}proton_params = {'mass': 10, 'charge': 1}sim_settings = {'magnetic_field': 2.0, 'temperature': 273}
calculate_electron_force = create_force_calculator(electron_params, sim_settings)calculate_proton_force = create_force_calculator(proton_params, sim_settings)
# Later in your simulation loop:electron_state = {'velocity': 100}proton_state = {'velocity': 50}
force_on_electron = calculate_electron_force(electron_state)force_on_proton = calculate_proton_force(proton_state)
print(f"Force on electron: {force_on_electron}")print(f"Force on proton: {force_on_proton}")