Elegant Coding Style for Python
This serves as a note and a summary on my journey to become a coder who writes very elegant python code. Python is very different compared with most of other language; it is not like C/C++, which only has some basic key words support and takes a lot effort to import and integrate with other non-built in libraries. Python has large amount of built-in functions that can ease your coding life and tons of third party libraries which you can easily install with just pip install command and import them in one second. So, there is flexibility.
Currently, I am studying how to balance the amount of using built-in functions and third party libraries. Which one is better, and which one is more important? I would prefer to know both. But, anyway, this is not my final conclusion, going to learn more and come back to re-conclude.
- map, filter, reduce
Using filter to get rid of irrelevant character which can be used as a pre-processing or used in algorithms. As the name suggests filter extracts each element in the sequence for which the function returns True. The reduce function is a little less obvious in its intent. This function reduces a list to a single value by combining elements via a supplied function. The map function is the simplest one among Python built-ins used for functional programming.
filtered = map(lambda x: x.lower(), filter(lambda x: x.isalnum(),s)) #get only alpha and numeric and convert it to lower case
filtered=filter(lambda x:x.isalnum() or x=='.' or x=='-' or x==' ' or x=='+', s).lstrip().rstrip().lstrip('-').lstrip('+');#any
a = any(x<0 for x in lst) #return True or False
Here is another use case for filter(): finding intersection of two lists:
a = [1,2,3,5,7,9]
b = [2,3,5,6,7,8]
print filter(lambda x: x in a, b) # prints out [2, 3, 5, 7]
The reduce is in the functools in Python 3.0. It is more complex. It accepts an iterator to process, but it’s not an iterator itself. It returns a single result:
>>> from functools import reduce
>>> reduce( (lambda x, y: x * y), [1, 2, 3, 4] )
24
>>> reduce( (lambda x, y: x / y), [1, 2, 3, 4] )
0.041666666666666664
At each step, reduce passes the current product or division, along with the next item from the list, to the passed-in lambda function. By default, the first item in the sequence initialized the starting value.
Let’s make our own version of reduce.
>>> def myreduce(fnc, seq):
tally = seq[0]
for next in seq[1:]:
tally = fnc(tally, next)
return tally>>> myreduce( (lambda x, y: x * y), [1, 2, 3, 4])
24
>>> myreduce( (lambda x, y: x / y), [1, 2, 3, 4])
0.041666666666666664
>>>
We can concatenate a list of strings to make a sentence. Using the Dijkstra’s famous quote on bug:
import functools
>>> L = ['Testing ', 'shows ', 'the ', 'presence', ', ','not ', 'the ', 'absence ', 'of ', 'bugs']
>>> functools.reduce( (lambda x,y:x+y), L)
'Testing shows the presence, not the absence of bugs'
We can get the same result by using join :
>>> ''.join(L)
'Testing shows the presence, not the absence of bugs'
We can also use operator to produce the same result:
>>> import functools, operator
>>> functools.reduce(operator.add, L)
'Testing shows the presence, not the absence of bugs'
The built-in reduce also allows an optional third argument placed before the items in the sequence to serve as a default result when the sequence is empty.
2. if else abbreviation
x = 10 if a > b else 11
3. Use collections
Python is known for its powerful general purpose built-in data types like list, dict, tuple and set. But Python also has collection objects like Java and C++. These objects are developed on top of the general built-in containers with additional functionalities which can be used in special scenarios.
The objective of this article is to introduce python collection objects and explain them with appropriate code snippets. The collections library contains the collections objects, they are namedtuples (v2.6), deque (v2.4), ChainMap(v3.3), Counter(v2.7 ), OrderedDict(v2.7), defaultdict(v2.5) .
Counter
A Counter is a container that keeps track of how many times equivalent values are added. It can be used to implement the same algorithms for which bag or multiset data structures are commonly used in other languages.
#initialization
import collectionsprint collections.Counter(['a', 'b', 'c', 'a', 'b', 'b'])#a sequence of items
print collections.Counter({'a':2, 'b':3, 'c':1})#a dictionary containing keys and counts
print collections.Counter(a=2, b=3, c=1)#keyword arguments mapping string names to counts
#the same result
Counter({'b': 3, 'a': 2, 'c': 1})
An empty Counter can be constructed with no arguments and populated via the update() method.
import collectionsc = collections.Counter()
print 'Initial :', cc.update('abcdaab')
print 'Sequence:', cc.update({'a':1, 'd':5})
print 'Dict :', c#output
Initial : Counter()
Sequence: Counter({'a': 3, 'b': 2, 'c': 1, 'd': 1})
Dict : Counter({'d': 6, 'a': 4, 'b': 2, 'c': 1})
Accessing Counts
Once a Counter is populated, its values can be retrieved using the dictionary API.
import collectionsc = collections.Counter('abcdaab')for letter in 'abcde':
print '%s : %d' % (letter, c[letter])#output
a : 3
b : 2
c : 1
d : 1
e : 0
Counter does not raise KeyError for unknown items. If a value has not been seen in the input (as with e in this example), its count is 0.
The elements() method returns an iterator that produces all of the items known to the Counter.
import collectionsc = collections.Counter('extremely')
c['z'] = 0
print c
print list(c.elements())
The order of elements is not guaranteed, and items with counts less than zero are not included.
Counter({'e': 3, 'm': 1, 'l': 1, 'r': 1, 't': 1, 'y': 1, 'x': 1, 'z': 0})
['e', 'e', 'e', 'm', 'l', 'r', 't', 'y', 'x']
Use most_common() to produce a sequence of the n most frequently encountered input values and their respective counts.
import collectionsc = collections.Counter()
with open('/usr/share/dict/words', 'rt') as f:
for line in f:
c.update(line.rstrip().lower())print 'Most common:'
for letter, count in c.most_common(3):
print '%s: %7d' % (letter, count)
This example counts the letters appearing in all of the words in the system dictionary to produce a frequency distribution, then prints the three most common letters. Leaving out the argument to most_common() produces a list of all the items, in order of frequency.
$ python collections_counter_most_common.pyMost common:
e: 235331
i: 201032
a: 199554
Arithmetic
Counter instances support arithmetic and set operations for aggregating results.
import collectionsc1 = collections.Counter(['a', 'b', 'c', 'a', 'b', 'b'])
c2 = collections.Counter('alphabet')
print c1 + c2print '\nSubtraction:'
print c1 - c2print '\nIntersection (taking positive minimums):'
print c1 & c2print '\nUnion (taking maximums):'
print c1 | c2
Each time a new Counter is produced through an operation, any items with zero or negative counts are discarded. The count for a is the same in c1 and c2, so subtraction leaves it at zero.
$ python collections_counter_arithmetic.pyC1: Counter({'b': 3, 'a': 2, 'c': 1})
C2: Counter({'a': 2, 'b': 1, 'e': 1, 'h': 1, 'l': 1, 'p': 1, 't': 1})Combined counts:
Counter({'a': 4, 'b': 4, 'c': 1, 'e': 1, 'h': 1, 'l': 1, 'p': 1, 't': 1})Subtraction:
Counter({'b': 2, 'c': 1})Intersection (taking positive minimums):
Counter({'a': 2, 'b': 1})Union (taking maximums):
Counter({'b': 3, 'a': 2, 'c': 1, 'e': 1, 'h': 1, 'l': 1, 'p': 1, 't': 1})
Basic list,set, mapping, dictionary,string
4. Set min or max value
Python set min or max’s initial value:
from sys import maxint
max_value = -maxint-1
min_value = maxint#float
float_max_value = float('-inf')
float_min_value = float('inf')
5. Pay close attention to the followings
Python Set; Python List; Python list copy: this is very important, especially if we need to copy a two dimensional list or even higher, use deepcopy() from copy module.
A solution to the described problems is to use the module “copy”. This module provides the method “copy”, which allows a complete copy of a arbitrary list, i.e. shallow and other lists.
The following script uses our example above and this method:
from copy import deepcopylst1 = ['a','b',['ab','ba']]lst2 = deepcopy(lst1)
A*i # repeat A for i times
lest_repeat_times = (len(B)-1)//len(A)+1
if B in A: #check if B is in A
ord('A')# Given a string of length one, return an integer representing the Unicode code point of the character when the argument is a unicode object,
If we want to put string or tuple in set, it should be like this:
Compare also the difference between {} and set() with a single word argument.>>> a = set('aardvark')
>>>
{'d', 'v', 'a', 'r', 'k'}
>>> b = {'aardvark'}# or set(['aardvark']), convert a list of strings to set
>>> b
{'aardvark'}
or put a tuple in the set
a =set([tuple]) or {(tuple)}
Reference
http://www.bogotobogo.com/python/python_fncs_map_filter_reduce.php