Home > Enterprise >  Can function pointers access data outside their scope?
Can function pointers access data outside their scope?

Time:10-20

I am currently learning Python pointers and I am having trouble wrapping my head around them. Let's say that you have a function that creates other functions like this:

def create_function(data):
    def new_function(other_data):
        if data.member == 0:
            other_data.member  = 1
    return new_function

test_func = create_function(object)

How would this work, since the function pointer is only able to access the data while inside the scope of create_function()? Is it only callable within the context of the containing function, or does the function object keep a reference to this data?

CodePudding user response:

The function keeps a reference to this data. (This kind of thing, a function along with "captured" variables is often called a closure).

From the function definitions section of the language reference:

Programmer’s note: Functions are first-class objects. A “def” statement executed inside a function definition defines a local function that can be returned or passed around. Free variables used in the nested function can access the local variables of the function containing the def. See section Naming and binding for details.

CodePudding user response:

python will look up for names in the sequence of local, enclosed, global and finally build-ins. in this case new_function is enclosed in create_function, so new_function will find data in create_function.

CodePudding user response:

A closure is function object that remembers values in enclosing scope .

  1. It stores function with enclosing environment.
  2. 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.

CodePudding user response:

I assume you're coming from a C background since you mentioned function pointers.

In C, a function has access to all variables in scope. This most often includes local variables declared within it as well as any arguments the function is specified to receive. More subtly, it also includes global variables which are declared in the outermost scope. Global variables are the closest analogue to what's happening here. Functions have access to them even though they're outside the function.

In C, the addresses of all global variables are known during compilation. When the function accesses this variable, it uses this address. It is static. Also, it is not possible to create new functions or variables at runtime. The variables the compiler observed cannot change.

In dynamic languages that support closures, the functions and variables are created dynamically. You can write code to generate new functions for you. You can have a function that accepts parameters specifying how the new function should behave and then generates and returns it for you. It's as if your C program had a C compiler embedded into it that could generate new functions on the fly.

In order to support these powerful features, the function must store a reference to all variables in scope, just like how the C compiler does internally. So while in C a compiled function can be nearly fully described by a simple function pointer, in Python functions are objects with a pointer to the code that will run as well as pointers to all variables in scope at the time they were created.

When the function is created, we say the variables have been captured. How these variables can change is determined by their scopes and who has access to them. Note that function scopes end when they return. If no other function captures those variables, they won't be referenced again.

Let's break down an example:

z = 0

def f(x):
    def g(y):
        return x   y   z
    return g

f(1)(2)

Here's whar's happening in this code:

  1. z is a variable in global or file scope.

    It's visible to everything below it.

  2. f is defined when execution reaches this line.

    It captures the z variable. Changing z globally will change how the function behaves. This is possible because other code also has access to z due to its global scope.

    x is not bound at this time. It only has value when the function is called.

  3. g is defined when f is called.

    It also captures z.

    Since x has now been bound to a value, it captures that too. This happens even though it is a local variable that will change every time f is called. Every new instance of g will store a reference to the x passed to the invocation of f that created it. It can be a different value every time.

    y only has value when g is called.

  4. f is called with 1 as argument.

    This creates and returns a new g function with a reference to global z and local x.

    Since f finishes executing and returns, the scope containing x is rendered inaccessible. g is now the only scope referencing this x variable. It can never be changed from outside that scope.

  5. The new g is returned and called with 2 as argument.

    Finally, a result is calculated. z refers to a global variable. x refers to the parameter in the particular invocation of f that created this g. y is the argument to the function.

    They resolve to 0 1 2 and the result is 3.

  • Related