[go: up one dir, main page]

0% found this document useful (0 votes)
12 views30 pages

ch2_9

Download as pdf or txt
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 30

Chapter 2: Python Data Types

Data types are nothing but variables you use to reserve some space in memory. Python variables do not need an
explicit declaration to reserve memory space. The declaration happens automatically when you assign a value to a
variable.

Section 2.1: String Data Type


String are identified as a contiguous set of characters represented in the quotation marks. Python allows for either
pairs of single or double quotes. Strings are immutable sequence data type, i.e each time one makes any changes
to a string, completely new string object is created.

a_str = 'Hello World'


print(a_str) #output will be whole string. Hello World
print(a_str[0]) #output will be first character. H
print(a_str[0:5]) #output will be first five characters. Hello

Section 2.2: Set Data Types


Sets are unordered collections of unique objects, there are two types of set:

1. Sets - They are mutable and new elements can be added once sets are defined

basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}


print(basket) # duplicates will be removed
> {'orange', 'banana', 'pear', 'apple'}
a = set('abracadabra')
print(a) # unique letters in a
> {'a', 'r', 'b', 'c', 'd'}
a.add('z')
print(a)
> {'a', 'c', 'r', 'b', 'z', 'd'}

2. Frozen Sets - They are immutable and new elements cannot added after its defined.

b = frozenset('asdfagsa')
print(b)
> frozenset({'f', 'g', 'd', 'a', 's'})
cities = frozenset(["Frankfurt", "Basel","Freiburg"])
print(cities)
> frozenset({'Frankfurt', 'Basel', 'Freiburg'})

Section 2.3: Numbers data type


Numbers have four types in Python. Int, float, complex, and long.

int_num = 10 #int value


float_num = 10.2 #float value
complex_num = 3.14j #complex value
long_num = 1234567L #long value

GoalKicker.com – Python® Notes for Professionals 33


Section 2.4: List Data Type
A list contains items separated by commas and enclosed within square brackets [].lists are almost similar to arrays
in C. One difference is that all the items belonging to a list can be of different data type.

list = [123,'abcd',10.2,'d'] #can be an array of any data type or single data type.
list1 = ['hello','world']
print(list) #will output whole list. [123,'abcd',10.2,'d']
print(list[0:2]) #will output first two element of list. [123,'abcd']
print(list1 * 2) #will gave list1 two times. ['hello','world','hello','world']
print(list + list1) #will gave concatenation of both the lists.
[123,'abcd',10.2,'d','hello','world']

Section 2.5: Dictionary Data Type


Dictionary consists of key-value pairs. It is enclosed by curly braces {} and values can be assigned and accessed
using square brackets[].

dic={'name':'red','age':10}
print(dic) #will output all the key-value pairs. {'name':'red','age':10}
print(dic['name']) #will output only value with 'name' key. 'red'
print(dic.values()) #will output list of values in dic. ['red',10]
print(dic.keys()) #will output list of keys. ['name','age']

Section 2.6: Tuple Data Type


Lists are enclosed in brackets [ ] and their elements and size can be changed, while tuples are enclosed in
parentheses ( ) and cannot be updated. Tuples are immutable.

tuple = (123,'hello')
tuple1 = ('world')
print(tuple) #will output whole tuple. (123,'hello')
print(tuple[0]) #will output first value. (123)
print(tuple + tuple1) #will output (123,'hello','world')
tuple[1]='update' #this will give you error.

GoalKicker.com – Python® Notes for Professionals 34


Chapter 3: Indentation
Section 3.1: Simple example
For Python, Guido van Rossum based the grouping of statements on indentation. The reasons for this are explained
in the first section of the "Design and History Python FAQ". Colons, :, are used to declare an indented code block,
such as the following example:

class ExampleClass:
#Every function belonging to a class must be indented equally
def __init__(self):
name = "example"

def someFunction(self, a):


#Notice everything belonging to a function must be indented
if a > 5:
return True
else:
return False

#If a function is not indented to the same level it will not be considers as part of the parent class
def separateFunction(b):
for i in b:
#Loops are also indented and nested conditions start a new indentation
if i == 1:
return True
return False

separateFunction([2,3,5,6,1])

Spaces or Tabs?

The recommended indentation is 4 spaces but tabs or spaces can be used so long as they are consistent. Do not
mix tabs and spaces in Python as this will cause an error in Python 3 and can causes errors in Python 2.

Section 3.2: How Indentation is Parsed


Whitespace is handled by the lexical analyzer before being parsed.

The lexical analyzer uses a stack to store indentation levels. At the beginning, the stack contains just the value 0,
which is the leftmost position. Whenever a nested block begins, the new indentation level is pushed on the stack,
and an "INDENT" token is inserted into the token stream which is passed to the parser. There can never be more
than one "INDENT" token in a row (IndentationError).

When a line is encountered with a smaller indentation level, values are popped from the stack until a value is on top
which is equal to the new indentation level (if none is found, a syntax error occurs). For each value popped, a
"DEDENT" token is generated. Obviously, there can be multiple "DEDENT" tokens in a row.

The lexical analyzer skips empty lines (those containing only whitespace and possibly comments), and will never
generate either "INDENT" or "DEDENT" tokens for them.

At the end of the source code, "DEDENT" tokens are generated for each indentation level left on the stack, until just
the 0 is left.

For example:

GoalKicker.com – Python® Notes for Professionals 35


if foo:
if bar:
x = 42
else:
print foo

is analyzed as:

<if> <foo> <:> [0]


<INDENT> <if> <bar> <:> [0, 4]
<INDENT> <x> <=> <42> [0, 4, 8]
<DEDENT> <DEDENT> <else> <:> [0]
<INDENT> <print> <foo> [0, 2]
<DEDENT>

The parser than handles the "INDENT" and "DEDENT" tokens as block delimiters.

Section 3.3: Indentation Errors


The spacing should be even and uniform throughout. Improper indentation can cause an IndentationError or
cause the program to do something unexpected. The following example raises an IndentationError:

a = 7
if a > 5:
print "foo"
else:
print "bar"
print "done"

Or if the line following a colon is not indented, an IndentationError will also be raised:

if True:
print "true"

If you add indentation where it doesn't belong, an IndentationError will be raised:

if True:
a = 6
b = 5

If you forget to un-indent functionality could be lost. In this example None is returned instead of the expected False:

def isEven(a):
if a%2 ==0:
return True
#this next line should be even with the if
return False
print isEven(7)

GoalKicker.com – Python® Notes for Professionals 36


Chapter 4: Comments and Documentation
Section 4.1: Single line, inline and multiline comments
Comments are used to explain code when the basic code itself isn't clear.

Python ignores comments, and so will not execute code in there, or raise syntax errors for plain English sentences.

Single-line comments begin with the hash character (#) and are terminated by the end of line.

Single line comment:

# This is a single line comment in Python

Inline comment:

print("Hello World") # This line prints "Hello World"

Comments spanning multiple lines have """ or ''' on either end. This is the same as a multiline string, but
they can be used as comments:

"""
This type of comment spans multiple lines.
These are mostly used for documentation of functions, classes and modules.
"""

Section 4.2: Programmatically accessing docstrings


Docstrings are - unlike regular comments - stored as an attribute of the function they document, meaning that you
can access them programmatically.

An example function
def func():
"""This is a function that does nothing at all"""
return

The docstring can be accessed using the __doc__ attribute:

print(func.__doc__)

This is a function that does nothing at all

help(func)

Help on function func in module __main__:

func()

This is a function that does nothing at all

Another example function

GoalKicker.com – Python® Notes for Professionals 37


function.__doc__ is just the actual docstring as a string, while the help function provides general information
about a function, including the docstring. Here's a more helpful example:

def greet(name, greeting="Hello"):


"""Print a greeting to the user `name`

Optional parameter `greeting` can change what they're greeted with."""

print("{} {}".format(greeting, name))

help(greet)

Help on function greet in module __main__:

greet(name, greeting='Hello')

Print a greeting to the user name


Optional parameter greeting can change what they're greeted with.

Advantages of docstrings over regular comments

Just putting no docstring or a regular comment in a function makes it a lot less helpful.

def greet(name, greeting="Hello"):


# Print a greeting to the user `name`
# Optional parameter `greeting` can change what they're greeted with.

print("{} {}".format(greeting, name))

print(greet.__doc__)

None

help(greet)

Help on function greet in module main:

greet(name, greeting='Hello')

Section 4.3: Write documentation using docstrings


A docstring is a multi-line comment used to document modules, classes, functions and methods. It has to be the
first statement of the component it describes.

def hello(name):
"""Greet someone.

Print a greeting ("Hello") for the person with the given name.
"""

print("Hello "+name)

class Greeter:
"""An object used to greet people.

GoalKicker.com – Python® Notes for Professionals 38


It contains multiple greeting functions for several languages
and times of the day.
"""

The value of the docstring can be accessed within the program and is - for example - used by the help command.

Syntax conventions
PEP 257

PEP 257 defines a syntax standard for docstring comments. It basically allows two types:

One-line Docstrings:

According to PEP 257, they should be used with short and simple functions. Everything is placed in one line, e.g:

def hello():
"""Say hello to your friends."""
print("Hello my friends!")

The docstring shall end with a period, the verb should be in the imperative form.

Multi-line Docstrings:

Multi-line docstring should be used for longer, more complex functions, modules or classes.

def hello(name, language="en"):


"""Say hello to a person.

Arguments:
name: the name of the person
language: the language in which the person should be greeted
"""

print(greeting[language]+" "+name)

They start with a short summary (equivalent to the content of a one-line docstring) which can be on the same line
as the quotation marks or on the next line, give additional detail and list parameters and return values.

Note PEP 257 defines what information should be given within a docstring, it doesn't define in which format it
should be given. This was the reason for other parties and documentation parsing tools to specify their own
standards for documentation, some of which are listed below and in this question.

Sphinx

Sphinx is a tool to generate HTML based documentation for Python projects based on docstrings. Its markup
language used is reStructuredText. They define their own standards for documentation, pythonhosted.org hosts a
very good description of them. The Sphinx format is for example used by the pyCharm IDE.

A function would be documented like this using the Sphinx/reStructuredText format:

def hello(name, language="en"):


"""Say hello to a person.

:param name: the name of the person


:type name: str
:param language: the language in which the person should be greeted
:type language: str

GoalKicker.com – Python® Notes for Professionals 39


:return: a number
:rtype: int
"""

print(greeting[language]+" "+name)
return 4

Google Python Style Guide

Google has published Google Python Style Guide which defines coding conventions for Python, including
documentation comments. In comparison to the Sphinx/reST many people say that documentation according to
Google's guidelines is better human-readable.

The pythonhosted.org page mentioned above also provides some examples for good documentation according to
the Google Style Guide.

Using the Napoleon plugin, Sphinx can also parse documentation in the Google Style Guide-compliant format.

A function would be documented like this using the Google Style Guide format:

def hello(name, language="en"):


"""Say hello to a person.

Args:
name: the name of the person as string
language: the language code string

Returns:
A number.
"""

print(greeting[language]+" "+name)
return 4

GoalKicker.com – Python® Notes for Professionals 40


Chapter 5: Date and Time
Section 5.1: Parsing a string into a timezone aware datetime
object
Python 3.2+ has support for %z format when parsing a string into a datetime object.

UTC offset in the form +HHMM or -HHMM (empty string if the object is naive).

Python 3.x Version ≥ 3.2

import datetime
dt = datetime.datetime.strptime("2016-04-15T08:27:18-0500", "%Y-%m-%dT%H:%M:%S%z")

For other versions of Python, you can use an external library such as dateutil, which makes parsing a string with
timezone into a datetime object is quick.

import dateutil.parser
dt = dateutil.parser.parse("2016-04-15T08:27:18-0500")

The dt variable is now a datetime object with the following value:

datetime.datetime(2016, 4, 15, 8, 27, 18, tzinfo=tzoffset(None, -18000))

Section 5.2: Constructing timezone-aware datetimes


By default all datetime objects are naive. To make them timezone-aware, you must attach a tzinfo object, which
provides the UTC offset and timezone abbreviation as a function of date and time.

Fixed Offset Time Zones

For time zones that are a fixed offset from UTC, in Python 3.2+, the datetime module provides the timezone class, a
concrete implementation of tzinfo, which takes a timedelta and an (optional) name parameter:

Python 3.x Version ≥ 3.2

from datetime import datetime, timedelta, timezone


JST = timezone(timedelta(hours=+9))

dt = datetime(2015, 1, 1, 12, 0, 0, tzinfo=JST)


print(dt)
# 2015-01-01 12:00:00+09:00

print(dt.tzname())
# UTC+09:00

dt = datetime(2015, 1, 1, 12, 0, 0, tzinfo=timezone(timedelta(hours=9), 'JST'))


print(dt.tzname)
# 'JST'

For Python versions before 3.2, it is necessary to use a third party library, such as dateutil. dateutil provides an
equivalent class, tzoffset, which (as of version 2.5.3) takes arguments of the form dateutil.tz.tzoffset(tzname,
offset), where offset is specified in seconds:

Python 3.x Version < 3.2

GoalKicker.com – Python® Notes for Professionals 42


Python 2.x Version < 2.7

from datetime import datetime, timedelta


from dateutil import tz

JST = tz.tzoffset('JST', 9 * 3600) # 3600 seconds per hour


dt = datetime(2015, 1, 1, 12, 0, tzinfo=JST)
print(dt)
# 2015-01-01 12:00:00+09:00
print(dt.tzname)
# 'JST'

Zones with daylight savings time

For zones with daylight savings time, python standard libraries do not provide a standard class, so it is necessary to
use a third party library. pytz and dateutil are popular libraries providing time zone classes.

In addition to static time zones, dateutil provides time zone classes that use daylight savings time (see the
documentation for the tz module). You can use the tz.gettz() method to get a time zone object, which can then
be passed directly to the datetime constructor:

from datetime import datetime


from dateutil import tz
local = tz.gettz() # Local time
PT = tz.gettz('US/Pacific') # Pacific time

dt_l = datetime(2015, 1, 1, 12, tzinfo=local) # I am in EST


dt_pst = datetime(2015, 1, 1, 12, tzinfo=PT)
dt_pdt = datetime(2015, 7, 1, 12, tzinfo=PT) # DST is handled automatically
print(dt_l)
# 2015-01-01 12:00:00-05:00
print(dt_pst)
# 2015-01-01 12:00:00-08:00
print(dt_pdt)
# 2015-07-01 12:00:00-07:00

CAUTION: As of version 2.5.3, dateutil does not handle ambiguous datetimes correctly, and will always default to
the later date. There is no way to construct an object with a dateutil timezone representing, for example
2015-11-01 1:30 EDT-4, since this is during a daylight savings time transition.

All edge cases are handled properly when using pytz, but pytz time zones should not be directly attached to time
zones through the constructor. Instead, a pytz time zone should be attached using the time zone's localize
method:

from datetime import datetime, timedelta


import pytz

PT = pytz.timezone('US/Pacific')
dt_pst = PT.localize(datetime(2015, 1, 1, 12))
dt_pdt = PT.localize(datetime(2015, 11, 1, 0, 30))
print(dt_pst)
# 2015-01-01 12:00:00-08:00
print(dt_pdt)
# 2015-11-01 00:30:00-07:00

Be aware that if you perform datetime arithmetic on a pytz-aware time zone, you must either perform the
calculations in UTC (if you want absolute elapsed time), or you must call normalize() on the result:

GoalKicker.com – Python® Notes for Professionals 43


dt_new = dt_pdt + timedelta(hours=3) # This should be 2:30 AM PST
print(dt_new)
# 2015-11-01 03:30:00-07:00
dt_corrected = PT.normalize(dt_new)
print(dt_corrected)
# 2015-11-01 02:30:00-08:00

Section 5.3: Computing time dierences


the timedelta module comes in handy to compute differences between times:

from datetime import datetime, timedelta


now = datetime.now()
then = datetime(2016, 5, 23) # datetime.datetime(2016, 05, 23, 0, 0, 0)

Specifying time is optional when creating a new datetime object

delta = now-then

delta is of type timedelta

print(delta.days)
# 60
print(delta.seconds)
# 40826

To get n day's after and n day's before date we could use:

n day's after date:

def get_n_days_after_date(date_format="%d %B %Y", add_days=120):

date_n_days_after = datetime.datetime.now() + timedelta(days=add_days)


return date_n_days_after.strftime(date_format)

n day's before date:

def get_n_days_before_date(self, date_format="%d %B %Y", days_before=120):

date_n_days_ago = datetime.datetime.now() - timedelta(days=days_before)


return date_n_days_ago.strftime(date_format)

Section 5.4: Basic datetime objects usage


The datetime module contains three primary types of objects - date, time, and datetime.

import datetime

# Date object
today = datetime.date.today()
new_year = datetime.date(2017, 01, 01) #datetime.date(2017, 1, 1)

# Time object
noon = datetime.time(12, 0, 0) #datetime.time(12, 0)

# Current datetime
now = datetime.datetime.now()

GoalKicker.com – Python® Notes for Professionals 44


# Datetime object
millenium_turn = datetime.datetime(2000, 1, 1, 0, 0, 0) #datetime.datetime(2000, 1, 1, 0, 0)

Arithmetic operations for these objects are only supported within same datatype and performing simple arithmetic
with instances of different types will result in a TypeError.

# subtraction of noon from today


noon-today
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'datetime.time' and 'datetime.date'
However, it is straightforward to convert between types.

# Do this instead
print('Time since the millenium at midnight: ',
datetime.datetime(today.year, today.month, today.day) - millenium_turn)

# Or this
print('Time since the millenium at noon: ',
datetime.datetime.combine(today, noon) - millenium_turn)

Section 5.5: Switching between time zones


To switch between time zones, you need datetime objects that are timezone-aware.

from datetime import datetime


from dateutil import tz

utc = tz.tzutc()
local = tz.tzlocal()

utc_now = datetime.utcnow()
utc_now # Not timezone-aware.

utc_now = utc_now.replace(tzinfo=utc)
utc_now # Timezone-aware.

local_now = utc_now.astimezone(local)
local_now # Converted to local time.

Section 5.6: Simple date arithmetic


Dates don't exist in isolation. It is common that you will need to find the amount of time between dates or
determine what the date will be tomorrow. This can be accomplished using timedelta objects

import datetime

today = datetime.date.today()
print('Today:', today)

yesterday = today - datetime.timedelta(days=1)


print('Yesterday:', yesterday)

tomorrow = today + datetime.timedelta(days=1)


print('Tomorrow:', tomorrow)

print('Time between tomorrow and yesterday:', tomorrow - yesterday)

GoalKicker.com – Python® Notes for Professionals 45


This will produce results similar to:

Today: 2016-04-15
Yesterday: 2016-04-14
Tomorrow: 2016-04-16
Difference between tomorrow and yesterday: 2 days, 0:00:00

Section 5.7: Converting timestamp to datetime


The datetime module can convert a POSIX timestamp to a ITC datetime object.

The Epoch is January 1st, 1970 midnight.

import time
from datetime import datetime
seconds_since_epoch=time.time() #1469182681.709

utc_date=datetime.utcfromtimestamp(seconds_since_epoch) #datetime.datetime(2016, 7, 22, 10, 18, 1,


709000)

Section 5.8: Subtracting months from a date accurately


Using the calendar module

import calendar
from datetime import date

def monthdelta(date, delta):


m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
if not m: m = 12
d = min(date.day, calendar.monthrange(y, m)[1])
return date.replace(day=d,month=m, year=y)

next_month = monthdelta(date.today(), 1) #datetime.date(2016, 10, 23)

Using the dateutils module

import datetime
import dateutil.relativedelta

d = datetime.datetime.strptime("2013-03-31", "%Y-%m-%d")
d2 = d - dateutil.relativedelta.relativedelta(months=1) #datetime.datetime(2013, 2, 28, 0, 0)

Section 5.9: Parsing an arbitrary ISO 8601 timestamp with


minimal libraries
Python has only limited support for parsing ISO 8601 timestamps. For strptime you need to know exactly what
format it is in. As a complication the stringification of a datetime is an ISO 8601 timestamp, with space as a
separator and 6 digit fraction:

str(datetime.datetime(2016, 7, 22, 9, 25, 59, 555555))


# '2016-07-22 09:25:59.555555'

but if the fraction is 0, no fractional part is output

GoalKicker.com – Python® Notes for Professionals 46


str(datetime.datetime(2016, 7, 22, 9, 25, 59, 0))
# '2016-07-22 09:25:59'

But these 2 forms need a different format for strptime. Furthermore, strptime' does not support at all
parsing minute timezones that have a:in it, thus2016-07-22 09:25:59+0300can be parsed, but the
standard format2016-07-22 09:25:59+03:00` cannot.

There is a single-file library called iso8601 which properly parses ISO 8601 timestamps and only them.

It supports fractions and timezones, and the T separator all with a single function:

import iso8601
iso8601.parse_date('2016-07-22 09:25:59')
# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<iso8601.Utc>)
iso8601.parse_date('2016-07-22 09:25:59+03:00')
# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<FixedOffset '+03:00' ...>)
iso8601.parse_date('2016-07-22 09:25:59Z')
# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<iso8601.Utc>)
iso8601.parse_date('2016-07-22T09:25:59.000111+03:00')
# datetime.datetime(2016, 7, 22, 9, 25, 59, 111, tzinfo=<FixedOffset '+03:00' ...>)

If no timezone is set, iso8601.parse_date defaults to UTC. The default zone can be changed with default_zone
keyword argument. Notably, if this is None instead of the default, then those timestamps that do not have an
explicit timezone are returned as naive datetimes instead:

iso8601.parse_date('2016-07-22T09:25:59', default_timezone=None)
# datetime.datetime(2016, 7, 22, 9, 25, 59)
iso8601.parse_date('2016-07-22T09:25:59Z', default_timezone=None)
# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<iso8601.Utc>)

Section 5.10: Get an ISO 8601 timestamp


Without timezone, with microseconds
from datetime import datetime

datetime.now().isoformat()
# Out: '2016-07-31T23:08:20.886783'

With timezone, with microseconds


from datetime import datetime
from dateutil.tz import tzlocal

datetime.now(tzlocal()).isoformat()
# Out: '2016-07-31T23:09:43.535074-07:00'

With timezone, without microseconds


from datetime import datetime
from dateutil.tz import tzlocal

datetime.now(tzlocal()).replace(microsecond=0).isoformat()
# Out: '2016-07-31T23:10:30-07:00'

See ISO 8601 for more information about the ISO 8601 format.

Section 5.11: Parsing a string with a short time zone name into

GoalKicker.com – Python® Notes for Professionals 47


a timezone aware datetime object
Using the dateutil library as in the previous example on parsing timezone-aware timestamps, it is also possible to
parse timestamps with a specified "short" time zone name.

For dates formatted with short time zone names or abbreviations, which are generally ambiguous (e.g. CST, which
could be Central Standard Time, China Standard Time, Cuba Standard Time, etc - more can be found here) or not
necessarily available in a standard database, it is necessary to specify a mapping between time zone abbreviation
and tzinfo object.

from dateutil import tz


from dateutil.parser import parse

ET = tz.gettz('US/Eastern')
CT = tz.gettz('US/Central')
MT = tz.gettz('US/Mountain')
PT = tz.gettz('US/Pacific')

us_tzinfos = {'CST': CT, 'CDT': CT,


'EST': ET, 'EDT': ET,
'MST': MT, 'MDT': MT,
'PST': PT, 'PDT': PT}

dt_est = parse('2014-01-02 04:00:00 EST', tzinfos=us_tzinfos)


dt_pst = parse('2016-03-11 16:00:00 PST', tzinfos=us_tzinfos)

After running this:

dt_est
# datetime.datetime(2014, 1, 2, 4, 0, tzinfo=tzfile('/usr/share/zoneinfo/US/Eastern'))
dt_pst
# datetime.datetime(2016, 3, 11, 16, 0, tzinfo=tzfile('/usr/share/zoneinfo/US/Pacific'))

It is worth noting that if using a pytz time zone with this method, it will not be properly localized:

from dateutil.parser import parse


import pytz

EST = pytz.timezone('America/New_York')
dt = parse('2014-02-03 09:17:00 EST', tzinfos={'EST': EST})

This simply attaches the pytz time zone to the datetime:

dt.tzinfo # Will be in Local Mean Time!


# <DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>

If using this method, you should probably re-localize the naive portion of the datetime after parsing:

dt_fixed = dt.tzinfo.localize(dt.replace(tzinfo=None))
dt_fixed.tzinfo # Now it's EST.
# <DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)

Section 5.12: Fuzzy datetime parsing (extracting datetime out


of a text)
It is possible to extract a date out of a text using the dateutil parser in a "fuzzy" mode, where components of the

GoalKicker.com – Python® Notes for Professionals 48


string not recognized as being part of a date are ignored.

from dateutil.parser import parse

dt = parse("Today is January 1, 2047 at 8:21:00AM", fuzzy=True)


print(dt)

dt is now a datetime object and you would see datetime.datetime(2047, 1, 1, 8, 21) printed.

Section 5.13: Iterate over dates


Sometimes you want to iterate over a range of dates from a start date to some end date. You can do it using
datetime library and timedelta object:

import datetime

# The size of each step in days


day_delta = datetime.timedelta(days=1)

start_date = datetime.date.today()
end_date = start_date + 7*day_delta

for i in range((end_date - start_date).days):


print(start_date + i*day_delta)

Which produces:

2016-07-21
2016-07-22
2016-07-23
2016-07-24
2016-07-25
2016-07-26
2016-07-27

GoalKicker.com – Python® Notes for Professionals 49


Chapter 6: Date Formatting
Section 6.1: Time between two date-times
from datetime import datetime

a = datetime(2016,10,06,0,0,0)
b = datetime(2016,10,01,23,59,59)

a-b
# datetime.timedelta(4, 1)

(a-b).days
# 4
(a-b).total_seconds()
# 518399.0

Section 6.2: Outputting datetime object to string


Uses C standard format codes.

from datetime import datetime


datetime_for_string = datetime(2016,10,1,0,0)
datetime_string_format = '%b %d %Y, %H:%M:%S'
datetime.strftime(datetime_for_string,datetime_string_format)
# Oct 01 2016, 00:00:00

Section 6.3: Parsing string to datetime object


Uses C standard format codes.

from datetime import datetime


datetime_string = 'Oct 1 2016, 00:00:00'
datetime_string_format = '%b %d %Y, %H:%M:%S'
datetime.strptime(datetime_string, datetime_string_format)
# datetime.datetime(2016, 10, 1, 0, 0)

GoalKicker.com – Python® Notes for Professionals 50


Chapter 7: Enum
Section 7.1: Creating an enum (Python 2.4 through 3.3)
Enums have been backported from Python 3.4 to Python 2.4 through Python 3.3. You can get this the enum34
backport from PyPI.

pip install enum34

Creation of an enum is identical to how it works in Python 3.4+

from enum import Enum

class Color(Enum):
red = 1
green = 2
blue = 3

print(Color.red) # Color.red
print(Color(1)) # Color.red
print(Color['red']) # Color.red

Section 7.2: Iteration


Enums are iterable:

class Color(Enum):
red = 1
green = 2
blue = 3

[c for c in Color] # [<Color.red: 1>, <Color.green: 2>, <Color.blue: 3>]

GoalKicker.com – Python® Notes for Professionals 51


Chapter 8: Set
Section 8.1: Operations on sets
with other sets

# Intersection
{1, 2, 3, 4, 5}.intersection({3, 4, 5, 6}) # {3, 4, 5}
{1, 2, 3, 4, 5} & {3, 4, 5, 6} # {3, 4, 5}

# Union
{1, 2, 3, 4, 5}.union({3, 4, 5, 6}) # {1, 2, 3, 4, 5, 6}
{1, 2, 3, 4, 5} | {3, 4, 5, 6} # {1, 2, 3, 4, 5, 6}

# Difference
{1, 2, 3, 4}.difference({2, 3, 5}) # {1, 4}
{1, 2, 3, 4} - {2, 3, 5} # {1, 4}

# Symmetric difference with


{1, 2, 3, 4}.symmetric_difference({2, 3, 5}) # {1, 4, 5}
{1, 2, 3, 4} ^ {2, 3, 5} # {1, 4, 5}

# Superset check
{1, 2}.issuperset({1, 2, 3}) # False
{1, 2} >= {1, 2, 3} # False

# Subset check
{1, 2}.issubset({1, 2, 3}) # True
{1, 2} <= {1, 2, 3} # True

# Disjoint check
{1, 2}.isdisjoint({3, 4}) # True
{1, 2}.isdisjoint({1, 4}) # False

with single elements

# Existence check
2 in {1,2,3} # True
4 in {1,2,3} # False
4 not in {1,2,3} # True

# Add and Remove


s = {1,2,3}
s.add(4) # s == {1,2,3,4}

s.discard(3) # s == {1,2,4}
s.discard(5) # s == {1,2,4}

s.remove(2) # s == {1,4}
s.remove(2) # KeyError!

Set operations return new sets, but have the corresponding in-place versions:

method in-place operation in-place method


union s |= t update
intersection s &= t intersection_update
difference s -= t difference_update

GoalKicker.com – Python® Notes for Professionals 52


symmetric_difference s ^= t symmetric_difference_update

For example:

s = {1, 2}
s.update({3, 4}) # s == {1, 2, 3, 4}

Section 8.2: Get the unique elements of a list


Let's say you've got a list of restaurants -- maybe you read it from a file. You care about the unique restaurants in
the list. The best way to get the unique elements from a list is to turn it into a set:

restaurants = ["McDonald's", "Burger King", "McDonald's", "Chicken Chicken"]


unique_restaurants = set(restaurants)
print(unique_restaurants)
# prints {'Chicken Chicken', "McDonald's", 'Burger King'}

Note that the set is not in the same order as the original list; that is because sets are unordered, just like dicts.

This can easily be transformed back into a List with Python's built in list function, giving another list that is the
same list as the original but without duplicates:

list(unique_restaurants)
# ['Chicken Chicken', "McDonald's", 'Burger King']

It's also common to see this as one line:

# Removes all duplicates and returns another list


list(set(restaurants))

Now any operations that could be performed on the original list can be done again.

Section 8.3: Set of Sets


{{1,2}, {3,4}}

leads to:

TypeError: unhashable type: 'set'

Instead, use frozenset:

{frozenset({1, 2}), frozenset({3, 4})}

Section 8.4: Set Operations using Methods and Builtins


We define two sets a and b

>>> a = {1, 2, 2, 3, 4}
>>> b = {3, 3, 4, 4, 5}

NOTE: {1} creates a set of one element, but {} creates an empty dict. The correct way to create an
empty set is set().

GoalKicker.com – Python® Notes for Professionals 53


Intersection

a.intersection(b) returns a new set with elements present in both a and b

>>> a.intersection(b)
{3, 4}

Union

a.union(b) returns a new set with elements present in either a and b

>>> a.union(b)
{1, 2, 3, 4, 5}

Difference

a.difference(b) returns a new set with elements present in a but not in b

>>> a.difference(b)
{1, 2}
>>> b.difference(a)
{5}

Symmetric Difference

a.symmetric_difference(b) returns a new set with elements present in either a or b but not in both

>>> a.symmetric_difference(b)
{1, 2, 5}
>>> b.symmetric_difference(a)
{1, 2, 5}

NOTE: a.symmetric_difference(b) == b.symmetric_difference(a)

Subset and superset

c.issubset(a) tests whether each element of c is in a.

a.issuperset(c) tests whether each element of c is in a.

>>> c = {1, 2}
>>> c.issubset(a)
True
>>> a.issuperset(c)
True

The latter operations have equivalent operators as shown below:

Method Operator
a.intersection(b) a & b
a.union(b) a|b
a.difference(b) a - b
a.symmetric_difference(b) a ^ b
a.issubset(b) a <= b
a.issuperset(b) a >= b

Disjoint sets

GoalKicker.com – Python® Notes for Professionals 54


Sets a and d are disjoint if no element in a is also in d and vice versa.

>>> d = {5, 6}
>>> a.isdisjoint(b) # {2, 3, 4} are in both sets
False
>>> a.isdisjoint(d)
True

# This is an equivalent check, but less efficient


>>> len(a & d) == 0
True

# This is even less efficient


>>> a & d == set()
True

Testing membership

The builtin in keyword searches for occurances

>>> 1 in a
True
>>> 6 in a
False

Length

The builtin len() function returns the number of elements in the set

>>> len(a)
4
>>> len(b)
3

Section 8.5: Sets versus multisets


Sets are unordered collections of distinct elements. But sometimes we want to work with unordered collections of
elements that are not necessarily distinct and keep track of the elements' multiplicities.

Consider this example:

>>> setA = {'a','b','b','c'}


>>> setA
set(['a', 'c', 'b'])

By saving the strings 'a', 'b', 'b', 'c' into a set data structure we've lost the information on the fact that 'b'
occurs twice. Of course saving the elements to a list would retain this information

>>> listA = ['a','b','b','c']


>>> listA
['a', 'b', 'b', 'c']

but a list data structure introduces an extra unneeded ordering that will slow down our computations.

For implementing multisets Python provides the Counter class from the collections module (starting from version
2.7):

Python 2.x Version ≥ 2.7

GoalKicker.com – Python® Notes for Professionals 55


>>> from collections import Counter
>>> counterA = Counter(['a','b','b','c'])
>>> counterA
Counter({'b': 2, 'a': 1, 'c': 1})

Counter is a dictionary where where elements are stored as dictionary keys and their counts are stored as
dictionary values. And as all dictionaries, it is an unordered collection.

GoalKicker.com – Python® Notes for Professionals 56


Chapter 9: Simple Mathematical Operators
Numerical types and their metaclasses

The numbers module contains the abstract metaclasses for the numerical types:

subclasses numbers.Number numbers.Integral numbers.Rational numbers.Real numbers.Complex


bool ✓ ✓ ✓ ✓ ✓
int ✓ ✓ ✓ ✓ ✓
fractions.Fraction ✓ ― ✓ ✓ ✓
float ✓ ― ― ✓ ✓
complex ✓ ― ― ― ✓
decimal.Decimal ✓ ― ― ― ―
Python does common mathematical operators on its own, including integer and float division, multiplication,
exponentiation, addition, and subtraction. The math module (included in all standard Python versions) offers
expanded functionality like trigonometric functions, root operations, logarithms, and many more.

Section 9.1: Division


Python does integer division when both operands are integers. The behavior of Python's division operators have
changed from Python 2.x and 3.x (see also Integer Division ).

a, b, c, d, e = 3, 2, 2.0, -3, 10

Python 2.x Version ≤ 2.7

In Python 2 the result of the ' / ' operator depends on the type of the numerator and denominator.

a / b # = 1

a / c # = 1.5

d / b # = -2

b / a # = 0

d / e # = -1

Note that because both a and b are ints, the result is an int.

The result is always rounded down (floored).

Because c is a float, the result of a / c is a float.

You can also use the operator module:

import operator # the operator module provides 2-argument arithmetic functions


operator.div(a, b) # = 1
operator.__div__(a, b) # = 1

Python 2.x Version ≥ 2.2

What if you want float division:

Recommended:

GoalKicker.com – Python® Notes for Professionals 57


from __future__ import division # applies Python 3 style division to the entire module
a / b # = 1.5
a // b # = 1

Okay (if you don't want to apply to the whole module):

a / (b * 1.0) # = 1.5
1.0 * a / b # = 1.5
a / b * 1.0 # = 1.0 (careful with order of operations)

from operator import truediv


truediv(a, b) # = 1.5

Not recommended (may raise TypeError, eg if argument is complex):

float(a) / b # = 1.5
a / float(b) # = 1.5

Python 2.x Version ≥ 2.2

The ' // ' operator in Python 2 forces floored division regardless of type.

a // b # = 1
a // c # = 1.0

Python 3.x Version ≥ 3.0

In Python 3 the / operator performs 'true' division regardless of types. The // operator performs floor division and
maintains type.

a / b # = 1.5
e / b # = 5.0
a // b # = 1
a // c # = 1.0

import operator # the operator module provides 2-argument arithmetic functions


operator.truediv(a, b) # = 1.5
operator.floordiv(a, b) # = 1
operator.floordiv(a, c) # = 1.0

Possible combinations (builtin types):

int and int (gives an int in Python 2 and a float in Python 3)


int and float (gives a float)
int and complex (gives a complex)
float and float (gives a float)
float and complex (gives a complex)
complex and complex (gives a complex)

See PEP 238 for more information.

Section 9.2: Addition


a, b = 1, 2

# Using the "+" operator:


a + b # = 3

GoalKicker.com – Python® Notes for Professionals 58


# Using the "in-place" "+=" operator to add and assign:
a += b # a = 3 (equivalent to a = a + b)

import operator # contains 2 argument arithmetic functions for the examples

operator.add(a, b) # = 5 since a is set to 3 right before this line

# The "+=" operator is equivalent to:


a = operator.iadd(a, b) # a = 5 since a is set to 3 right before this line

Possible combinations (builtin types):

int and int (gives an int)


int and float (gives a float)
int and complex (gives a complex)
float and float (gives a float)
float and complex (gives a complex)
complex and complex (gives a complex)

Note: the + operator is also used for concatenating strings, lists and tuples:

"first string " + "second string" # = 'first string second string'

[1, 2, 3] + [4, 5, 6] # = [1, 2, 3, 4, 5, 6]

Section 9.3: Exponentiation


a, b = 2, 3

(a ** b) # = 8
pow(a, b) # = 8

import math
math.pow(a, b) # = 8.0 (always float; does not allow complex results)

import operator
operator.pow(a, b) # = 8

Another difference between the built-in pow and math.pow is that the built-in pow can accept three arguments:

a, b, c = 2, 3, 2

pow(2, 3, 2) # 0, calculates (2 ** 3) % 2, but as per Python docs,


# does so more efficiently

Special functions

The function math.sqrt(x) calculates the square root of x.

import math
import cmath
c = 4
math.sqrt(c) # = 2.0 (always float; does not allow complex results)
cmath.sqrt(c) # = (2+0j) (always complex)

To compute other roots, such as a cube root, raise the number to the reciprocal of the degree of the root. This
could be done with any of the exponential functions or operator.

GoalKicker.com – Python® Notes for Professionals 59


import math
x = 8
math.pow(x, 1/3) # evaluates to 2.0
x**(1/3) # evaluates to 2.0

The function math.exp(x) computes e ** x.

math.exp(0) # 1.0
math.exp(1) # 2.718281828459045 (e)

The function math.expm1(x) computes e ** x - 1. When x is small, this gives significantly better precision than
math.exp(x) - 1.

math.expm1(0) # 0.0

math.exp(1e-6) - 1 # 1.0000004999621837e-06
math.expm1(1e-6) # 1.0000005000001665e-06
# exact result # 1.000000500000166666708333341666...

Section 9.4: Trigonometric Functions


a, b = 1, 2

import math

math.sin(a) # returns the sine of 'a' in radians


# Out: 0.8414709848078965

math.cosh(b) # returns the inverse hyperbolic cosine of 'b' in radians


# Out: 3.7621956910836314

math.atan(math.pi) # returns the arc tangent of 'pi' in radians


# Out: 1.2626272556789115

math.hypot(a, b) # returns the Euclidean norm, same as math.sqrt(a*a + b*b)


# Out: 2.23606797749979

Note that math.hypot(x, y) is also the length of the vector (or Euclidean distance) from the origin (0, 0)
to the point (x, y).

To compute the Euclidean distance between two points (x1, y1) & (x2, y2) you can use math.hypot as
follows

math.hypot(x2-x1, y2-y1)

To convert from radians -> degrees and degrees -> radians respectively use math.degrees and math.radians

math.degrees(a)
# Out: 57.29577951308232

math.radians(57.29577951308232)
# Out: 1.0

GoalKicker.com – Python® Notes for Professionals 60


Section 9.5: Inplace Operations
It is common within applications to need to have code like this:

a = a + 1

or

a = a * 2

There is an effective shortcut for these in place operations:

a += 1
# and
a *= 2

Any mathematic operator can be used before the '=' character to make an inplace operation:

-= decrement the variable in place


+= increment the variable in place
*= multiply the variable in place
/= divide the variable in place
//= floor divide the variable in place # Python 3
%= return the modulus of the variable in place
**= raise to a power in place

Other in place operators exist for the bitwise operators (^, | etc)

Section 9.6: Subtraction


a, b = 1, 2

# Using the "-" operator:


b - a # = 1

import operator # contains 2 argument arithmetic functions


operator.sub(b, a) # = 1

Possible combinations (builtin types):

int and int (gives an int)


int and float (gives a float)
int and complex (gives a complex)
float and float (gives a float)
float and complex (gives a complex)
complex and complex (gives a complex)

Section 9.7: Multiplication


a, b = 2, 3

a * b # = 6

import operator

GoalKicker.com – Python® Notes for Professionals 61


operator.mul(a, b) # = 6

Possible combinations (builtin types):

int and int (gives an int)


int and float (gives a float)
int and complex (gives a complex)
float and float (gives a float)
float and complex (gives a complex)
complex and complex (gives a complex)

Note: The * operator is also used for repeated concatenation of strings, lists, and tuples:

3 * 'ab' # = 'ababab'
3 * ('a', 'b') # = ('a', 'b', 'a', 'b', 'a', 'b')

Section 9.8: Logarithms


By default, the math.log function calculates the logarithm of a number, base e. You can optionally specify a base as
the second argument.

import math
import cmath

math.log(5) # = 1.6094379124341003
# optional base argument. Default is math.e
math.log(5, math.e) # = 1.6094379124341003
cmath.log(5) # = (1.6094379124341003+0j)
math.log(1000, 10) # 3.0 (always returns float)
cmath.log(1000, 10) # (3+0j)

Special variations of the math.log function exist for different bases.

# Logarithm base e - 1 (higher precision for low values)


math.log1p(5) # = 1.791759469228055

# Logarithm base 2
math.log2(8) # = 3.0

# Logarithm base 10
math.log10(100) # = 2.0
cmath.log10(100) # = (2+0j)

Section 9.9: Modulus


Like in many other languages, Python uses the % operator for calculating modulus.

3 % 4 # 3
10 % 2 # 0
6 % 4 # 2

Or by using the operator module:

import operator

operator.mod(3 , 4) # 3

GoalKicker.com – Python® Notes for Professionals 62


operator.mod(10 , 2) # 0
operator.mod(6 , 4) # 2

You can also use negative numbers.

-9 % 7 # 5
9 % -7 # -5
-9 % -7 # -2

If you need to find the result of integer division and modulus, you can use the divmod function as a shortcut:

quotient, remainder = divmod(9, 4)


# quotient = 2, remainder = 1 as 4 * 2 + 1 == 9

GoalKicker.com – Python® Notes for Professionals 63

You might also like