CV4GS - Python tutorial
python2
. Throughout this course we'll be using python3
.$ python --version
!python --version
Python 3.9.12
**Note**: there are a number of differences between Python2 and Python3. Here are a few:
- print function:
print 'hello world' # Python2 syntax print('hello world') # Python3 syntax- integer division:
3/2 # Python 2 => returns 1 3/2 # Python 3 => returns 1.5- unicode: Python 2 has ASCII str() type, unicode() type, but no byte type. Python 3, has unicode UTF-8 str() type, and byte type
print(Popocatépetl) # Python2 => ERROR: non-ASCII characters not handled (e.g. accents) print(Popocatépetl) # Python3 => SUCCESS: UTF-8 characters handled (e.g. accents)- xrange & range functions to create iterable objects:
xrange(5) # Python2 syntax range(5) # Python3 syntax
object-oriented programming (OOP)
allows thinking of problems in terms of classes
and objects
, thereby allowing the creation of reusable patterns of codepackages
, libraries
, and frameworks are available to handle various aspectspackage managers
(pip, conda):$ pip install <package_name> #>> Python's package manager
$ conda install <package_name> #>> Anaconda's package manager
matplotlib
, bokeh, seaborn, plotly, mayavinumpy
, pandasscikit-image
, imageio
, pillow, opencvscikit-learn
, tensorflow/keras
, pytorchFor those with experience with Matlab, see numpy for Matlab users
print('Hello World')
# this text is commented
a = [1, 2, 3]
a[0] # access first element of list with index = 0
# EX: for-loop
for k in range(10):
print(k)
# EX: if-statement
if k > 0:
print(k)
modules
and packages
, which are imported
at the begining of the file.import sys
import pandas as pd
from matplotlib import pyplot as plt
Basic data types in Python include numbers
, booleans
and strings
.
Types: integer
, float
, complex
a = 1 # int = signed integer (= positive or negative whole numbers with no decimal point)
print(type(a))
b = 1.0 # float = floating point real values (= real numbers with a decimal point)
print(type(b))
c = 2.0 + 3j # complex = complex numbers (= a + bj, where a represents the real part, anb b the imaginary part)
print(type(c))
<class 'int'> <class 'float'> <class 'complex'>
In Python, boolean variables are defined by the True
and False
keywords.
t = True
f = False
print(type(t))
<class 'bool'>
hello = 'hello' # string with single quotes
world = "world" # string with double quotes (same as single quote)
helloworld = '''hello world ''' # string with triple quotes
hellocruelworld = """ # string with triple quotes (can span multiple lines, include single/double quotes)
hello 'cruel' world
"""
print(type(hello))
print(type(world))
print(type(helloworld))
print(type(hellocruelworld))
<class 'str'> <class 'str'> <class 'str'> <class 'str'>
.format()
'Hello {}! We are in {}.'.format('world', 2024)
'Hello world! We are in 2024.'
'{word1} {word2} {word3}'.format(word1='hello', word2='cruel', word3='world')
'hello cruel world'
'{:.2f}'.format(3.141592) # keep only 2 decimal points
'{:.2f}'.format(3) # add 2 decimal points
'3.00'
f-strings
(in Python 3.6+)word1 = 'world'
word2 = 2024
f'Hello {word1}! We are in {word2}'
'Hello world! We are in 2024'
%
(older formatting syntax)name = 'world'
year = 2024
formatted_string = 'Hello %s! We are in %d.' % (name, year)
print(formatted_string)
Hello world! We are in 2024.
x = 'Hello'
y = 'World'
x + y
'HelloWorld'
List of all string methods in the documentation.
s = "hello"
print(s.capitalize()) # Capitalize a string
print(s.upper()) # Convert a string to uppercase; prints "HELLO"
print(s.rjust(7)) # Right-justify a string, padding with spaces
print(s.center(7)) # Center a string, padding with spaces
print(s.replace('l', 'L')) # Replace all instances of one substring with another
print(' world '.strip()) # Strip leading and trailing whitespace
print('hello world'.split(' ')) # Split string at specified character
Hello HELLO hello hello heLLo world ['hello', 'world']
# - unicode string
type('test')
type(u'test') # Note: u'strings' are unicode for backwards compatibility with python 2)
str
# - byte string
type(b'test') # Note: bytes can only contain ASCII literal characters (no accents)
bytes
# - convert unicode to bytes
# Note: UTF-8 is an encoding supporting accents, ASCII does not
print(type('Popocatépetl'))
'Popocatépetl'.encode('utf-8') # unicode is .encoded(encoding) to bytes;
<class 'str'>
b'Popocat\xc3\xa9petl'
# - convert byte to unicode
mystring = b'test'.decode('utf-8')
type(mystring)
str
x = 1
print(x + 1) # Addition
print(x - 1) # Subtraction
print(x * 2) # Multiplication
print(x ** 2) # Exponentiation
print(x % 2) # Modulus
print(x // 2) # Floor division (note: since python3 dividing an int always casts to float)
2 0 2 1 1 0
x = 1
x += 2 # x = x + 2
x -= 2 # x = x - 2
x /= 2 # x = x / 2
x *= 2 # x = x * 2
# Example:
x = 1
x *= 2
print(x)
2
Multiple variable assignments:
x, y = 1, 'a'
print(x)
print(y)
1 a
x = 1
y = 2
x == y # Equal
x != y # Not equal
x > y # Greater than
x < y # Less than
x >= y # Greater than or equal to
x <= y # Less than or equal to
Logical operators are used to combine conditional statements.
Python implements all of the usual operators for Boolean logic, but uses English words rather than symbols (&&, ||, etc.):
x = 1
x < 5 and x < 10 # Returns True if both statements are true
x < 5 or x < 4 # Returns True if one of the statements is true
not(x < 5 and x < 10) # Reverse the result, returns False if the result is true
Membership operators are used to test if a sequence is presented in an object:
l = ['a', 'b']
'a' in l # Returns True if a sequence with the specified value is present in the object
'c' not in l # Returns True if a sequence with the specified value is not present in the object
Python includes several built-in container types: lists
, dictionaries
, sets
, and tuples
.
A list
is a mutable
list of elements, which can be of multiple types.
l = [] # create empty list
l = list() # create empty list
l = [1, 2, 3, 4, 5] # create list by comma seperated values inside square brackets
l = [1, 'a', 'b', 4, 5] # lists can hold several data types
l = list(range(5)) # create list of integers using the built-in function 'range'
print(l)
[0, 1, 2, 3, 4]
l1 = [1, 2, 3]
l2 = [4, 5, 6]
l = [l1, l2] # concatenate lists (create list of lists)
print(l)
l = l1 + l2 # append lists
print(l)
l *= 2
print(l) # replicate list
[[1, 2, 3], [4, 5, 6]] [1, 2, 3, 4, 5, 6] [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
len(l) # get number of elements in list
12
Note: a list can only have 1 dimension
l = [1,2,3; 4,5,6] # INVALID SYNTAX (Matlab style)
Access list elements using square brackets.
Reminder: Python is zero-based, meaning the first element is accessed with the index 0
Important: the result of the slicing includes the start index, but excludes the end index
l = [1, 2, 3, 4, 5]
# - access single element
l[0] # access first element
l[-1] # access last element
l[-2] # access second to last element
# - slice (access multiple elements)
# Important: the result includes the start index, but excludes the end index
l[1:3] # access 2nd & 3rd elements
l[1:-2] # access 2nd until 2nd to last element
l[:3] # access all elements from start until 4th element
l[3:] # access all elements from 4th element until end
l[::2] # access every nth element
# - assign element
l[0] = 0 # replace element
l[1:2] = [-1, -2] # assign a sublist to a slice
print(l)
[0, -1, -2, 3, 4, 5]
l = []
l.append(1) # add element at the end of the list
print(l)
l.extend([2, -3]) # append list at the end of the list
print(l)
l.insert(1, .5) # insert element at index n: insert(n, value)
print(l)
l.pop(1) # remove element at index n: pop(n)
print(l)
l.sort() # sorts elements
print(l)
[1] [1, 2, -3] [1, 0.5, 2, -3] [1, 2, -3] [-3, 1, 2]
A list is an iterable
container, to iterate through its elements use a for-loop:
l = [1, 2, 3]
for element in l:
print(element)
1 2 3
To get both index and value during iteration, use the built-in function enumerate
:
for index, element in enumerate(l):
print('index={}, value={}'.format(index, element))
index=0, value=1 index=1, value=2 index=2, value=3
Use list comprehension
to iterate through list and edit its values in a single line:
l = [1, 2, 3]
ll = [elt*2 for elt in l] # list comprehension
print(ll)
ll = [elt*2 for elt in l if elt == 2] # list comprehension with if condition
print(ll)
ll = [elt*2 if elt == 2 else elt*1 for elt in l] # list comprehension with if-else condition
print(ll)
[2, 4, 6] [4] [1, 4, 3]
A dictionary
stores key-value pairs, values can be retrieved via their key.
d = {} # create empty dictionary
d = dict() # create empty dictionary
d = {'a':1, 'b':2, 'c':3} # create dictionary by 'key':value
d = dict(a=1, b=2, c=3) # create dictionary by key=value
d = dict(a=1, b=2, c=dict(c1=.1, c2=.2)) # create nested dictionaries
print(d)
{'a': 1, 'b': 2, 'c': {'c1': 0.1, 'c2': 0.2}}
d = {1:1, 2:2, 3:3} # keys can be numeric values
d = {'hello world':1, 'united we stand':1} # keys can be complex strings
d = {(0,1):0, (0,2):1} # keys can be tuples
print(d)
{(0, 1): 0, (0, 2): 1}
d = {'a':1, 'b':2, 'c':3}
d['d'] = 4 # append key to dictionary
print(d)
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
d = dict(a=1, b=2, c=dict(c1=.1, c2=.2))
print(d['a']) # access value using key
print(d['c']['c1']) # access value in nested dictionaries
print(d.get('a')) # access value using build-in method
d = {1:1, 2:2, 3:3}
print(d[3]) # access value using key
1 0.1 1 3
d = dict(a=1, b=2, c=3)
d['c'] = 'c' # replace value
print(d)
{'a': 1, 'b': 2, 'c': 'c'}
Dictionaries are iterator objects, you can iterate through it using a for-loop:
d = dict(a=1, b=2, c=3)
for key in d:
print('key={}, value={}'.format(key, d[key]))
key=a, value=1 key=b, value=2 key=c, value=3
Use dictionary comprehension
to create or edit dictionaries:
d = {key: 0 for key in ['a', 'b', 'c']} # create a dictionary with keys defined by list values
print(d)
{'a': 0, 'b': 0, 'c': 0}
d = {key: d[key]+1 for key in d} # edit existing dictionary
print(d)
{'a': 1, 'b': 1, 'c': 1}
# - update a dictionary with values from another dictionary
d1 = dict(a=1, b=2, c=3)
d2 = dict(c=4, d=5)
d1.update(d2)
print(d1)
{'a': 1, 'b': 2, 'c': 4, 'd': 5}
# - access keys / values (returns an iterator)
d = dict(a=1, b=2, c=3)
d.keys()
d.values()
# => loop through values
for v in d.values():
print(v)
# => return list of values
list(d.values())
1 2 3
[1, 2, 3]
# - remove value
d = dict(a=1, b=2, c=3)
removed_value = d.pop('a')
print(d)
print(removed_value)
{'b': 2, 'c': 3} 1
A tuple is an immutable
list of values, meaning they cannot be changed once created.
(This also means they are hashable, and can be used as a dictionary key).
t = (1, 2, 3) # create tuple
t = 1, 2, 3 # create tuple (parenthesis are optional)
print(t)
print(type(t))
Indexing and slicing work like lists.
print(t[0]) # access tuple element
(1, 2, 3) <class 'tuple'> 1
Use tuple unpacking
to assign tuple elements to multiple variables at once:
a, b, c = 1, 2, 3 # unpack (parenthesis are optional)
_, _, c = 1, 2, 3 # unpack and ignore elements
a, *b, c = 1, 2, 3, 4 # unpack with multiple elements casted to a list (Python3 only)
print(b)
print(c)
[2, 3] 4
Combine iteration and tuple unpacking:
students = [
('Alice', ('F', 29)),
('Bob', ('M', 23)),
('Eve', ('F', 44)),
]
for name, (sex, age) in students:
print('{name}, {pronoun} is {age}'.format(name=name, age=age, pronoun=dict(F='she', M='he')[sex]))
Alice, she is 29 Bob, he is 23 Eve, she is 44
**Notes**:
t = 1,
print(t)
t[0] = 1 # will generate an error
def multiple_values():
return 1, 2, 3, 4
A set
is an unordered collection of distinct (unique) elements.
s = {'tiger', 'monkey', (1,2,3), .1} # create set
s = set(['tiger', 'monkey', (1,2,3), .1]) # create set
print(s)
print(type(s))
s = {'tiger', 'monkey', 'monkey', (1,2,3), .1} # elements are unique (duplicates are ignored)
print(s)
s.add('monkey') # adding an existing element does nothing
print(s)
s.add('zebra') # add element
print(s)
s.remove(.1) # remove element
print(s)
print('cat' in s) # check if an element is in a set
{0.1, 'tiger', (1, 2, 3), 'monkey'} <class 'set'> {0.1, 'tiger', (1, 2, 3), 'monkey'} {0.1, 'tiger', (1, 2, 3), 'monkey'} {0.1, 'tiger', (1, 2, 3), 'monkey', 'zebra'} {'tiger', (1, 2, 3), 'monkey', 'zebra'} False
Note: standard "trick" to remove duplicates from a list (WARNING: will change the list order!)
data = [3, 5, 1, 6, 2, 1, 3, 5]
list(set(data)) # remove duplicates by converting list to set
[1, 2, 3, 5, 6]
Python uses the if
, elif
, and else
clauses to conditionally execute blocks of statements.
x = -10
if x < 0:
print("x is negative")
elif x > 0:
print("x is positive")
else:
print("x = 0")
x is negative
Any non-zero number or non-empty string, tuple, list, or dictionary evaluates as true:
# - evaluate a string
x = []
if x:
print('List is not empty')
else:
print('List is empty')
# - evaluate a number
y = 0
if y:
print('This is evaluated as True')
else:
print('This is evaluated as False')
List is empty This is evaluated as False
Python uses the for
statement to loop through an iterable
object.
for letter in 'ciao':
print(letter)
c i a o
for elt in ['h', 'o', 'l', 'a']:
print(elt)
h o l a
for idx in range(5):
print(idx)
0 1 2 3
Use the built-in function enumerate
to get both index and value during iteration:
l = ['h', 'o', 'l', 'a']
for index, element in enumerate(l):
print('index={}, value={}'.format(index, element))
index=0, value=h index=1, value=o index=2, value=l index=3, value=a
Python uses the while
clause to loop over body as long as the condition is True.
a = 5
while a>0:
a -= 1
print(a)
4 3 2 1 0
Python supports exception handling with the try statement, which includes try
, except
, finally
, and else
clauses.
try:
print('Try dividing by 0')
1 / 0
except:
print('You fool!')
Try dividing by 0 You fool!
Exceptions
happen at runtime and are used for error handling. Here are some standard errors:
1 / 0
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-24-bc757c3fda29> in <module> ----> 1 1 / 0 ZeroDivisionError: division by zero
d = dict(a=1)
d['b']
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) Input In [26], in <cell line: 2>() 1 d = dict(a=1) ----> 2 d['b'] KeyError: 'b'
In the cells below, we generate an error called "ZeroDivisionError" (triggered when a number is divided by zero), and we catch that error with the except
statement to run another code block.
# Set function to computer the inverse value of the parsed variable.
def inverse(a):
return 1. / a
# Calling the inverse function on a 0 returns the error 'ZeroDivisionError'
inverse(0)
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-372-6020e9ef8186> in <module> 1 # Calling the inverse function on a 0 returns the error 'ZeroDivisionError' ----> 2 inverse(0) <ipython-input-371-107370f37cde> in inverse(a) 1 # Set function to computer the inverse value of the parsed variable. 2 def inverse(a): ----> 3 return 1. / a ZeroDivisionError: float division by zero
# Test for the 'ZeroDivisionError'
try:
b = inverse(0)
except ZeroDivisionError:
# execute if 'ZeroDivisionError' caught
print('Caught "ZeroDivisionError" in the expression.')
b = 99999
print('b =', b)
Caught "ZeroDivisionError" in the expression. b = 99999
# Test for various error types
try:
b = inverse(1)
except (ZeroDivisionError, KeyError):
# execute if 'ZeroDivisionError' or 'KeyError' caught
b = 99999
except ValueError:
# execute if 'ValueError' caught
b = 88888
else:
# excetute if no exceptions caught
print('No exception occurred')
finally:
# always execute this
print('Try statement finished')
print('b =', b)
No exception occurred Try statement finished b = 1.0
x = 10
if x > 5:
raise Exception('x should not exceed 5. The value of x was: {}'.format(x))
--------------------------------------------------------------------------- Exception Traceback (most recent call last) <ipython-input-391-3dcc1a597936> in <module> 1 x = 10 2 if x > 5: ----> 3 raise Exception('x should not exceed 5. The value of x was: {}'.format(x)) Exception: x should not exceed 5. The value of x was: 10
The body of a Python compound statement cannot be empty—it must contain at least one statement. The pass
statement, which performs no action, can be used as a placeholder when a statement is syntactically required but you have nothing specific to do.
def function_to_prepare():
pass
The break
statement is allowed only inside a loop body (for
or while
loop). When break executes, the loop terminates.
for idx in range(5):
print(idx)
if idx>=2:
print('Index >= 2, stopping the loop')
break
0 1 2 Index >= 2, stopping the loop
Use assert
statement to test that a certain condition is met. If this condition is True, the program can continue, otherwise you can have the program throw an AssertionError exception.
x = -1
assert (x > 0), "This value of x should be positive"
--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-394-81a5e5e6332a> in <module> 1 x = -1 ----> 2 assert (x > 0), "This value of x should be positive" AssertionError: This value of x should be positive
Python functions are defined using the def
keyword.
- the body of the function is indented (always use 4 spaces for one indentation level)
- the returned value preceded by the
return
keyword; (functions can have multiple return statements)- arguments can be parsed as positional arguments (
args
), i.e. a list of comma seperated values: func(a, b, c)- arguments can be parsed as keyword arguments (
kwargs
), which have a default value if not explicitely parsed: func(spam=1, eggs=2)- when using args and kwargs, args must always come before kwargs: func(a, spam=1, eggs=2)
def add(x, y):
return x + y
def inverse(x):
if x != 0:
return 1/x
else:
print('warning: cannot return the inverse of 0, returning None')
return None
add(2, 2)
4
inverse(2)
0.5
inverse(0)
warning: cannot return the inverse of 0, returning None
Arguments can be parsed as keyword arguments, and default values can be set.
def greetings(language='english', name='Jake'):
if language == 'english':
print('Hello {}!'.format(name))
elif language == 'spanish':
print('Hola {}!'.format(name))
else:
print('I dont speak this language.')
greetings(language='spanish', name='Emiliano')
greetings(language='spanish') # name not parsed => will take use default value defined in funtion
Hola Emiliano! Hola Jake!
d = dict(language='english')
greetings(**d) # unpack dictionary keys-values as keywarg arguments
Hello Jake!
def addone(a):
'''This function is used to add one to the parsed variable.'''
return a + 1
addone.__doc__
'This function is used to add one to the parsed variable.'
Call by value
: for primitive variables (ex: numbers), Python copies the content of the variable into the function.
def addone(a):
a = a + 1
n = 3
addone(n) # => variable 'n' is copied to new variable 'a' inside the function => 'a' is changed 'n' is not
print(n)
3
# => to change 'n' we need to return the copied variable 'a' which was changed
def addone(a):
a = a + 1
return a
n = 3
n = addone(n)
print(n)
4
Call by reference
: for complex variables (ex: lists), Python does not copy the variable inside the function, instead it references it. This mean that the parsed variable will suffer the changes, even though the variable is not returned from the function.
mylist = [1, 2, 3, 4]
def func(a):
a[1] = -10
func(mylist)
print(mylist) # => the array is modified even though the list was not returned from the function!
[1, -10, 3, 4]
Solution:
def get_max(a, b):
"""
Return the larger of two values.
Example:
>>> get_max(3.5, 1.2)
3.5
"""
# Using numpy:
# import numpy as np
# return np.maximum(a, b)
# Using built-in method:
return max(a, b)
Solution:
def get_ratio(a, b):
"""
Compute the inverse of two values.
Example:
>>> get_ratio(5, 2)
2.5
>>> get_ratio(3, 0)
Warning: Division by zero. The result is undefined.
"""
if b == 0:
print("Warning: Division by zero. The result is undefined.")
raise ZeroDivisionError("Denominator cannot be zero.")
return a / b
Solution:
# Solution without list comprehension:
squared_values = [] # Initialize an empty list to store squared values
for num in range(21): # Iterate through numbers from 0 to 20
if num > 10:
break # Exit the loop if the iterator exceeds 10
squared_values.append(num ** 2) # Square the number and append to the list
print(squared_values)
# Solution with list comprehension
squared_values = [num ** 2 for num in range(21) if num <= 10]
print(squared_values)
Solution:
# Create the dictionary with volcanoes and their altitudes
volcano_altitudes = {
"Popocatépetl": 5426,
"Etna": 3329,
"Mount Fuji": 3776
}
# Print the altitude of your favorite volcano
volcano_name = "Popocatépetl"
print(f"The altitude of {volcano_name} is {volcano_altitudes[volcano_name]} meters.")
In Python, everything is an object
, even functions and attributes.
OOP
= Object Oriented Programing
Classes
are defined with the class
keyword.Methods
are functions inside classes, and are defined with the def
keywordAttributes
are set like that instance.attribute = value, and are also accessed via instance.attributeclass Volcano():
def __init__(self, name):
self.name = name
self.type = 'mountain' # public attribute
self.__imminentexplosion = False # private attribute (starts with double underscore)
def print_name(self):
print('The volcano name is', self.name)
def set_altitude(self, altitude):
self.altitude = altitude
# - instantiate class
volc = Volcano('colima')
# - get class attribute (public):
volc.type
'mountain'
# - private class attribute unaccesible
# volc.__imminentexplosion # command returns 'AttributeError'
# - call class method:
volc.print_name()
The volcano name is colima
# - set attribute through class method:
volc.set_altitude(3820)
print(volc.altitude)
3820
# - get class attributes (public + private) as dictionary
volc.__dict__
{'name': 'colima', 'type': 'mountain', '_Volcano__imminentexplosion': False, 'altitude': 3820}
# - check class instance
print(type(volc))
isinstance(volc, Volcano)
<class '__main__.Volcano'>
True
A class can inherit
methods and attributes from a parent class.
super().method()
let's you call an instances parent's method from an instance method
class ExplosiveVolcano(Volcano):
def __init__(self, name):
super().__init__(name)
def set_expected_VEI(self, VEI):
'''Volcanic Explosivity Index (VEI) is a relative measure of the explosiveness of volcanic eruptions.'''
self.expected_VEI = VEI
# - instantiate class which inherited from class Volcano
popo = ExplosiveVolcano('Popocatépetl') # needs to parse arguments for parent class Volcano
popo.set_expected_VEI(5)
print(popo.expected_VEI)
5
A class can inherit from multiple classes:
class Mountain():
def __init__(self):
self.category = 'geology'
class SuperVolcano(ExplosiveVolcano, Mountain):
# Note: because ExplosiveVolcano already inherits from Volcano, should not inherit both
def __init__(self, name):
super().__init__(name)
self.info = 'stay away'
def breathe(self):
print("breathing")
yellowstone = SuperVolcano('Yellow Stone')
print(yellowstone.info)
stay away
Example: __str__
and __repr__
instances
- instance description ugly by default: <main.ExplosiveVolcano at 0x7fb66dca6160>
- __str__() is supposed to give a nice string representation of the class, but uses __repr__() as a fallback
class ExplosiveVolcano(Volcano):
def __init__(self, name):
super().__init__(name)
def set_expected_VEI(self, VEI):
'''Volcanic Explosivity Index (VEI) is a relative measure of the explosiveness of volcanic eruptions.'''
self.expected_VEI = VEI
def __repr__(self):
return '< Volcano: name=' + self.name + '>'
popo = ExplosiveVolcano('Popocatépetl') # needs to parse arguments for parent class Volcano
print(popo)
< Volcano: name=Popocatépetl>
module
is python file, which can be imported if in your PYTHONPATH
package
is a collection of python modules, in practice as a directory containing python modules and a __init__.py
file.Import the numpy
package:
import numpy
numpy.add(2,3)
5
Import the numpy
package using a shorter name (recommended):
import numpy as np
np.add(2,3)
5
Import a specific function from numpy:
from numpy import add
add(2,3)
5
from numpy import add as npadd
npadd(2,3)
5
Import everything from the package in your current workspace using *
(not recommended):
from numpy import * # not recommended
Check version of a module:
np.__version__
'1.21.5'
Check where the module is located:
np.__file__
'/home/balam/anaconda3/lib/python3.9/site-packages/numpy/__init__.py'
Check out module content (using Linux built-in cat
command):
!cat /home/balam/anaconda3/lib/python3.9/site-packages/numpy/__init__.py
Check out package architecture (using Linux third-party tree
command):
$ sudo apt install tree
!tree /home/balam/anaconda3/lib/python3.9/site-packages/numpy/
Third-party packages are usually installed using package managers
:
pip
=> Python Packaging Authority’s recommended tool for installing packages from the Python Package Index (PyPI)$ pip install <package_name>
conda
=> Anaconda's package manager for installing packages from the Anaconda repository and Anaconda cloud:$ conda install <package_name>
You can create your own packages and modules to reuse your code in an organized manner.
!mkdir /home/khola/Documents/CODE/python/volcano/
__init__.py
file to tell python the directory is a package:!touch /home/khola/Documents/CODE/python/volcano/__init__.py
%%writefile /home/khola/Documents/CODE/python/volcano/mymodule.py
import numpy
myvariable1 = 1
myvariable2 = 2
def add(x,y):
return x+y
Overwriting /home/khola/Documents/CODE/python/volcano/mymodule.py
Install Linux third-party tree
command:
$ sudo apt install tree
!tree /home/khola/Documents/CODE/python/
You should add the following line to your .bashrc
file (in Linux):
export PYTHONPATH=/path/to/your/python/dir
#export PYTHONPATH=/home/khola/Documents/CODE/python
The cell below adds the line 'export PYTHONPATH=/home/khola/Documents/CODE/python' to the end of your .bashrc file.
#!echo 'export PYTHONPATH=/home/khola/Documents/CODE/python' >> ~/.bashrc
Check results:
!tail /home/khola/.bashrc # replace </home/khola/> with your path
else if [ -f "/home/khola/anaconda3/etc/profile.d/conda.sh" ]; then . "/home/khola/anaconda3/etc/profile.d/conda.sh" else export PATH="/home/khola/anaconda3/bin:$PATH" fi fi unset __conda_setup # <<< conda initialize <<<
Source your file (or restart your computer):
# !source ~/.bashrc
from volcano import mymodule
print(mymodule.myvariable1)
1
mymodule.add(2,3)
5
Python supports functional programming with list/dict/set comprehensions
, map
, reduce
, etc.
Functional programming is a programming paradigm — a style of building the structure and elements of computer programs — that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data (wikipedia)
# - list comprehension
squares = [x*2 for x in range(5)] # list comprehension
print(squares)
squares = [x**2 for x in range(5) if x == 2] # list comprehension with if condition
print(squares)
squares = [x**2 if x == 2 else x*1 for x in range(5)] # list comprehension with if-else condition
print(squares)
[0, 2, 4, 6, 8] [4] [0, 1, 4, 3, 4]
# - dictionary comprehension
squares_d = {x: str(x ** 2) for x in range(5)}
squares_d
{0: '0', 1: '1', 2: '4', 3: '9', 4: '16'}
map
maps a function to an iterable:
list_of_iteratables = [range(x) for x in range(5)]
list_of_iteratables
[range(0, 0), range(0, 1), range(0, 2), range(0, 3), range(0, 4)]
list(range(0, 4))
[0, 1, 2, 3]
m = map(sum, list_of_iteratables)
m
<map at 0x7fca6bd5b940>
list(m)
[0, 0, 1, 3, 6]
lambda
functions are anonymous
functions, i.e. functions that are not bound to a name.
def f(x): return x**2 # standard function
g = lambda x: x**2 # lambda function
print(f(2))
print(g(2))
4 4
Python code style is defined in PEP8 (Python Enhancement Proposal).
Some key rules:
pep8
, flake8
, etcdecorators
iterators
, generators
, yield
keywordcontext manangers
for elegant file readingglobal
variables and scope
Solution:
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def compute_area(self):
return self.length * self.width
# Example usage:
rectangle = Rectangle(5, 10)
print(f"Area of rectangle = {rectangle.compute_area()}")
Solution:
[x**2 if x<2 else x*2 for x in range(-10, 10, 2)]