Black Mamba

Faster, Higher, Stronger.

Python Notes V

Python Version Binary Search

1
2
3
4
5
6
7
8
9
10
11
12
def search2Binary(seq, num, lower=0, upper=None):
    if upper is None:
        upper = len(seq) - 1
    if lower == upper:
        assert(num == seq[upper])
        return upper
    else:
        mid = (upper + lower) // 2
        if num > seq[mid]:
            return search2Binary(seq, num, mid + 1, upper)
        else:
            return search2Binary(seq, num, lower, mid)

Throwing Functions Around

  • map() Applies the function to all the elements in the sequences
1
2
map(str, range(3)) # Equivalent to [str(i) for i in range(3)
['0', '1', '2', '3']
  • filter() Returns a list of those elements for which the function is true
1
2
3
4
5
6
7
8
9
10
def func(x):
    return x.isalnum()

seq = ["foo", "x41", "?!", "***"]
filter(func, seq)
['foo', 'x41']

# another way
[x for x in seq if x.isalnum()]
['foo', 'x41']
  • lambda
1
2
filter(lambda x: x.isalnum(), seq)
['foo', 'x41']
  • reduce() Equivalent to func(func(func(seq[0], seq[1]), seq[2]), …)
1
2
3
numbers = [75, 101, 13, 100]
reduce(lambda x, y: x+y, numbers)
288

Python STL

  • Set
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
set(range(5))
{0, 1, 2, 3, 4}

set([1, 2, 6, 4, 6, 2, 4,  3, 3])
{1, 2, 3, 4, 6}

a = set([1, 2, 3])
b = set([2, 3, 4])

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

a | b
{1, 2, 3, 4}

a & b
{2, 3}

c = a & b
c.issubset(a)
True

a > c
True

a.intersection(b)
{2, 3}
>>> a.difference(b)
{1}
a - b
{1}

a.symmetric_difference(b)
{1, 4}

a ^ b
{1, 4}

a.copy()
{1, 2, 3}

a.copy is a
False
  • Heap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from heapq import *
from random import shuffle

data = range(10)
shuffle(data)
data
[7, 2, 1, 9, 3, 4, 5, 6, 8, 0]

heap = []
for n in data:
    heappush(heap, n)

heap
[0, 1, 2, 6, 3, 4, 5, 9, 8, 7]

# heappush(heap, value), heappop(heap), heapify(heap)
heappush(heap, 0.5)
heap
[0, 0.5, 2, 6, 1, 4, 5, 9, 8, 7, 3]

# heappop(heap)
heappop(heap)
0
heappop(heap)
0.5
heap
[1, 3, 2, 6, 7, 4, 5, 9, 8]

# heapify(heap)
heap = [3, 2, 5, 9, 4, 8, 7, 1, 6]
heapify(heap)
heap
[1, 2, 5, 3, 4, 8, 7, 9, 6]

# heapreplace()
heapreplace(heap, 0.5)
1

heap
[0.5, 2, 5, 3, 4, 8, 7, 9, 6]

heapreplace(heap, 10)
0.5

heap
[2, 3, 5, 6, 4, 8, 7, 9, 10]
  • Deque
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from collections import deque

# append(), appendleft()
q = deque(range(5))
q.append(5)
q.appendleft(6)
q
deque([6, 0, 1, 2, 3, 4, 5])

# pop(), popleft()
q.pop()
5
q.popleft()
6
q
deque([0, 1, 2, 3, 4])

# rotate(), shift to right
q.rotate(3)
q
([2, 3, 4, 0, 1])
q.rotate(1)
q
deque([1, 2, 3, 4, 0])
q.rotate(-1)
q
deque([2, 3, 4, 0, 1])
  • time
1
2
time.asctime()
'Fri May  2 13:32:20 2015'
  • random
1
2
3
# generate number from [0, n)
n = 6
randrange(n)
  • re
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import re
text= 'alpha, beta,,,,gamma   delta'
re.split('[, ]+', text)
['alpha', 'beta', 'gamma', 'delta']

# maxsplit indicates the max number of splits allowed
re.split('[, ]+', text, maxsplit=2)
['alpha', 'beta', 'gamma   delta']
re.split('[, ]+', text, maxsplit=1)
['alpha', 'beta,,,,gamma   delta']

pat = '[a-zA-Z]+'
text = '"Hm... Err -- are you sure?" he said, sounding insecure.'

re.findall(pat, text)
['Hm', 'Err', 'are', 'you', 'sure', 'he', 'said', 'sounding', 'insecure']

sng = r'[.?\",]+'
re.findall(sng, text)
['"', '...', '?"', ',', '.']
  • sub(origin, ‘text’, substitute)
1
2
3
4
origin = ' '
substi = 'Hello, '
re.sub(origin, 'Peter', substi)
'Hello,Peter'
  • escape()

    Used to scape all the characters in a string that might be interpreted as a regular expression operator. If there is a long string with lots of special characters and escape() can help avoid typing a lot of backslashes.

1
2
3
4
re.escape('www.python.org')
'www\\.python\\.org'
re.escape('Today is a good day.')
'Today\\ is\\ a\\ good\\ day\\.'
  • match()
1
2
3
4
5
6
7
8
9
10
11
12
m = re.match(r'www\.(.*)\..{3}', 'www.python.org')
m.group(1)
'python'
m.start(1)
4
m.end(1)
10
m.span(1)
(4, 10)

m.group(0)
'www.python.org'

Python Database

  • Sqlite
1
2
3
4
5
6
7
8
import sqlite3
conn = sqlite3.connect('somedatabase.db')

# get the cursor from the connection
cur = conn.cursor()

conn.commit()
conn.close()

Tools for Testing

  • doctest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# my_math.py
def mySquare(x):
'''
Square a number and returns the result.

mySquare(2)
4
mySquare(3)
9
'''
    return x * x

# add the lollowing code at the bottom
if __name__ == '__main__':
    import doctest, my_math
    doctest.testmod(my_math)

Then, run the testmod and watch the script

1
2
$ python my_math.py
$ python my_math.py -v

The test output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Trying:
    mySquare(2)
Expecting:
    4
ok
Trying:
    mySquare(3)
Expecting:
    9
ok
1 items had no tests:
    my_math
1 items passed all tests:
    2 tests in my_math.mySquare
2 tests in 2 items.
2 passed and 0 failed.
Test passed.
  • unittest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# my_math.py
def product(x, y):
    return x*y

# test_my_math.py
import unittest, my_math

class ProductTestCase(unittest.TestCase):

    def testIntegers(self):
        for x in range(-10, 10):
            for y in range(-10, 10):
                p = my_math.product(x, y)
                self.failUnless(p == x*y, 'Integer failed')

    def testFloat(self):
        for x in range(-10, 10):
            for y in range(-10, 10):
                x = x/10.0
                y = y/10.0
                p = my_math.product(x, y)
                self.failUnless(p == x*y, 'Float failed')

# add the lollowing code at the bottom
if __name__ == '__main__': unittest.main()

Then, type F5 To run test_my_math.py

1
2
3
4
5
..
---------------------------------------------------
Ran 2 tests in 0.050s

OK

Octopress Error: Pygments Can’t Parse Unknown Language: </p>

Octopress is good, but not perfect.

  • One of the common error when type “rake generate” is:
1
Error: Pygments can't parse unknown language: </p>

Although there is a error, jekyll don’t point out the detailed location where the error come from in its default setting. It was very annoying.

To deal with the error, one way is modify the Ruby file plugins/pygments_code.rb, add #{code} after #{lang}:

1
2
3
rescue MentosError
raise "Pygments can't parse unknown language: #{lang}#{code}."
end

Then, when “rake generate” again, the error location will be listed.

  • Another thing worth noted is that when blogging ‘’ should be replaced with ‘ ’, i.e., add a blank between ‘’, otherwise, when rake generate, ‘’ without blank between them will also produce this error and it is difficult to detect through error description

Python Notes IV

input() and raw_input()

  • input(): Gets inputs from the user
1
2
3
input("Enter a number: ")
Enter a number: 3
3
  • raw_input(): Gets input from the user, as a string
1
2
3
raw_input("Enter a number: ")
Enter a number: 3
'3'

repr() and str()

  • repr(): Returns a string representation of a value
  • A synonym for repr(‘x’) is ‘x’
1
2
3
4
print repr("Hello, world!")
'Hello, world!'
print repr(10000L)
10000L
  • str(): Converts a value to a string
1
2
3
4
print str("Hello, world!")
Hello, world!
print str(10000L)
10000

Slicing

  • numbers[beg : end : direction(interval)]
  • range(beg…<end), i.e., [beg, end)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

numbers[3:6] = [4, 5, 6]
numbers[-3:-1] = [8, 9]
numbers[-3:] = [8, 9, 10]
numbers[:3] = [1, 2, 3]

numbers[0:10:2] = [1, 3, 5, 7, 9]
numbers[3:6:2] = [4, 6]

numbers[::3] = [1, 4, 7, 10]
numbers[8:3] = []
numbers[8:3:-1] = [9, 8, 7, 6, 5]

numbers[10:0:-2] = [10, 8, 6, 4, 2]
numbers[5::-2] = [6, 4, 2]
numbers[:5:-2] = [10, 8]

numbers[5::-2] = [6, 4, 2]
numbers[:5:-1] = [10, 9, 8, 7]

Membership

  • if … in …
  • if … not in …

Lists

  • To convert a list of characters such as the preceding code back to a string, use ‘ ’.join(somelist)
1
2
3
4
somelist = ['b', 'o', 'y']
' '.join(somelist)

'boy'
  • Deleting Elements use del
1
2
3
4
5
names = ['Ada', 'Bob', 'Cecil', 'David']
del names[2]

names
['Ada', 'Bob', 'David']
  • Assigning to Slices
1
2
3
4
5
name = list('Perl')
name[1:] = list('ython')

name
['P', 'y', 't', 'h', 'o', 'n']
  • Slice assignments can be used to insert elements without replacing any of the original ones
1
2
3
4
5
6
7
8
nums = [1, 5]
nums[1:1] = [2, 3, 4]
nums
[1, 2, 3, 4, 5]

nums[1:4] = []  # del nums[1:4]
nums
[1, 5]
  • String Formatting
1
2
3
4
5
6
7
8
9
str = "Hello, %s! %s are you?"
val = ('Peter', 'How')
print (str % val)

Hello, Peter! How are you?

# for short
'%s + %s = %s' % (1, 1, 2)
'1 + 1 = 2'
  • Template Strings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from string import Template

s = Template('$x,  glorious $x!')
s.substitute(x = 'slurm')
'slurm,  glorious slurm!'

# the replacement is part of a word
s = Template("It's ${x}tastic!")
s.substitute(x = ' slurm')
"It's  slurmtastic!"

# insert a dollar sign, use $$
s = Template("Make $$ selling $x!")
s.substitute(x='slurm')
'Make $ selling slurm!'

# supply the value-name pairs in a dictionary
s = Template('A $thing must never $action.')
d = {}
d['thing'] = 'dog'
d['action'] = 'eat grass'
s.substitute(d)
'A dog must never eat grass.'
  • find()
1
2
3
title = "Monty Python's Flying Circus"
title.find('Python')
6
  • split()
1
2
3
4
5
6
7
8
'1+2+3+4+5'.split('+')
['1', '2', '3', '4', '5']

'/usr/bin/env'.split('/')
['', 'usr', 'bin', 'env']

'a    aa    aaa    '.split()
['a', 'aa', 'aaa']
  • join() The inverse of split, used to join the elements of a sequence
1
2
3
4
5
6
7
8
9
10
11
12
13
seq = ['1', '2', '3', '4', '5']
'+'.join(seq)
'1+2+3+4+5'

dirs = '', 'usr', 'bin', 'env'
dirs
('', 'usr', 'bin', 'env')

'/'.join(dirs)
'/usr/bin/env'

print('C:' + '\\'.join(dirs))
C:\usr\bin\env
  • strip() Get rid of the characters listed in strip()
1
2
3
4
5
6
7
8
9
'!!!   a    aa    aaa    !!!!!'.strip('!')
'   a    aa    aaa    '

'   a    aa    aaa    '.strip()
'a    aa    aaa'

# list all that to remove
'*** SPAN * for * everyone!!! ***'.strip(' *!')
'SPAN * for * everyone'
  • title()
1
2
"that's all, folks".title()
"That'S All, Folks"
  • string.capwords()
1
2
3
import string
string.capwords("that's all, folks")
"That's All, Folks"
  • replace()
1
2
'This is a cat.'.replace('cat', 'dog')
'This is a dog.'
  • maketrans() and translate()
1
2
3
4
5
6
from string import maketrans

trantab = maketrans('aeiou', '12345')  # (in -> out)
"this is string example...wow!".translate(trantab);

'th3s 3s 1 str3ng 2x1mpl2...w4w!'
  • An optional second argument can be supplied to specify that should be deleted
1
2
3
4
5
'this is an incredible test..'.translate(trantab)
'th3s 3s 1n 3ncr2d3bl2 t2st.'

'this is an incredible test'.translate(trantab, ' ')
'th3s3s1n3ncr2d3bl2t2st'

Dictionary

  • dict()
1
2
3
# (key, value)
dict(name = 'Peter', age = 12)
{'name': 'Peter', 'age': 12}
  • clear()
1
2
3
4
5
6
7
8
9
10
11
x = {}
y = x   # refer to the same dictionary
x['key'] = 'value'

y
{'key': 'value'}

x.clear()

y   # y is also empty
{}
  • copy()
1
2
3
4
5
6
7
8
9
x = {'username': 'admin', 'machines': ['foo', 'bar']}
y = x.copy()
y['username'] = 'peter'
y['machines'].remove('bar')

y
{'username': 'peter', 'machines': ['foo']}
x
{'username': 'admin', 'machines': ['foo']}
  • deepcopy() Avoid the situation that modify the value.
1
2
3
4
5
6
7
8
9
10
11
12
13
d = {}
d['names'] = ['Alfred', 'Bertrand']

c = d.copy()
deepc = deepcopy(d)
d['names'].append('Clive')

d
{'names': ['Alfred', 'Bertrand', 'Clive']}
c
{'names': ['Alfred', 'Bertrand', 'Clive']}
deepc
{'names': ['Alfred', 'Bertrand']}
  • fromkeys Create a new dictionary with the given keys.
1
2
3
4
5
6
7
8
{}.fromkeys(['name', 'age'])
{'name': None, 'age': None}

dict.fromkeys(['name', 'age'])
{'name': None, 'age': None}

dict.fromkeys(['name', 'age'], '(default)')
{'name': '(default)', 'age': '(default)'}
  • get()
1
2
3
4
5
6
7
d = {}
d['name'] = 'Peter'
d['addr'] = 'England'
d.get('name')
'Peter'
d.get('addr')
'England'
  • has_key() Check whether a dictionary has a given key.
1
2
3
4
5
6
7
# Be gone after Python 3.0
d = {}
d.has_key('name')
False
d['name'] = 'Peter'
d.has_key('name')
True
  • items() Return all the items of dictionary as a list of the form (key, value)
1
2
3
d = {'title': 'Python Web Site', 'url': 'http:#www.python.org', 'spam': 0}
d.items()
[('url', 'http:#www.python.org'), ('spam', 0), ('title', 'Python Web Site')]
  • iteritems()
1
2
3
4
5
6
Return an iterator instead of a list
it = d.iteritems()
it
`dictionary-itemiterator object at 0x10b918788`
list(it)
[('url', 'http:#www.python.org'), ('spam', 0), ('title', 'Python Web Site')]
  • pop()
1
2
3
4
5
6
7
d = {'spam': 0, 'url': 'http:#www.python.org', 'title': 'Python Web Site'}

d.pop('spam')
0

d
{'url': 'http:#www.python.org', 'title': 'Python Web Site'}
  • popitem()
1
2
3
4
5
d = {'url': 'http:#www.python.org', 'title': 'Python Web Site'}
d.popitem()
('url', 'http:#www.python.org')
d
{'title': 'Python Web Site'}
  • setdefault() Set the value corresponding to the given key if it not already in the dictionary
1
2
3
4
5
d = {}
d.setdefault('name', 'N/A')
'N/A'
d
{'name': 'N/A'}
  • update()
1
2
3
4
5
6
7
8
9
d = {
'name': 'Peter',
'addr': 'England',
}
x = {'addr': 'France'}
d.update(x)

d
{'name': 'Peter', 'addr': 'France'}
  • values
1
2
3
4
5
6
d = {}
d[1] = 1
d[2] = 2

d.values()
dict_values([1, 2])
  • range(a, b), [a, b)
1
2
3
4
5
for i in range(10, 12):
print(i)

10
11

Importing

  • import sth. from a module
1
2
3
from somemodule import somefunction
or
from somemodule import *
  • Define aliases
1
2
3
from math import sqrt as foo
foo(4)
2.0
  • loop the key of a dictionary
1
2
3
4
5
6
7
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print(key, d[key])

# this one is better
for key, value in d.items():
print(key, value)
  • Slightly Loopy
1
2
[x*x for x in range(10) if x % 3 == 0]
[0, 9, 36, 81]
1
2
3
4
5
6
7
8
res = []
for x in range(3):
for y in range(3):
res.append((x, y))

# for short
[(x, y) for x in range(2) for y in range(2)]
[(0, 0), (0, 1), (1, 0), (1, 1)]

Executing and Evaluating

  • exec
1
2
exec "print 'hello, world!'"
hello, world!
  • eval
1
2
3
4
d = {}
d['x'] = 3  # exec 'x = 3' in d
eval('x * x', d)
9

Bonus: Trick of Reduce Code

  • Comparison
1
2
3
# using the former instead of the latter
1 < num < 10
1 < num and num < 10
  • or
1
2
3
4
5
name = input('Enter name: ') or 'N/A'
Enter name:

name
'N/A'
  • a if b else c
1
2
3
4
5
score = int(99)
grade = 'A' if 90 <= score <= 100 else 'B'

grade
'A'

Python Notes III

Sort in two ways

  • sort(): In-place sorting, replaces the original data
  • sorted(): Copied sorting, return a sorted copy of the original data
  • sorting order
1
2
sorted(data)    # Ascending
sorted(data, reverse=True)  # Descending
  • Get top 3 data from file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def sanitize(time_string):
    if '-' in time_string:
        splitter = '-'
    elif ':' in time_string:
        splitter = ':'
    else:
        return (time_string)

    (mins, secs) = time_string.split(splitter)
    return (mins + '.' + secs)

def get_data(filename):
    try:
        with open(filename) as file:
            data = file.readline()
        return data.strip().split(',')
    except IOError as ioerr:
        print('File error: ' + str(ioerr))
        return(None)

# file operation
james = get_data('james.txt')

clean_james = []
for each_t in james:
    clean_james.append(sanitize(each_t))

unique_james = []
for each_t in clean_james:
    if each_t not in unique_james:
        unique_james.append(each_t)
print(sorted(unique_james)[0:3])
  • Remove the duplicates
1
2
# file operation can be replaced with one line code
print(sorted(set([sanitize(each_t) for each_t in get_date("james.txt")]))[0:3])
  • Bundle the code and data in a dictionary
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def get_data(filename):
    try:
        with open(filename) as file:
            data = file.readline()
        temp = data.strip().split(',')

        # return a dictionary
        return({'Name' : temp.pop(0),
                'DOB'  : temp.pop(0),
                'Times': str(sorted(set([sanitize(each_t) for each_t in temp]))[0:3])})
        except IOError as ioerr:
            print('File error: ' + str(ioerr))
            return(None)

sarah = get_data('sarah2.txt')
print(sarah['Name'] + "'s fastest times are: " + sarah['Times'])
  • Amend the code and data in a class that inherit from BIF list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Athlete(list):
    def __init__(self, a_name, a_dob=None, a_times=[]):
        list.__init__([])
        self.name = a_name
        self.dob = a_dob
        self.extend(a_times)

def top3(self):
    return(str(sorted(set([sanitize(each_t) for each_t in self]))[0:3]))

def get_data(filename):
    try:
        ...
        return(Athlete(temp.pop(0), temp.pop(0), temp))
    except IOError as ioerr:
        ...

sarah = get_data('sarah2.txt')
print(sarah.name + "'s fastest times are: " + sarah.top3())

Model the data

  • Put class AthleteList in a module file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import pickle
# class AthleteList is saved in athletelist.py, import AthleteList using this line of code
# use dir() command to confirm that the import has been successful
from athletelist import AthleteList

def get_data(filename):
    ...

def put_to_store(file_list):
    all_athletes = {}
    for each_file in file_list:
        ath = get_data(each_file)
        all_athletes[ath.name] = ath
    try:
        with open('athletes.pickle', 'wb') as athf:
            pickle.dump(all_athletes, athf)
    except IOError as ioerr:
        print('File error (put_and_store): ' + str(ioerr))
        return (all_athletes)

def get_from_store():
    all_athletes = {}
    try:
        with open('athletes.pickle', 'rb') as athf:
            all_athletes = pickle.load(athf)
        except IOError as ioerr:
            print('File error (get_from_store): ' + str(ioerr))
            return (all_athletes)

Bonus I: Factory Function: set()

  • Build an unordered collection of unique elements
1
2
3
4
data = [1,1,13,3,3,2,2,3,1,13,1]
set(data)
# output
{1, 2, 3, 13}

Bonus II: BIF: pop(i)

  • pop(i) call returns and removes data from the front of a list at location
1
2
3
4
5
6
data = [1,13,3,3,1]
data.pop(3)
# output
3
data
[1,13,3,1]

Bonus III: List Comprehension

  • When the code is like this
1
2
3
4
new = []
for each_item in old:
    ...
append(len(each_item))
  • Rewrite it like this
1
new = [len(each_item) for each_item in old]

Bonus IV: Dictionary

  • Two way to create an empty dictionary
1
2
3
4
# method 1
d1 = {}
# method 2
d2 = dict()

Wither and Fall

It should be a splendid flowering season

But grass wither and the flowers fall

It was painful

No flowers nor fruits

Reluctant withered at this time

But falled just this time

Python Notes II

Operation for text

  • Open and close a file
1
2
the_file = open('sketch.txt')
the_file.close()
  • Get and change the current working directory
1
2
3
4
import os
os.getcwd()
os.chdir('.../targetDirectory')
os.listdir()
  • Read line and back to the start location of the file
1
2
3
data = open('sketch.txt')
print(data.readline(), end='')
data.seek(0)    # “rewind” a file to the beginning
  • Process every line of a file
1
2
for eachLine in data:
    print(eachLine, end='')
  • Using split() method to process each line to extract part of the line
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import os

if os.path.exists('sketch.txt'):
    data = open('sketch.txt')

for eachLine in data:
    # only process the line that contains ':'
    if not eachLine.find(':') == -1:
        # optional arg is set to 1, line of data is only broken into 2 pieces
        (role, line_spoken) = eachLine.split(':', 1)
        line_spoken = line_spoken.strip()

        print(role, end='')
        print(' said: ', end='')
        print(line_spoken, end='')

    data.close()
else:
    print('The data file is missing!')

Handle Exceptions: try/except Machanism

  • Python try to run code first, then deal with runtime errors (exceptions) as they happen
1
2
3
4
try:
    code (which might cause a runtime error)
except ErrorType:
    error-recovery code
  • Python catch exceptions as they occur, gives you a chance to possibly recover from the error and, critically, not crash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try:
    data = open('sketch.txt')

    for eachLine in data:
    try:
        (role, spoken) = eachLine.split(':', 1)
        line_spoken = line_spoken.strip()

        print(role, end='')
        print(' said: ', end='')
        print(spoken, end='')

    # for handling the case there is no ':' in a line
    except ValueError:
        pass

    data.close()
except IOError:
    print('The data file is missing!')

Extend try/except with finally

  • No matter what errors occur, code in the finally suite is always run
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
man = []
other = []

try:
    data = open('sketch.txt')

    for eachLine in data:
    try:
        (role, spoken) = eachLine.split(':', 1)
        spoken = spoken.strip()

        if role == 'Man':
            man.append(spoken)
        elif role == 'Other Man':
            other.append(spoken)
        except ValueError:
            pass

    data.close()
except IOError:
    print('The data file is missing!')

try:
    man_file = open('man_data.txt', 'w')
    other_file = open('other_data.txt', 'w')
    print(man, file=man_file)
    print(other, file=other_file)
except IOError as err:
    print('File Error: ' + str(err))
finally:
    if 'man_file' in locals():
        man_file.close()
    if 'other_file' in locals():
        other_file.close()

Knowing the detailed error imformation

  • Python creates an exception object that is passed as an argument to the except suite
1
2
3
4
5
6
7
8
9
10
11
12
try:
    data = open('missingFile.txt')
        print(data.readline(), file=data)
# the error imformation is named as 'err'
except IOError as err:
    print('File error: ' + str(err))
finally:
    if 'data' in locals():
        data.close()

# output:
File error: [Errno 2] No such file or directory: 'missingFile.txt'

Use with to reduce the amount of code

  • The following code is identical to the former as a short version
1
2
3
4
5
try:
    with open('missingFile.txt', "w") as data:
        print(data.readline(), file=data)
except IOError as err:
    print('File error: ' + str(err))
  • try/except/finally code can be rewrite using with
1
2
3
4
5
6
try:
    with open('man_data.txt', 'w') as man_file, open('other_data.txt', 'w') as other_file:
        print(man, file=man_file)
        print(other, file=other_file)
except IOError as err:
    print('File error: ' + str(err))
  • Note: no need to close file, because with does that job

Open the file in write mode

  • Assume there is a file named “example.txt” in the current directory
1
2
3
out = open("example.txt", "w")
print("Write something to example.txt", file=out)
out.close()

Update nester.py for formating the output files

  • Add the 4th argument (fh=sys.out) be the output file
1
2
3
4
5
6
7
8
9
10
11
12
# nester.py
import sys

def print_item (the_list, indent=False, level=0, fh=sys.stdout):
    for each_item in the_list:
        if isinstance(each_item, list):
            print_item (each_item, indent, level+1, fh)
        else:
            if indent:
                for tab_stop in range(level):
                    print("\t", end='@!', file=fh)
            print (each_item, file=fh)
  • Using func print_item for formating the output file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import nester

man = []
other = []

try:
    data = open('sketch.txt')

for eachLine in data:
    try:
        (role, line_spoken) = eachLine.split(':', 1)
        line_spoken = line_spoken.strip()

        if role == 'Man':
            man.append(line_spoken)
        elif role == 'Other Man':
            other.append(line_spoken)
    except ValueError:
        pass
    data.close()
except IOError:
    print('The data file is missing!')

try:
    with open('man_data.txt', 'w') as man_file, open('other_data.txt', 'w') as other_file:
    # format the output files
    nester.print_item(man, fh=man_file)
    nester.print_item(other, fh=other_file)
except IOError as err:
    print('File error: ' + str(err))

Pickle the data

  • Store data using pickle.dump()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pickle

man = []
other = []

try:
    ...
except IOError:
    ...

try:
    # 'wb' indicate the access mode to be "writeable, binary"
    with open('man_data.txt', 'wb') as man_file, open('other_data.txt', 'wb') as other_file:
    # store data
        pickle.dump(man, man_file)
        pickle.dump(other, other_file)
except IOError as err:
    print('File error: ' + str(err))
# handle pickle exceptions
except pickle.PickleError as perr:
    print('Pickling error: ' + str(perr))
  • Load data using pickle.load()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pickle
import nester

new_man = []

try:
    with open('man_data.txt', 'rb') as man_file:
        new_man = pickle.load(man_file)
except IOError as err:
    print('File error: ' + str(err))
except pickle.PickleError as perr:
    print('Pickle error: ' + str(perr))

nester.print_item(new_man)

Bonus I: BIF split()

  • split(…)
1
str.split([sep[, maxsplit]]) -> list of strings
  • Return a list of the words in str, using sep as the delimiter string
  • If maxsplit is given, at most maxsplit splits are done
  • If sep is not specified or is None, any whitespace string is a separator and empty strings are removed from the results
  • If the optional argument is set to 1, line of data is only broken into 2 pieces, effectively negating the effect of any extra colon on any line

Bonus II: BIF strip()

  • strip(…)
1
2
3
str = "!!!!Today is a good day...Yeah.!!!!!!"
str.strip('!')
'Today is a good day...Yeah.'
  • Returns a copy in which all chars have been stripped at the beginning and the end

Bonus III: BIFs Recall

  • open()
  • close()
  • readline()
  • seek()
  • split()
  • strip()
  • find()
  • help()
  • not
  • pass
  • pickle.dump()
  • pickle.load()
  • sys.out
  • try/except/finally
  • with … as
  • ValueError: Occurs when data doesn’t conform to an expected format
  • IOError: Occurs when data can’t be accessed properly

Bonus IV: Python Variable

  • Python variables don’t actually contain the data assigned to them
  • Python variables contain a reference to a data object

Python Notes I

Work effectively with IDLE

  • Press TAB key, IDLE will offer suggestions to help you complete your statement
  • Press Alt-P to recall the previous code statement and press Alt-N to move to the next code statement

Deal with Python list

  • Python’s variable identifiers don’t have a type, Python’s list is a high-level collection
  • Using print() and len() to work out how many data items are in the list
1
2
3
4
5
6
7
animal  = ["Dog", 'Pig', 'Cat', "Duck"]
print(animal)
['Dog', 'Pig', 'Cat', 'Duck']
print(len(animal))
4
print(animal[1])
Pig
  • Using append(), extend() and pop() method to add and remove data from the list
1
2
3
4
5
6
7
8
9
10
animal.append("Tiger")
print(animal)
['Dog', 'Pig', 'Cat', 'Duck', 'Tiger']
animal.pop()
'Tiger'
print(animal)
['Dog', 'Pig', 'Cat', 'Duck']
animal.extend(["Fish", "Bird"])
print(animal)
['Dog', 'Pig', 'Cat', 'Duck', 'Fish', 'Bird']
  • Using remove() and insert() to find and remove or add a specific data from list
1
2
3
4
5
6
animal.remove("Pig")
print(animal)
['Dog', 'Cat', 'Duck', 'Fish', 'Bird']
animal.insert(1, "Bull")
print(animal)
['Dog', 'Bull', 'Cat', 'Duck', 'Fish', 'Bird']
  • For loops work with lists of any size
1
2
3
animals = ["Dog", 'Pig', 'Cat', "Duck", "Fish"]
for each_animal in animals:
    print each_animal
  • Store list within lists
1
2
3
4
5
6
7
8
9
10
11
12
movie = ["Titanic", 1997, "Romance & Disaster", "194 minutes", ["James Cameron", ["Leonardo DiCaprio", "Kate Winslet", "Billy Zane", "Kathy Bates", "Frances Fisher"]]]
for each_item in movie:
    print each_item

Titanic
1997
Romance & Disaster
194 minutes
['James Cameron', ['Leonardo DiCaprio', 'Kate Winslet', 'Billy Zane', 'Kathy Bates', 'Frances Fisher']]

print movie[4][1][0]
Leonardo DiCaprio

Don’t repeat code and create a function

  • isinstance() BIF checks whether an identifier refers to a data object of some specified type
  • Using def to define a custom function
1
2
def function_name (arguments):
    code suite
  • Python3 defaults its recursion limit to 1,000
  • Print items in list within lists
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def print_item(the_list):
    for each_item in the_list:
        if isinstance(each_item, list):
            print_item(each_item)
        else:
            print(each_item)

print_item(movie)

Titanic
1997
Romance & Disaster
194 minutes
James Cameron
Leonardo DiCaprio
Kate Winslet
Billy Zane
Kathy Bates
Frances Fisher

Build a distribution and upload code to PyPI

  • Create a folder for the module
  • Create a file called “setup.py” in the new folder
1
2
3
4
5
6
7
8
9
10
11
from distutils.core import setup

setup(
    name = 'nester',
    version = '1.0',
    py_modules = ['nester'],
    author = 'name',
    author_email = 'name@somewhere.com',
    url = 'name@someplace.com',
    description = 'A simple printer of nested lists',
    )
  • Build a distribution file, enter the command at the prompt
1
python3 setup.py sdist
  • Install the distribution into local copy of Python
1
python3 setup.py install
  • Then, the module has been transformed into a distribution and installed into local copy of Python
1
2
# at the first time, should type the username and password
python3 setup.py register
  • Finally, upload code to PyPI
1
python3 setup.py sdist upload

Import a module to use it

  • For instance, there is a function named “nester.py”
1
2
3
4
5
6
7
def print_item (the_list):
    # This function takes a argument called "the_list"
    for each_item in the_list:
        if isinstance(each_item, list):
            print_item (each_item)
        else:
            print (each_item)
  • Type F5 to run the module’s code, use the following list data
1
2
3
4
5
# allow us to access nester's functions
import nester
animals = ['Pig', 'Dog', 'Cat', 'Bird', 'Fish']
# "nester" is associated namespace which like family names helps to qualify what the code mean
nester.print_item(animals)

Use optional arguments

  • Update the function “nester.py” with default arguments
1
2
3
4
5
6
7
8
9
def print_item (the_list, indent=False, level=0):
    for each_item in the_list:
        if isinstance(each_item, list):
            print_item (each_item, indent, level+1)
        else:
            if indent:
                for tab_stop in range(level):
                    print("\t", end='@!')
            print (each_item)
  • Use indent to control whether indent code
  • Use level to control the init indentation level

Update reversion to PyPI

  • Edit “setup.py” so that it has a new version
1
version = '1.1',
  • Upload the new distribution to PyPI
1
python3 setup.py sdisk upload

Bonus I: Python BIFs

  • BIFs is short for build-in functions, it can mean less code to write
  • There were over 70 BIFs in Python3
  • BIFs have their very own namespace called builtins
  • At Python or IDLE shell, typing dir( builtins ) to see a list of the built-in functions
  • To find out what any BIF does—like input(), for example—type help(input) at the shell for a description of the BIFs function
  • Before write new code, think BIF at first

Bonus II: .pyc Files

  • If the module code hasn’t changed, no translation occurs and the “compiled” code is executed
  • If the code has changed, the translation occurs (creating a new .pyc file) as needed
  • When Python sees a .pyc file, it tries to use it because doing so makes everything go much faster
  • The use of .pyc file (if found) is primarily a potential runtime optimization performed by the interpreter, it can’t be created by users

Variable Property Attributes in iOS

In iOS, variable property attributes indicate data accessibility and storage considerations,

1
2
3
4
5
6
7
8
9
10
- atomic              //default
- nonatomic
- strong = retain        //default
- weak = unsafe_unretained
- retain
- assign                //default
- unsafe_unretained
- copy
- readonly
- readwrite             //default

  • atomic (default)
    • Only one thread access the variable (static type)
    • Thread safe, but slow

Example :

1
2
@property (atomic, retain) NSString *name;
@synthesize name;
  • nonatomic
    • Multiple threads access the variable (dynamic type)
    • Thread unsafe, but fast
    • Not a default behavior, need to add nonatomic keyword

Example:

1
2
@property (nonatomic, retain) NSString *name;
@synthesize name;
  • strong (iOS4 = retain, default)
    • Own the object strongly, keep it in the heap until don’t point to it anymore
    • Can’t dealloc this before aim fine with that same as “retain”
    • Generally, using for UIViewControllers (UI item’s parents)
    • Used with ARC and ARC automatically releases it when beyond its area or the strong reference is invalid

Example:

1
2
@property (nonatomic, strong) ViewController *viewController;
@synthesize viewController;
  • weak (In iOS 4 & OS X Snow Leopand = unsafe_unretained )
    • Keep it as long as someone else points to it strongly
    • A “weak” reference is a reference that you don’t retain
    • Can’t own the instance of object
    • When the object is “deallocated”, the weak pointer is automatically set to nil
    • Generally using for IBOutlets (UIViewController’s Childs) because the child object only needs to exist as long as the parent object does

Example :

1
2
@property (nonatomic, weak) IBOutlet UIButton *myButton;
@synthesize myButton;
  • retain = strong
    • Old value is released and it is assigned
    • Specifies the new value should be sent “-retain” on assignment and the old value sent “-release”
    • If you write retain it will auto work like strong
    • Methods like “alloc” include an implicit “retain”

Example:

1
2
@property (nonatomic, retain) NSString *name;
@synthesize name;
  • assign (default)
    • A property attribute tells the compiler how to synthesize the property’s setter implementation

Example:

1
2
@property (nonatomic, assign) NSString *address;
@synthesize address;
  • unsafe_unretained (In iOS 4 & OS X Snow Leopand)
    • An ownership qualifier that tells ARC how to insert retain/release calls
    • The ARC version of assign
    • The old version of weak but not safe

Example:

1
2
@property (nonatomic, unsafe_unretained) NSString *nickName;
@synthesize nickName;
  • copy
    • Required when the object is mutable
    • Specifies the new value should be sent “-copy” on assignment and the old value should be sent “-release”
    • Like retain, returns an object which you must explicitly release (e.g., in dealloc) in non-garbage collected environments
    • Need to release the object when finished with it because you are retaining the copy

Example:

1
2
@property (nonatomic, copy) NSArray *myArray;
@synthesize myArray;
  • readonly
    • Tell compiler not to generate “setter” method automatically
    • If you specify readonly, only a “getter” method is required in the @implementation block
    • If you use the @synthesize directive in the @implementation block, only the “getter” method is synthesized

Example:

1
2
@property (nonatomic, readonly) NSString *name;
@synthesize name;
  • readwrite (default)
    • “setter” and “getter” are both generated
    • Both “setter” and “getter” method are required in the @implementation block
    • If you use the @synthesize directive in the implementation block, both the “setter” and “getter” methods are synthesized

Example:

1
2
@property (nonatomic, readwrite) NSString *name;
@synthesize name;

Reference Count Style Memory Management and ARC Rules

Reference Count Style Memory Management

  • A variable hold the objects generate by itself
1
id obj = [[NSObject alloc] init];
  • A variable can hold the objects generate by other variables
1
2
id obj = [NSMutableArray array];
[obj retain];
  • If the objects of a variable are no longer needed, the variable can release the objects held by itself
1
2
3
4
5
6
7
8
// Generate by itself and hold the objects by itself
id obj = [[NSObject alloc] init];
[obj release];

// Generate by others and hold the objects by itself
id obj = [NSMutableArray array];
[obj retain];
[obj release];
  • A variable cannot release the objects held by others
1
2
id obj1 = [obj0 object];
[obj1 release];    // error

ARC Rules

  • Can’t use retain / release / retainCount / autorelease

    • Memory management is the compiler’s job, so there is no need to use this methods
    • This methods is need to use when the ARC is invalid
  • Can’t use NSAllocateObject / NSDeallocateObject

    • When ARC is available, the methods NSAllocateObject and NSDeallocateObject are both forbidden
  • Don’t call dealloc explicitly

    • When the object is abandoned, dealloc is called automatically no matter ARC is available or not
  • Using @autoreleasepool instead of using NSAutoreleasePool

  • Object type variables can’t be a member of structure

    • Structure can’t manage the life circle of its member

Bonus: The Diffence Between Objective-C Objects and Core Foundation Objects

  • Objective-C objects are generated by Foundation Framework
  • Core foundation objects are generated by Core Foundation Framework

How to Add Stuff on GitHub via Command Line

  • Register an “username” and login in GitHub
  • Click “+” sign at the upper right corner to create a new repository and give it a name
  • Open your repository and you can see the clone URL is located at the right side, for instance: https://github.com/yourname/yourRepositoryName.git
  • Copy the URL of your repository and clone it from remote to local by typing: git clone https://github.com/yourname/yourRepositoryName.git
  • See the current configured remote repository for your fork by typing: git remote -v
  • Add something to the local repository, such as a “README.md” file
  • Push the new added file “README.md” to the remote version on GitHub by typing:
  • Typing your username and password to submit the changes to your repository on GitHub
  • Now you can refresh the web page of your repository to see the “README.md” file that just added
  • For removing the file/document named “sometingToRemove” of your local repository:
    • git rm sometingToRemove