Python Simple Tips
It is very much to forget the simple python programming tips. Here the blog to remember.
Collection manipulation tips
How to concatenate to to tuple as follows
t = 'ABC', 24
t = t + ('Sydeny',)
In the second line ,
is the important character in the above code.
You can repeate the tuple:
t * 3
#('ABC', 24, 'Sydeny', 'ABC', 24, 'Sydeny', 'ABC', 24, 'Sydeny')
this is the simple and not need to mentions
#simple list
a = [1,2,3,4,5]
print a[1:3]
#[2, 3]
unpacking the data structure
letters = ('A', 'B'), 'a','b'
(l1,l2),l3,l4 = letters
print (l1,l2,l3,l4)
unpack the dictionary
d = {'a':1, 'b':2, 'c':3}
(k1,v1), (k2, v2), (k3,v3) = d.items() # ('c', 3)
Order is not guaranteed.
Create own Iterator
Two methods are mandatory:
__iter__()
function and__next__()
in python 3 but innext()
in pytho 2.
For example:
class MyIter:
def __init__(self, *elements):
self.elements = elements
def __iter__(self):
self.i = 0
return self
def next(self):
if len(self.elements) > self.i:
self.i = self.i + 1
return self.elements[self.i-1]
else:
raise StopIteration('My iterator cannot continue because iterator reached to the end of elements: {}'.format(self.i))
test = MyIter(1,2,3,4)
for e in test:
print(e)
Create the above iterator using yield
:
def mygen():
yield 'a'
yield 'b'
yield 'c'
g = mygen()
# similar effect
next(g)
g.send(None)
# support the for loop
for e in g:
print(e)
Lazy generator example:
def add_series():
l =[0,0]
while True:
l[0] = l[0] + 1
l[1] = sum(l)
yield l[-1]
for i, n in enumerate(add_series()):
if i == 6:
break
print(n)
# 1
# 3
# 6
# 10
# 15
# 21
To stop the loop you need to break inside the for
.
Generators can hold the state:
def keepval():
val = []
while True:
data = yield
val.append(data)
yield val
g = keepval()
g.send(None)
g.send('a') # ['a']
g.send(None)
g.send('b') # ['a', 'b']
g.send(None)
g.send('c') # ['a', 'b', 'c']
Defaults
Default for dictionary:
from collections import defaultdict
p = {'a':1, 'b':2, 'c':3}
d = defaultdict(lambda: 0)
d.update(p)
d['a'] # 1
d['d'] # 0
or use the following way:
from collections import defaultdict
p = {'a':1, 'b':2, 'c':3}
l = lambda : 0
resilt = defaultdict(l, p)
result['a'] # 1
resilt['c'] # 0
You can create an incremented for default using class because class methods are still first class functions in python:
from collections import defaultdict
class Counter(object):
def __init__(self):
self.c =0
def __call__(self):
self.c += 1
return self.c
counter = Counter()
callable(counter)
d = defaultdict(counter)
d.update({'a':1,'b':2})
for i in list('abcdefgh'):
d[i]
print(d) # defaultdict(<__main__.Counter object at 0x111768c90>, {'a': 1, 'c': 1, 'b': 2, 'e': 2, 'd': 3, 'g': 5, 'f': 4, 'h': 6})
In the above code __call__()
is the callable methed.
Blend with zip
How to create dictionary from List of tuples
l = 'a','b','c'
p = 1,2,3
#blend dict ([('a',1),('b',2), ('c',3)])
dict(zip(l,p)) #{'a': 1, 'b': 2, 'c': 3}
Generator expression
For example:
p = 1,2,3
g = (i*i for i in p)
next(g) #1
next(g) #4
Here the use of add_series() generator in the generator expression:
def stop():
raise StopIteration()
g = (i for i in add_series() if i < 6 or stop() )
[i for i in g] #[1, 3]
Use of itertool
Following will breake the it.count() to have all the number below 10.
# import itertools as it
# for i in it.count():
# if i > 10:
# break
# print(i)
for i in it.takewhile(lambda x: x < 10, it.count()):
print (i)
Group by odd and even numbers
isEven = lambda x : not x % 2
# sorted(range(10), key=isEven) => [1, 3, 5, 7, 9, 0, 2, 4, 6, 8]
for e, g in it.groupby(sorted(range(10), key=isEven), key=isEven):
print(e, list(g))
# =>
# (False, [1, 3, 5, 7, 9])
# (True, [0, 2, 4, 6, 8])
Cartician Product
for x, y in it.product(['a','b','c'], [1,2,3]):
print (x, y)
# ('a', 1)
# ('a', 2)
# ('a', 3)
# ('b', 1)
# ('b', 2)
# ('b', 3)
# ('c', 1)
# ('c', 2)
# ('c', 3)
Permutations as follows:
for i in it.permutations(['a','b','c']):
print(i)
# ('a', 'b', 'c')
# ('a', 'c', 'b')
# ('b', 'a', 'c')
# ('b', 'c', 'a')
# ('c', 'a', 'b')
# ('c', 'b', 'a')
for i in it.permutations(['a','b','c'], r=2):
print(i)
# ('a', 'b')
# ('a', 'c')
# ('b', 'a')
# ('b', 'c')
# ('c', 'a')
# ('c', 'b')
Combinations as follows:
for i in it.combinations(['a','b','c'], r = 2):
print(i)
('a', 'b')
('a', 'c')
('b', 'c')
functiontools
Here the partial function
import functools as ft
def double(x):
return x * x
d = ft.partial(double, 3)
d() #9
To add any number of values using partial functools :
def add(*n):
return sum(n)
# same as bellow partial
# add(1,2,3,4) # => 10
#---- use of partial
from functools import partial
one = partial(add, 1)
two = partial(one,2)
three = partial(two,3)
three(4) # => 10
Decorator
Decorator wrap the function to decorate such as validate input:
def decor(func):
print('decoreate')
return func
@decor
def hello(name):
return name
print(hello('test'))
If you need to pass the argument to decorator
def outer_decor(arg):
def inner_decor(func):
if arg:
print(arg)
print('decorate')
return func
return inner_decor
@outer_decor(arg='outer')
def hello(name):
return name
print(hello('test'))
# outer
# decorate
# test
pass dictionary as an argument list:
def unpack(*val):
for k ,v in val:
print('{} => {}'.format(k,v))
unpack(*{'a':1,'b':2,'c':3}.items())
# by the way this is an unordered.
# a => 1
# c => 3
# b => 2
Here the way to create event handler using decorator
def event_handler(func):
func.is_event_handler = True
return func
@event_handler
def foo(event):
pass
foo.is_event_handler
#True
Class Comparison
Python classes can be compared directly like c1 >= c2 implementing the method __ge__()
. However, for all the comparisons, there is dedicated method to implement in the class level. The functools.total_ordering
decorator can be used to simplify this process.
'''
This examples shows the hospital domain where wards and patients. Dynamically
wards can be filled by patients.
Used the total_ordering decorator and __eq__ and __lt__ minimum requirments
to implement the comparisons for the ==, >=, <= and so on.
'''
from functools import total_ordering
class Patient(object):
def __init__(self, name, age):
self.name = name
self.age = age
@total_ordering
class Ward(object):
def __init__(self, ward_no):
self.ward_no = ward_no
self.patients = list()
def add_patient(self, patient):
self.patients.append(patient)
def __str__(self):
return 'Ward {} has {} patients'.format(self.ward_no, len(self.patients))
#current capacity is decide by the number of patients in the ward
@property
def capacity(self):
return len(self.patients)
#minimum required functions
def __eq__(self, other):
return self.capacity == other.capacity
def __lt__(self, other):
return self.capacity < other.capacity
# This is ward no# 1
ward_1 = Ward(1)
ward_1.add_patient(Patient('A',25)) # add patients to wards
ward_1.add_patient(Patient('B',26))
ward_1.add_patient(Patient('C',27))
ward_1.add_patient(Patient('D',28))
# ward no# 2
ward_2 = Ward(2)
ward_2.add_patient(Patient('X',25)) # add patients to wards
ward_2.add_patient(Patient('Y',26))
ward_2.add_patient(Patient('Z',27))
# As you see, can do all the comparisons
ward_1 < ward_2 # False
ward_1 <= ward_2 # False
ward_1 == ward_2 # False
ward_1 >= ward_2 # True
ward_1 > ward_2 # True
The last bit of the above python program shows the use of all the comparison operators.
Maybe Decorator
This is one of the good pattern found in the Functional Programming in Python by Sebastiaan Mathot.
add_str = lambda s: sum([int(i) for i in s.split('+')])
add_str('1+2') #-> 3
def lambda_exception_wrapper(func):
def inner(*args):
for a in args:
if isinstance(a, Exception):
return a
try:
return func(*args)
except Exception as e:
return e.args
return inner
safe_add_str = lambda_exception_wrapper(add_str)
safe_add_str('1+2')
#-> 3
safe_add_str(1+3)
#-> ("'int' object has no attribute 'split'",)
Memoization
This is a functional caching mechanism. You can achieve this design pattern using decorators.
def decor(func):
print('decoreate')
cache = {}
def inner(*args):
if args in cache:
print('found')
return cache[args]
print('not found')
cache[args] =func(*args)
return cache[args]
return inner
@decor
def hello(*n):
return sum(n)
print(hello(*[i for i in range(100)])) # =>
# not found
# 4950
Curring
Here the use of decorator and the Curring desing pattern to add numbers explained under the functools section.
from functools import partial
import inspect
def curry(func):
def inner(arg):
print(len(inspect.getargspec(func)))
if len(inspect.getargspec(func).args) == 1:
return func(arg)
print('-> {}'.format(arg))
return curry(partial(func,arg))
return inner
@curry
def add(a,b,c):
return a + b +c
Python Lambda calculus
As a first example see the identity lambda function
\[
\lambda x.x
\]
In Python this is written as lambda x: x
.
The simplest application can be created by applying variable y
to above identity function
\[
(\lambda x.x)y \rightarrow y
\]
right arrow shows the reduction with the result. In python, you can write this as (lambda x: x)(y)
where y
can be any value.
It is complete valid expression to write as follows using identity function:
\[
(\lambda x.x)(\lambda y.y+1) \rightarrow \lambda y.y+1
\]
For example in the python you can test the validity of using identity function by (lambda x: x)(lambda y: y * y)(2)
.
Consider the substitution:
\[
(\lambda x.(\lambda t. xt))y \rightarrow (\lambda t.yt)
\]
In the python you can test this as (lambda x: lambda t:[x,t])(3)(2)
is the same result of (lambda x, t : [x, t])(1,2)
.
For example to find the even numbers in the list of numbers in lambda calculus is :
\[
even = \lambda \space x \rightarrow x \equiv 0(\mod 2)
\]
Python
For example, the simplest from of lambda in the Python (lambda x: x+1)(3)
which returns result 4. Mathamatically this can be written as
\[
\lambda \space x \rightarrow x +1
\]
Lambda can be nested as follows
(lambda x: lambda y:lambda z: x + y * z)(5)(2)(3) #11
As explain above, if you implements the even lambda function:
even = lambda x : x % 2 == 0
#For example, use the built in function to go through the list
filter(even, [1,2,3,4,5])
#[2, 4]
Above bulit in filter
method can be written as :
def myfilter(a,b):
"""
param: a : condition in lambda
param: b : list of ints
"""
if len(b) > 0:
if a(b[0]):
return [b[0]] + myfilter(a,b[1::])
else:
return myfilter(a,b[1::])
else:
return []
#for example:
myfilter(lambda x : x % 2 == 0, [1,2,3,4,6,10]) #[2, 4, 6, 10]
If you are still uncomfortable with the above myfilter
method, here the simple example to built in sum
. Let's create sumlist
function in functional programming:
def sumlist(l):
if len(l)>1:
return l[0] + sumlist(l[1::])
return l[0]
#example
sumlist([1,2,3,4,5,6,7]) #28
The built in reduce
function can be written as reduceints
:
c = lambda x: lambda y: x + y
#Let's test the lambda function
c(3)(c(2)(c(1)(0))) # result = 6
def reduceints(a,b):
"""
param: a : lambda calculation
param: b : list of ints
"""
if len(b) > 2:
return a(b[0])(myreduce(a,b[1::]))
else:
return a(b[0])(b[1])
# For example
reduceints(c, [1,2,3]) # result = 6
Factorial can be written in lambda as follows:
f = lambda n: 1 if n == 0 else n * f(n-1)
f(3) # 6
In the above example lambda expression need to be assign to variable because factorial is recursion based and need a name to refer itself.
if expression in the lambda:
(lambda a: 'good' if a > 10 else 'ok' if a > 5 else 'bad')(4) # 'bad'
Closures
Here the example of incrementor
def count(val):
c = [val]
def inc(n):
c[0] = c[0] + n
return c[0]
return inc
f = count(2)
f(2)
f(2)
List operations
Length example
def length (list):
tail = list[1::]
return 1 + length(tail) if tail != [] else 1
length([1,2,3,4,5,6,7,8,9])
element at operation
def elementAt(list,n):
if (n> 1):
return elementAt(list[1::], n-1)
else:
return list[0]
elementAt([1,2,3,4,5,6,7,8,9], 8)
reverse
def reverse(list):
h = list[0]
tail = list[1::]
return reverse(tail)+[h] if (tail != []) else [h]
reverse([1,2,3])
The replacement to the above code in the parctical python is list[::-1]
which will create copy of the list in the reverse order. Note: to copy the list l2 = l1[:]
.
Here the quick sort algo
def qsort(list):
if (list != []):
h = list[0]
print('-- head ---: {}'.format(h))
tail = list[1::]
print('tail => {}'.format(tail))
left = filter((lambda x: x < h),tail)
print('left => {}'.format(left))
right = filter((lambda x: x > h),tail)
print('right => {}'.format(right))
return qsort(left)+[h]+qsort(right)
else:
return []
# Example
qsort([5,7,6,0,4])
context manager
This is the item 7 got from the Effective Python by Brett SlatkinPublished by Addison-Wesley Professional, 2015.
import logging
from contextlib import contextmanager
@contextmanager
def debug_logging(level):
logger = logging.getLogger()
old_level = logger.getEffectiveLevel()
logger.setLevel(level)
try:
yield #immidely start to run withing the with block
finally:
logger.setLevel(old_level)
Uisng with
statement you can run any function where logging.<level>('.....')
set as follows:
with debug_logging(logging.DEBUG):
my_function()
Above context propagation override the default debugging level as well.
Another good example is use of contextlib use for the try/catch:
from contextlib import contextmanager
import logging
@contextmanager
def my_exception(cls):
try:
yield
except cls:
logging.exception("my Exception")
v = 10
with my_exception(ZeroDivisionError):
v /=0
#above excetion handled, therefore continue with next line
print('continue ...............')
Because expection is handle within the my_exception, next line will be executed and program continue without stopping.
Sort with priority
In the following example, priority must go to the gorup
.
num = [8,3,1,2,5,4,7,6]
group = {3,7,5,4}
def helper(x):
print(x)
if x in group:
return (0,x)
return (1,x)
num.sort(key=helper)
print(num) # [3, 4, 5, 7, 1, 2, 6, 8]
As you see group
elements are in the head of the list in sorted order and the sorted element of the the rest of the list.
If you use the class, there the code for the above:
class SortHelper (object):
def __init__(self, group):
self.group = group
def __call__(self, x):
if x in self.group:
return (0,x)
return (1,x)
helper = SortHelper(group)
num.sort(key=helper) # [3, 4, 5, 7, 1, 2, 6, 8]
In the above code, the helper method is __call__()
.
References:
Effective Python by Brett Slatkin Published by Addison-Wesley Professional, 2015
Comments
Post a Comment
commented your blog