Python Tutorial
Concepts
Python is a high-level scripting programming language.
The three major versions of Python is 1.x, 2.x and 3.x. Both Python version 2.x and 3.x are used currently. Code written for Python 3.x is guaranteed for working in all future versions.
Python has several different implementations, CPython is the most popular by far.
Data Structures
None
The None
object is used to represent the absence of a value. The None is returned by any function that doesn't explicitly return anything else.
Numbers
2 * (3 + 4)
# 14
10 / 2
# 5.0
(-7 + 2) * (-4)
# 20
1 + 7.0 + 3
# 11.0
2**5
# 32
9**(1/2)
# 3.0
abs(-99)
# 99
# floor division
20 // 6
# 3
# modulo
20 % 9
# 2
# In-Place Operators
x = 4
x *= 3
x
# 12
Strings
"Python is fun!"
# 'Python is fun!'
"""Customers: Good morning.
Owner: Good morning, Sir."""
# 'Customers: Good morning.\nOwner: Good morning, Sir.'
"Spam" + 'eggs'
# 'Spameggs'
"a" * 3
# 'aaa'
'Numbers: {0}, {1}, {0}'.format(3, 4)
# 'Numbers: 3, 4, 3'
'Hello, {x} {y}'.format(x='John', y='Smith')
# 'Hello, John Smith'
', '.join(['spam', 'eggs'])
# 'spam, eggs'
'Hello world!'.replace('world', 'John')
# 'Hello John!'
'This is a sentence.'.startswith('This')
# True
'This is a sentence.'.endswith('sentence.')
# True
'Hello'.upper()
# 'HELLO'
'Hello'.lower()
# 'hello'
'spam,eggs,ham'.split(',')
# ['spam', 'eggs', 'ham']
Lists
A list can contain items of different types. Lists can also be nested within other lists.
words = ["hello", "world", ["a"], "!"]
print(words[1])
# world
print(words[2][0])
# a
words[1] = "John"
print(words[1])
# John
nums = [1, 2, 3]
print(nums + [4, 5, 6])
# [1, 2, 3, 4, 5, 6]
print(nums * 2)
# [1, 2, 3, 1, 2, 3]
1 in nums
# True
4 not in nums
# True
nums = [1, 2, 3]
len(nums)
# 3
nums.append(5)
nums
# [1, 2, 3, 5]
nums.insert(3, 4)
nums
# [1, 2, 3, 4, 5]
max(nums)
# 5
min(nums)
# 1
sum([1, 2, 3])
# 6
nums.reverse()
nums
# [5, 4, 3, 2, 1]
letters = ['p', 'q', 'p', 'r']
letters.index('p')
# 0
letters.count('p')
# 2
letters.remove('q')
letters
# ['p', 'p', 'r']
nums = list(range(5))
nums
# [0, 1, 2, 3, 4]
nums = list(range(5, 8))
nums
# [5, 6, 7]
nums = list(range(2, 8, 3))
nums
# [2, 5]
nums = [0, 1, 2, 3, 4]
nums[1:4]
# [1, 2, 3]
nums[:4]
# [0, 1, 2, 3]
nums[1:]
# [1, 2, 3, 4]
nums[::2]
# [0, 2, 4]
nums[:-1]
# [0, 1, 2, 3]
nums[::-1]
# [4, 3, 2, 1, 0]
# Comprehensions
cubes = [i**3 for i in range(5)]
cubes
# [0, 1, 8, 27, 64]
evens = [i**2 for i in range(10) if i**2 % 2 == 0]
evens
# [0, 4, 16, 36, 64]
nums = [2, 3]
all(i > 1 for i in nums)
# True
any(i > 2 for i in nums)
# True
for v in enumerate(nums):
print(v)
# (0, 2)
# (1, 3)
Tuples
Tuples are very similar to lists, except that they are immutable.
words = ('spam', 'eggs', 'sausages')
words[0]
# 'spam'
my_tuple = 'one', 'two', 'three'
my_tuple
# ('one', 'two', 'three')
# unpacking
nums = (1, 2, 3)
a, b, c = nums
print(b)
# 2
# swap value
a, b = (1, 2)
a, b = b, a
print(a)
# 2
a, *b, c = (1, 2, 3, 4)
print(a)
print(b)
print(c)
# 1
# [2, 3]
# 4
Dictionaries
Dictionaries are data structures used to map arbitrary keys to values. Only immutable objects can be used as keys.
ages = {'Dave': 24, 'Mary': 42, 'John': 58}
ages['Dave']
# 24
ages['Mary'] = 34
ages['Mary']
# 34
'Mary' in ages
# True
'Ai' not in ages
# True
ages.get('Dave')
# 24
ages.get('Ai')
# None
ages.get('Ai', 'not exist')
# 'not exist'
Sets
Sets are unordered and they cannot contain duplicate elements. It's faster to check whether an item is part of a set, rather than part of a list.
num_set = {1, 2, 3}
word_set = set(['spam', 'eggs', 'sausage'])
print(3 in num_set)
print('apple' not in word_set)
# True
# True
num_set.add(4)
print(num_set)
# {1, 2, 3, 4}
nums.remove(3)
print(num_set)
# {1, 2, 4}
nums.pop() # remove an arbitrary element
# {2, 4}
first = {1, 2, 3}
second = {3, 4, 5}
print(first | second) # gets items in either
print(first & second) # gets items in both
print(first - second) # gets items in the first set but not in the second
print(first ^ second) # gets items in either set, but not both
# {1, 2, 3, 4, 5}
# {3}
# {1, 2}
# {1, 2, 4, 5}
Booleans
2 == 3
# False
2 != 3
# True
2 > 3
# False
3 <= 3
# True
True and True
# True
True or False
# True
not False
# True
# tenary operator
a = 7
b = 1 if a <= 5 else 42
print(b)
# 42
Type Conversion
int("2") + int("3")
# 5
float("40")
# 40.0
str(2)
# '2'
Input and Output
print(1+1)
# 2
print("Hello\nWorld!")
# Hello
# World!
input("Enter someting else:")
# Enter someting else:This is what\n the user enters!
# 'This is what\\n the user enters!'
Files
# Open a file.
# Mode r means read, it is the default.
# Mode w means write, for rewriting the contents of a file.
# Mode a means append, for adding new content to the end of the file.
# Mode b means binary, for non-text files (such as image and sound files)
myfile = open('/path/filename', mode)
# Once a file has been opened and used, you should close it.
myfile.close()
# read all the content
cont = myfile.read()
myfile.read(16) # return 16 bytes
myfile.read() # return the rest of the file
myfile.readlines() # return a list in which each element is a line in the file
myfile.write('something') # write something to the file
# It is good practice to close file after they have been used
try:
f = open('filename')
print(f.read())
finally:
f.close()
# Or this way
with open('filename') as f:
print(f.read())
Control Flow
if Statements
num = 7
if num == 5:
print("Number is 5")
else:
if num == 11:
print("Number is 11")
else:
if num == 7:
print("Number is 7")
else:
print("Number isn't 5, 11 or 7")
num = 7
if num == 5:
print("Number is 5")
elif num == 11:
print("Number is 11")
elif num == 7:
print("Number is 7")
else:
print("Number isn't 5, 11 or 7")
while Loops
i = 1
while i <=5:
print(i)
i = i + 1
# break and continue
i = 0
while True:
i += 1
if i == 2:
print("Skipping 2")
continue
if i == 5:
print("Breaking")
break
print(i)
for Loops
for word in words:
print(word + '!')
# hello!
# world!
for i in range(0, 4, 2):
print(i)
# 0
# 2
for i in range(10):
if i == 999:
break
else:
# only executed if the loop finishes normally
print(1)
# 1
Variables
In Python, variables don't have specific types, so variables can be ressigned values of different types.
Python is case sensitive. Variable names can be consist of letters, numbers and underscores, and they can't start with numbers.
x = 7
print(x + 3)
# 10
x = 'abc'
print(x)
# abc
foo = 'a string'
del foo
foo
# NameError: name 'foo' is not defined
Functions
Functions are just like any other kind of value, they can be assigned to variables and be used as arguments of other functions.
def add(x, y):
return x + y
print(add(2, 3))
# 5
def do_twice(func, x, y):
return func(func(x, y), func(x, y))
print(do_twice(add, 2, 3))
# 10
# default value
def func(x, y, food='spam'):
print(food)
func(1, 2)
# spam
func(1, 2, 'egg')
# egg
# arbitrary number of arguments
def func(named_arg, *args):
print(args)
func(1, 2, 3, 4, 5)
# (2, 3, 4, 5)
# undefined named arguments
def func(x, y=7, *args, **kwargs):
print(kwargs)
func(2, a=7, b=8)
# {'a': 7, 'b': 8}
Comments and Docstrings
# This is a comment
print('below a comment')
def hello(name):
'''
This is a docstring to explain the function
'''
print('hello ' + name)
Modules
There are three main types of modules in Python, those you write yourself, those you install from external sources, and those that are preinstalled with Python.
import math
print(math.pi)
# 3.1415926...
from math import pi
print(pi)
# 3.1415926...
from math import pi as PI
print(PI)
# 3.1415926...
# code inside here will not run if the file is imported
if __name__ == '__main__':
print('This is a script')
Packaging
Place all of the files you want to put in a library in the same parent directory. This directory should also contain a file called __init__.py
, which can be blank but must be present in the directory.
This directory goes into another directory containing the readme and license, as well as an important file called setup.py.
Example directory structure:
SoloLearn/
LICENSE.txt
README.txt
setup.py
sololearn/
__init__.py
sololearn.py
sololearn2.py
Example of a setup.py file:
from distutils.core import setup
setup(
name='SoloLearn',
version='0.1dev',
packages=['sololearn',],
license='MIT',
long_description=open('README.txt').read(),
)
To build a source distribution python setup.py sdist
To build a binary distribution python setup.py bdist
Use python setup.py register
, followed by python setup.py sdist upload
to upload a package.
Use python setup.py install
to install.
Exceptions
try:
variable = 10
print(variable + "hello")
print(variable / 2)
except ZeroDivisionError:
print("Divided by zero")
except (ValueError, TypeError):
print("Error occurred")
except:
print('will catch all exceptions')
finally:
print('This code will run no matter what')
# raise exceptions
raise ValueError
raise NameError("Invalid name!")
# re-raise whatever exception occurred
try:
num = 5 / 0
except:
raise
try:
print(1)
except ZeroDivisionError:
print(2)
else:
# only executed if no error occurs in the try statement
print(3)
# 1
# 3
Assertions
assert 2 + 2 == 4
print(2)
assert 1 + 1 == 3
print(3)
# 2
# AssertionError
temp = -10
assert (temp >= 0), "Colder than absolute zero!"
# AssertionError: Colder than absolute zero!
Functional Programming
Functional programming is a style of programming that is based around functions. A key part of functional programming is higher-order functions. Functional programming seeks to use pure functions. Pure functions have no side effects and return a value that depends only on their arguments.
# use a functions as an argument
def add(x, y):
return x + y
print(add(2, 3))
# 5
def do_twice(func, x, y):
return func(func(x, y), func(x, y))
print(do_twice(add, 2, 3))
# 10
# pure function
def pure_function(x, y):
temp = x + 2 * y
return temp + x
# impure function
some_list = []
def impure(arg):
some_list.append(arg)
Lambdas
(lambda x: x + 2)(4)
# 6
def func(f, arg):
return f(arg)
func(lambda x: x * 2, 3)
# 6
Map and Filter
nums = [0, 1, 2, 3]
list(map(lambda x: x + 5, nums))
# [5, 6, 7, 8]
# filter
list(filter(lambda x: x % 2 == 0, nums))
# [0, 2]
Generators
Generators are a type of iterable, they can be iterated through with for loops.
def count_down():
i = 3
while i > 0:
yield i
i -= 1
for i in count_down():
print(i)
# 3
# 2
# 1
Decorators
Decorators provide a way to modify functions.
def decor(func):
def wrap():
print('===')
func()
return wrap
def print_text():
print('hello world!')
print_text = decor(print_text)
print_text()
# ===
# hello world!
@decor
def print_hi():
print('hi')
print_hi()
# ===
# hi
Recursion
The fundamental part of recursion is self-reference - functions call themselves.
def factorial(x):
if x == 1:
return 1
else:
return x * factorial(x-1)
print(factorial(5))
# 120
Itertools
The module itertools is a standard library that contains several functions that are useful in functional programming.
# counts up infinitely from a value
for i in count(3):
print(i)
if i > 4:
break
# 3
# 4
# 5
Object-Oriented Programming
Class, Inheritance and Object
Destruction of an object occurs when its reference count reaches zero.
class Animal:
# self refers to the instance
def __init__(self, name):
self.name = name
def say_hi(self):
print('Hi I\'m ' + self.name + '.')
# class Cat inherits from class Animal.
class Cat(Animal):
def __init__(self, name, color, legs):
Animal.__init__(self, name)
self.color = color
self.legs = legs
def say_hi(self):
super().say_hi()
print('I\'m a ' + self.color + ' cat with ' + str(self.legs) + ' legs.')
felix = Cat('Felix', 'brown', 4)
felix.say_hi()
# Hi I'm Felix.
# I'm a brown cat with 4 legs.
Magic Methods
Magic methods are special methods which have double underscores at the beginning and the end of their names. One common use of them is operator overloading.
# Overload + operator
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
# x + y is translated into x.__add__(y)
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)
v1 = Vector2D(5, 7)
v2 = Vector2D(3, 9)
v = v1 + v2
print(v.x)
print(v.y)
# 8
# 16
Data Hiding
Weakly private methods and attributes have a single underscore at the beginning. This signals that they shouldn't be used by external code. But it does not stop external code from accessing them, its only actual effect is that from module_name import *
won't import variables that start with a single underscore.
Strongly private methods and attributes have a double underscore at the beginning of their names. This causes their names to be mangled. Name mangled methods can still be accessed externally, but by a different name.
class Spam:
_apple = 3
__egg = 7
def print_egg(self):
print(self.__egg)
s = Spam()
print(s._apple)
s.print_egg()
print(s._Spam__egg)
# 3
# 7
# 7
Class Methods
Class methods are marked with a @classmethod
decorator, they are called by a class. A common use of theses are factory methods.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
@classmethod
def new_square(cls, side_length):
return cls(side_length, side_length)
square = Rectangle.new_square(5)
print(square.area())
# 25
Static Methods
Static methods are marked with a @staticmethod
decorator. They are similar to class methods, except they don't receive any additional arguments.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@staticmethod
def is_square(width, height):
return width == height
print(Rectangle.is_square(5, 5))
# True
Properties
Properties provide a way of customizing access to instance attributes. They are marked with a @property
decorator, when the instance attribute with the same name as the method is accessed, the method will be called instead. One common use of the property is to make an attribute read-only.
Properties can also be set by definning setter/getter functions.
from math import pi, sqrt
class Pizza:
def __init__(self, diameter):
self.diameter = diameter
@property
def size(self):
return pi * ((self.diameter / 2) ** 2)
@size.setter
def size(self, value):
if value:
self.diameter = sqrt(value / pi) * 2
pizza = Pizza(4)
print(pizza.size)
# 12.566370614359172
pizza.size = pi
print(pizza.size)
# 3.141592653589793
Regular Expressions
Regular expressions are a powerful tool for various kinds of string manipulation. They are useful for two main tasks: verifying that strings match a pattern, performing substitutions in a string.
import re
pattern = r'spam'
s = 'eggspamsausagespam'
# returns an object if the pattern matches the beginning of a string
print(re.match(pattern, s))
# None
# returns an object if the pattern matches anywhere of a string
print(re.search(pattern, s))
# <_sre.SRE_Match object; span=(3, 7), match='spam'>
# returns a list of all substrings that match the pattern
print(re.findall(pattern, s))
# ['spam', 'spam']
match = re.search(pattern, s)
# returns the string matched
print(match.group())
# spam
# returns the start and ending position of the first match
print(match.start())
# 3
print(match.end())
# 7
# returns the start and end position of the first match as a tuple
print(match.span())
# (3, 7)
# re.sub replaces all occurences of the pattern int the string with repl, unless max provided. It returns the modified string.
str = 'My name is David. Hi David.'
pattern = r'David'
print(re.sub(pattern, 'Amy', str))
# My name is Amy. Hi Amy.
Metacharacters
. match any character other than a new line
* zero or more repetitions
+ one or more repetitions
? zero or one repetitions
^ match the start
$ match the end
\d match digits
\s match whitespace
\w match word characters
\D match anything that isn't a digit
\S match anything that isn't a whitespace
\W match anything that isn't a word character
\b match the boundary between words
[aeiou] match only one of the set of characters
[a-z] match any lowercase letter
[A-Za-z] match any letter of any case
[0-9] match any digit
(a|e) match a or e
[^ae] match any character other than the ones included
{x,y} between x and y repetitions, default x is 0, default y is infinity
Groups
A group can be given as an argument to metacharacters such as * and ?.
import re
pattern = r'a(bc)(d)(e)?(?P<first>f)g'
match = re.match(pattern, 'abcdefghi')
print(match.group()) # return the whole match
# abcdefg
print(match.group(0)) # return the whole match
# abcdefg
print(match.group(1)) # return 1st group
# bc
print(match.group('first')) # return the named group
# f
print(match.groups()) # return all groups up from 1
# ('bc', 'd', 'e', 'f')
# special sequences. This matches the expression of the group of that number. '(.+) \1' is not the same as '(.+) (.+)', because \1 refers to the first group's subexpression and not the regex pattern.
match = re.match(r'(.+) \1', 'word word')
print(match.groups())
# ('word',)
match = re.match(r'(abc|xyz)\1', 'abcxyz')
print(match)
# None
Pythonicness
import this
will prints the Zen of Python.
PEP 8 is a style guide on the subject of writing readable code.
- modules should have short, all-lowercase names;
- class names should be in the CapWords style;
- most variables and function names should be lowercase_with_underscores;
- constants (variables that never change value) should be CAPS_WITH_UNDERSCORES;
- names that would clash with Python keywords (such as 'class' or 'if') should have a trailing underscore.
- use spaces, rather than tabs, to indent.
- using spaces around operators and after commas to increase readability.
- avoid having any space directly inside any type of brackets.
- lines shouldn't be longer than 80 characters;
- 'from module import *' should be avoided;
- there should only be one statement per line.