Python Variable Assignment. Explaining One Of The Most Fundamental... | by Farhad Malik | Towards Data Science

This article aims to explain how Python variable assignment works.
Variables store information that can be used and/or changed in your program. This information can be an integer, text, collection, etc.
Variables are used to hold user inputs, local states of your program, etc.
Variables have a name so that they can be referenced in the code.
The fundamental concept to understand is that everything is an object in Python.
Python supports numbers, strings, sets, lists, tuples, and dictionaries. These are the standard data types. I will explain each of them in detail.
Assignment sets a value to a variable.
To assign variable a value, use the equals sign (=)
myFirstVariable = 1mySecondVariable = 2myFirstVariable = "Hello You"
Assigning a value is known as binding in Python. In the example above, we have assigned the value of 2 to mySecondVariable.
Note how I assigned an integer value of 1 and then a string value of “Hello You” to the same myFirstVariable variable. This is possible due to the fact that the data types are dynamically typed in python.
This is why Python is known as a dynamically typed programming language.
If you want to assign the same value to more than one variable then you can use the chained assignment:
myFirstVariable = mySecondVariable = 1
Integers, decimals, floats are supported.
value = 1 #integervalue = 1.2 #float with a floating point
Longs are also supported. They have a suffix of L e.g. 9999999999999L
Textual information. Strings are a sequence of letters.
A string is an array of characters
A string value is enclosed in quotation marks: single, double or triple quotes.
name = 'farhad'name = "farhad"name = """farhad"""
Strings are immutable. Once they are created, they cannot be changed e.g.
a = 'me'Updating it will fail:a[1]='y'It will throw a Type Error
When variables are assigned a new value then internally, Python creates a new object to store the value.
Therefore a reference/pointer to an object is created. This pointer is then assigned to the variable and as a result, the variable can be used in the program.
We can also assign one variable to another variable. All it does is that a new pointer is created which points to the same object:
a = 1 #new object is created and 1 is stored there, new pointer is created, the pointer connects a to 1b = a #new object is not created, new pointer is created only that connects b to 1
Variables declared within a function, as an example, can only exist within the block.
Once the block exists, the variables also become inaccessible.
def some_funcion():  TestMode = Falseprint(TestMode) <- Breaks as the variable doesn't exist outside
In Python, if-else and for/while loop block doesn’t create any local scope.
for i in range(1, 11):    test_scope = "variable inside for loop"print(test_scope)
Output:
variable inside for loop
With if-else block
is_python_awesome = Trueif is_python_awesome:    test_scope = "Python is awesome"print(test_scope)
Output:
Python is awesome
Variables that can be accessed from any function have a global scope. They exist in the __main__ frame.
You can declare a global variable outside of functions. It’s important to note that to assign a global variable a new value, you will have to use the “global” keyword:
TestMode = Truedef some_function():  global TestMode  TestMode = Falsesome_function()print(TestMode) <--Returns False
Removing the line “global TestMode” will only set the variable to False within the some_function() function.
Note: Although I will write more on the concept of modules later, but if you want to share a global variable across a number of modules then you can create a shared module file e.g. configuration.py and locate your variable there. Finally, import the shared module in your consumer modules.
If you want to find the type of a variable, you can implement:
type('farhad')--> Returns <type 'str'>
Commas are treated as a sequence of variables e.g.
9,8,7 are three numeric variables
Allows us to perform computation on variables
Python supports basic *, /, +, -
Python also supports floor division
1//3  #returns 01/3 #returns 0.333
Additionally, python supports exponentiation via ** operator:
2**3 = 2 * 2 * 2 = 8
Python supports Modulus (remainder) operator too:
7%2 = 1
There is also a divmod in-built method. It returns the divider and modulus:
print(divmod(10,3)) #it will print 3 and 1 as 3*3 = 9 +1 = 10
Concat Strings:
'A' + 'B' = 'AB'
Remember string is an immutable data type, therefore, concatenating strings creates a new string object.
Repeat String:
‘A’*3 will repeat A three times:  AAA
Slicing:
y = 'Abc'y[:2] = aby[1:] = bcy[:-2] = ay[-2:] = bc
Reversing:
x = 'abc'x = x[::-1]
Negative Index:
If you want to start from the last character then use a negative index.
y = 'abc'print(y[:-1]) # will return ab
It is also used to remove any new line carriages/spaces.
Each element in an array gets two indexes:
From left to right, the index starts at 0 and increments by 1
From right to left, the index starts at -1 and decrements by 1
Therefore, if we do y[0] and y[-len(y)] then both will return the same value: ‘a’
y = 'abc'print(y[0])print(y[-len(y)])
Finding Index
name = 'farhad'index = name.find('r')#returns 2name = 'farhad'index = name.find('a', 2) # finds index of second a#returns 4
For Regex, use:
split(): splits a string into a list via regex
sub(): replaces matched string via regex
subn(): replaces matched string via regex and returns the number of replacements
str(x): To string
int(x): To integer
float(x): To floats
tuple(list) : To tuple: print(tuple([1,2,3]))
list(tuple(1,2,3)): To list: print(list((1,2,3)))
Remember list is mutable (can be updated) and tuple is immutable (read-only)
The set is an unordered data collection without any duplicates. We can define a set variable as:
a = {1,2,3}
Intersect Sets
To get what’s common in two sets
a = {1,2,3}b = {3,4,5}c = a.intersection(b)
Difference In Sets
To retrieve the difference between the two sets:
a = {1,2,3}b = {3,4,5}c = a.difference(b)
Union Of Collections
To get a distinct combined set of two sets
a = {1,2,3}b = {3,4,5}c = a.union(b)
Used to write conditional statements in a single line.
Syntax:
[If True] if [Expression] Else [If False]
For example:
Received = True if x == 'Yes' else False
I will attempt to explain the important subject of Object Identity now.
Whenever we create an object in Python such as a variable, function, etc, the underlying Python interpreter creates a number that uniquely identifies that object. Some of the objects are created up-front.
When an object is not referenced anymore in the code then it is removed and its identity number can be used by other variables.
Python code is loaded into frames that are located into a Stack.
Functions are loaded in a frame along with their parameters and variables.
Subsequently, frames are loaded into a stack in the right order of execution.
Stack outlines the execution of functions. Variables that are declared outside of functions are stored in __main__
Stacks executes the last frame first.
You can use traceback to find the list of functions if an error is encountered.
dir() and help()
dir() -displays defined symbols
help() — displays documentation
Consider the code below:
var_one = 123def func_one(var_one):    var_one = 234    var_three = 'abc'var_two = 456print(dir())
var_one and var_two are the two variables that are defined in the code above. Along with the variables, a function named func_one is also defined. An important note to keep in mind is that everything is an object in Python, including a function.
Within the function, we have assigned the value of 234 to var_one and created a new variable named var_three and assigned it a value of ‘abc’.
Now, let’s understand the code with the help of dir() and id()
The above code and its variables and functions will be loaded in the Global frame. The global frame will hold all of the objects that the other frames require. As an example, there are many built-in methods loaded in Python that are available to all of the frames. These are the function frames.
Running the above code will print:
[‘__annotations__’, ‘__builtins__’, ‘__cached__’, ‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__spec__’, ‘func_one’, ‘var_one’, ‘var_two’]
The variables that are prefixed with __ are known as the special variables.
Notice that the var_three is not available yet. Let’s execute func_one(var_one) and then assess the dir():
var_one = 123def func_one(var_one):    var_one = 234    var_three = 'abc'var_two = 456func_one(var_one)print(dir())
We will again see the same list:
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'func_one', 'var_one', 'var_two']
This means that the variables within the func_one are only within the func_one. When func_one is executed then a Frame is created. Python is top-down therefore it always executes the lines from top to the bottom.
The function frame can reference the variables in the global frame but any other function frame cannot reference the same variables that are created within itself. As an instance, if I create a new function func_two that tries to print var_three then it will fail:
var_one = 123def func_one(var_one):    var_one = 234    var_three = 'abc'var_two = 456def func_two():    print(var_three)func_one(var_one)func_two()print(dir())
We get an error that NameError: name ‘var_three’ is not defined
What if we create a new variable inside func_two() and then print the dir()?
var_one = 123def func_one(var_one):    var_one = 234    var_three = 'abc'var_two = 456def func_two():    var_four = 123    print(dir())func_two()
This will print var_four as it is local to func_two.
This is by far one of the most important concepts to understand in Python. Python has an id() function.
When an object (function, variable, etc.) is created, CPython allocates it an address in memory. The id() function returns the “identity” of an object. It is essentially a unique integer.
As an instance, let’s create four variables and assign them values:
variable1 = 1variable2 = "abc"variable3 = (1,2)variable4 = ['a',1]#Print their Idsprint('Variable1: ', id(variable1))print('Variable2: ', id(variable2))print('Variable3: ', id(variable3))print('Variable4: ', id(variable4))
The ids will be printed as follows:
Variable1: 1747938368Variable2: 152386423976Variable3: 152382712136Variable4: 152382633160
Each variable has been assigned a new integer value.
The first assumption is that whenever we use the assignment “=” then Python creates a new memory address to store the variable. Is it 100% true, not really!
I am going to create two variables and assign them to the existing variables.
variable5 = variable1variable6 = variable4print('Variable1: ', id(variable1))print('Variable4: ', id(variable4))print('Variable5: ', id(variable5))print('Variable6: ', id(variable6))
Python printed:
Variable1: 1747938368Variable4: 819035469000Variable5: 1747938368Variable6: 819035469000
Notice that Python did not create new memory addresses for the two variables. This time, it pointed both of the variables to the same memory location.
Let’s set a new value to the variable1. Remember 2 is an integer and integer is an immutable data type.
print('Variable1: ', id(variable1))variable1 = 2print('Variable1: ', id(variable1))
This will print:
Variable1: 1747938368Variable1: 1747938400
It means whenever we use the = and assign a new value to a variable that is not a variable reference then internally a new memory address is created to store the variable. Let’s see if it holds!
What happens when the variable is a mutable data type?
variable6 is a list. Let’s append an item to it and print its memory address:
print('Variable6: ', id(variable6))variable6.append('new')print('Variable6: ', id(variable6))
Note that the memory address remained the same for the variable as it is a mutable data type and we simply updated its elements.
Variable6: 678181106888Variable6: 678181106888
Let’s create a function and pass a variable to it. If we set the value of the variable inside the function, what will it do internally? let’s assess
def update_variable(variable_to_update): print(id(variable_to_update))update_variable(variable6)print(’Variable6: ', id(variable6))
We get:
678181106888Variable6: 678181106888
Notice that the id of variable_to_update points to the id of the variable 6.
This means that if we update the variable_to_update in a function and if variable_to_update is a mutable data type then we’ll update variable6.
variable6 = [’new’]print(’Variable6: ', variable6def update_variable(variable_to_update):    variable_to_update.append(’inside’)update_variable(variable6)print('Variable6: ', variable6)
This printed:
Variable6: [‘new’]Variable6: [‘new’, ‘inside’]
It shows us that the same object is updated within the function as it was expected because both of them had the same ID.
If we assign a new value to a variable, regardless of if it’s immutable and mutable data type then the change will be lost once we come out of the function:
print('Variable6: ', variable6)def update_variable(variable_to_update):    print(id(variable_to_update))    variable_to_update = ['inside']update_variable(variable6)print('Variable6: ', variable6)
Variable6: [‘new’]344115201992Variable6: [‘new’]
Now an interesting scenario: Python doesn’t always create a new memory address for all new variables. Let me explain.
Finally, what if we assign two different variables a string value such as ‘a’. Will it create two memory addresses?
variable_nine = "a"variable_ten = "a"print('Variable9: ', id(variable_nine))print('Variable10: ', id(variable_ten))
Notice, both the variables have the same memory location:
Variable9: 792473698064Variable10: 792473698064
What if we create two different variables and assign them a long string value:
variable_nine = "a"*21variable_ten = "a"*21print('Variable9: ', id(variable_nine))print('Variable10: ', id(variable_ten))
This time Python created two memory locations for the two variables:
Variable9: 541949933872Variable10: 541949933944
This is because Python creates an internal cache of values when it starts up. This is done to provide faster results. It creates a handful of memory addresses for small integers such as between -5 to 256 and smaller string values. This is the reason why both of the variables in our example had the same ID.
This article explained how variables are assigned.
If you want to understand Python in detail then read this article: