Variable Scope in Python and Postgres

Introduction

In this article, we will learn the best use of variable scope in our Python and Postgres applications. What you can expect in this lesson:

  • How and why? We will study how and where to define variables so that their scope is predictable in reach. We’ll also look at how variable scope works in both Python and PostgreSQL. Finally, we will use both Python and Postgres code samples throughout this lesson to show you how variable scope works in context.
  • What else? Because functions have a direct relationship to variable scope in both Python and Postgres, we will take a quick look at what a function is in each framework and how to define it.

Prerequisites

  • SQL: A beginner- or novice- level of understanding of how PostgreSQL queries work. You may wish to find an IDE or “database manager” application that allows you to manage your Postgres database. Most of them include a tool to help you write SQL and most of them have a free version available.
  • Naming conventions: Shows why you may want to prefix your variables, column names, table names, etc. as you see done in this article. For example, naming “tvariable” with the “t” prefix to define it as a “text” (string) object and “tbl_” before table names in order to clearly distinguish those objects as tables. The tutorial goes a bit deeper, as well, talking about how to name variables based on a hierarchy system.

Overview of Python Functions

A Python function is code that executes when referenced by another part of your application. You can send data to functions when you call them, or not. That optional data is known as a “parameter(s)”. You can have a function return data (or not). Functions are used for many purposes, including:

  • Boost Efficiency. Rather than use ten lines of code for populating variables with data pulled from a Postgres table, those ten lines of script can be placed in a function that you reference from every module that requires it and every time, you see “GetUserSecurityLevel()” instead of those ten lines of script multiple times.
  • Increase Readability. Boost code readability for yourself and anyone who inherits your application by giving your function a name that exemplifies the function’s purpose, like “GetUserSecurityLevel()”, for example.
  • Modularize the application. Within one module or page, you may want to do certain actions more than one time. Rather than code that set of actions more than once, introducing excess redundancy, added difficulty for maintenance, and error potential, you can refer to a function that is written once and lives in one spot. You may place a function in a file all by itself so you can refer to it from different modules or pages and can be easily added to other projects!

Syntax for a Function in Python

def function_name(parameters):
    # code run by the function

Analysis

  • def: In Python we use the “def” keyword to designate a function.
  • function_name: This is where we name a function. As mentioned above in the introduction, it is important to give the function a name that reflects how the function will be used or what problem it will solve.
  • parameters: This is OPTIONAL data you give your function.

Note: Functions can return data or merely accomplish an operation.

Example of use of a Python function

def Pluralize(t_source_string):
    return t_source_string + "s"

print (Pluralize("Mom"))

The above example will print “Moms” because the function we named “Pluralize” will take a source string and add an “s” to the end of it.

Variable Scope in Python

i_variable_1 = 'A'

def change_value(i_variable_2):
    i_variable_1 = i_variable_2

print(i_variable_1)
change_value('B')
print(i_variable_1)

Notice in the code above the first thing we did – outside of the function – is to set the value of “i_variable_1” to be “A”. The next thing that happens is “print(i_variable_1)”, which – as you might expect – prints “A”. Now is where you might be surprised: You would expect after the “change_value(‘B’)”, that the value of “i_variable_1” would become “B”, right? But it stays “A”. The reason is because the “i_variable_1” inside of our “change_value” function is treated by Python as a whole other variable. You could call it “local to the function” where the “i_variable_1” declared outside the function as a “global variable”.

So how do we allow the function to modify our global variable? We put the key word “global” before the variable, like you see in the following code:

i_variable_1 = 'A'

def change_value(i_variable_2):
    global i_variable = i_variable_2

print(i_variable_1)
change_value('B')
print(i_variable_1)

Now your results will look like:

A
B

Postgres Functions

CREATE OR REPLACE FUNCTION name_of_function (parameters)
RETURNS return_datatype AS $names_of_variables$
   DECLARE
      -- declaration of variables here;

   BEGIN
      -- code goes here
      RETURN { variable_name | VALUE }
   END;
   LANGUAGE plpgsql;

So that is the syntax of a PostgreSQL function. Let’s set up a larger program that includes a function and weave in some variables, so we can see how scope works in Postgres.

Before we go further, it’s important to note that Postgres doesn’t have built-in global variables. In order to get around that issue, we’ll create a function called “globalized” and show you how to use it:

CREATE OR REPLACE FUNCTION globalized(a_var_name text)
RETURNS INTEGER LANGUAGE SQL AS $$
    SELECT current_setting('globalized.' || a_var_name)::INTEGER;
$$;

What we’ve done above is defined a custom configuration parameter of “globalized” and tacked it on to the beginning of any variables we want to act like a global variable in the rest of our SQL program.

Let’s write some more SQL that will utilize what we’ve created:

-- Declare "local" variables and one "global"
DECLARE
SET globalized.ID_user := 10;
i_start INT := 0;
i_increment INT := 1;
i_current INT := 1;
i_end INT := 4;
-- Tell Postgres the boundaries of our program, nested in a BEGIN..END container.
BEGIN
    -- Define our loop within a LOOP..END LOOP container.
    WHILE i_current <= i_end
        LOOP
            -- Code to be executed. In this case, we are doing two things:
            -- Incrementing our i_current variable.
            i_current := i_current + i_increment;
            -- Printing the value of local variable: i_current.
            RAISE NOTICE i_current;
            -- Printing the value of our one global variable.
            RAISE NOTICE globalized('ID_user');
        END LOOP;
END;

Look for future articles where we make more in-depth use of different variable scopes in both Python and PostgreSQL.

Conclusion

We took a brief look at how both Python and Postgres functions work, so that we could then move on to learning about variable scope in Python and Postgres. The basic idea being that sometimes you will want to keep variables isolated between function and the rest of your application and other times you’ll want your function to be able to change the value in a “global” variable. In Postgres it works slightly different, as there are no global variables, but there will be times when you will want to have a more global-type variable in Postgres that acts much like a session variable, per user. Finally, we listed the source code here in each part of this tutorial.

Pilot the ObjectRocket Platform Free!

Try Fully-Managed CockroachDB, Elasticsearch, MongoDB, PostgreSQL (Beta) or Redis.

Get Started

Keep in the know!

Subscribe to our emails and we’ll let you know what’s going on at ObjectRocket. We hate spam and make it easy to unsubscribe.