Basic Syntax, Variables and Data Types#
Python can do basic math straightaway, either at the python interpreter prompt:
macbookpro> python
Python 3.13.3 | packaged by conda-forge | (main, Apr 14 2025, 20:46:04) [Clang 18.1.8 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 3+3
6
>>>
or in a Jupyter notebook cell:
3+3
6
In addition to code that Python will execute, one can add “comments” to clarify what the code is doing. This is done with a #
symbol. Anything written after a #
on a given line is ignored.
# This is a comment
9+9 # Here I double 9, my favorite number
18
However the value of writing computer programs is that they are more than simple calculators performing operations on specific data types. They can generalize beyond specific numbers and represent more complex algorithms and operations on data.
Representing data in programs#
So how do we generalize over data? From mathematics we talk about different sets of numbers that we might want to represent in programs:
integers (positive, negative and zero)
real numbers (including both rational and irrational numbers)
We also talk about other kinds of things we might want to represent:
text - i.e. “HSF India” or your name
boolean values {True, False}
We usually want to represent these things within our programs, but often we don’t know the actual value, or it may change during the program. Thus in the program we give values we want to represent names, and because they may change during the execution of the program we refer to them as “variable names”.
Variable types - “dynamic typing”#
In other programming languages, e.g. C++ (C, FORTRAN, …) one has to declare the variable types (tell the compiler what kind of thing each variable is) before you actually run the program. This is called static typing as it is set and fixed in the program:
C++
#include <iostream>
int main() {
int myInt = 42;
float myFloat = 3.14;
std::cout << "Integer: " << myInt << std::endl;
std::cout << "Float: " << myFloat << std::endl;
return 0;
}
PYTHON
In Python it is not required to tell the interpreter the type for a given variable. It is inferred from the data the first time a variable is set. Variables in Python are said to be dynamically typed and that type can change as the program evolves.
x = 3 # Python will recognize that 3 is an integer
print(x)
x = 'HSF India' # Python will recognize that x now represents a string
print(x)
3
HSF India
You can use the type(varname) function to check the type of a variable.
x = 3 # Python will recognize that 3 is an integer
print(x)
print(type(x))
x = 3.14
print(x)
print(type(x))
x = 'HSF India'
print(x)
print(type(x))
x = True # Alternative is False (note capitalization)
print(x)
print(type(x))
3
<class 'int'>
3.14
<class 'float'>
HSF India
<class 'str'>
True
<class 'bool'>
Integers and Floats#
i = 42
print(i)
print(type(i))
42
<class 'int'>
x = 3.14
print(x)
print(type(x))
3.14
<class 'float'>
And as planned, one can do math with numeric data types, including setting other variables:
print(i+10)
j = 12
print(i+j)
k = i + j
print(k)
52
54
54
y = x**2 + 7
print(y)
16.8596
In addition to operations like addition (+), subtraction (-), multiplication (*) and division (/), we also can do things like get the “quotient” and “remainder” when doing integer division via the “floor division” operator (//) and “mod(ulus)” operator (%):
print('Integer division of 7 by 2 = 2 * 3 + 1')
print(7//2)
print(7%2)
print('Integer division of 7 by 4 = 1 * 4 + 1')
print(7//4)
print(7%4)
Integer division of 7 by 2 = 2 * 3 + 1
3
1
Integer division of 7 by 4 = 1 * 4 + 1
1
3
Booleans and Boolean Operations#
Often in a program we will need to represent whether something is True or False. Note that Python expects those to be capitalized.
In addition boolean operations in Python familiar from math exist, such as and, or and not:
a = False
print(a)
False
b = True
print(b)
True
print(not a)
print(not b)
print(a and b)
print(a or b)
c = True
print(a and c)
True
False
False
True
False
Strings#
Text is represented by string variables. The actual text must be included in between quotes.
s = 'Hello World!'
print(s)
print(type(s))
Hello World!
<class 'str'>
Note that both single and double quotes can be used, as long as you are consistent for a given string.
s2 = "Goodbye Cruel World!"
print(s2)
Goodbye Cruel World!
And multi-line strings are possible when demarcated with triple-quotes, e.g.
s3 = '''Hello
World!
'''
print(s3)
Hello
World!
A number of functions are available for strings, for example:
s4 = 'Hello World!'
print(s4.lower())
print(s4.upper())
print(s4.swapcase())
print(s4.lower().capitalize())
# strip() removes leading and trailing whitespace
# [lstrip() will remove only leading whitespace, rstrip() will remove only training whitespace]
s5 = ' Hello! '
print(s5)
s6 = s5.strip()
print(s6)
# We can also replace substrings
s7 = s5.replace(' ','#')
print(s7)
s8 = s7.replace('ll','--')
print(s8)
# We can split a string (default delimiter is space, but can be changed)
s9 = s4.split()
print(s9)
s10 = 'alpha|beta|gamma'
s11 = s10.split('|')
print(s11)
# And we can join lists of strings back together, using a specified delimiter (here '-')
s12 = '-'.join(s11)
print(s12)
hello world!
HELLO WORLD!
hELLO wORLD!
Hello world!
Hello!
Hello!
##Hello!#
##He--o!#
['Hello', 'World!']
['alpha', 'beta', 'gamma']
alpha-beta-gamma
And there are a number of functions to examine the nature of strings:
ss1 = 'ABC'
ss2 = 'Abc'
ss3 = 'abc'
ss4 = '123'
ss5 = 'Abc123'
ss6 = 'Abc-123'
print(ss1.islower(), ss2.islower(), ss3.islower(), ss4.islower(), ss5.islower(), ss6.islower())
print(ss1.isupper(), ss2.isupper(), ss3.isupper(), ss4.isupper(), ss5.isupper(), ss6.isupper())
print(ss1.isalpha(), ss2.isalpha(), ss3.isalpha(), ss4.isalpha(), ss5.isalpha(), ss6.isalpha())
print(ss1.isnumeric(), ss2.isnumeric(), ss3.isnumeric(), ss4.isnumeric(), ss5.isnumeric(), ss6.isnumeric())
print(ss1.isalnum(), ss2.isalnum(), ss3.isalnum(), ss4.isalnum(), ss5.isalnum(), ss6.isalnum())
# But be careful, numeric means in [0123456789]
ss7 = '12.3'
print(ss7.isnumeric())
False False True False False False
True False False False False False
True True True False False False
False False False True False False
True True True True True False
False
It is also possible to perform other types of operations with strings:
x = 'Hello'
y = 'World!'
z = x + ' ' + y
print(z)
Hello World!
However there are better ways to do this, especially as the resulting string (or printout) gets more complicated. (See f-strings below.)
Lists#
Lists are one of the most and flexible data types in basic Python. They are ordered and mutable and duplicates are allowed. The elements of a list do not need to be all of the same data type. One can append items to a list, and remove items from the list.
l1 = ['Paris', 42, 'Mumbai', 'Paris']
print(l1)
['Paris', 42, 'Mumbai', 'Paris']
l1.append(3.14)
print(l1)
['Paris', 42, 'Mumbai', 'Paris', 3.14]
l1.remove('Paris') # removes the first match
print(l1)
[42, 'Mumbai', 'Paris', 3.14]
The (ordered) elements of a list can be accessed by indices. They are numbered starting with 0. It is possible to change the individual elements (including their type).
print(l1[0])
print(l1[2])
l1[2] = 'Lyon' # changes 'Paris' to 'Lyon'
l1[3] = 'London' # changes 3.14 to 'London'
print(l1)
42
Paris
[42, 'Mumbai', 'Lyon', 'London']
Tuples#
Tuples are ordered like a list, but are immutable. The elements are not required to be of the same type and, like lists, can also be accessed via indices.
t1 = (1,2,3.14,'Foo')
print(t1)
print(t1[2])
(1, 2, 3.14, 'Foo')
3.14
Because they are immutable one cannot change them:
t1[2] = 7
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[24], line 1
----> 1 t1[2] = 7
TypeError: 'tuple' object does not support item assignment
Lists vs Tuples#
So when to use a list, a tuple a dict or a set?
Lists are more dynamic and useful when the elements (and their number) may change. For example, a list could represent the list of orders for a cook in a restaurant kitchen.
Tuples are useful when fixing the elements and their number makes sense in the program context. For example, RGB colors are often represented as 3 integer numbers between 0 and 255, e.g. rgb = (255, 128, 0) is a shade of orange.
Dictionaries#
A dictionary (“dict”) is a a set of key-value pairs. It is unordered and is mutable. One accesses a dictionary using the “key” to obtain the associated “value”. Keys are unique.
# Initialize a dictionary with some values when the dict is created
capitals1 = {'India': 'New Delhi', 'France': 'Paris', 'Finland': 'Helsinki'}
print(capitals1)
print(capitals1['India'])
{'India': 'New Delhi', 'France': 'Paris', 'Finland': 'Helsinki'}
New Delhi
# We can add new elements to an existing dictionary
capitals1['Thailand']='Bangkok'
print(capitals1)
{'India': 'New Delhi', 'France': 'Paris', 'Finland': 'Helsinki', 'Thailand': 'Bangkok'}
We can also remove elements (two different methods):
del capitals1['France']
print(capitals1)
capitals1.pop('Finland')
print(capitals1)
{'India': 'New Delhi', 'Finland': 'Helsinki', 'Thailand': 'Bangkok'}
{'India': 'New Delhi', 'Thailand': 'Bangkok'}
# Create an empty dictionary and add elements
capitals2 = {}
capitals2['India'] = 'New Delhi'
print(capitals2)
capitals2['France'] = 'Paris'
print(capitals2)
{'India': 'New Delhi'}
{'India': 'New Delhi', 'France': 'Paris'}
Note that both the keys and the values can be different types, even within the same dictionary:
d3 = {}
d3[42] = 'Foo'
d3['Bar'] = 3.14
print(d3)
{42: 'Foo', 'Bar': 3.14}
Lastly, one can change the value for a given key:
d4 = {'France':'Paris', 'India': 'New Delhi'}
print(d4)
d4['France'] = 'Lyon'
print(d4)
{'France': 'Paris', 'India': 'New Delhi'}
{'France': 'Lyon', 'India': 'New Delhi'}
Sets#
A set is what you would expect from the analogous mathematical concept. A set is unordered and mutable. It will not contain duplicate elements.
s = {1,2,3,7,9}
print(s)
print(type(s))
{1, 2, 3, 7, 9}
<class 'set'>
One can add new elements to a set:
s.add(8)
print(s)
{1, 2, 3, 7, 8, 9}
However adding an existing element will not change the set:
s.add(1)
print(s)
{1, 2, 3, 7, 8, 9}
One can also remove elements from the set:
s.remove(2)
print(s)
{1, 3, 7, 8, 9}
And, lastly, the functionalities you would expect from the mathematical concept of “Set” are also available:
s1 = {1,2,3,7,9,11,33,45}
s2 = {1,2,4,8,9,12,33,46}
print(s1.union(s2))
print(s1.intersection(s2))
print(s1.difference(s2))
{1, 2, 3, 33, 4, 7, 8, 9, 11, 12, 45, 46}
{1, 2, 9, 33}
{11, 3, 45, 7}
Fancier structured printing via f-strings#
Above we used the print() function to print various things (variables, text, data types) to the screen. As the things you want to print get more complicated, and you are combining text you write in the program with the current value of data variables, you probably want to use an so-called “f-string” (i.e. a formatted string). We give some basic examples here, more detailed guides/information can be found elsewhere:
There is even a “mini-language” to given you fine-grained control over the printout, alignment, whitespace or other fill, numerical precision, etc.
Here we just provide some common examples.
s1 = "Hello World!"
print(f'A common test printout when programming is {s1}')
A common test printout when programming is Hello World!
capitals = {'France': 'Paris', 'India': 'New Delhi', 'Argentina': 'Buenos Aires'}
country = 'France'
print(f'The capital of {country} is {capitals[country]}')
The capital of France is Paris
city = 'Amsterdam'
population = 920000
print(f'The population of {city} is {population}')
The population of Amsterdam is 920000
A quick and useful trick to show both a variable name and its current value when debugging is this syntax:
some_variable = 42
print(f'{some_variable=}')
some_variable=42
Even without f-strings, you can give a series of variables, separted by commas, to the print() function and it will insert a whitespace.
s1 = "Hello"
s2 = "World!"
print(s1,s2)
Hello World!
Type Conversions#
Sometimes it is necessary to convert between types.
# Integer truncation from a float
r = 3.14
print(r)
ir = int(3.14)
print(ir)
3.14
3
For example in cases where you read numbers from user input or a file, they may initially be read into a string variable and you will need to convert them to a numeric (e.g. integer) variable.
s = "50"
print(f's = {s} is of type {type(s)}')
i = int(s)
print(f'i = {i} is of type {type(i)}')
s = 50 is of type <class 'str'>
i = 50 is of type <class 'int'>
The following generates an error. Do you understand why?
s = "3.14"
i = int(s)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[65], line 2
1 s = "3.14"
----> 2 i = int(s)
ValueError: invalid literal for int() with base 10: '3.14'
The type conversion needs to match the initial type:
s = "3.14"
r = float(s)
print(f's = {s} is of type {type(s)}')
print(f'r = {r} is of type {type(r)}')
s = 3.14 is of type <class 'str'>
r = 3.14 is of type <class 'float'>
And numeric data can be converted to a string (and indexing/functions used):
i = 12345
s = str(i)
print(f'i = {i} is of type {type(i)}')
print(f's = {s} is of type {type(s)}')
print(f'Slicing the int as a string: {s[2:4]}')
i = 12345 is of type <class 'int'>
s = 12345 is of type <class 'str'>
Slicing the int as a string: 34
Tuples can be unpacked into individual variables by simple assignment:
t = (1,2)
print(f't = {t} is of type {type(t)}')
a, b = t
print(f'a = {a} is of type {type(a)}')
print(f'b = {b} is of type {type(b)}')
t = (1, 2) is of type <class 'tuple'>
a = 1 is of type <class 'int'>
b = 2 is of type <class 'int'>
At times, the length of a typle or list may not be known, but one knows that a fixed number of elements at
the beginning or end need to be unpacked. This can be managed using *
, the so-called ‘unpacking operator’.
Here the middle elements are collected as a list in variable c
.
t = (1,2,3,4,5,6)
a,b,*c,d = t
print(f't = {t} is of type {type(t)}')
print(f'a = {a} is of type {type(a)}')
print(f'b = {b} is of type {type(b)}')
print(f'c = {c} is of type {type(c)}')
print(f'd = {d} is of type {type(d)}')
a = 1 is of type <class 'int'>
b = 2 is of type <class 'int'>
c = [3, 4, 5] is of type <class 'list'>
d = 6 is of type <class 'int'>
Lists can also be unpacked and assigned to other variables in a similar fashion using *
.
l = [1,2,3,4,5,6] # a list
a,b,*c,d = l
print(f'l = {l} is of type {type(l)}')
print(f'a = {a} is of type {type(a)}')
print(f'b = {b} is of type {type(b)}')
print(f'c = {c} is of type {type(c)}')
print(f'd = {d} is of type {type(d)}')
l = [1, 2, 3, 4, 5, 6] is of type <class 'list'>
a = 1 is of type <class 'int'>
b = 2 is of type <class 'int'>
c = [3, 4, 5] is of type <class 'list'>
d = 6 is of type <class 'int'>
Lists can also be concatenated using the *
operator.
a = [1,2]
b = [3,4]
c = [*a,*b]
print(c)
[1, 2, 3, 4]
Complex Numbers#
Python can also handle complex numbers.
import cmath
z = complex(3,4)
print(z)
(3+4j)
print(z**2)
(-7+24j)
r = abs(z)
theta = cmath.phase(z)
print(f'{z} has (r,theta) = ({r},{theta})')
(3+4j) has (r,theta) = (5.0,0.9272952180016122)