# CREATE ALIASES OF METHODS
# When working with a specific set of variables, it is
# often handy to write a couple of aliases to save a few redundant keystrokes.
# The pythonic way to do thisis quite interesting and let you feel once more
# how cool is our friend the Python.
# Let's say you got a list where you store words.
# You want to save keystrokes for appending and deleting items.
# Let's create aw() for 'a'dding 'w'ord and dw() for ... well you guessed it.
# This works for any instance of an object.
>>> words = ['eggs', 'spam']
>>> aw = words.append
>>> dw = words.remove
>>> words
['eggs', 'spam']
>>> aw('potatoes')
>>> words
['eggs', 'potatoes', 'spam']
>>> dw('spam')
>>> words
['eggs', 'potatoes']
# If you assign your alias to a class name you can still use the same syntax.
# However, be sure to tell your alias on what instance it impacts.
# Example with al() for 'a'dd to 'l'ist:
>>> al = list.append
# Wrong syntax -- It can't guess what instance you play with.
>>> al('cherry')
Traceback (most recent call last):
File "(stdin)", line 1, in <module>
TypeError: descriptor 'append' requires a 'list' object but received a 'str'
# Proper call
>>> al(words, 'cherry')
>>> words
['cherry', 'eggs', 'potatoes']
# Last point:
# Be sure to document your aliases not to turn your code into a real cypher.
-------8<-------8<------8<-------8<------8<-------8<------8<-------8<------8<-------8<------
# USING A CLASS AS CONTAINER.
# Situations happen where you need something handy to store a few variables
# into a single container. A dictionary would fit for the task, however having
# a class can ease the way to access and store those variables.
# Each class wraps a built-in dictionary, let's use it!
>>> class Container:
... def __init__(self, **elements):
... self.__dict__ = elements
... def __repr__(self):
... return repr(self.__dict__)
... def iteritems(self):
... for x in self.__dict__.iteritems():
... yield x
>>> Entry = Container(word="house", synonyms=['apartment', 'flat'])
# Access your elements with a mix of dictionary and object syntax:
>>> Entry.word
"house"
>>> Entry
{'synonyms': ['apartement', 'flat'], 'word': 'house'}
>>> for k,v in Entry.iteritems():
... print k,"=>",v
synonyms => ['apartment', 'flat']
word => house
# You can delete the container and its attributes with the 'del' statement:
>>> del Entry.word
>>> Entry.word
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: Container instance has no attribute 'word'
>>> del Entry.synonyms[0]
>>> Entry.synonyms
['flat']
>>> del Entry
>>> Entry
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'Entry' is not defined
-------8<-------8<------8<-------8<------8<-------8<------8<-------8<------8<-------8<------
# REDUCING CLASSES MEMORY FOOTPRINT
# When using class as a container for storing a couple of variables (such as
# in the example above) which are predefinied, it is possible to reduce the
# memory footprint used by the class by assigning to __slots__ these
# predefined attributes. This lighten the class memory use by preventing it
# from using its inner __dict__ to store its attributes.
>>> class Container:
... def __init__(self):
... __slots__ = 'word', 'synonyms'
-------8<-------8<------8<-------8<------8<-------8<------8<-------8<------8<-------8<------
# RETURNING A LIST OR DICTIONARY ELEMENT IF IT EXISTS
# You want to get the value of say list[4] or dict['food'] but
# you aren't sure whether it exits.
# Here is a snippet for each case that solve this.
# We wll return None when the index or key doesn't exists.
# For a dictionary first:
>>> dict = {"key": "value"}
>>> dict.get("key", None)
'value'
>>> r = dict.get('not_here', None)
>>> r is None
True
# Unfortunately get() isn't implemented for lists.
# A way to do this via exception handling. Wrap these 2 lines in a function for
# a handy usage.
>>> list = ['eggs', 'spam']
>>> try: r = list[0]
... except IndexError: r = None
>>> r
'eggs'
>>> try: r = list[42]
... except IndexError: r = None
>>> r is None
True
-------8<-------8<------8<-------8<------8<-------8<------8<-------8<------8<-------8<------
# ONE TO MANY MAPPING WITH A DICTIONARY
# The usual implementation for this is to have the dict['key'] mapped to a
# list. Here we will stick to this idea and will make use of the setdefault()
# method to make it amazingly easy.
# The python doc explain it like this:
# setdefault(key[, default])
# If key is in the dictionary, return its value. If not, insert key with a
# value of 'default' and return 'default'. 'default' defaults to None.
# When dict['key'] exists the element is appended to its list.
# Otherwise it is created and then the element is appended.
>>> dict = {'cake': []}
>>> dict.setdefault('cake', []).append('flour')
>>> dict.setdefault('cake', []).append('butter')
>>> dict
{'cake': ['flour', 'butter']}
>>> dict.setdefault('brownie', []).append('chocolate')
>>> dict
{'cake': ['flour', 'butter'], 'brownie': ['chocolate']}
-------8<-------8<------8<-------8<------8<-------8<------8<-------8<------8<-------8<------
# LIST KEYS COMMON TO TWO DIFFERENT DICTIONARIES
>>> dict1 = {'eggs': 'yummy', 'spam': 'yummmmmy!'}
>>> dict2 = {'eggs': 'taste ok...', 'spinach': 'beurk!'}
>>> filter(dict1.has_key, dict2.keys())
['eggs']
-------8<-------8<------8<-------8<------8<-------8<------8<-------8<------8<-------8<------
# SET A RECURSION LIMIT
# Python defaults to a recursion limit of 1000 levels.
# You can tell python the recursion limit via the sys module
# by invocing the setrecursinglimit method as follow:
>>> import sys
>>> sys.setrecursionlimit(1500)
-------8<-------8<------8<-------8<------8<-------8<------8<-------8<------8<-------8<------
# MERGING TWO DICTIONARIES
>>> dict1 = {"foo": 3, "alpha": 42}
>>> dict2 = {"echo": 10, "alpha": 11}
# When common key found, values of dict1 are overided by dict2's.
>>> dict1.update(dict2)
{'alpha': 11, 'foo': 3, 'echo': 10}
# When common key found, values of dict2 are overided by dict1's.
>>> dict2.update(dict1)
{'alpha': 42, 'foo': 3, 'echo': 10}
# Another way of doing it:
# When common key found, values of dict1 are overided by dict2's.
>>> dict(dict1, **dict2)
{'alpha': 11, 'foo': 3, 'echo': 10}
# When common key found, values of dict2 are overided by dict1's.
>>> dict(dict2, **dict1)
{'alpha': 42, 'foo': 3, 'echo': 10}
# To keep both values in a list run the code below before the merging step.
# When merging be sure to overide the keys of the dict you looped through.
# Thanks to has_key() we keep a O(n) running time (n being the dict size).
>>> for k in dict1.keys():
... if dict2.has_key(k): dict2[k] = [dict2[k],dict1[k]]
>>> dict(dict1, **dict2)
{'alpha': [22, 42], 'foo': 3, 'echo': 10}
-------8<-------8<------8<-------8<------8<-------8<------8<-------8<------8<-------8<------
# IMPLEMENT STATIC METHOD
# Static method in python are possible.
# Before each method you want to make static insert the idiom
# @staticmethod right above the method's name.
# Note that static methods do not take the implicit first argument 'self'.
# You can either call them from the class name or a class instance.
>>> class NepsilonClass:
... @staticmethod
... def do_something(arg1, arg2):
... pass
-------8<-------8<------8<-------8<------8<-------8<------8<-------8<------8<-------8<------
# INTRODUCTION TO PYTHON DECORATORS
# Python supports decorator -- not to be confused with the decorator pattern
# --, although they can be use to implement this pattern.
# Python's decorator can trigger another function/method when the function we
# 'decorated' is called.
# This allow you for instance to do some monitoring against functions/methods
# without editing them.
# Below decorators are used to time the running duration of the quicksort
# function and to count its recusion number.
import time,random
def timing(func):
def wrapper(*arg):
t1 = time.clock()
if (len(*arg) < 42): print arg
func(*arg)
if (len(*arg) < 42): print arg
t2 = time.clock()
print 'The function %s took %0.3f ms and went through %s recursions.'\
% (func.func_name, (t2-t1)*1000.0, count)
return wrapper
def recursion_count(func):
def wrapper(*arg):
global count
func(*arg)
count += 1
return wrapper
@recursion_count
def quicksort(array, start, end):
if (end <= start):
return
q = start
p = end - 1
pivot = array[end-1]
while (p > q):
while (array[p] >= pivot and p > start):
p -= 1
while (array[q] < pivot and q < end-1):
q += 1
if (p > q):
(array[p], array[q]) = (array[q], array[p])
if (q != end - 1):
(array[q], array[end-1]) = (array[end-1], array[q])
quicksort(array, start, q)
quicksort(array, q+1, end)
@timing
def sort(array):
quicksort(array, 0, len(array))
if __name__ == "__main__":
count = 0
list = [random.random() for x in range(1,10000)]
sort(list)