Python: Variables and Scope

When a program runs, it stores the data it requires, in the memory(RAM). A variable is used to store a reference address of a memory. So the program can store that in the reference address and retrieve data when required.

In simple language-

A variable is a named identifier(of some memory location), and we can use the named identifier to store data on it.

A valid identifier contains a nonempty sequence of characters, with a starting character and then other characters. We have discussed the variable/identifier naming rules in later sections.

NOTES

Python variables are not data storage. Rather the data object is saved in memory, and the variable just references that data object.

Variable Declaration

To define a variable we just need an identifier(which is valid). We can assign any value to the identifier and use it as a variable.

Check the following code:

# variable.py

# Declare a variable and assign value
my_val = 100

print(my_val)

# Change the value of the variable
my_val = 900

print(my_val)

# Change the value again
my_val = my_val * 2

print(my_val)
Python

Output:

100
900
1800
Plaintext

Here are some more examples of variable declaration assignments in Python-

In the code below we have used 2 variables-

  • siteName
  • siteURL

As we can see, we can store data/values, in these named identifiers, and use these data/values when we need them, later in the program.

# site_info.py

# Here we have used the variable name
# "siteName" to store the name of the site
siteName = "BigBoxCode"

# Here we are using the variable
# "siteName" to print the value stored in it
print("Name of the site is:" + siteName)

# Here we are taking some input
# and saving in the variable "siteURL"
siteURL = input("Enter the URL of {}: ".format(siteName)) 
# the above line will prompt for an input and will continue after we input some string using keyboard


# Here we are using the "siteURL" variable
print("Entered url: " + siteURL)
Python

Output:

It will generate output as below. In the process, the script will prompt for input. So we have to input some string, and then press enter “enter”

Name of the site is:BigBoxCode
Enter the URL of BigBoxCode: bigboxcode.com
Entered url: bigboxcode.com
Plaintext

Variable Reassignment

We can assign any type of value in Python, and then replace it by reassigning some other type of value-

# variable_assign.py

# Assign some integer value
big_box = 20

print("Value of big_box: ", big_box)
print("Type of big_box: ", type(big_box))

# Assign string to the same variable
big_box = "Some string value here"

print("Value of big_box: ", big_box)
print("Type of big_box: ", type(big_box))

# Assign some float to the same variable
big_box = 99.99

print("Value of big_box: ", big_box)
print("Type of big_box: ", type(big_box))
Python

Output:

Value of big_box:  20
Type of big_box:  <class 'int'>

Value of big_box:  Some string value here
Type of big_box:  <class 'str'>

Value of big_box:  99.99
Type of big_box:  <class 'float'>
Plaintext

Variable Naming Rules

Variable names should follow certain rules. We can not just name a variable anything we want, as that can cause some readability issues.

WARNING

Variable(identifier) names are case-sensitive. So my_var, My_Var, and mY_VAR represent different variables.

Here are the criteria for a valid Python identifier. An identifier should be-

  • A non-empty sequence of characters.
  • Must start with a letter(a-z, A-Z, non-English Unicode characters) or an underscore(_).
  • Can only contain letters(a-z, A-Z, non-English Unicode characters), numbers(0-9), and underscore(_).
  • Can not be a reserved Python keyword(mentioned below).

WARNING

The following keywords are reserved keywords in Python, and can not be used as variable names in Python-

and
as
assert
async
await
break
class
continue
def
del
elif
else
except
false
finally
for
from
global
if
import
in
is
lambda
None
nonlocal
not
or
pass
raise
return
True
try
while
with
yield

Try the following code-

for = 100
Python

Output will be-

 File "variable.py", line 1
    for = 100
        ^
SyntaxError: invalid syntax
Plaintext

If you want to get the list of reserved(builtin) keywords, then use the following code-

dir()
dir(__builtins__)
Python

You will get the list of all keywords, that can not be used as an identifier-

['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']


['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError',
...... 
'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
Plaintext

Variable Naming Convention

Follow the conventions mentioned below for an appropriate name for a variable-

  • The name should be meaningful and represent the purpose of the variable.
  • If the variable name contains multiple words then separate those with an underscore(_). i.e. first_name, customer_id, etc.
  • Do not use double underscore(__) in the beginning or end of the variable name.
  • Though a single underscore(_) is a valid variable name, but do not use it. (only use in case you want to ignore the variable)

Variable as Object Reference

In Python, the variables do not store some values. Instead, these variables work as references to objects.

Especially, for integer, float, string, etc. data types the variables behave just as references, because of the immutable behavior of those data.

Object Referencing

Let’s assign some integer value to variables and check the id-

i1 = 100
i2 = 100
i3 = 200
i4 = i1

print("integer i1: ", id(i1))
print("integer i2: ", id(i2))
print("integer i3: ", id(i3))
print("integer i4: ", id(i4))
Python

Output:

The variable with the same value has the same ID, also the variable assigned with reference has the same ID.

ID ofIDNote
integer i1139663237303632Value is 100
integer i2139663237303632Value is 100
integer i3139663237306832
integer i4139663237303632Value assigned from i1

This is how it looks-

Python variable reference for integer
Python variable reference for integer

Check the same thing with float-

f1 = 99.99
f2 = 99.99
f3 = 3.5
f4 = f1

print("float f1: ", id(f1))
print("float f2: ", id(f2))
print("float f3: ", id(f3))
print("float f4: ", id(f4))
Python

Output:

The variable with the same value has the same ID, also the variable assigned with reference has the same ID.

ID ofIDNote
float f1139663238335760Value is 99.99
float f2139663238335760Value is 99.99
float f3139663238342352
float f4139663238335760Value assigned from f1

This is how it looks-

Python variable reference for float
Python variable reference for float

And the same with strings-

s1 = "bigboxcode"
s2 = "bigboxcode"
s3 = "BigBoxCode"
s4 = s1

print("string s1: ", id(s1))
print("string s2: ", id(s2))
print("string s3: ", id(s3))
print("string s4: ", id(s4))
Python

Output:

The variable with the same value has the same ID, also the variable assigned with reference has the same ID.

ID ofIDNote
float s1139663236856368Value is ‘bigboxcode’
float s2139663236856368Value is ‘bigboxcode’
float s3139663236856560
float s4139663236856368Value assigned from s1

This is how it looks-

Python variable reference for String
Python variable reference for String

Object Reference Rebounding

Once a variable is assigned a value, it works as an identifier to a reference of an object. But what happens when we reassign another value to that variable?

The variable will be rebound to another object reference.

Check the example below-

# Define integers i1 and i2
i1 = 100
i2 = 100

print(f"i1 => value: {i1} || type: {type(i1)} || id: {id(i1)}")
print(f"i2 => value: {i2} || type: {type(i2)} || id: {id(i2)}")

# Define another integer
i3 = 200

print(f"i3 => value: {i3} || type: {type(i3)} || id: {id(i3)}")

# Assign 200 to i2
i2 = 200

print(f"i2 => value: {i2} || type: {type(i2)} || id: {id(i2)}")

# Define a string s1
s1 = "bigboxcode"

print(f"s1 => value: {s1} || type: {type(s1)} || id: {id(s1)}")

# Change value of i2 to the same value of s2
i2 = "bigboxcode"

print(f"i2 => value: {i2} || type: {type(i2)} || id: {id(i2)}")

# Change value of i2 again to a float value
i2 = 99.99

print(f"i2 => value: {i2} || type: {type(i2)} || id: {id(i2)}")

# Define a float
f1 = 99.99

print(f"f1 => value: {f1} || type: {type(f1)} || id: {id(f1)}")

# Check the details of i2
print(f"i2 => value: {i2} || type: {type(i2)} || id: {id(i2)}")
Python

Output:

After every reassignment, the value and type of “i2” changes. And also the reference changes. If the value already exists in memory, it refers to that existing object.

i1 => value: 100 || type: <class 'int'> || id: 139809004637520
i2 => value: 100 || type: <class 'int'> || id: 139809004637520

i3 => value: 200 || type: <class 'int'> || id: 139809004640720
i2 => value: 200 || type: <class 'int'> || id: 139809004640720

s1 => value: bigboxcode || type: <class 'str'> || id: 139809004190384
i2 => value: bigboxcode || type: <class 'str'> || id: 139809004190384

i2 => value: 99.99 || type: <class 'float'> || id: 139809003179280
f1 => value: 99.99 || type: <class 'float'> || id: 139809003179280
i2 => value: 99.99 || type: <class 'float'> || id: 139809003179280
Plaintext

Object Reference Rebound on Type Change

What happens when a variable is assigned a different type of data, and the type is changed and the value already exists in memory?

The new value will be taken from the existing object reference.

# Assign some integer values
i1 = 100
i2 = 100

print(f"i1 => value: {i1} || type: {type(i1)} || id: {id(i1)}")
print(f"i2 => value: {i2} || type: {type(i2)} || id: {id(i2)}")

# Assign some string values
s1 = "100"
i2 = "100"

print(f"s1 => value: {s1} || type: {type(s1)} || id: {id(s1)}")
print(f"i2 => value: {i2} || type: {type(i2)} || id: {id(i2)}")

# Convert i2 to integer form string

print(f"i2 => value: {i2} || type: {type(int(i2))} || id: {id(int(i2))}")
Python

Output:

After converting the value of “i2” from string(“100”) to integer(100), it started referencing the already exiting integer(100) object.

i1 => value: 100 || type: <class 'int'> || id: 140430198689104
i2 => value: 100 || type: <class 'int'> || id: 140430198689104

s1 => value: 100 || type: <class 'str'> || id: 140430198241456
i2 => value: 100 || type: <class 'str'> || id: 140430198241456

i2 => value: 100 || type: <class 'int'> || id: 140430198689104
Plaintext

Get Object from ID

We have already seen that we can get the object ID of any Python object using the “id” function.

Now how to do the reverse? How to get the object if we have the ID?

We can use the package “ctypes” for that. Check the code below-

import ctypes

big_box_int = 100

big_box_int_id = id(big_box_int)

print(f'value of big_box_id is: {big_box_int}')
print(f'id of big_box_id is: {big_box_int_id}')

# Fetch value using the id
object_from_id = ctypes.cast(big_box_int_id, ctypes.py_object)

print("Object from id: ", object_from_id)
print("Value from object(of id): ", object_from_id.value)
Python

Output:

value of big_box_id is: 100
id of big_box_id is: 139730918952272

Object from id:  py_object(100)
Value from object(of id):  100
Plaintext

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.