Introduction

Not all variables are accessible from all parts of our program, and not all variables exist for the same amount of time. Where a variable is accessible and how long it exists depend on how it is defined. We call the part of a program where a variable is accessible its scope, and the duration for which the variable exists its lifetime.

 

Global Scope

A variable which is defined in the main body of a file is called a global variable. It will be visible throughout the file, and also inside any file which imports that file. Global variables can have unintended consequences because of their wide-ranging effects – that is why we should almost never use them. Only objects which are intended to be used globally, like functions and classes, should be put in the global namespace.

 

Local Scope

A variable which is defined inside a function is local to that function. It is accessible from the point at which it is defined until the end of the function, and exists for as long as the function is executing. The parameter names in the function definition behave like local variables, but they contain the values that we pass into the function when we call it. When we use the assignment operator (=) inside a function, its default behaviour is to create a new local variable – unless a variable with the same name is already defined in the local scope.

# Global scope
a = 0

if a == 0:
    # Global scope
    b = 1

def my_function(c):
    # Local scope
    d = 3
    print(c)
    print(d)

# Call the function, passing the value 7
my_function(7)

# a and b still exist
print(a)
print(b)

# c and d don't exist anymore -- these statements will give us name errors!
print(c)
print(d)

 

Enclosing Scope

In this code, ‘b’ has local scope in function ‘blue()’, and ‘a’ has nonlocal scope in ‘blue()’. A variable scope that isn’t global or local is nonlocal. This is also called enclosing scope.

def red():
  # Enclosing scope
  a=1
  def blue():
    # Local scope
    b=2
    print(a)
    print(b)
  
  blue()
  print(a)

 

Constants

In some languages, it is possible to define special variables which can be assigned a value only once, they cannot be changed later on. We call these kinds of variables constants. Python does not allow us to set such a restriction on variables, but there is a widely used convention for marking certain variables to indicate that their values are not meant to change: we write their names in all caps, with underscores separating words.

# These variables are "constants" by convention:
NUMBER_OF_DAYS_IN_A_WEEK = 7
NUMBER_OF_MONTHS_IN_A_YEAR = 12

 

Mutable and immutable types

Some values in python can be modified, and some cannot. If a variable contains a value of an immutable type, we can only assign it a new value. We cannot alter the existing value in any way. Integers, floating-point numbers and strings are all immutable types, when we changed the values of existing variables we used the assignment operator to assign them new values.

 

Type conversion

We often need to convert data from one type to another, for example from a string to an integer or from an integer to a floating-point number. There are two kinds of type conversions in Python: implicit and explicit conversions.

Implicit conversion

We can arbitrarily combine integers and floating-point numbers in an arithmetic expression – and that the result of any such expression will always be a floating-point number. This is because Python will convert the integers to floating-point numbers before evaluating the expression. This is an implicit conversion – we don’t have to convert anything ourselves. There is usually no loss of precision when an integer is converted to a floating-point number.  Let’s have a look at an example:

result = 8.5 + 7 // 3 - 2.5

Python performs operations according to the order of precedence, and decides whether a conversion is needed on a per-operation basis. In our example // has the highest precedence, so it will be processed first. 7 and 3 are both integers and // is the integer division operator – the result of this operation is the integer 2. Now we are left with 8.5 + 2 – 2.5. The addition and subtraction are at the same level of precedence, so they are evaluated left-to-right, starting with addition. First 2 is converted to the floating-point number 2.0, and the two floating-point numbers are added, which leaves us with 10.5 – 2.5. The result of this floating-point subtraction is 2.0, which is assigned to result.

 

Explicit conversion

Converting numbers from float to int will result in a loss of precision. For example, try to convert 5.834 to an int – it is not possible to do this without losing precision. In order for this to happen, we must explicitly tell Python that we are aware that precision will be lost.

# int function converts a float to an int by discarding the fractional part
i = int(5.834)

# Ceil returns the closest integer greater than or equal to the number i.e. it always rounds up
i = math.ceil(5.834)

# Floor returns the closest integer less than or equal to the number i.e. it always rounds down
i = math.floor(5.834)

# Round returns the closest integer to the number i.e. it rounds up or down
i = round(5.834)