0% found this document useful (0 votes)
84 views

Spam Spam: Python Basics Math Operators Highest Lowest Data Types Data Type Examples

Python Basics document that discusses: 1) Math operators from highest to lowest precedence including exponents, multiplication/division, addition/subtraction 2) Data types including integers, floating point numbers, strings, and examples of each 3) Variables naming rules and examples of assigning variables 4) Comments including inline, multiline, and docstring comments 5) Functions including print(), input(), len(), and boolean, comparison, and logical operators

Uploaded by

Marvin Pineda
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
84 views

Spam Spam: Python Basics Math Operators Highest Lowest Data Types Data Type Examples

Python Basics document that discusses: 1) Math operators from highest to lowest precedence including exponents, multiplication/division, addition/subtraction 2) Data types including integers, floating point numbers, strings, and examples of each 3) Variables naming rules and examples of assigning variables 4) Comments including inline, multiline, and docstring comments 5) Functions including print(), input(), len(), and boolean, comparison, and logical operators

Uploaded by

Marvin Pineda
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 42

Python Basics 16.0 3. It can’t begin with a number.

4. Variable name starting with an underscore


Math Operators Data Types (_) are considered as "unuseful`.
Example:
From Highest to Lowest precedence: Data Type Examples
>>> spam = 'Hello'

>>> spam
Integers -2, -1, 0, 1, 2, 3, 4, 5
'Hello'

Floating-point -1.25, -1.0, --0.5, 0.0, >>> _spam = 'Hello'


numbers 0.5, 1.0, 1.25
_spam should not be used again in the code.

Strings 'a', 'aa', 'aaa',


'Hello!', '11 cats' Comments

Inline comment:

# This is a comment
String Concatenation and Replication

Examples of expressions in the interactive shell: String concatenation: Multiline comment:

>>> 2 + 3 * 6 >>> 'Alice' 'Bob' # This is a

20 'AliceBob' # multiline comment

>>> (2 + 3) * 6 Note: Avoid + operator for string concatenation. Code with a comment:


Prefer string formatting.
30 a = 1 # initialization

>>> 2 ** 8 String Replication:


Please note the two spaces in front of the comment.
>>> 'Alice' * 5
256 Function docstring:
'AliceAliceAliceAliceAlice'
>>> 23 // 7 def foo():

3 Variables """

>>> 23 % 7 You can name a variable anything as long as it obeys This is a function docstring
the following three rules:
2 You can also use:
1. It can be only one word.
>>> (5 - 1) * ((7 + 1) / (3 - 1))
2. It can use only letters, numbers, and the ''' Function Docstring '''
underscore (_) character.
""" >>> if a:
Operator Meaning
>>> print("the list is not empty!")
The print() Function
>>> print('Hello world!') The str(), int(), and float() Functions
Hello world! Integer to String or Float:
> Greater Than
>>> a = 1 >>> str(29)

>>> print('Hello world!', a) '29' <= Less than or Equal to


Hello world! 1 >>> print('I am {} years
old.'.format(str(29)))
>= Greater than or Equal to
The input() Function
I am 29 years old.
Example Code: These operators evaluate to True or False depending
>>> str(-3.14)
on the values you give them.
>>> print('What is your name?') # ask
for their name '-3.14'
Examples:
>>> myName = input() Float to Integer:
>>> 42 == 42
>>> print('It is good to meet you, >>> int(7.7)
{}'.format(myName)) True
7
What is your name? >>> 40 == 42
>>> int(7.7) + 1
Al False
8
It is good to meet you, Al >>> 'hello' == 'hello'

Flow Control True


The len() Function
Comparison Operators >>> 'hello' == 'Hello'
Evaluates to the integer value of the number of
characters in a string: False
Operator Meaning
>>> len('hello') >>> 'dog' != 'cat'

5 == Equal to True

Note: test of emptiness of strings, lists, dictionary, etc, >>> 42 == 42.0


should not use len, but prefer direct boolean != Not equal to
evaluation. True

>>> a = [1, 2, 3] >>> 42 == '42'


< Less than
False >>> if a is not True: The not Operator’s Truth Table:

>>> pass
Boolean evaluation Expression Evaluates to
Never use == or != operator to evaluate boolean >>> if not a:
operation. Use the is or is not operators, or use
>>> pass not True False
implicit boolean evaluation.

NO (even if they are valid Python): Boolean Operators


not False True
>>> True == True There are three Boolean operators: and, or, and not.

True The and Operator’s Truth Table:
Mixing Boolean and Comparison Operators
>>> True != False
Expression Evaluates to >>> (4 < 5) and (5 < 6)

True True
True and True True
YES (even if they are valid Python): >>> (4 < 5) and (9 < 6)

>>> True is True False


True and False False
True >>> (1 == 2) or (2 == 2)

>>> True is not False False and True False True

True You can also use multiple Boolean operators in an


False and False False
expression, along with the comparison operators:
These statements are equivalent:
The or Operator’s Truth Table: >>> 2 + 2 == 4 and not 2 + 2 == 5 and 2
>>> if a is True: * 2 == 2 + 2

>>> pass Expression Evaluates to True

>>> if a is not False:


if Statements
True or True True
>>> pass if name == 'Alice':

>>> if a: print('Hi, Alice.')


True or False True
>>> pass
else Statements
False or True True
And these as well: name = 'Bob'

>>> if a is False: if name == 'Alice':


False or False False
>>> pass print('Hi, Alice.')
else: If the execution reaches a break statement, it >>> print('Jimmy Five Times
immediately exits the while loop’s clause: ({})'.format(str(i)))
print('Hello, stranger.')
while True: My name is

elif Statements Jimmy Five Times (0)


print('Please type your name.')
name = 'Bob'
name = input() Jimmy Five Times (1)
age = 5
if name == 'your name': Jimmy Five Times (2)
if name == 'Alice':
break Jimmy Five Times (3)
print('Hi, Alice.')
print('Thank you!') Jimmy Five Times (4)
elif age < 12:
The range() function can also be called with three
continue Statements
print('You are not Alice, kiddo.') arguments. The first two arguments will be the start
When the program execution reaches a continue and stop values, and the third will be the step
name = 'Bob'
statement, the program execution immediately jumps argument. The step is the amount that the variable is
back to the start of the loop. increased by after each iteration.
age = 30
while True: >>> for i in range(0, 10, 2):
if name == 'Alice':
print('Who are you?') >>> print(i)
print('Hi, Alice.')
name = input() 0
elif age < 12:
if name != 'Joe': 2
print('You are not Alice, kiddo.')
continue 4
else:
print('Hello, Joe. What is the 6
print('You are neither Alice nor a
password? (It is a fish.)')
little kid.') 8
password = input()
while Loop Statements You can even use a negative number for the step
if password == 'swordfish': argument to make the for loop count down instead of
spam = 0
up.
break
while spam < 5:
>>> for i in range(5, -1, -1):
print('Access granted.')
print('Hello, world.')
>>> print(i)
spam = spam + 1 for Loops and the range() Function
5
>>> print('My name is')
break Statements 4
>>> for i in range(5):
3
2 if response == 'exit': elif answerNumber == 4:

1 sys.exit() return 'Reply hazy try again'

0 print('You typed elif answerNumber == 5:


{}.'.format(response))
return 'Ask again later'
For else statement
Functions
This allows to specify a statement to execute in case elif answerNumber == 6:
>>> def hello(name):
of the full loop has been executed. Only useful when
return 'Concentrate and ask
a break condition can occur in the loop: >>> print('Hello {}'.format(name)) again'
>>> for i in [1, 2, 3, 4, 5]: >>> elif answerNumber == 7:
>>> if i == 3: >>> hello('Alice') return 'My reply is no'
>>> break >>> hello('Bob') elif answerNumber == 8:
>>> else: Hello Alice return 'Outlook not so good'
>>> print("only executed when no item Hello Bob elif answerNumber == 9:
of the list is equal to 3")
return 'Very doubtful'
Return Values and return Statements
Importing Modules
When creating a function using the def statement,
import random
you can specify what the return value should be with a
return statement. A return statement consists of the r = random.randint(1, 9)
for i in range(5):
following:
fortune = getAnswer(r)
print(random.randint(1, 10))
 The return keyword. print(fortune)
import random, sys, os, math  The value or expression that the function
should return.
from random import *. import random The None Value
>>> spam = print('Hello!')
def getAnswer(answerNumber):
Ending a Program Early with sys.exit()
Hello!
import sys if answerNumber == 1:
>>> spam is None
return 'It is certain'
True
while True: elif answerNumber == 2:

return 'It is decidedly so' Note: never compare to None with the == operator.


print('Type exit to exit.')
Always use is.
response = input() elif answerNumber == 3:
Keyword Arguments and print()
return 'Yes'
>>> print('Hello', end='') spam None

>>> print('World') There are four rules to tell whether a variable is in a 42.0
local scope or global scope:
HelloWorld
Final code in exception handling
1. If a variable is being used in the global scope
>>> print('cats', 'dogs', 'mice') Code inside the finally section is always executed,
(that is, outside of all functions), then it is always
a global variable. no matter if an exception has been raised or not, and
cats dogs mice
2. If there is a global statement for that variable even if an exception is not caught.
>>> print('cats', 'dogs', 'mice', in a function, it is a global variable.
3. Otherwise, if the variable is used in an >>> def spam(divideBy):
sep=',')
assignment statement in the function, it is a
>>> try:
cats,dogs,mice local variable.
4. But if the variable is not used in an
>>> return 42 / divideBy
Local and Global Scope assignment statement, it is a global variable.
>>> except ZeroDivisionError as e:
 Code in the global scope cannot use any Exception Handling
local variables. >>> print('Error: Invalid
 However, a local scope can access global argument: {}'.format(e))
Basic exception handling
variables.
 Code in a function’s local scope cannot use >>> def spam(divideBy): >>> finally:
variables in any other local scope.
 You can use the same name for different >>> try: >>> print("-- division finished
--")
variables if they are in different scopes. That is,
there can be a local variable named spam and a >>> return 42 / divideBy
>>> print(spam(12))
global variable also named spam.
>>> except ZeroDivisionError as e:
>>> print(spam(0))
The global Statement >>> print('Error: Invalid
argument: {}'.format(e)) 21.0
If you need to modify a global variable from within a
function, use the global statement: >>> -- division finished --

>>> def spam(): >>> print(spam(2)) 3.5

>>> global eggs >>> print(spam(12)) -- division finished --

>>> eggs = 'spam' >>> print(spam(0)) Error: Invalid argument: division by


zero
>>> >>> print(spam(1))
-- division finished --
>>> eggs = 'global' 21.0
None
>>> spam() 3.5
-- division finished --
>>> print(eggs) Error: Invalid argument: division by
zero 42.0
-- division finished -- >>> 'The {} is afraid of the Getting a List’s Length with len()
{}.'.format(spam[-1], spam[-3])
>>> spam = ['cat', 'dog', 'moose']
Lists
'The elephant is afraid of the bat.'
>>> spam = ['cat', 'bat', 'rat', >>> len(spam)
'elephant']
Getting Sublists with Slices 3
>>> spam = ['cat', 'bat', 'rat',
'elephant'] Changing Values in a List with Indexes
>>> spam
>>> spam[0:4] >>> spam = ['cat', 'bat', 'rat',
['cat', 'bat', 'rat', 'elephant'] 'elephant']
['cat', 'bat', 'rat', 'elephant']
>>> spam[1] = 'aardvark'
Getting Individual Values in a List with Indexes
>>> spam[1:3]
>>> spam = ['cat', 'bat', 'rat',
'elephant'] ['bat', 'rat']
>>> spam
>>> spam[0] >>> spam[0:-1]
['cat', 'aardvark', 'rat', 'elephant']
'cat' ['cat', 'bat', 'rat']

>>> spam[1] >>> spam = ['cat', 'bat', 'rat',


'elephant'] >>> spam[2] = spam[1]
'bat'
>>> spam[:2]
>>> spam[2]
['cat', 'bat'] >>> spam
'rat'
>>> spam[1:] ['cat', 'aardvark', 'aardvark',
>>> spam[3] 'elephant']
['bat', 'rat', 'elephant']
'elephant'
Slicing the complete list will perform a copy:
>>> spam[-1] = 12345
Negative Indexes
>>> spam2 = spam[:]
>>> spam = ['cat', 'bat', 'rat',
'elephant'] ['cat', 'bat', 'rat', 'elephant']
>>> spam
>>> spam[-1] >>> spam.append('dog')
['cat', 'aardvark', 'aardvark', 12345]
'elephant' >>> spam
List Concatenation and List Replication
>>> spam[-3] ['cat', 'bat', 'rat', 'elephant', 'dog']
>>> [1, 2, 3] + ['A', 'B', 'C']
'bat' >>> spam2
[1, 2, 3, 'A', 'B', 'C']
['cat', 'bat', 'rat', 'elephant']
Index 0 in supplies is: pens The multiple assignment trick is a shortcut that lets
you assign multiple variables with the values in a list
>>> ['X', 'Y', 'Z'] * 3 Index 1 in supplies is: staplers in one line of code. So instead of doing this:

['X', 'Y', 'Z', 'X', 'Y', 'Z', 'X', 'Y', Index 2 in supplies is: flame-throwers >>> cat = ['fat', 'orange', 'loud']
'Z']
Index 3 in supplies is: binders

Looping Through Multiple Lists with zip() >>> size = cat[0]


>>> spam = [1, 2, 3]
>>> name = ['Pete', 'John', 'Elizabeth']

>>> age = [6, 23, 44] >>> color = cat[1]


>>> spam = spam + ['A', 'B', 'C']
>>> for n, a in zip(name, age):

>>> print('{} is {} years >>> disposition = cat[2]


>>> spam old'.format(n, a))
You could type this line of code:
[1, 2, 3, 'A', 'B', 'C'] Pete is 6 years old
>>> cat = ['fat', 'orange', 'loud']
Removing Values from Lists with del Statements John is 23 years old

>>> spam = ['cat', 'bat', 'rat', Elizabeth is 44 years old


'elephant']
>>> size, color, disposition = cat
>>> del spam[2] The in and not in Operators
The multiple assignment trick can also be used to
>>> 'howdy' in ['hello', 'hi', 'howdy',
>>> spam swap the values in two variables:
'heyas']

['cat', 'bat', 'elephant'] >>> a, b = 'Alice', 'Bob'


True

>>> del spam[2] >>> a, b = b, a


>>> spam = ['hello', 'hi', 'howdy',
'heyas']
>>> spam >>> print(a)
>>> 'cat' in spam
['cat', 'bat'] 'Bob'
False
>>> print(b)
Using for Loops with Lists
>>> 'howdy' not in spam
'Alice'
>>> supplies = ['pens', 'staplers',
'flame-throwers', 'binders'] False
Augmented Assignment Operators
>>> for i, supply in >>> 'cat' not in spam
enumerate(supplies):
True
>>> print('Index {} in supplies is:
{}'.format(str(i), supply))
The Multiple Assignment Trick
1 If the value appears multiple times in the list, only the
Operator Equivalent
first instance of the value will be removed.
Adding Values to Lists with the append() and
spam += 1 spam = spam + 1 insert() Methods Sorting the Values in a List with the sort() Method

append(): >>> spam = [2, 5, 3.14, 1, -7]

spam -= 1 spam = spam - 1 >>> spam = ['cat', 'dog', 'bat'] >>> spam.sort()

>>> spam
spam *= 1 spam = spam * 1
>>> spam.append('moose') [-7, 1, 2, 3.14, 5]

spam /= 1 spam = spam / 1 >>> spam = ['ants', 'cats', 'dogs',


'badgers', 'elephants']
>>> spam
spam %= 1 spam = spam % 1 >>> spam.sort()
['cat', 'dog', 'bat', 'moose']
>>> spam
Examples: insert():
['ants', 'badgers', 'cats', 'dogs',
>>> spam = 'Hello' >>> spam = ['cat', 'dog', 'bat'] 'elephants']

>>> spam += ' world!' You can also pass True for the reverse keyword
argument to have sort() sort the values in reverse
>>> spam >>> spam.insert(1, 'chicken') order:

'Hello world!' >>> spam.sort(reverse=True)

>>> spam >>> spam

>>> bacon = ['Zophie'] ['cat', 'chicken', 'dog', 'bat'] ['elephants', 'dogs', 'cats', 'badgers',
'ants']
>>> bacon *= 3
Removing Values from Lists with remove()
If you need to sort the values in regular alphabetical
>>> bacon
>>> spam = ['cat', 'bat', 'rat', order, pass str. lower for the key keyword argument in
'elephant'] the sort() method call:
['Zophie', 'Zophie', 'Zophie']
>>> spam = ['a', 'z', 'A', 'Z']
Finding a Value in a List with the index() Method
>>> spam.remove('bat') >>> spam.sort(key=str.lower)
>>> spam = ['Zophie', 'Pooka', 'Fat-
tail', 'Pooka']
>>> spam

>>> spam ['a', 'A', 'z', 'Z']


>>> spam.index('Pooka') ['cat', 'rat', 'elephant']
You can use the built-in function sorted to return a Example Dictionary: >>>
new list:
myCat = {'size': 'fat', 'color': 'gray', >>> for k, v in spam.items():
>>> spam = ['ants', 'cats', 'dogs', 'disposition': 'loud'}
'badgers', 'elephants'] >>> print('Key: {} Value:
{}'.format(k, str(v)))
The keys(), values(), and items() Methods
>>> sorted(spam)
Key: age Value: 42
values():
['ants', 'badgers', 'cats', 'dogs',
'elephants'] Key: color Value: red
>>> spam = {'color': 'red', 'age': 42}

Tuple Data Type >>> for v in spam.values(): Checking Whether a Key or Value Exists in a
Dictionary
>>> eggs = ('hello', 42, 0.5) >>> print(v)
>>> spam = {'name': 'Zophie', 'age': 7}
>>> eggs[0] red
>>> 'name' in spam.keys()
'hello' 42
True
>>> eggs[1:3] keys():
>>> 'Zophie' in spam.values()
(42, 0.5) >>> for k in spam.keys():
True
>>> len(eggs) >>> print(k)
>>> # You can omit the call to keys()
3 when checking for a key
color

The main way that tuples are different from lists is >>> 'color' in spam
age
that tuples, like strings, are immutable.
False
items():
Converting Types with the list() and tuple() >>> 'color' not in spam
>>> for i in spam.items():
Functions
True
>>> tuple(['cat', 'dog', 5]) >>> print(i)

('cat', 'dog', 5) ('color', 'red') The get() Method


>>> picnic_items = {'apples': 5, 'cups':
>>> list(('cat', 'dog', 5)) ('age', 42)
2}
['cat', 'dog', 5] Using the keys(), values(), and items() methods, a for
loop can iterate over the keys, values, or key-value
>>> list('hello') pairs in a dictionary, respectively. >>> 'I am bringing {}
cups.'.format(str(picnic_items.get('cups
['h', 'e', 'l', 'l', 'o'] ', 0)))

Dictionaries and Structuring Data >>> spam = {'color': 'red', 'age': 42} 'I am bringing 2 cups.'
>>> 'I am bringing {} >>> message = 'It was a bright cold day 'l': 3,
eggs.'.format(str(picnic_items.get('eggs in April, and the clocks were striking
', 0))) 'n': 4,
>>> thirteen.'
'I am bringing 0 eggs.' 'o': 2,
>>> count = {}
The setdefault() Method 'p': 1,
>>>
Let's consider this code: 'r': 5,
>>> for character in message:
spam = {'name': 'Pooka', 'age': 5} 's': 3,
>>> count.setdefault(character, 0)
't': 6,
>>> count[character] =
if 'color' not in spam: count[character] + 1 'w': 2,

spam['color'] = 'black' >>> 'y': 1}

>>> pprint.pprint(count)
Using setdefault we could write the same code Merge two dictionaries
more succinctly: {' ': 13, # in Python 3.5+:
>>> spam = {'name': 'Pooka', 'age': 5} ',': 1, >>> x = {'a': 1, 'b': 2}
>>> spam.setdefault('color', 'black') '.': 1, >>> y = {'b': 3, 'c': 4}
'black' 'A': 1, >>> z = {**x, **y}
>>> spam 'I': 1, >>> z
{'color': 'black', 'age': 5, 'name': 'a': 4, {'c': 4, 'a': 1, 'b': 3}
'Pooka'}
'b': 1,
>>> spam.setdefault('color', 'white')
'c': 3, # in Python 2.7
'black'
'd': 3, >>> z = dict(x, **y)
>>> spam
'e': 5, >>> z
{'color': 'black', 'age': 5, 'name':
'Pooka'}
'g': 2, {'c': 4, 'a': 1, 'b': 3}

Pretty Printing 'h': 3,


sets
>>> import pprint
'i': 6, From the Python 3 documentation
>>>
'k': 2,
A set is an unordered collection with no duplicate
elements. Basic uses include membership testing and
eliminating duplicate entries. Set objects also support set add() and update() >>> s = {1, 2, 3}
mathematical operations like union, intersection,
difference, and symmetric difference. Using the add() method we can add a single >>> s.discard(3)
element to the set.
>>> s
Initializing a set >>> s = {1, 2, 3}
{1, 2}
There are two ways to create sets: using curly >>> s.add(4)
braces {} and the bult-in function set() >>> s.discard(3)
>>> s
>>> s = {1, 2, 3} >>>
{1, 2, 3, 4}
>>> s = set([1, 2, 3])
set union()
And with update(), multiple ones .
When creating an empty set, be sure to not use the
union() or | will create a new set that contains all
curly braces {} or you will get an empty dictionary >>> s = {1, 2, 3} the elements from the sets provided.
instead.
>>> s.update([2, 3, 4, 5, 6]) >>> s1 = {1, 2, 3}
>>> s = {}
>>> s >>> s2 = {3, 4, 5}
>>> type(s)
{1, 2, 3, 4, 5, 6} # remember, sets >>> s1.union(s2) # or 's1 | s2'
<class 'dict'> automatically remove duplicates
{1, 2, 3, 4, 5}
sets: unordered collections of unique elements set remove() and discard()
set intersection
A set automatically remove all the duplicate values. Both methods will remove an element from the set,
but remove() will raise a key error if the value intersection or & will return a set containing only
>>> s = {1, 2, 3, 2, 3, 4} doesn't exist. the elements that are common to all of them.
>>> s >>> s = {1, 2, 3} >>> s1 = {1, 2, 3}
{1, 2, 3, 4} >>> s.remove(3) >>> s2 = {2, 3, 4}

And as an unordered data type, they can't be indexed. >>> s >>> s3 = {3, 4, 5}

>>> s = {1, 2, 3} {1, 2} >>> s1.intersection(s2, s3) # or 's1 &


s2 & s3'
>>> s[0] >>> s.remove(3)
{3}
Traceback (most recent call last): Traceback (most recent call last):

File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <module> set difference

difference or - will return only the elements that


TypeError: 'set' object does not support KeyError: 3
indexing are in one of the sets.

discard() won't raise any errors. >>> s1 = {1, 2, 3}


>>>
>>> s2 = {2, 3, 4} Example: >>> print(each)

>>> s1.difference(s2) # or 's1 - s2' >>> data = [1, 2, 3, 4, 5] 5

{1} >>> result = itertools.accumulate(data, 7


operator.mul)
13
set symetric_difference
>>> for each in result:
symetric_difference or ^ will return all the 17
elements that are not common between them. >>> print(each)
22
>>> s1 = {1, 2, 3} 1
31
>>> s2 = {2, 3, 4} 2
32
>>> s1.symmetric_difference(s2) # or 6
's1 ^ s2' If no function is designated the items will be summed:
24
{1, 4} 5
120
5 + 2 = 7
itertools Module
The operator.mul takes two numbers and multiplies
The itertools module is a colection of tools intented to them: 7 + 6 = 13
be fast and use memory efficiently when handling
iterators (like lists or dictionaries). operator.mul(1, 2) 13 + 4 = 17

2 17 + 5 = 22
From the official Python 3.x documentation:
operator.mul(2, 3) 22 + 9 = 31
The module standardizes a core set of fast, memory
efficient tools that are useful by themselves or in 6 31 + 1 = 32
combination. Together, they form an “iterator
algebra” making it possible to construct specialized operator.mul(6, 4) combinations()
tools succinctly and efficiently in pure Python.
24 Takes an iterable and a integer. This will create all the
The itertools module comes in the standard library
unique combination that have r members.
and must be imported. operator.mul(24, 5)
itertools.combinations(iterable, r)
The operator module will also be used. This module is 120
not necessary when using itertools, but needed for
Example:
some of the examples below. Passing a function is optional:
>>> shapes = ['circle', 'triangle',
>>> data = [5, 2, 6, 4, 5, 9, 1] 'square',]
accumulate()

Makes an iterator that returns the results of a >>> result = itertools.accumulate(data) >>> result =
function. itertools.combinations(shapes, 2)
>>> for each in result:
itertools.accumulate(iterable[, func]) >>> for each in result:
>>> print(each) Example: red

('circle', 'triangle') >>> for i in itertools.count(10,3): orange

('circle', 'square') >>> print(i) When reached the end of the iterable it start over
again from the beginning.
('triangle', 'square') >>> if i > 20:

>>> break chain()


combinations_with_replacement()
Take a series of iterables and return them as one long
Just like combinations(), but allows individual 10
iterable.
elements to be repeated more than once.
13
itertools.chain(*iterables)
itertools.combinations_with_replacement(
iterable, r) 16
Example:

Example: 19
>>> colors = ['red', 'orange', 'yellow',
'green', 'blue']
>>> shapes = ['circle', 'triangle', 22
'square'] >>> shapes = ['circle', 'triangle',
cycle() 'square', 'pentagon']
>>> result =
itertools.combinations_with_replacement( This function cycles through an iterator endlessly. >>> result = itertools.chain(colors,
shapes, 2) shapes)
itertools.cycle(iterable)
>>> for each in result: >>> for each in result:
Example:
>>> print(each) >>> print(each)
>>> colors = ['red', 'orange', 'yellow',
('circle', 'circle') 'green', 'blue', 'violet'] red

('circle', 'triangle') >>> for color in orange


itertools.cycle(colors):
('circle', 'square') yellow
>>> print(color)
('triangle', 'triangle') green
red
('triangle', 'square') blue
orange
('square', 'square') circle
yellow
count() triangle
green
Makes an iterator that returns evenly spaced values square
starting with number start. blue
pentagon
itertools.count(start=0, step=1) violet
compress() 7 Example:

Filters one iterable with another. 8 >>> robots = [{

itertools.compress(data, selectors) 9 'name': 'blaster',

Example: 10 'faction': 'autobot'

>>> shapes = ['circle', 'triangle', 1 }, {


'square', 'pentagon']
filterfalse() 'name': 'galvatron',
>>> selections = [True, False, True,
False] Makes an iterator that filters elements from iterable 'faction': 'decepticon'
returning only those for which the predicate is False.
>>> result = itertools.compress(shapes, }, {
selections)
itertools.filterfalse(predicate,
iterable) 'name': 'jazz',
>>> for each in result:

Example: 'faction': 'autobot'


>>> print(each)
>>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, }, {
circle
10]
'name': 'metroplex',
square
>>> result =
itertools.filterfalse(lambda x: x<5, 'faction': 'autobot'
dropwhile() data)
}, {
Make an iterator that drops elements from the >>> for each in result:
iterable as long as the predicate is true; afterwards, 'name': 'megatron',
returns every element. >>> print(each)
'faction': 'decepticon'
itertools.dropwhile(predicate, iterable) 5
}, {
Example: 6
'name': 'starcream',
>>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 7
10, 1] 'faction': 'decepticon'
8
>>> result = itertools.dropwhile(lambda }]
x: x<5, data) 9
>>> for key, group in
>>> for each in result: 10 itertools.groupby(robots, key=lambda x:
x['faction']):
>>> print(each)
groupby() >>> print(key)
5 Simply put, this function groups things together.
>>> print(list(group))
6 itertools.groupby(iterable, key=None)
autobot itertools.permutations(iterable, r=None) (2, 'b')

[{'name': 'blaster', 'faction': Example: (2, 'c')


'autobot'}]
>>> alpha_data = ['a', 'b', 'c'] (3, 'a')
decepticon
>>> result = (3, 'b')
[{'name': 'galvatron', 'faction': itertools.permutations(alpha_data)
'decepticon'}] (3, 'c')
>>> for each in result:
autobot
repeat()
>>> print(each)
[{'name': 'jazz', 'faction': 'autobot'},
{'name': 'metroplex', 'faction': This function will repeat an object over and over
('a', 'b', 'c') again. Unless, there is a times argument.
'autobot'}]
('a', 'c', 'b') itertools.repeat(object[, times])
decepticon
('b', 'a', 'c')
[{'name': 'megatron', 'faction': Example:
'decepticon'}, {'name': 'starcream',
('b', 'c', 'a')
'faction': 'decepticon'}] >>> for i in itertools.repeat("spam",
3):
('c', 'a', 'b')
islice() print(i)
('c', 'b', 'a')
This function is very much like slices. This allows you
spam
to cut out a piece of an iterable.
product()
spam
itertools.islice(iterable, start, stop[,
step]) Creates the cartesian products from a series of
iterables. spam
Example:
>>> num_data = [1, 2, 3]
starmap()
>>> colors = ['red', 'orange', 'yellow',
>>> alpha_data = ['a', 'b', 'c'] Makes an iterator that computes the function using
'green', 'blue',]
arguments obtained from the iterable.
>>> result = itertools.product(num_data,
>>> few_colors =
alpha_data)
itertools.islice(colors, 2) itertools.starmap(function, iterable)
>>> for each in result:
>>> for each in few_colors: Example:
print(each)
>>> print(each) >>> data = [(2, 6), (8, 4), (7, 3)]
(1, 'a')
red >>> result =
itertools.starmap(operator.mul, data)
(1, 'b')
orange
>>> for each in result:
(1, 'c')
permutations()
>>> print(each)
(2, 'a')
12 >>> for each in alpha_colors: >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9,
10,]
32 >>> print(each)
>>> for each in
21 red itertools.zip_longest(colors, data,
fillvalue=None):
orange
takewhile() >>> print(each)
The opposite of dropwhile(). Makes an iterator and yellow
('red', 1)
returns elements from the iterable as long as the
green
predicate is true. ('orange', 2)
blue
itertools.takwwhile(predicate, iterable) ('yellow', 3)
>>> colors = ['red', 'orange', 'yellow',
Example: 'green', 'blue'] ('green', 4)

>>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, >>> alpha_colors, beta_colors = ('blue', 5)


10, 1] itertools.tee(colors)
(None, 6)
>>> result = itertools.takewhile(lambda >>> for each in beta_colors:
x: x<5, data) (None, 7)
>>> print(each)
>>> for each in result: (None, 8)
red
>>> print(each) (None, 9)
orange
1 (None, 10)
yellow
2
Comprehensions
green
3
blue List comprehension
4
>>> a = [1, 3, 5, 7, 9, 11]
zip_longest()
tee()
Makes an iterator that aggregates elements from each
Return n independent iterators from a single iterable.
of the iterables. If the iterables are of uneven length, >>> [i - 1 for i in a]
missing values are filled-in with fillvalue. Iteration
itertools.tee(iterable, n=2)
continues until the longest iterable is exhausted. [0, 2, 4, 6, 8, 10]

Example: itertools.zip_longest(*iterables, Set comprehension


fillvalue=None)
>>> colors = ['red', 'orange', 'yellow',
>>> b = {"abc", "def"}
'green', 'blue']
Example:
>>> {s.upper() for s in b}
>>> alpha_colors, beta_colors =
itertools.tee(colors) >>> colors = ['red', 'orange', 'yellow',
'green', 'blue',] {"ABC", "DEF}
Dict comprehension Hello there! To keep a nicer flow in your code, you can use
the dedent function from the textwrap standard
>>> c = {'name': 'Pooka', 'age': 5} How are you? package.
>>> {v: k for k, v in c.items()} I'm doing fine. >>> from textwrap import dedent
{'Pooka': 'name', 5: 'age'}
Raw Strings >>>

A List comprehension can be generated from a A raw string completely ignores all escape characters >>> def my_function():
dictionary: and prints any backslash that appears in the string.
>>> print('''
>>> c = {'name': 'Pooka', 'first_name': >>> print(r'That is Carol\'s cat.')
'Oooka'} >>> Dear Alice,
That is Carol\'s cat.
>>> ["{}:{}".format(k.upper(), >>>
v.upper()) for k, v in c.items()]
Note: mostly used for regular expression definition
(see re package) >>> Eve's cat has been arrested
['NAME:POOKA', 'FIRST_NAME:OOOKA'] for catnapping, cat burglary, and
extortion.
Manipulating Strings Multiline Strings with Triple Quotes
>>>
>>> print('''Dear Alice,
Escape Characters
>>> Sincerely,
>>>
Escape Prints as >>> Bob
character >>> Eve's cat has been arrested for
catnapping, cat burglary, and extortion.
>>> ''').strip()
>>>
\' Single quote This generates the same string than before.
>>> Sincerely,
Indexing and Slicing Strings
\" Double quote >>> Bob''')
H e l l o w o r l
Dear Alice, d !
\t Tab 0 1 2 3 4 5 6 7 8 9
10 11
Eve's cat has been arrested for
\n Newline (line break) catnapping, cat burglary, and extortion. >>> spam = 'Hello world!'

\\ Backslash
Sincerely, >>> spam[0]

Example: Bob 'H'

>>> print("Hello there!\nHow are >>> spam[4]


you?\nI\'m doing fine.")
'o' >>> 'Hello' in 'Hello' isupper() and islower():

>>> spam[-1] True >>> spam = 'Hello world!'

'!' >>> 'HELLO' in 'Hello World' >>> spam.islower()

Slicing: False False

>>> '' in 'spam' >>> spam.isupper()

>>> spam[0:5] True False

'Hello' >>> 'cats' not in 'cats and dogs' >>> 'HELLO'.isupper()

>>> spam[:5] False True

'Hello' The in and not in Operators with list >>> 'abc12345'.islower()

>>> spam[6:] >>> a = [1, 2, 3, 4] True

'world!' >>> 5 in a >>> '12345'.islower()

>>> spam[6:-1] False False

'world' >>> 2 in a >>> '12345'.isupper()

>>> spam[:-1] True False

'Hello world'
The upper(), lower(), isupper(), and islower() The isX String Methods
>>> spam[::-1] String Methods
 isalpha() returns True if the string consists
upper() and lower(): only of letters and is not blank.
'!dlrow olleH'
 isalnum() returns True if the string consists
>>> spam = 'Hello world!'
>>> spam = 'Hello world!' only of lettersand numbers and is not blank.
>>> spam = spam.upper()  isdecimal() returns True if the string consists
>>> fizz = spam[0:5] only ofnumeric characters and is not blank.

>>> fizz
>>> spam  isspace() returns True if the string consists
only of spaces,tabs, and new-lines and is not
'HELLO WORLD!' blank.
'Hello'
>>> spam = spam.lower()  istitle() returns True if the string consists
The in and not in Operators with Strings only of wordsthat begin with an uppercase
>>> spam letter followed by onlylowercase letters.
>>> 'Hello' in 'Hello World'
'hello world!' The startswith() and endswith() String Methods
True
>>> 'Hello world!'.startswith('Hello')
True >>> '=======Hello========'
'MyABCnameABCisABCSimon'.split('ABC')
>>> 'Hello world!'.endswith('world!')
['My', 'name', 'is', 'Simon'] Removing Whitespace with strip(), rstrip(), and
True lstrip()
>>> 'My name is Simon'.split('m') >>> spam = ' Hello World '
>>> 'abc123'.startswith('abcdef')
['My na', 'e is Si', 'on'] >>> spam.strip()
False
Justifying Text with rjust(), ljust(), and center() 'Hello World'
>>> 'abc123'.endswith('12')
rjust() and ljust(): >>> spam.lstrip()
False
>>> 'Hello'.rjust(10) 'Hello World '
>>> 'Hello world!'.startswith('Hello
world!') ' Hello' >>> spam.rstrip()

True >>> 'Hello'.rjust(20) ' Hello World'

>>> 'Hello world!'.endswith('Hello ' Hello' >>> spam =


world!') 'SpamSpamBaconSpamEggsSpamSpam'
>>> 'Hello World'.rjust(20)
True >>> spam.strip('ampS')
' Hello World'
The join() and split() String Methods 'BaconSpamEggs'
>>> 'Hello'.ljust(10)
join():
Copying and Pasting Strings with the pyperclip
'Hello '
>>> ', '.join(['cats', 'rats', 'bats']) Module (need pip install)

An optional second argument to rjust() and ljust() will >>> import pyperclip
'cats, rats, bats' specify a fill character other than a space character.
Enter the following into the interactive shell:
>>> ' '.join(['My', 'name', 'is',
'Simon']) >>> pyperclip.copy('Hello world!')
>>> 'Hello'.rjust(20, '*')
'My name is Simon'
'***************Hello'
>>> 'ABC'.join(['My', 'name', 'is', >>> pyperclip.paste()
>>> 'Hello'.ljust(20, '-')
'Simon'])
'Hello---------------' 'Hello world!'
'MyABCnameABCisABCSimon'

center(): String Formatting


split():
>>> 'Hello'.center(20)
>>> 'My name is Simon'.split() % operator
' Hello ' >>> name = 'Pete'
['My', 'name', 'is', 'Simon']
>>> 'Hello'.center(20, '=')
>>> 'Hello %s' % name dictionaries correctly). Using the newer formatted Template Strings
string literals or the str.format() interface helps avoid
"Hello Pete" these errors. These alternatives also provide more A simpler and less powerful mechanism, but it is
powerful, flexible and extensible approaches to recommended when handling format strings
We can use the %x format specifier to convert an int formatting text. generated by users. Due to their reduced complexity
value to a string: template strings are a safer choice.

>>> num = 5 Lazy string formatting >>> from string import Template

You would only use %s string formatting on functions >>> name = 'Elizabeth'


>>> 'I have %x apples' % num
that can do lazy parameters evaluation, the most
"I have 5 apples" common being logging: >>> t = Template('Hey $name!')

Note: For new code, using str.format or f- Prefer: >>> t.substitute(name=name)


strings (Python 3.6+) is strongly recommended over
>>> name = "alice" 'Hey Elizabeth!'
the % operator.
>>> logging.debug("User name: %s", name) Regular Expressions
String Formatting (str.format)
Over: 1. Import the regex module with import re.
Python 3 introduced a new way to do string
2. Create a Regex object with
formatting that was later back-ported to Python 2.7. >>> logging.debug("User name: the re.compile() function. (Remember to
This makes the syntax for string formatting more {}".format(name))
use a raw string.)
regular.
Or: 3. Pass the string you want to search into the
>>> name = 'John' Regex object’s search() method. This returns
>>> logging.debug("User name: " + name) a Match object.
>>> age = 20'
4. Call the Match object’s group() method to
Formatted String Literals or f-strings (Python return a string of the actual matched text.
3.6+) All the regex functions in Python are in the re module:
>>> "Hello I'm {}, my age is
>>> name = 'Elizabeth' >>> import re
{}".format(name, age)
>>> f'Hello {name}!'
"Hello I'm John, my age is 20" Matching Regex Objects
'Hello Elizabeth!
>>> "Hello I'm {0}, my age is >>> phone_num_regex =
{1}".format(name, age) re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
It is even possible to do inline arithmetic with it:
"Hello I'm John, my age is 20"
>>> a = 5
The official Python 3.x >>> mo = phone_num_regex.search('My
>>> b = 10 number is 415-555-4242.')
documentation recommend str.format over
the % operator: >>> f'Five plus ten is {a + b} and not
{2 * (a + b)}.'
The formatting operations described here exhibit a >>> print('Phone number found:
variety of quirks that lead to a number of common 'Five plus ten is 15 and not 30.' {}'.format(mo.group()))
errors (such as failing to display tuples and
Phone number found: 415-555-4242 >>> bat_regex = re.compile(r'Bat(man|
mobile|copter|bat)')
>>> print(area_code)
Grouping with Parentheses
>>> phone_num_regex = 415
re.compile(r'(\d\d\d)- >>> mo = bat_regex.search('Batmobile
(\d\d\d-\d\d\d\d)') lost a wheel')

>>> print(main_number)

>>> mo = phone_num_regex.search('My 555-4242 >>> mo.group()


number is 415-555-4242.')
'Batmobile'
Matching Multiple Groups with the Pipe

The | character is called a pipe. You can use it


>>> mo.group(1)
anywhere you want to match one of many >>> mo.group(1)
expressions. For example, the regular expression
'415'
r'Batman|Tina Fey' will match either 'Batman' or 'Tina 'mobile'
Fey'.

>>> hero_regex = re.compile (r'Batman| Optional Matching with the Question Mark
>>> mo.group(2)
Tina Fey')
The ? character flags the group that precedes it as an
'555-4242' optional part of the pattern.

>>> mo1 = hero_regex.search('Batman and >>> bat_regex = re.compile(r'Bat(wo)?


Tina Fey.') man')
>>> mo.group(0)
>>> mo1 = bat_regex.search('The
'415-555-4242' Adventures of Batman')
>>> mo1.group()
>>> mo1.group()
'Batman'
>>> mo.group() 'Batman'

'415-555-4242'
>>> mo2 = hero_regex.search('Tina Fey
To retrieve all the groups at once: use the groups() and Batman.') >>> mo2 = bat_regex.search('The
method—note the plural form for the name. Adventures of Batwoman')

>>> mo.groups() >>> mo2.group()


>>> mo2.group()
('415', '555-4242') 'Batwoman'
'Tina Fey'
Matching Zero or More with the Star
You can also use the pipe to match one of several
>>> area_code, main_number = mo.groups()
patterns as part of your regex:
The * (called the star or asterisk) means “match zero >>> mo2 = bat_regex.search('The match the longest string possible. The non-greedy
or more”—the group that precedes the star can occur Adventures of Batwowowowoman') version of the curly brackets, which matches the
any number of times in the text. shortest string possible, has the closing curly bracket
>>> mo2.group()
followed by a question mark.
>>> bat_regex =
re.compile(r'Bat(wo)*man') 'Batwowowowoman'
>>> greedy_ha_regex = re.compile(r'(Ha)
{3,5}')
>>> mo1 = bat_regex.search('The >>> mo3 = bat_regex.search('The
Adventures of Batman') Adventures of Batman')
>>> mo1 =
greedy_ha_regex.search('HaHaHaHaHa')
>>> mo1.group() >>> mo3 is None
>>> mo1.group()
'Batman' True
'HaHaHaHaHa'
Matching Specific Repetitions with Curly Brackets
>>> nongreedy_ha_regex =
>>> mo2 = bat_regex.search('The If you have a group that you want to repeat a specific re.compile(r'(Ha){3,5}?')
Adventures of Batwoman') number of times, follow the group in your regex with
a number in curly brackets. For example, the regex >>> mo2 =
>>> mo2.group() (Ha){3} will match the string 'HaHaHa', but it will not nongreedy_ha_regex.search('HaHaHaHaHa')
match 'HaHa', since the latter has only two repeats of
'Batwoman' >>> mo2.group()
the (Ha) group.
'HaHaHa'
Instead of one number, you can specify a range by
>>> mo3 = bat_regex.search('The writing a minimum, a comma, and a maximum in
Adventures of Batwowowowoman') between the curly brackets. For example, the regex The findall() Method
(Ha){3,5} will match 'HaHaHa', 'HaHaHaHa', and
In addition to the search() method, Regex objects also
>>> mo3.group() 'HaHaHaHaHa'.
have a findall() method. While search() will return a
Match object of the first matched text in the searched
'Batwowowowoman' >>> ha_regex = re.compile(r'(Ha){3}')
string, the findall() method will return the strings of
>>> mo1 = ha_regex.search('HaHaHa') every match in the searched string.
Matching One or More with the Plus
>>> mo1.group() >>> phone_num_regex =
While * means “match zero or more,” the + (or plus) re.compile(r'\d\d\d-\d\d\d-\d\d\d\d') #
means “match one or more”. The group preceding a has no groups
'HaHaHa'
plus must appear at least once. It is not optional:
>>> mo2 = ha_regex.search('Ha')
>>> bat_regex = re.compile(r'Bat(wo)
+man') >>> phone_num_regex.findall('Cell: 415-
>>> mo2 is None
555-9999 Work: 212-555-0000')
>>> mo1 = bat_regex.search('The
Adventures of Batwoman') True
['415-555-9999', '212-555-0000']

>>> mo1.group() Greedy and Nongreedy Matching To summarize what the findall() method returns,
remember the following:
'Batwoman' Python’s regular expressions are greedy by default,
which means that in ambiguous situations they will
 When called on a regex with no groups, such >>> consonant_regex.findall('Robocop
as \d-\d\d\d-\d\d\d\d, the method findall() eats baby food. BABY FOOD.')
returns a list of ng matches, such as ['415-555- >>>
['R', 'b', 'c', 'p', ' ', 't', 's', ' ', whole_string_is_num.search('1234567890')
9999', '212-555-0000']. 'b', 'b', 'y', ' ', 'f', 'd', '.', '
 When called on a regex that has groups,
<_sre.SRE_Match object; span=(0, 10),
such as (\d\d\d)-d\d)-(\d\ d\d\d), the method ', 'B', 'B', 'Y', ' ', 'F', 'D', '.'] match='1234567890'>
findall() returns a list of es of strings (one string
for each group), such as [('415', ', '9999'), ('212',
The Caret and Dollar Sign Characters
'555', '0000')].
 You can also use the caret symbol (^) at the >>>
whole_string_is_num.search('12345xyz6789
Making Your Own Character Classes start of a regex to indicate that a match must 0') is None
occur at the beginning of the searched text.
There are times when you want to match a set of  Likewise, you can put a dollar sign ($) at the True
characters but the shorthand character classes (\d, end of the regex to indicate the string must end
\w, \s, and so on) are too broad. You can define your with this regex pattern.
own character class using square brackets. For  And you can use the ^ and $ together to
example, the character class [aeiouAEIOU] will match indicate that the entire string must match the >>> whole_string_is_num.search('12
any vowel, both lowercase and uppercase. regex—that is, it’s not enough for a match to be 34567890') is None
made on some subset of the string.
>>> vowel_regex = True
The r'^Hello' regular expression string matches strings
re.compile(r'[aeiouAEIOU]')
that begin with 'Hello':
The Wildcard Character
>>> begins_with_hello =
re.compile(r'^Hello') The . (or dot) character in a regular expression is
>>> vowel_regex.findall('Robocop eats
baby food. BABY FOOD.') called a wildcard and will match any character except
for a newline:
['o', 'o', 'o', 'e', 'a', 'a', 'o', 'o',
'A', 'O', 'O'] >>> begins_with_hello.search('Hello >>> at_regex = re.compile(r'.at')
world!')
You can also include ranges of letters or numbers by
<_sre.SRE_Match object; span=(0, 5),
using a hyphen. For example, the character class [a- match='Hello'> >>> at_regex.findall('The cat in the hat
zA-Z0-9] will match all lowercase letters, uppercase sat on the flat mat.')
letters, and numbers.
['cat', 'hat', 'sat', 'lat', 'mat']
By placing a caret character (^) just after the character >>> begins_with_hello.search('He said
class’s opening bracket, you can make a negative hello.') is None
Matching Everything with Dot-Star
character class. A negative character class will match
all the characters that are not in the character class. True
>>> name_regex = re.compile(r'First
For example, enter the following into the interactive Name: (.*) Last Name: (.*)')
shell: The r'\d$' regular expression string matches strings
that end with a numeric character from 0 to 9:
>>> consonant_regex =
re.compile(r'[^aeiouAEIOU]') >>> whole_string_is_num = >>> mo = name_regex.search('First Name:
re.compile(r'^\d+$') Al Last Name: Sweigart')
'Serve the public trust.'
Symbol Matches
>>> mo.group(1) >>> newline_regex = re.compile('.*',
re.DOTALL)
'Al' {n,m}? or *? or +? performs a nongreedy match
>>> newline_regex.search('Serve the of the preceding p.
>>> mo.group(2) public trust.\nProtect the
innocent.\nUphold the law.').group()
'Sweigart'
'Serve the public trust.\nProtect the
^spam means the string must begin
innocent.\nUphold the law.' with spam.
The dot-star uses greedy mode: It will always try to
match as much text as possible. To match any and all
text in a nongreedy fashion, use the dot, star, and Review of Regex Symbols spam$ means the string must end
question mark (.*?). The question mark tells Python to
with spam.
match in a nongreedy way: Symbol Matches

>>> nongreedy_regex = re.compile(r'<.*?


>') . any character, except newline
? zero or one of the preceding characters.
>>> mo = nongreedy_regex.search('<To group.
serve man> for dinner.>')
\d, \w, and \s a digit, word, or space
>>> mo.group() * zero or more of the character, ectively.
preceding group.
'<To serve man>'

>>> greedy_regex = re.compile(r'<.*>') \D, \W, and \S anything except a digit, word,


+ one or more of the preceding or space acter, respectively.
group.
>>> mo = greedy_regex.search('<To serve
man> for dinner.>')
[abc] any character between the
>>> mo.group() {n} exactly n of the preceding brackets (such as a, b, ).
group.
'<To serve man> for dinner.>'
[^abc] any character that isn’t
Matching Newlines with the Dot Character
{n,} n or more of the preceding between the brackets.
group.
The dot-star will match everything except a newline.
By passing re.DOTALL as the second argument to
re.compile(), you can make the dot character match all {,m} 0 to m of the preceding Case-Insensitive Matching
characters, including the newline character: group.
To make your regex case-insensitive, you can pass
>>> no_newline_regex = re.compile('.*') re.IGNORECASE or re.I as a second argument to
{n,m} at least n and at most m of re.compile():
>>> no_newline_regex.search('Serve the
public trust.\nProtect the the preceding p.
>>> robocop = re.compile(r'robocop',
innocent.\nUphold the law.').group() re.I)
>>> agent_names_regex.sub(r'\1****', There are two main modules in Python that deals with
'Agent Alice told Agent Carol that Agent path manipulation. One is the os.path module and
>>> robocop.search('Robocop is part man, Eve knew Agent Bob was a double agent.')
the other is the pathlib module.
part machine, all cop.').group()
A**** told C**** that E**** knew B**** The pathlib module was added in Python 3.4,
'Robocop' was a double agent.' offering an object-oriented way to handle file system
paths.
>>> robocop.search('ROBOCOP protects the Managing Complex Regexes
innocent.').group() Backslash on Windows and Forward Slash on OS X
To tell the re.compile() function to ignore whitespace and Linux
'ROBOCOP' and comments inside the regular expression string,
“verbose mode” can be enabled by passing the On Windows, paths are written using backslashes () as
>>> robocop.search('Al, why does your the separator between folder names. On Unix based
variable re.VERBOSE as the second argument to
programming book talk about robocop so
re.compile(). operating system such as macOS, Linux, and BSDs, the
much?').group()
forward slash (/) is used as the path separator. Joining
'robocop' Now instead of a hard-to-read regular expression like paths can be a headache if your code needs to work
this: on different platforms.

Substituting Strings with the sub() Method phone_regex = re.compile(r'((\d{3}|\ Fortunately, Python provides easy ways to handle this.
The sub() method for Regex objects is passed two
(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4} We will showcase how to deal with this with
(\s*(ext|x|ext.)\s*\d{2,5})?)') both os.path.join and pathlib.Path.joinpat
arguments:
h
you can spread the regular expression over multiple
1. The first argument is a string to replace any
lines with comments like this: Using os.path.join on Windows:
matches.
2. The second is the string for the regular phone_regex = re.compile(r'''( >>> import os
expression.
The sub() method returns a string with the (\d{3}|\(\d{3}\))? # area
substitutions applied: code
>>> os.path.join('usr', 'bin', 'spam')
>>> names_regex = re.compile(r'Agent (\s|-|\.)? #
\w+') separator 'usr\\bin\\spam'
\d{3} #
first 3 digits And using pathlib on *nix:

>>> names_regex.sub('CENSORED', 'Agent >>> from pathlib import Path


Alice gave the secret documents to Agent (\s|-|\.) #
Bob.') separator

'CENSORED gave the secret documents to \d{4} # last


4 digits >>>
CENSORED.'
print(Path('usr').joinpath('bin').joinpa
(\s*(ext|x|ext.)\s*\d{2,5})? # th('spam'))
Another example:
extension
usr/bin/spam
>>> agent_names_regex =
)''', re.VERBOSE)
re.compile(r'Agent (\w)\w*')
pathlib also provides a shortcut to joinpath using
Handling File and Directory Paths the / operator:
>>> from pathlib import Path /home/asweigart/details.csv >>> import os

/home/asweigart/invite.docx >>>
os.makedirs('C:\\delicious\\walnut\\waff
>>> print(Path('usr') / 'bin' / 'spam') les')
The Current Working Directory
usr/bin/spam Using os on Windows: Using pathlib on *nix:

Notice the path separator is different between >>> import os >>> from pathlib import Path
Windows and Unix based operating system, that's why
you want to use one of the above methods instead of >>> cwd = Path.cwd()
adding strings together to join paths together.
>>> os.getcwd() >>> (cwd / 'delicious' / 'walnut' /
'waffles').mkdir()
Joining paths is helpful if you need to create different
file paths under the same directory. 'C:\\Python34'
Traceback (most recent call last):
>>> os.chdir('C:\\Windows\\System32')
Using os.path.join on Windows: File "<stdin>", line 1, in <module>

>>> my_files = ['accounts.txt', File "/usr/lib/python3.6/pathlib.py",


'details.csv', 'invite.docx'] line 1226, in mkdir
>>> os.getcwd()
self._accessor.mkdir(self, mode)
'C:\\Windows\\System32'
>>> for filename in my_files: File "/usr/lib/python3.6/pathlib.py",
Using pathlib on *nix: line 387, in wrapped
>>>
print(os.path.join('C:\\Users\\asweigart >>> from pathlib import Path return strfunc(str(pathobj), *args)
', filename))
>>> from os import chdir FileNotFoundError: [Errno 2] No such
C:\Users\asweigart\accounts.txt file or directory:
'/home/asweigart/delicious/walnut/waffle
C:\Users\asweigart\details.csv s'
>>> print(Path.cwd())
C:\Users\asweigart\invite.docx Oh no, we got a nasty error! The reason is that the
/home/asweigart 'delicious' directory does not exist, so we cannot make
Using pathlib on *nix: the 'walnut' and the 'waffles' directories under it. To
fix this, do:
>>> my_files = ['accounts.txt',
'details.csv', 'invite.docx'] >>> chdir('/usr/lib/python3.6') >>> from pathlib import Path

>>> home = Path.home() >>> print(Path.cwd()) >>> cwd = Path.cwd()

>>> for filename in my_files: /usr/lib/python3.6 >>> (cwd / 'delicious' / 'walnut' /


'waffles').mkdir(parents=True)
>>> print(home / filename)
Creating New Folders
And all is good :)
/home/asweigart/accounts.txt Using os on Windows:
Absolute vs. Relative Paths >>> import os Using os.path on *nix:

There are two ways to specify a file path. >>> os.getcwd() import os

 An absolute path, which always begins with '/home/asweigart' >>> os.path.exists('.')


the root folder
>>> os.path.abspath('..') True
 A relative path, which is relative to the
program’s current working directory '/home' >>> os.path.exists('setup.py')
There are also the dot (.) and dot-dot (..) folders.
These are not real folders but special names that can Using pathlib on *nix: True
be used in a path. A single period (“dot”) for a folder
name is shorthand for “this directory.” Two periods from pathlib import Path >>> os.path.exists('/etc')
(“dot-dot”) means “the parent folder.”
print(Path.cwd()) True
Handling Absolute and Relative Paths
/home/asweigart >>> os.path.exists('nonexistentfile')
To see if a path is an absolute path:
print(Path('..').resolve()) False
Using os.path on *nix:
/home Using pathlib on *nix:
>>> import os
You can get a relative path from a starting path to from pathlib import Path
>>> os.path.isabs('/') another path.
>>> Path('.').exists()
True Using os.path on *nix:
True
>>> os.path.isabs('..') >>> import os
>>> Path('setup.py').exists()
False >>> os.path.relpath('/etc/passwd', '/')
True
Using pathlib on *nix: 'etc/passwd'
>>> Path('/etc').exists()
>>> from pathlib import Path Using pathlib on *nix:
True
>>> Path('/').is_absolute() >>> from pathlib import Path
>>> Path('nonexistentfile').exists()
True >>>
print(Path('/etc/passwd').relative_to('/ False
>>> Path('..').is_absolute() '))
Checking if a path is a file:
False etc/passwd
Using os.path on *nix:
You can extract an absolute path with Checking Path Validity
both os.path and pathlib >>> import os
Checking if a file/directory exists:
>>> os.path.isfile('setup.py')
Using os.path on *nix:
True >>> Path('/').is_dir() 10024

>>> os.path.isfile('/home') True Listing directory contents using os.listdir on


Windows:
False >>> Path('setup.py').is_dir()
>>> import os
>>> os.path.isfile('nonexistentfile') False
>>> os.listdir('C:\\Windows\\System32')
False >>> Path('/spam').is_dir()
['0409', '12520437.cpx', '12520850.cpx',
Using pathlib on *nix: False '5U877.ax', 'aaclient.dll',

>>> from pathlib import Path Finding File Sizes and Folder Contents --snip--

>>> Path('setup.py').is_file() Getting a file's size in bytes: 'xwtpdui.dll', 'xwtpw32.dll', 'zh-CN',


'zh-HK', 'zh-TW', 'zipfldr.dll']
True Using os.path on Windows:
Listing directory contents using pathlib on *nix:
>>> Path('/home').is_file() >>> import os
>>> from pathlib import Path
False >>>
os.path.getsize('C:\\Windows\\System32\\ >>> for f in Path('/usr/bin').iterdir():
>>> Path('nonexistentfile').is_file() calc.exe')
>>> print(f)
False 776192
...
Checking if a path is a directory: Using pathlib on *nix:
/usr/bin/tiff2rgba
Using os.path on *nix: >>> from pathlib import Path
/usr/bin/iconv
>>> import os >>> stat = Path('/bin/python3.6').stat()
/usr/bin/ldd
>>> os.path.isdir('/') >>> print(stat) # stat contains some
other information about the file as /usr/bin/cache_restore
True well
/usr/bin/udiskie
>>> os.path.isdir('setup.py') os.stat_result(st_mode=33261,
st_ino=141087, st_dev=2051, st_nlink=2, /usr/bin/unix2dos
False st_uid=0,
/usr/bin/t1reencode
>>> os.path.isdir('/spam') --snip--
/usr/bin/epstopdf
False st_gid=0, st_size=10024,
st_atime=1517725562, /usr/bin/idle3
st_mtime=1515119809,
Using pathlib on *nix: st_ctime=1517261276) ...
>>> from pathlib import Path >>> print(stat.st_size) # size in bytes
To find the total size of all the files in this directory:
WARNING: Directories themselves also have a size! Copying Files and Folders 'C:\\eggs\\bacon.txt'
So you might want to check for whether a path is a
file or directory using the methods in the methods The shutil module provides functions for copying files, The destination path can also specify a filename. In
discussed in the above section! as well as entire folders. the following example, the source file is moved and
renamed:
>>> import shutil, os
Using os.path.getsize() and os.listdir() to
gether on Windows: >>> shutil.move('C:\\bacon.txt',
'C:\\eggs\\new_bacon.txt')
>>> import os >>> os.chdir('C:\\') 'C:\\eggs\\new_bacon.txt'
>>> total_size = 0
If there is no eggs folder, then move() will rename
bacon.txt to a file named eggs.
>>> shutil.copy('C:\\spam.txt',
'C:\\delicious')
>>> for filename in >>> shutil.move('C:\\bacon.txt',
os.listdir('C:\\Windows\\System32'): 'C:\\eggs')
'C:\\delicious\\spam.txt'

total_size = total_size + 'C:\\eggs'


os.path.getsize(os.path.join('C:\\Window
s\\System32', filename))
>>> shutil.copy('eggs.txt', Permanently Deleting Files and Folders
'C:\\delicious\\eggs2.txt')
 Calling os.unlink(path) or Path.unlink() will
'C:\\delicious\\eggs2.txt' delete the file at path.
>>> print(total_size)
 Calling os.rmdir(path) or Path.rmdir() will
While shutil.copy() will copy a single file, delete the folder at path. This folder must be
1117846456
shutil.copytree() will copy an entire folder and every empty of any files or folders.
folder and file contained in it:  Calling shutil.rmtree(path) will remove the
Using pathlib on *nix:
folder at path, and all files and folders it
>>> from pathlib import Path
>>> import shutil, os contains will also be deleted.

>>> total_size = 0 Safe Deletes with the send2trash Module


>>> os.chdir('C:\\')
You can install this module by running pip install
send2trash from a Terminal window.
>>> for sub_path in
Path('/usr/bin').iterdir(): >>> import send2trash
>>> shutil.copytree('C:\\bacon',
'C:\\bacon_backup')
... total_size +=
sub_path.stat().st_size
'C:\\bacon_backup'
>>> with open('bacon.txt', 'a') as
>>> bacon_file: # creates the file
Moving and Renaming Files and Folders
>>> print(total_size) ... bacon_file.write('Bacon is not a
>>> import shutil vegetable.')
1903178911
>>> shutil.move('C:\\bacon.txt', 25
'C:\\eggs')
string values from the file, one string
for each line of text:
>>> send2trash.send2trash('bacon.txt') The current folder is
C:\delicious\walnut

Walking a Directory Tree SUBFOLDER OF C:\delicious\walnut: >>> with open('sonnet29.txt') as


>>> import os waffles sonnet_file:

>>> ... sonnet_file.readlines()

>>> for folder_name, subfolders, The current folder is [When, in disgrace with fortune and
filenames in os.walk('C:\\delicious'): C:\delicious\walnut\waffles men's eyes,\n', ' I all alone beweep my

>>> print('The current folder is FILE INSIDE C:\delicious\walnut\waffles: outcast state,\n', And trouble deaf
{}'.format(folder_name)) butter.txt heaven with my bootless cries,\n', And

>>> pathlib provides a lot more functionality than the look upon myself and curse my fate,']
ones listed above, like getting file name, getting file
>>> for subfolder in subfolders: extension, reading/writing a file without manually
opening it, etc. Check out the official documentation if
>>> print('SUBFOLDER OF {}: >>> # You can also iterate through the
you want to know more! file line by line:
{}'.format(folder_name, subfolder))

>>> for filename in filenames: Reading and Writing Files >>> with open('sonnet29.txt') as
sonnet_file:
>>> print('FILE INSIDE {}: The File Reading/Writing Process
{}'.format(folder_name, filename)) ... for line in sonnet_file: # note
the new line character will be included
To read/write to a file in Python, you will want to use
in the line
>>> the with statement, which will close the file for you
after you are done. ... print(line, end='')
>>> print('')

The current folder is C:\delicious Opening and reading files with the open() function
>>> with When, in disgrace with fortune and men's
SUBFOLDER OF C:\delicious: cats open('C:\\Users\\your_home_folder\\hello eyes,
.txt') as hello_file:
SUBFOLDER OF C:\delicious: walnut
I all alone beweep my outcast state,
... hello_content =
FILE INSIDE C:\delicious: spam.txt hello_file.read() And trouble deaf heaven with my bootless
cries,
>>> hello_content
And look upon myself and curse my fate,
The current folder is C:\delicious\cats 'Hello World!'

FILE INSIDE C:\delicious\cats: Writing to Files


catnames.txt
>>> with open('bacon.txt', 'w') as
>>> # Alternatively, you can use the bacon_file:
FILE INSIDE C:\delicious\cats: *readlines()* method to get a list of
zophie.jpg
... bacon_file.write('Hello >>> with shelve.open('mydata') as >>> with open('myCats.py', 'w') as
world!\n') shelf_file: file_obj:

13 ... print(type(shelf_file)) ... file_obj.write('cats =


{}\n'.format(pprint.pformat(cats)))
... print(shelf_file['cats'])
83
>>> with open('bacon.txt', 'a') as <class 'shelve.DbfilenameShelf'>
bacon_file:
Reading ZIP Files
['Zophie', 'Pooka', 'Simon']
... bacon_file.write('Bacon is not a >>> import zipfile, os
vegetable.') Just like dictionaries, shelf values have keys() and
values() methods that will return list-like values of the
25
keys and values in the shelf. Since these methods
return list-like values instead of true lists, you should >>> os.chdir('C:\\') # move to the
folder with example.zip
pass them to the list() function to get them in list
>>> with open('bacon.txt') as form.
>>> with zipfile.ZipFile('example.zip')
bacon_file: as example_zip:
>>> with shelve.open('mydata') as
... content = bacon_file.read() shelf_file:
... print(example_zip.namelist())
... print(list(shelf_file.keys()))
... spam_info =
example_zip.getinfo('spam.txt')
>>> print(content) ... print(list(shelf_file.values()))
... print(spam_info.file_size)
Hello world! ['cats']
... print(spam_info.compress_size)
Bacon is not a vegetable. [['Zophie', 'Pooka', 'Simon']]
... print('Compressed file is %sx
Saving Variables with the pprint.pformat() smaller!' % (round(spam_info.file_size /
Saving Variables with the shelve Module spam_info.compress_size, 2)))
Function
To save variables:
>>> import pprint
>>> import shelve
['spam.txt', 'cats/',
'cats/catnames.txt', 'cats/zophie.jpg']
>>> cats = [{'name': 'Zophie', 'desc':
'chubby'}, {'name': 'Pooka', 'desc': 13908
>>> cats = ['Zophie', 'Pooka', 'Simon']
'fluffy'}]
3828
>>> with shelve.open('mydata') as
shelf_file:
'Compressed file is 3.63x smaller!'
>>> pprint.pformat(cats)
... shelf_file['cats'] = cats
"[{'desc': 'chubby', 'name': 'Zophie'}, Extracting from ZIP Files
To open and read variables: {'desc': 'fluffy', 'name': 'Pooka'}]"
The extractall() method for ZipFile objects extracts all This code will create a new ZIP file named new.zip that specification, and allow for example to modify a YAML
the files and folders from a ZIP file into the current has the compressed contents of spam.txt. content without altering comments.
working directory.
JSON, YAML and configuration files Open a YAML file with:
>>> import zipfile, os
from ruamel.yaml import YAML
JSON

Open a JSON file with:


>>> os.chdir('C:\\') # move to the
folder with example.zip with open("filename.yaml") as f:
import json
yaml=YAML()
with open("filename.json", "r") as f:
>>> with zipfile.ZipFile('example.zip') yaml.load(f)
as example_zip: content = json.loads(f.read())

... example_zip.extractall() Write a JSON file with: Anyconfig

import json Anyconfig is a very handy package allowing to


The extract() method for ZipFile objects will extract a
abstract completly the underlying configuration file
single file from the ZIP file. Continue the interactive
format. It allows to load a Python dictionary from
shell example:
JSON, YAML, TOML, and so on.
content = {"name": "Joe", "age": 20}
>>> with zipfile.ZipFile('example.zip')
as example_zip: Install it with:
with open("filename.json", "w") as f:
... pip install anyconfig
print(example_zip.extract('spam.txt')) f.write(json.dumps(content,
indent=2)) Usage:
...
print(example_zip.extract('spam.txt', YAML import anyconfig
'C:\\some\\new\\folders'))
Compared to JSON, YAML allows a much better
'C:\\spam.txt' humain maintainance and gives ability to add
comments. It is a convinient choice for configuration conf1 =
'C:\\some\\new\\folders\\spam.txt' files where human will have to edit. anyconfig.load("/path/to/foo/conf.d/a.ym
l")
Creating and Adding to ZIP Files There are two main librairies allowing to access to
YAML files: Debugging
>>> import zipfile

 PyYaml Raising Exceptions


 Ruamel.yaml
Exceptions are raised with a raise statement. In code, a
>>> with zipfile.ZipFile('new.zip', 'w') Install them using pip install in your virtual
as new_zip: raise statement consists of the following:
environment.

... new_zip.write('spam.txt',  The raise keyword


The first one it easier to use but the second one,
compress_type=zipfile.ZIP_DEFLATED)  A call to the Exception() function
Ruamel, implements much better the YAML
 A string with a helpful error message passed for sym, w, h in (('*', 4, 4), ('O', 20, The 116 is the return value from the write() method,
to the Exception() function 5), ('x', 1, 3), ('ZZ', 3, 3)): since 116 characters were written to the file. The
>>> raise Exception('This is the error traceback text was written to errorInfo.txt.
message.') try:
Traceback (most recent call last):
Traceback (most recent call last): box_print(sym, w, h)
File "<pyshell#28>", line 2, in
File "<pyshell#191>", line 1, in except Exception as err: <module>
<module>
print('An exception happened: ' Exception: This is the error message.
raise Exception('This is the error + str(err))
message.')
Assertions
Getting the Traceback as a String
Exception: This is the error message.
An assertion is a sanity check to make sure your code
The traceback is displayed by Python whenever a
isn’t doing something obviously wrong. These sanity
Often it’s the code that calls the function, not the raised exception goes unhandled. But can also obtain
checks are performed by assert statements. If the
function itself, that knows how to handle an it as a string by calling traceback.format_exc(). This
sanity check fails, then an AssertionError exception is
expection. So you will commonly see a raise statement function is useful if you want the information from an
raised. In code, an assert statement consists of the
inside a function and the try and except statements in exception’s traceback but also want an except
following:
the code calling the function. statement to gracefully handle the exception. You will
need to import Python’s traceback module before
def box_print(symbol, width, height):  The assert keyword
calling this function.
 A condition (that is, an expression that
if len(symbol) != 1: >>> import traceback evaluates to True or False)
 A comma
raise Exception('Symbol must be a
single character string.')  A string to display when the condition is
>>> try: False
if width <= 2: >>> pod_bay_door_status = 'open'
>>> raise Exception('This is the
raise Exception('Width must be error message.')
greater than 2.')
>>> assert pod_bay_door_status ==
>>> except:
if height <= 2: 'open', 'The pod bay doors need to be
"open".'
>>> with open('errorInfo.txt', 'w')
raise Exception('Height must be as error_file:
greater than 2.')
>>>
print(symbol * width) >>> pod_bay_door_status = 'I\'m sorry,
error_file.write(traceback.format_exc())
Dave. I\'m afraid I can\'t do that.'
for i in range(height - 2): >>> print('The traceback info was
written to errorInfo.txt.')
print(symbol + (' ' * (width -
2)) + symbol) >>> assert pod_bay_door_status ==
116
'open', 'The pod bay doors need to be
print(symbol * width) "open".'
The traceback info was written to
errorInfo.txt.
Traceback (most recent call last): following code. It has a bug in it, but you will also >>> print(factorial(5))
enter several log messages to help yourself figure out
File "<pyshell#10>", line 1, in what is going wrong. Save the program as >>> logging.debug('End of program')
<module>
factorialLog.py.
2015-05-23 16:20:12,664 - DEBUG - Start
assert pod_bay_door_status == of program
>>> import logging
'open', 'The pod bay doors need to be
"open".' 2015-05-23 16:20:12,664 - DEBUG - Start
>>>
of factorial(5)
AssertionError: The pod bay doors need
to be "open". >>>
2015-05-23 16:20:12,665 - DEBUG - i is
logging.basicConfig(level=logging.DEBUG,
0, total is 0
format=' %(asctime)s - %(levelname)s- %
In plain English, an assert statement says, “I assert that (message)s')
this condition holds true, and if not, there is a bug 2015-05-23 16:20:12,668 - DEBUG - i is
somewhere in the program.” Unlike exceptions, your 1, total is 0
>>>
code should not handle assert statements with try and
2015-05-23 16:20:12,670 - DEBUG - i is
except; if an assert fails, your program should crash. >>> logging.debug('Start of program')
2, total is 0
By failing fast like this, you shorten the time between
the original cause of the bug and when you first >>>
2015-05-23 16:20:12,673 - DEBUG - i is
notice the bug. This will reduce the amount of code 3, total is 0
you will have to check before finding the code that’s >>> def factorial(n):
causing the bug. 2015-05-23 16:20:12,675 - DEBUG - i is
>>> 4, total is 0
Disabling Assertions
>>> logging.debug('Start of 2015-05-23 16:20:12,678 - DEBUG - i is
factorial(%s)' % (n)) 5, total is 0
Assertions can be disabled by passing the -O option
when running Python. >>> total = 1 2015-05-23 16:20:12,680 - DEBUG - End of
factorial(5)
>>>
Logging
0
To enable the logging module to display log >>> for i in range(1, n + 1):
messages on your screen as your program runs, copy 2015-05-23 16:20:12,684 - DEBUG - End of
the following to the top of your program (but under >>> total *= i program
the #! python shebang line):
>>> logging.debug('i is ' +
str(i) + ', total is ' + str(total)) Logging Levels
import logging
Logging levels provide a way to categorize your log
>>>
messages by importance. There are five logging levels,
>>> logging.debug('End of described in Table 10-1 from least to most important.
logging.basicConfig(level=logging.DEBUG, Messages can be logged at each level using a
factorial(%s)' % (n))
format=' %(asctime)s - %(levelname)s- %
different logging function.
(message)s')
>>>
Say you wrote a function to calculate the factorial of a >>> return total
number. In mathematics, factorial 4 is 1 × 2 × 3 × 4,
or 24. Factorial 7 is 1 × 2 × 3 × 4 × 5 × 6 × 7, or 5,040. >>>
Open a new file editor window and enter the
8
Level Logging Function Description
>>> logging.disable(logging.CRITICAL) It's not even need to bind it to a name like add
before:
DEBUG logging.debug() The lowest level. Used for small details. Usually you care about these messages only when diagnosing problems.
>>> (lambda x, y: x + y)(5, 3)
>>> logging.critical('Critical error!
Critical error!') 8
INFO logging.info() Used to record information on general events in your program or confirm that things are working at their point
in the program.
Like regular nested functions, lambdas also work as
lexical closures:
>>> logging.error('Error! Error!')
WARNING logging.warning() Used to indicate a potential problem that doesn’t prevent the program from working but might do so in the
>>> def make_adder(n):
future.
Logging to a File
return lambda x: x + n
Instead of displaying the log messages to the screen,
ERROR logging.error() Used to record an error
you canthat caused
write them the
to aprogram
text file. to
Thefail to do something.
logging.basicConfig() function takes a filename
keyword argument, like so: >>> plus_3 = make_adder(3)
CRITICAL logging.critical() The highest level. Used to indicate a fatal error that has caused or is about to cause the program to stop running
entirely. import logging >>> plus_5 = make_adder(5)

Disabling Logging logging.basicConfig(filename='myProgramL >>> plus_3(4)


og.txt', level=logging.DEBUG, format='%
After you’ve debugged your program, you probably (asctime)s - %(levelname)s - % 7
(message)s')
don’t want all these log messages cluttering the
screen. The logging.disable() function disables these >>> plus_5(4)
so that you don’t have to go into your program and Lambda Functions
remove all the logging calls by hand. 9
This function:
>>> import logging Note: lambda can only evaluate an expression, like a
>>> def add(x, y):
single line of code.
return x + y
Ternary Conditional Operator
>>>
logging.basicConfig(level=logging.INFO, Many programming languages have a ternary
format=' %(asctime)s -%(levelname)s - %
>>> add(5, 3) operator, which define a conditional expression. The
(message)s') most common usage is to make a terse simple
8 conditional assignment statement. In other words, it
offers one-line code to evaluate the first expression if
Is equivalent to the lambda function: the condition is true, otherwise it evaluates the
>>> logging.critical('Critical error!
Critical error!') second expression.
>>> add = lambda x, y: x + y
2015-05-22 11:10:48,054 - CRITICAL - <expression1> if <condition> else
Critical error! Critical error! >>> add(5, 3) <expression2>
Example: keyword arguments (except it uses a dictionary, >>> for key, value in kwargs.items():
not a tuple).
>>> age = 15 2. In a function call, * means “unpack tuple or >>> print("{0}: {1}".format(key,
value))
list named <name> to positional arguments at
this position”, while ** is the same for keyword
arguments.
>>> print('kid' if age < 18 else
'adult') For example you can make a function that you can >>> fruit(name = "apple", color = "red")
use to call any other function, no matter what
kid parameters it has:

Ternary operators can be chained: def forward(f, *args, **kwargs): name: apple

>>> age = 15 return f(*args, **kwargs) color: red

Inside forward, args is a tuple (of all positional >>> def show(arg1, arg2, *args,
arguments except the first one, because we specified kwarg1=None, kwarg2=None, **kwargs):
>>> print('kid' if age < 13 else it - the f), kwargs is a dict. Then we call f and unpack
>>> print(arg1)
'teenager' if age < 18 else 'adult') them so they become normal arguments to f.

teenager >>> print(arg2)


You use *args when you have an indefinite amount
of positional arguments. >>> print(args)
The code above is equivalent to:
>>> def fruits(*args): >>> print(kwarg1)
if age < 18:
>>> for fruit in args: >>> print(kwarg2)
if age < 13:
>>> print(fruit) >>> print(kwargs)
print('kid')

else:
>>> fruits("apples", "bananas", >>> data1 = [1,2,3]
print('teenager') "grapes")
>>> data2 = [4,5,6]
else:
>>> data3 = {'a':7,'b':8,'c':9}
print('adult') "apples"

args and kwargs "bananas"


>>> show(*data1,*data2,
The names args and kwargs are arbitrary - the "grapes" kwarg1="python",kwarg2="cheatsheet",**da
important thing are the * and ** operators. They can ta3)
mean: Similarly, you use **kwargs when you have an
indefinite number of keyword arguments. 1
1. In a function declaration, * means “pack all
remaining positional arguments into a tuple >>> def fruit(**kwargs): 2
named <name>”, while ** is the same for
(3, 4, 5, 6)
python 2. You can use the items from a sequence as >>> with open(filename) as f:
the positional arguments for a function with
cheatsheet the * operator. >>> file_contents = f.read()

{'a': 7, 'b': 8, 'c': 9} 3. Using the * operator with a generator may


cause your program to run out of memory and
crash. # the open_file object has
4. Adding new positional parameters to automatically been closed.
>>> show(*data1, *data2, **data3) functions that accept *args can introduce
hard-to-find bugs. Anything that ends execution of the block causes the
1 context manager's exit method to be called. This
includes exceptions, and can be useful when an error
2 Things to Remember(kwargs) causes you to prematurely exit from an open file or
1. Function arguments can be specified by connection. Exiting a script without properly closing
(3, 4, 5, 6)
position or by keyword. files/connections is a bad idea, that may cause data
loss or other problems. By using a context manager
None 2. Keywords make it clear what the purpose of
you can ensure that precautions are always taken to
each argument is when it would be confusing
None prevent damage or loss in this way.
with only positional arguments.

{'a': 7, 'b': 8, 'c': 9} 3. Keyword arguments with default values


Writing your own contextmanager using
make it easy to add new behaviors to a
generator syntax
function, especially when the function has
existing callers. It is also possible to write a context manager using
# If you do not specify ** for kwargs 4. Optional keyword arguments should always generator syntax thanks to
be passed by keyword instead of by position. the contextlib.contextmanager decorator:
>>> show(*data1, *data2, *data3)

Context Manager >>> import contextlib


1
While Python's context managers are widely used, few >>> @contextlib.contextmanager
2
understand the purpose behind their use. These
statements, commonly used with reading and writing ... def context_manager(num):
(3, 4, 5, 6, "a", "b", "c")
files, assist the application in conserving system
memory and improve resource management by ... print('Enter')
None
ensuring specific resources are only in use for certain
... yield num + 1
None processes.
... print('Exit')
{} with statement
>>> with context_manager(2) as cm:
A context manager is an object that is notified when a
Things to Remember(args)
context (a block of code) starts and ends. You ... # the following instructions
1. Functions can accept a variable number of commonly use one with the with statement. It takes are run when the 'yield' point of the
positional arguments by using *args in the def care of the notifying. context
statement.
... # manager is reached.
For example, file objects are context managers. When
a context ends, the file object is closed automatically:
... # 'cm' will have the value that ... return a+b The setup script is the centre of all activity in building,
was yielded distributing, and installing modules using the Distutils.
... The main purpose of the setup script is to describe
... print('Right in the middle with
your module distribution to the Distutils, so that the
cm = {}'.format(cm)) >>> add(10, 20) # we can test it by
various commands that operate on your modules do
calling the function save it as
Enter calculate.py the right thing.

Right in the middle with cm = 3 30 The setup.py file is at the heart of a Python project.


It describes all of the metadata about your project.
Exit >>> # Now if we want to use that module There a quite a few fields you can add to a project to
by importing we have to comment out our give it a rich set of metadata describing the project.
call,
However, there are only three required fields: name,
version, and packages. The name field must be unique
>>> >>> # Instead we can write like this in
calculate.py if you wish to publish your package on the Python
Package Index (PyPI). The version field keeps track of
__main__ Top-level script environment different releases of the project. The packages field
>>> if __name__ == "__main__":
describes where you’ve put the Python source code
__main__ is the name of the scope in which top-
... add(3, 5) within your project.
level code executes. A module’s name is set equal
to __main__ when read from standard input, a script,
... This allows you to easily install Python packages.
or from an interactive prompt.
Often it's enough to write:
>>> import calculate
A module can discover whether or not it is running in python setup.py install
the main scope by checking its own __name__, which >>> calculate.add(3, 5)
allows a common idiom for conditionally executing and module will install itself.
code in a module when it is run as a script or 8
with python -m but not when it is imported: Our initial setup.py will also include information about
Advantages the license and will re-use the README.txt file for the
>>> if __name__ == "__main__":
long_description field. This will look like:
1. Every Python module has
... # execute only if run as a it’s __name__ defined and if this is __main__, >>> from distutils.core import setup
script
it implies that the module is being run
standalone by the user and we can do >>> setup(
... main()
corresponding appropriate actions.
... name='pythonCheatsheet',
For a package, the same effect can be achieved by 2. If you import this script as a module in
including a main.py module, the contents of which another script, the name is set to the name of
... version='0.1',
will be executed when the module is run with -m the script/module.
3. Python files can act as either reusable ... packages=['pipenv',],
For example we are developing script which is modules, or as standalone programs.
designed to be used as module, we should do: 4. if __name__ == “main”: is used to ... license='MIT',
execute some code only if the file was run
>>> # Python program to execute ...
function directly directly, and not imported. long_description=open('README.txt').read
(),
>>> def add(a, b): setup.py
... ) ... class Number: It is mandatory to define the data type in dataclass.
However, If you don't want specify the datatype then,
Find more information ... val: int use typing.Any.
visit http://docs.python.org/install/index.html.
... >>> from dataclasses import dataclass
Dataclasses
>>> obj = Number(2) >>> from typing import Any
Dataclasses are python classes but are suited for
storing data objects. This module provides a >>> obj.val
decorator and functions for automatically adding
2
generated special methods such >>> @dataclass
as __init__() and __repr__() to user-defined
classes. Default values ... class WithoutExplicitTypes:

It is easy to add default values to the fields of your ... name: Any
Features data class.
... value: Any = 42
1. They store data and represent a certain data >>> @dataclass
type. Ex: A number. For people familiar with ...
ORMs, a model instance is a data object. It ... class Product:
represents a specific kind of entity. It holds
Virtual Environment
attributes that define or represent the entity. ... name: str
2. They can be compared to other objects of The use of a Virtual Environment is to test python
the same type. Ex: A number can be greater ... count: int = 0 code in encapsulated environments and to also avoid
than, less than, or equal to another number. filling the base Python installation with libraries we
Python 3.7 provides a decorator dataclass that is used ... price: float = 0.0 might use for only one project.
to convert a class into a dataclass.
...
virtualenv
python 2.7
>>> obj = Product("Python")
1. Install virtualenv
>>> class Number:
>>> obj.name
2. pip install virtualenv
... def __init__(self, val):
Python 3. Install virtualenvwrapper-win (Windows)

... self.val = val 4. pip install virtualenvwrapper-


>>> obj.count
win
...
0 Usage:

>>> obj = Number(2) 1. Make a Virtual Environment


>>> obj.price
>>> obj.val 2. mkvirtualenv HelloWold
0.0
2
Anything we install now will be specific to this
Type hints
project. And available to the projects we
with dataclass
connect to this environment.
3. Set Project Directory
>>> @dataclass
To bind our virtualenv with our current working └── tests pipenv
directory we simply enter:
├── __init__.py Pipenv is a tool that aims to bring the best of all
setprojectdir . packaging worlds (bundler, composer, npm, cargo,
4. Deactivate └── test_poetry_demo.py yarn, etc.) to the Python world. Windows is a first-class
citizen, in our world.
To move onto something else in the command The pyproject.toml file will orchestrate your
project and its dependencies: 1. Install pipenv
line type ‘deactivate’ to deactivate your
environment. 2. pip install pipenv
[tool.poetry]
name = "my-project" 3. Enter your Project directory and install the
deactivate
version = "0.1.0" Packages for your project
description = ""
Notice how the parenthesis disappear. authors = ["your name 4. cd my_project
5. Workon <[email protected]>"]
5. pipenv install <package>
Open up the command prompt and type [tool.poetry.dependencies]
python = "*"
‘workon HelloWold’ to activate the environment Pipenv will install your package and create a
and move into your root project folder [tool.poetry.dev-dependencies] Pipfile for you in your project’s directory. The
pytest = "^3.4" Pipfile is used to track which dependencies your
workon HelloWold 5. Packages project needs in case you need to re-install
them.
poetry To add dependencies to your project, you can 6. Uninstall Packages
specify them in the tool.poetry.dependencies
Poetry is a tool for dependency management and section: 7. pipenv uninstall <package>
packaging in Python. It allows you to declare the 8. Activate the Virtual Environment associated
libraries your project depends on and it will manage [tool.poetry.dependencies] with your Python project
(install/update) them for you.
pendulum = "^1.4" 9. pipenv shell
1. Install Poetry 10. Exit the Virtual Environment
Also, instead of modifying the pyproject.toml
2. pip install --user poetry
file by hand, you can use the add command and 11. exit
3. Create a new project Find more information and a video in docs.pipenv.org.
it will automatically find a suitable version
constraint.
4. poetry new my-project
anaconda
$ poetry add pendulum
This will create a my-project directory:
Anaconda is another popular tool to manage python
To install the dependencies listed in the packages.
my-project
pyproject.toml:
├── pyproject.toml Where packages, notebooks, projects and
poetry install environments are shared. Your place for free public
├── README.rst conda package hosting.
To remove dependencies:
├── poetry_demo Usage:
poetry remove pendulum
│ └── __init__.py For more information, check the documentation. 1. Make a Virtual Environment
2. conda create -n HelloWorld
3. To use the Virtual Environment, activate it by:

4. conda activate HelloWorld

Anything installed now will be specific to the


project HelloWorld
5. Exit the Virtual Environment

conda deactivate

You might also like