杰瑞科技汇

Python函数闭包如何创建与使用?

Of course! Let's break down funcclosure (more commonly just called a closure) in Python. It's a powerful and elegant feature that every Python developer should understand.

Python函数闭包如何创建与使用?-图1
(图片来源网络,侵删)

What is a Closure? (The Simple Definition)

A closure is a function object that remembers values from the environment in which it was created, even if that environment is no longer active.

Let's break that down:

  • Function Object: In Python, functions are "first-class citizens," meaning you can treat them like any other variable (pass them as arguments, return them from other functions, etc.).
  • Remembers values from its creation environment: This is the key part. A closure "captures" local variables from the outer function where it was defined.

The Three Conditions for a Closure

For a closure to be created, three conditions must be met:

  1. There must be a nested function (a function defined inside another function).
  2. The nested function must reference a variable from the outer function's scope.
  3. The outer function must return the nested function.

If all three are true, you have a closure.

Python函数闭包如何创建与使用?-图2
(图片来源网络,侵删)

A Concrete Example

Let's build a closure step-by-step.

Example: A Simple Multiplier

Imagine you want to create specialized multiplication functions. Instead of writing multiply_by_2(x), multiply_by_3(x), etc., you can create a "factory" function that creates these specialized functions for you.

def make_multiplier(n):
    """This is the outer function."""
    print(f"Creating a multiplier for {n}")
    def multiplier(x):
        """This is the nested function."""
        # This is the crucial part: it 'captures' the variable 'n'
        # from the outer function's scope.
        return x * n
    # The outer function returns the nested function object.
    return multiplier
# --- Let's use it ---
# Create a function that multiplies by 3
multiply_by_3 = make_multiplier(3)
# Create a function that multiplies by 5
multiply_by_5 = make_multiplier(5)
# Now, let's use these new functions
print(f"5 * 3 = {multiply_by_3(5)}")
print(f"10 * 5 = {multiply_by_5(10)}")
# Let's inspect the functions to see the closure
print(f"Type of multiply_by_3: {type(multiply_by_3)}")
print(f"__closure__ of multiply_by_3: {multiply_by_3.__closure__}")

Output:

Creating a multiplier for 3
Creating a multiplier for 5
5 * 3 = 15
10 * 5 = 50
Type of multiply_by_3: <class 'function'>
__closure__ of multiply_by_3: (<cell at 0x...: int object at 0x...>,)

What's Happening Here?

  1. make_multiplier(3) is called.

    Python函数闭包如何创建与使用?-图3
    (图片来源网络,侵删)
    • The variable n is set to 3.
    • The multiplier function is defined inside make_multiplier. It knows about n.
    • make_multiplier returns the multiplier function object. Let's call this returned object multiply_by_3.
  2. The make_multiplier function finishes and its local scope is destroyed. Normally, the variable n would be gone. But because multiply_by_3 is a closure, it holds a reference to that n value.

  3. multiply_by_3(5) is called.

    • Even though make_multiplier is long gone, the multiply_by_3 function still has access to the n it captured (which is 3).
    • It calculates 5 * 3 and returns 15.

The __closure__ attribute confirms this. It shows a "cell" object containing the value of n that was captured. This is the mechanism that keeps the variable "alive" after the outer function has finished.


Practical Use Cases for Closures

Closures aren't just a theoretical concept. They are used all the time, often without you even realizing it.

Use Case 1: Function Factories (as shown above)

This is the most common pattern. You create a function that generates other functions with pre-configured behavior.

def make_greeter(greeting):
    def greeter(name):
        return f"{greeting}, {name}!"
    return greener
say_hello = make_greeter("Hello")
say_goodbye = make_greeter("Goodbye")
print(say_hello("Alice"))   # Output: Hello, Alice!
print(say_goodbye("Bob"))   # Output: Goodbye, Bob!

Use Case 2: Data Hiding / Encapsulation

Closures can be used to create private-like state. You can't access the "private" variable directly from the outside, but the inner functions can.

def counter_generator():
    count = 0  # This is a "private" variable
    def increment():
        nonlocal count  # Needed to modify a non-local variable
        count += 1
        return count
    def get_count():
        return count
    return increment, get_count
# We get two functions back
increment, get_count = counter_generator()
print(increment())  # Output: 1
print(increment())  # Output: 2
print(increment())  # Output: 3
print(get_count())  # Output: 3
# You cannot directly access or modify 'count'
# This would raise an error:
# print(count)  # NameError: name 'count' is not defined

This pattern is a simple way to achieve what other languages do with classes and private members.

Use Case 3: Decorators

Decorators are a core feature in Python, and they are fundamentally built on closures. A decorator is a function that takes another function as an argument and extends its behavior without explicitly modifying it.

import time
def timing_decorator(func):
    """This is the outer function (the decorator)."""
    def wrapper(*args, **kwargs):
        """This is the inner function (the closure)."""
        start_time = time.time()
        result = func(*args, **kwargs) # Call the original function
        end_time = time.time()
        print(f"'{func.__name__}' took {end_time - start_time:.4f} seconds to run.")
        return result
    return wrapper
@timing_decorator
def slow_function():
    time.sleep(1)
# When you call slow_function(), you are actually calling the wrapper()
slow_function()

Output:

'slow_function' took 1.0021 seconds to run.

Here, timing_decorator returns the wrapper function, which has "closed over" the func variable. This allows wrapper to call the original function and add timing logic around it.


Closures vs. Lambdas

You can often achieve the same result with a lambda function. Lambdas are just a more concise way to write simple, anonymous functions.

Let's rewrite our first multiplier example using a lambda:

def make_multiplier_lambda(n):
    return lambda x: x * n
multiply_by_7 = make_multiplier_lambda(7)
print(multiply_by_7(10)) # Output: 70

This works perfectly and is very clean. However, for more complex logic (multiple lines, statements, etc.), a standard def function is more readable and powerful. Closures created with def are often easier to debug and understand because they have a name and can have docstrings.

Summary

Feature Description
What it is A function that remembers variables from its enclosing scope.
How it's made A nested function that references a non-local variable, and the outer function returns it.
Key Mechanism The __closure__ attribute, which holds references to the captured variables.
Why use it? To create function factories, hide state (encapsulation), and build powerful decorators.
Pythonic Use It's a fundamental building block for many advanced Python patterns.
分享:
扫描分享到社交APP
上一篇
下一篇