What makes Python so awesome?
In [1]:
# import css and load slide show utilities
%run talktools
# inline matplotlib plot
%matplotlib inline
In [2]:
# Boolean
True
False
# Number
1, 2, 3 # int
1.1, 1.2, 1.3 # float
1 + 1j # complex number
# String
'hello world', "hello world"
r'\d+'
# Bytes
b'hello world'
# None
None
In [3]:
[1, 2, 3] # list
('apple', 10) # tuple
{1, 2, 3} # set
{'apple': 10, 'boy': 5, 'car': 3} # dict
Out[3]:
In [4]:
numbers = [0, 1, 2, 3, 4]
In [5]:
numbers[1]
Out[5]:
In [6]:
numbers[1:3]
Out[6]:
In [7]:
numbers[:2]
Out[7]:
In [8]:
numbers[2:]
Out[8]:
In [9]:
numbers[::2]
Out[9]:
In [10]:
numbers[-1]
Out[10]:
In [11]:
numbers[::-1]
Out[11]:
In [12]:
numbers.append(5)
numbers
Out[12]:
In [13]:
strlen = {'apple': 5, 'boy': 3, 'car': 3}
In [14]:
strlen['apple']
Out[14]:
In [15]:
strlen.get('dog', 'default')
Out[15]:
In [16]:
strlen['dog'] = 3
strlen
Out[16]:
In [17]:
1 + 1 - 1 * 1 / 1
Out[17]:
In [18]:
10 // 3
Out[18]:
In [19]:
10 % 3
Out[19]:
In [20]:
2 ** 100
Out[20]:
In [21]:
(1 + 5j) * (1 - 5j)
Out[21]:
In [22]:
'hello ' + 'world'
Out[22]:
In [23]:
'Hello' * 10
Out[23]:
In [24]:
1 == 1
Out[24]:
In [25]:
1 != 2
Out[25]:
In [26]:
1 > 2
Out[26]:
In [27]:
1 >= 2
Out[27]:
In [28]:
1 < 2
Out[28]:
In [29]:
1 <= 2
Out[29]:
In [30]:
not True
Out[30]:
In [31]:
True and False
Out[31]:
In [32]:
True or False
Out[32]:
In [33]:
x = 1
if x == 1:
print('Hello')
In [34]:
x = 2
if x == 1:
print('1')
elif x == 2:
print('2')
else:
print('3')
In [35]:
for i in range(5):
print(i)
In [36]:
words = ['apple', 'boy', 'cat', 'dog', 'egg']
In [37]:
for word in words:
print(word)
In [38]:
for i, word in enumerate(words, 1):
print("{}. {}".format(i, word))
In [39]:
!cat data/words.txt
In [40]:
words = open('data/words.txt')
for i, word in enumerate(words, 1):
print('{}. {}'.format(i, word.strip()))
words.close()
In [41]:
'this has a line break\n'.strip()
Out[41]:
In [42]:
max([1, 2, 3, 4, 5])
Out[42]:
In [43]:
sum([2, 4, 6, 8, 10])
Out[43]:
In [44]:
sorted([3, 2, 7, 4, 6])
Out[44]:
In [45]:
words = ['apple\n', 'boy\n', 'cat\n', 'dog\n', 'egg\n']
In [46]:
stripped_words = map(str.strip, words)
list(stripped_words)
Out[46]:
In [47]:
def has_a(word):
return 'a' in word
stripped_a_words = map(str.strip, filter(has_a, words))
list(stripped_a_words)
Out[47]:
In [48]:
stripped_a_words = map(str.strip, filter(lambda w: 'a' in w, words))
list(stripped_a_words)
Out[48]:
In [49]:
words = ['apple\n', 'boy\n', 'cat\n', 'dog\n', 'egg\n']
In [50]:
[w.strip() for w in words]
Out[50]:
In [51]:
[w.strip() for w in words if 'a' in w]
Out[51]:
In [52]:
words_has_a = (w for w in words if 'a' in w)
[w.strip() for w in words_has_a]
Out[52]:
In [53]:
{w.strip() for w in words}
Out[53]:
In [54]:
{w[0]: w.strip() for w in words}
Out[54]:
Round off the numbers in data/numbers.txt, then count the number of dinstinct intergers.
In [55]:
!head data/numbers.txt
In [56]:
numbers = open('data/numbers.txt')
floats = (float(line) for line in numbers)
ints = {round(value) for value in floats}
size = len(ints)
numbers.close()
size
Out[56]:
In [57]:
class Cat:
def __init__(self, name):
self.name = name
In [58]:
my_cat = Cat('Rain')
my_cat.name
Out[58]:
In [59]:
my_cat.name = 'Rainbow'
my_cat.name
Out[59]:
In [60]:
class Cat:
"""Schrödinger's Cat Store, Ltd"""
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
if any(char.isdigit() for char in name):
raise ValueError(name + ' contains number')
self._name = name
In [61]:
my_cat = Cat('Rain')
my_cat.name
Out[61]:
In [62]:
my_cat.name = 'Rainbow'
my_cat.name
Out[62]:
In [63]:
my_cat.name = '9upper'
In [ ]:
class Pet:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
if any(char.isdigit() for char in name):
raise ValueError(name + ' contains number')
self._name = name
class Cat(Pet):
def meows(self):
print('{}: mew-mew'.format(self.name))
class Dog(Pet):
def barks(self):
print('{}: bow-wow'.format(self.name))
You are selling:
How do you refactor the library to add flying cat and flying dog? If you use Java...
In [ ]:
class FlyMixin:
def fly(self):
print(self.name + ' is flying')
class FlyingCat(FlyMixin, Cat):
pass
class FlyingDog(FlyMixin, Dog):
pass
FlyingCat('SuperCat').fly()
Still remember @property?
It is not magic
In [64]:
def hello_world():
return print('hello world')
hello_world()
In [65]:
for _ in range(3):
hello_world()
In [66]:
def repeat_3_times(func):
def repeated(*args, **kwargs):
for _ in range(3):
func(*args, **kwargs)
return repeated
@repeat_3_times
def hello_world():
return print('hello world')
hello_world()
In [67]:
def repeat(n):
def repeat_decorator(func):
def repeated(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return repeated
return repeat_decorator
@repeat(5)
def hello_world():
return print('hello world')
hello_world()
Create a decorator that log how long the function takes?
>>> @time_it(10000)
>>> def heavy_computation():
>>> return 1+1
>>> heavy_computation()
heavy_computation ran 10000 times, total: 1.556ms, avg: 0.0001556ms
Things that maybe useful
In [68]:
import time
def time_it(n):
def time_it_n(func):
fname = func.__name__
def timed(*args, **kwargs):
start = time.time()
for _ in range(n):
func(*args, **kwargs)
end = time.time()
total = (end - start) * 1000
avg = total / n
print('{} ran {} times, total: {:.4}ms, avg: {:.4}ms'.format(fname, n, total, avg))
return timed
return time_it_n
@time_it(10000)
def heavy_computation():
return 1+1
heavy_computation()
In [69]:
with open('data/words.txt') as f:
for line in f:
print(line.strip())
In [70]:
import time
class TimeLogger:
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, type, value, traceback):
timespan = time.time() - self.start
print('Complete in {}ms'.format(timespan * 1000))
with TimeLogger():
1 + 1
In [71]:
def natural_number():
n = 0
while True:
yield n
n += 1
nums = natural_number()
for _ in range(5):
print(next(nums))
In [72]:
def group(items, group_size=5, sep='|'):
for i, item in enumerate(items):
if i % group_size == 0:
yield sep
yield item
''.join(group('abcdefghijklmnopqrstuvwxyz'))
Out[72]:
In [73]:
def chain(*iterables):
for iterable in iterables:
yield from iterable
list(chain([1, 2, 3, 4], [5, 6, 7, 8]))
Out[73]:
Count number of request of each IP in all the log files under data/www folder
List the 10 most frequent IP and their count
In [74]:
ls -R data/www
In [75]:
!head data/www/bar/access-log
In [76]:
import os
import gzip
import bz2
from collections import Counter
def gen_find(root):
for path, dirlist, filelist in os.walk(root):
for name in filelist:
yield os.path.join(path, name)
def gen_string(bytes):
for line in bytes:
yield line.decode('ascii')
def gen_open(filenames):
for name in filenames:
if name.endswith(".gz"):
yield gen_string(gzip.open(name))
elif name.endswith(".bz2"):
yield gen_string(bz2.open(name))
else:
yield open(name)
def gen_cat(sources):
for source in sources:
yield from source
def gen_ip(logfiles):
for line in log:
ip, _ = line.split(' ', 1)
yield ip
logpaths = gen_find('data/www')
logfiles = gen_open(logpaths)
log = gen_cat(logfiles)
ips = gen_ip(log)
ipcount = Counter(ips)
first_ten = ipcount.most_common(10)
first_ten
Out[76]:
In [77]:
import os
import gzip
import bz2
from collections import Counter
from functools import wraps
def foreach(func):
@wraps(func)
def wrapped(iterable):
for elem in iterable:
yield from func(elem)
return wrapped
def gen_find(root):
for path, dirlist, filelist in os.walk(root):
for name in filelist:
yield os.path.join(path, name)
@foreach
def gen_string(line):
yield line.decode('ascii')
@foreach
def gen_open(filename):
if filename.endswith(".gz"):
yield gen_string(gzip.open(filename))
elif filename.endswith(".bz2"):
yield gen_string(bz2.open(filename))
else:
yield open(filename)
@foreach
def gen_cat(source):
yield from source
@foreach
def gen_ip(line):
ip, _ = line.split(' ', 1)
yield ip
logpaths = gen_find('data/www')
logfiles = gen_open(logpaths)
log = gen_cat(logfiles)
ips = gen_ip(log)
ipcount = Counter(ips)
first_ten = ipcount.most_common(10)
first_ten
Out[77]:
In [78]:
import numpy as np
import matplotlib.pyplot as plt
ip, freq = zip(*first_ten)
plt.xkcd()
fig, ax = plt.subplots()
pos = np.arange(9, -1, -1) + .5
ax.barh(pos, freq, align='center', height=0.5)
plt.yticks(pos, ip)
ax.set_xlabel('Frequency')
ax.set_ylabel('IP')
ax.set_title('Top 10 IP')
ax.grid(True)
plt.show()
In [79]:
def print_if_divided_by(n):
while True:
value = yield
if value % n == 0:
print(value)
even_printer = print_if_divided_by(2)
next(even_printer)
for num in range(10):
even_printer.send(num)
In [80]:
def consumer(gen_func):
def consumer_func(*args, **kwargs):
generator = gen_func(*args, **kwargs)
next(generator)
return generator
return consumer_func
@consumer
def print_sum():
sum = 0
while True:
value = yield
sum += value
print('Current sum:', sum)
@consumer
def print_product():
product = 1
while True:
value = yield
product *= value
print('Current product:', product)
@consumer
def boardcast(*consumers):
while True:
value = yield
for consumer in consumers:
consumer.send(value)
receiver = boardcast(print_sum(), print_product())
for num in range(1, 6):
receiver.send(num)
In [81]:
from contextlib import contextmanager
@contextmanager
def tag(name):
print('<{}>'.format(name))
yield
print('</{}>'.format(name))
with tag('p'):
print('text')
exports.processJob = function(options, next) {
db.getUser(options.userId, function(err, user) {
if (err) return next(err);
db.updateAccount(user.accountId, options.total, function(err) {
if (err) return next(err);
http.post(options.url, function(err) {
if (err) return next(err);
next();
});
});
});
};
In [82]:
def process_job(options, next):
try:
user = yield from db.get_user(options.user_id)
yield from db.update_account(user.account_id, options.total)
yield from http.post(optional.url)
next()
except Exception as e:
next(error)
In [83]:
import asyncio
from datetime import datetime
def tick(loop):
print('{:%H:%M:%S.%f} tick'.format(datetime.now()))
loop.call_later(0.5, tick, loop)
@asyncio.coroutine
def sleep(t, log):
print('{:%H:%M:%S.%f} {} go to sleep'.format(datetime.now(), log))
yield from asyncio.sleep(t)
print('{:%H:%M:%S.%f} {} woke up'.format(datetime.now(), log))
return
@asyncio.coroutine
def get_user(user_id):
yield from sleep(1, 'get_user')
return 'kenny2tam'
@asyncio.coroutine
def update_account(account_id, total):
yield from sleep(2, 'update_account')
print('{:%H:%M:%S.%f} Account of {} is updated to {}'.format(datetime.now(), account_id, total))
@asyncio.coroutine
def post(url):
yield from sleep(3, 'post')
print('{:%H:%M:%S.%f} Posted to {}'.format(datetime.now(), url))
@asyncio.coroutine
def process_job(options):
user = yield from get_user(options['user_id'])
yield from update_account(user, options['total'])
yield from post(options['url'])
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.call_soon(tick, loop)
loop.run_until_complete(process_job({'user_id': 1, 'total': 10, 'url': 'fb.com/king.of.logic'}))
loop.close()
In [84]:
import this