--- title: "Python Basics" file_title: Python_Basics ---

In this post we'll look at some of the basics of Python. This isn't an exhaustive look, but does cover many of the fundamentals.

## Printing¶

Below are the two most basic print statements. Notice that the name of the function is print and that it takes a string as input. Also, at the end of the print statement, a newline is automatically added, no need to manually insert a newline.

In [1]:
print('Hello')
print('World!')

Hello
World!


Using Python 3.6+ fstrings is the best way to print strings intermixed with variables. It provides a very easy syntax for including varibles. Simply add the key letter f before the start of your string to print and inside the string you can use {} to reference variables.

In [2]:
var1 = 'Hello'
var2 = 'World!'
print(f'{var1} and {var2}')

Hello and World!

In [3]:
var1 = '1 divided by 3 is'
var2 = 1/3
print(f'{var1}: {var2}')

1 divided by 3 is: 0.3333333333333333


We can choose the precision printed by specifying the number of digits after the decimal using {var2:.4}, where 4 is the number of digits after the decimal.

In [4]:
print(f'{var1}: {var2:.4}')

1 divided by 3 is: 0.3333


Here is some more documentation on using Python fstrings. The first parts look over previous printing methods and finally goes over why fstrings are the best.

## Lists¶

A Python list is a collection of Python objects that are stored together and can be retrieved. They can be any type.

In [5]:
items = [1, 2, 'purple', True]
items

Out[5]:
[1, 2, 'purple', True]

We can retrieve individual values from the defined list using the following syntax:

In [6]:
items[0]

Out[6]:
1

Note that Python is a language that is zero-indexed meaning that the first item in a list is zero-th element[^1]. We can get the first two items using the following:

In [7]:
items[0:2]

Out[7]:
[1, 2]

Let's take a list of numbers and try to double the entries:

In [8]:
items2 = [1, 1]
2 * items2

Out[8]:
[1, 1, 1, 1]

Python lists, since they can store any data type do not follow the rules you may be familiar with in other languages. Multiplying a list by an integer makes a list longer, because it appends that number of links together. Note that you can only multiply by integers because you can't add 2.5 lists together, for instance. If you're looking to use Python for linear algebra applications, you'll want to use the Numpy library.

## Functions¶

In Python, functions can be defined anywhere. They are defined by the keyword def followed by the name of the function, in this case func, and in parenthses, it defines the input argument x, followed by a :. The function returns whatever is after the return keyword. Note that the code in the function is indented. Indentation is how Python determines what is a part of the function.

In [9]:
def func(x):
return x**2

print(f'2 squared is: {func(2)}')

2 squared is: 4


Functions can take multiple arguments as input. Note that the order of variables when you use the functions matters!

In [10]:
def quadratic(x, a, b, c):
return a*x**2 + b*x + c

print(f'The value is: {quadratic(1, 2, 3, 4)}')

The value is: 9


### Keyword arguments¶

Python functions can also take 'keyword' arguments. These arguments are passed by variable name, instead of by position. Keyword arguments must have defined defaults in case they are not assigned. The following function will print the variable keyword, if it is not passed as a keyword argument, then it will default to keyword=1. Positional arguments can be combined with keyword arguments, the only restriction is that positional arguments must be defined before the keyword arguments when defining the function.

In [11]:
def funKey(positionalArgument, keywordArgument=10):
print(f'positionalArgument: {positionalArgument}, keywordArgument: {keywordArgument}')

funKey(1)
funKey(2,keywordArgument=20)
funKey(3,keywordArgument=30)

positionalArgument: 1, keywordArgument: 10
positionalArgument: 2, keywordArgument: 20
positionalArgument: 3, keywordArgument: 30


### Loops¶

For loops allow dynamically iterating through items in a list, very elegantly. In Python, the syntax is shown below. The keyword for indicates that it is a loop. item is the variable that changes on each iteration of the loop, where they are assigned from the items in the list items. The line must end with a :, and items in the for loop must be indented, just like functions.

In [12]:
for item in items:
print(item)

1
2
purple
True


Python allows for accessing both the current item in the list as well as the current index. There's no need to define a counter and manually increase! This is accomplished by using the enumerate function, with the list as an input, and assigning index and item.

In [13]:
for index, item in enumerate(items):
print(f'{index} : {item}')

0 : 1
1 : 2
2 : purple
3 : True


Using the range function allows iterating through a range of numbers. Essentially, range produces a list of values, and for each iteration of the for loop, the value i is assigned each successive value. Note that the range function is inclusive on the lower bound and non-inclusive on the upper bound. In math notation [0,10).

In [14]:
for i in range(0, 10):
print(i)

0
1
2
3
4
5
6
7
8
9


### Conditionals & Boolean Operators¶

Python if statements allow for defining different scenarios based on values and boolean operations. In the example below, we compare the values a and b. We test if a is greater than b, if a is less than b, and add a condition for all other cases (which would simply be the values being equal). We print the values of the variables and how the variables are related.

In [15]:
a = 1
b = 2

if a > b:
print(f'{a} > {b}')
elif a < b:
print(f'{a} < {b}')
else:
print(f'{a} = {b}')

1 < 2


### Dictionaries¶

Dictionaries are a Python data type similar to JSON. They are like lists but instead of numerical indicies, the indicies are strings. They are also refered to as key value pairs, where each key is associated with each value. This means that we can retrieve information with no need to know the order of the items in the dictionary. Let's define a dictionary below.

In [16]:
# Braces enclose the dictionary
dict = {'key1': 'val1',  # the : seperates the keys and values
'key2': 'val2',   # there is a comma between the key/val pairs
'key3': 3,
'key3': [1, 2, 3, 'string']
}


Let's retrieve the first key of the dictionary called dict.

In [17]:
dict['key1']

Out[17]:
'val1'

We can redefine keys in a dictionary, or add new key value pairs like the following:

In [18]:
dict['key1'] = 'newval1'
dict['key4'] = 'val4'


Let's look at two ways of iterating through the dictionary and printing the key value pairs. This first way, we will set the variable key to each key in the dictionary called dict. Then inside the for loop, we print out the value of key and the value associated with that key by printing dict[key].

In [19]:
for key in dict:
print(f'{key} : {dict[key]}')

key1 : newval1
key2 : val2
key3 : [1, 2, 3, 'string']
key4 : val4


A slightly clearer way of doing the same thing is to set the value of both key and value from the dict. We can set both by calling the items method on the dicitonary object. Then in the print statement, we can directly print each key and value without manually retieving the value inside the for loop. This makes the code look much clearer.

In [20]:
for key, value in dict.items():
print(f'{key} : {value}')

key1 : newval1
key2 : val2
key3 : [1, 2, 3, 'string']
key4 : val4


### Importing Modules¶

Python is an incredibly extensible language. Python also ships with many packages. You can access these packages by using the import statement. For instance we can import thr Numerical Python library by the following:

In [21]:
import numpy


Then the functionality of that package bcomes available under the name numpy. For instance we can take the sine of $\pi$

In [22]:
numpy.sin(numpy.pi)

Out[22]:
1.2246467991473532e-16

Writing out the full package name each time can be cumbersome so you can create an alias with the as keyword.

In [23]:
import numpy as np
np.sin(np.pi)

Out[23]:
1.2246467991473532e-16

The functions can also be imported into the global namespace with no need to prefix with the namespace, like the following:

In [24]:
from numpy import sin, pi
sin(pi)

Out[24]:
1.2246467991473532e-16

However, this should be used sparingly. The namespace should be used to explicitly show where each function is being imported from. This is important particularly because there can be name clashes that create unexpec. There is another module called math that also has sin and pi defined.

In [25]:
import math
math.sin(math.pi)

Out[25]:
1.2246467991473532e-16

In this case they produce the same result. However, this may not always be the case. Explicit is always better than implicit. While this syntax may look hideous if you aren't comfortbale with the idea of namespaces, it is one of the features that allow Python to be extensible and what makes writing your own packages incredibly easy!