python note

 
 
#################################### 
####      python resource     ###### 
#################################### 
 
https://www.udacity.com/course/cs212 
https://www.udacity.com/course/cs101 
https://www.udacity.com/course/ud036 
www.diveintopython.net 
learnpythonthehardway.org 
Network programming: http://ilab.cs.byu.edu/python/ 
 
 
python is a dynamically typed language: data type determined at run time, rather than compiliation time. 
i.e. unlike C, Java, variables are implicitly decalared by defining them, then its data type automatically assigned. (notice the words declaration and definition) 
 
 
########################### 
####    line wrapper   #### 
########################### 
 
use back-slash '\' 
 
e.g. 
if aaa == bbb and \ 
   ccc == ddd or  \ 
   eee == fff: 
    return foo 
 
 
###################### 
####   comment    #### 
###################### 
 
for single line, use hash "#" 
for multiple lines, there is no special comment syntax, but just enclose it with three quotes (either single-quote or double-quote is fine). 
 
e.g. 
 
def some_func(self,input): 
    # comment1 
#   comment2 
    print "foo" 
    ''' 
    print 'bar' 
    print 'baz' 
    ''' 
 
====>  notice how identation doesnt matter for "#" but matters for multiple line commenting because what ''' does is just make things string. 
 
 
################################################ 
###     double quotes  VS  single quotes     ### 
################################################ 
 
unlike perl/php,  in python " and ' have identical functionality. 
 
you can enclose a single quote in double quotes, and vice versa. 
also you can escape with backslash \ if you wanna use it as a literal inside quotes. 
 
also any quotes within three quotes will be enclosed similarly. but as discussed above, triple quotes are normally used for commenting purpose. 
 
 
 
########################### 
####   control flow    #### 
########################### 
 
if n == 0: 
   do_something() 
elif n > 0: 
   pass               # when you don't wanna do anything, use "pass" 
else: 
   do_anything() 
 
 
n=0 
while True: 
   n = n + 1 
   if n % 3 == 0: 
      break           # other operators include "continue" if you wanna goto the next iteration in the loop 
   print n 
 
 
# one liner way 
 
a = 6 
if a == 5: print 5 
else: print 777 
 
 
############################## 
###    integer division    ### 
############################## 
 
print 7/4     # gives 1       (a common cause of bug) 
print 7/4.0   # gives 1.75 
 
 
########################################### 
###   prevent newline in print output   ### 
########################################### 
 
------- python 2.x 
print "hello",          # add a trailing comma 
------------------ 
 
------- python 3.x 
print ("hello", end="")     # "end" parameter 
------------------ 
 
 
#################### 
####   range    ####  it's a list generator 
#################### 
 
for i in range(19):   # equivalent to  for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] 
print i           # print 0 to 18 
 
for i in range(m,n): 
print i           # print m to n-1 
 
 
## 
##  descending order:  the 3rd arg specifies the internval 
## 
 
for i in range(16,1,-1): 
print i             # print 16 to 2 
 
for i in range(16,1,-5): 
print i             # print 16,11,6 
 
 
## 
##  fractional increment 
## 
 
range(m,n,step) expects integers. so you have to do something like this. 
 
for i in [x * 0.1 for x in range(0,10)]: 
   print(i)                                #  [0, 0.1, 0.2, 0.3,,,, 0.9] 
 
 
## 
##  range()  VS  xrange() 
## 
 
the both below will print 0 1 2 3 4 
 
--------------------- 
for i in range(5):      # creates a list 
   print i, 
 
for i in xrange(5):     # creates a generator that generates each number 
   print i, 
--------------------- 
 
>>> range(5) 
[0 1 2 3 4] 
 
>>> xrange(5) 
xrange(5) 
 
===>  apparently, if the input N is huuuuge, range(N) will blow up, but xrange(N) can handle as it generates each number one by one. 
 
 
 
################################################################### 
###  how to determine if all items within a list are the same   ### 
################################################################### 
 
http://stackoverflow.com/questions/3787908/python-determine-if-all-items-of-a-list-are-the-same-item 
 
either 
 
def all_same(items): 
    return all(x == items[0] for x in items) 
 
or 
 
if len(np.unique(items)) == 1:        # import numpy as np 
 
 
################## 
###   module   ### 
################## 
 
### 
### 
### command line arguments 
 
--------------- 
import sys 
print str(sys.argv)     # entire command line 
print len(sys.argv)     # how many arguments (note the script itself is counted as one) 
print sys.argv[0]       # name of the script 
print sys.argv[1]       # first input param 
print sys.argv[2]       # 2nd input param 
 
a = sys.argv[1]          # it comes as string 
b = int(sys.argv[1])     # so you must cast accordingly 
c = float(sys.argv[1])   # like so 
 
### 
###  running unix commands inside python script 
### 
 
---------------------- 
import os              # os.system() is deprecated 
os.system("ls")        # this returns shell output "0", not the actual file list 
os.system("date")      # same here, you get "0" for success, "1" for error, no actual date 
 
import subprocess      # recommended way 
subprocess.call('ls')  # this still returns "0" upon succss or "1" upon error, not the actual file list 
output = subprocess.check_output('ls')  # this returns the output, but in a string 
# here is a more elborate but still very common way 
output = subprocess.Popen('ls /tmp', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)   # shell=True lets you use cmd and its arg within quotes '' otherwise you have to do ['cat', '/tmp'] 
stdout_result, stderr_result = output.communicate()     # so you get stdout and stderr results separately 
                                                        # still one big str 
                                                        # for getting a list, 
----------------------- 
 
### 
###  how to get a list of files 
### 
 
e.g. 
-------------- 
import glob 
output = glob.glob("/tmp/test/*.txt") 
print(output)                             # gives you a list of files.  ['/tmp/test/a.txt', '/tmp/test/b.txt', ...] 
--------------                            # path is as you specified in the input 
 
-------------- 
import os 
output = os.listdir("/tmp/test/")    # returns a list of file names (doesn't inclde the path) 
print(output)                        # e.g.  ['a.txt', 'b.txt', ....] 
 
### 
###  recursion limit: 
### 
------------ 
import sys 
sys.setrecursionlimit(3000) 
------------ 
 
 
############################ 
####    IO / FileIO     #### 
############################ 
 
### 
###  fileIO 
### 
 
it's decently simple. 
 
(ref) 
http://www.tutorialspoint.com/python/python_files_io.htm 
 
----------------------------------- 
#!/usr/bin/python 
 
infile = open('/tmp/afile','r') 
 
print(infile.read())  # read all the content, returns it as string 
 
infile.seek(0)       # point the cursor back to the 0th byte 
infile.seek(4,0)     # 4 bytes from the beginning 
infile.seek(4,1)     # 4 bytes from the current pos 
infile.seek(-4,2)    # -4 bytes from the EOF 
 
print(infile.read(3)) # read 3 bytes 
 
while(True): 
    line = infile.readline()   # read a line. if empty line it will return "\n" 
    if line == "":             # returns '' if EOF 
        break 
    print(line)                # careful, this will print "\n" from input line and "\n" from print 
 
infile.seek(0) 
 
lines = infile.readlines()     # returns a list of lines 
for line in lines:             # this is probably the simplest way 
    print(line) 
 
infile.close()       # closing 
 
 
outfile = open('/tmp/bfile','w') 
 
outfile.write("test test test")   # make sure you convert non-str input to str() 
 
outfile.close() 
 
------------------------------------ 
 
[mode] 
r    # read-only 
rb   # read-only in binary 
r+   # both read/write 
rb+  # both read/write in binary 
w    # write-only 
wb   # write-only in binary 
w+   # both read/write 
wb+  # both read/write in binary 
a    # append 
ab   # append in binary 
a+   # append/read 
ab+  # append/read in binary 
 
### 
###  command line input 
### 
 
input() 
 
- gets an input from the keyboard, as terminated by a return key. 
- you can optionally put a prompt message. 
- it interprets the input data type. (string, int, float, or even a list) 
 
name = input("please enter your name")      #  type "john smith"   (here you need double or single quotes) 
print "your name is ", name                 # your name is john smith 
 
age = input("please enter your age")        # type 27 
print "your age is ", age                   # your age is 27 
 
alist = input("type a list of favorite numbers")     # type [12, 34, 56] 
print "your fav numbers are", alist                  # your fav numbers are [12, 34, 56] 
 
 
### 
###   buffering output 
### 
 
python foo.py | tee ./log_file      # it doesn't auto flush buffer after each print. 
                                    # you can write sys.stdout.flush() after each print. 
python -u foo.py | tee ./log_file   # or you use -u option 
 
 
################################### 
####    string, tuple, list    #### 
################################### 
 
some_str = "abcd efgh ijkl mnop" 
 
some_tuple = ('foobar', 123, ('whatever','duh'))    # immutable list. cannot add variables as elements, cannot add new elem, cannot remove elem 
some_list  = [some_str, 'foo', 'bar', [1,2,3,4]]    # mutable list 
 
print len(some_str)   #  15 
print len(some_list)  #  4        # length 
print some_str[2]     #  'c'      # indexing 
 
 
## 
##  slicing      # very important (duh) 
## 
 
some_list[a:b:c]    #  a = start_index,  b = end_index+1,  c = step 
                    #  if you don't specify, a = 0, b = last_index+1, c = 1 
 
print some_str[0:4]    # 'abcd'     notice it gets index 0,1,2,3 and not 4 
print some_str[:4]     # 'abcd' 
print some_str[:4:2]   # 'ac' 
print some_str[:-5]    # this means extract all elems excluding last 5 elems 
 
## 
##  concatenation 
## 
 
first_name = 'foo' 
last_name = 'bar' 
full_name = first_name + ' ' + last_name   # works for lists as well 
 
## 
##  string 
## 
 
str = 'foobar' 
 
str.lower() 
str.upper() 
str.replace('foo','bar')    # replaces all occurrences of 'foo' with 'bar' 
 
str.split('delimiter')      # splits a string into a list by delimiter char like a comma ',' NOTE: you cannot use regex for delim 
                            # without delim specified, it assumes any contiguous whitespace \s+ as delimiter 
str.split(':', 4)           # second arg (integer) specifies max number of times we split. so after 4 splits, this returns any chars as the final elem in the returned list 
str.rsplit(':',3)           # right split, starts splitting by delim from the right, upto max_split number of times. so the returned list will contain max_split+1 elems. 
str.split(' ',6)            # if you do this, it treats a single whitespace char as delimiter as opposed to default behavior of \s+ 
str.split(None,6)           # so you can use "None" and then put your max_split_count then it uses \s+ as delimiter 
 
str.rstrip("\n")            # returns str with any trailing (specified) char removed. if None char specified, then removes any trailing whitespace chars (\n, space, tab) 
str.lstrip()                # left strip, remove leading chars. 
str.strip()                 # removes both leading and trailing chars.  NOTE: str.[rl]strip() is not in-place, you have to update like str = str.rstrip() 
 
str.join(some_list)         # e.g.   '='.join([1,2,3])  will give "1=2=3" 
 
 
if "bar" in str:    # a simple way to regex 
   print str 
 
print "foo\"bar"         # backslash is an escape char in string 
print 'C:\\base\dir'     # but it can be annoyingly clumsy 
print "C:\\\\base\\dir"  # here is an example 
print r"C:\\base\dir"    # here is a solution. this still evaluate regex 
 
 
## 
##  list operations 
## 
 
import numpy as np 
 
# e.g.  initialization 
 
a_list = [3] * 5             # [3, 3, 3, 3, 3] 
a_list = [3, 4, 5] * 2       # [3, 4, 5, 3, 4, 5]] 
a_list = []                  # len(a_list) == 0 
a_list = range(3,8)          # [3, 4, 5, 6, 7] 
 
# concatenation, adding, multiplying 
 
a_list = [3, 4, 5] + [7, 8, 9]                         #  [3, 4, 5, 7, 8, 9] 
a_list = np.add( [3, 4, 5], [7, 8, 9])                 #  [10, 12, 14] 
a_list = np.multiply([3,4,5], 2)                       #  [6, 8, 10] 
a_list = np.subtract ([1,2,3,4,5] , [5, 5, 5, 5, 5])   #  [-4, -3, -2, -1,  0] 
 
 
for elem in some_list:        # checking the presence 
   print elem 
 
if some_elem not in some_list: 
   some_list.append(some_elem)    # appends to the tail 
 
if some_elem not in some_list: 
   some_list.insert(0,some_elem)    # adds to the top.  syntax: list.insert(index, elem) 
 
some_list.index(elem)   # returns the index of elem       # valueError if elem not present 
some_list.remove(elem)  # removes elem                    # valueError if elem not present 
some_list.pop(idx)      # removes and returns an elem at idx. e.g.  while len(some_list) > 200: some_list.pop(0)  # this removes from the front to resize the list to 200 elems 
some_list.sort()        # sort in place      # notice some_list = some_list.sort()  is wrong because some_list.sort() returns nothing 
some_list.reverse()     # reverse in place 
 
sorted_list = sorted(some_list)  # alternative to .sort() 
some_list = reversed(some_list)  # alternative to .reverse() 
 
 
## 
##  transpose a matrix 
## 
 
a list of lists is a matrix. (aka 2d list) 
 
 
(numpy) https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.matrix.transpose.html 
(ref) https://www.geeksforgeeks.org/transpose-matrix-single-line-python/ 
 
 
############################## 
####   set & frozenset    #### 
############################## 
 
(ref) https://www.python-course.eu/python3_sets_frozensets.php 
 
a set is a unordered collection of immutable and unique objects.   # notice "unordered" "immutable" "unique" 
 
but you can still add/remove objects from the set. so the set itself is mutable. 
if you want a const set, then we call it a frozenset. 
 
## 
##  initialize a set 
## 
-------------------------- 
some_set = set("i am foo") 
 
>>> some_set 
{'i', ' ', 'a', 'm', ' ', 'f', 'o', 'o'}     # notice curly brackets. also recall a string is considered a list of chars 
 
some_set = set(['foo', 'bar', 'foo'])       # you can cast set(some_list) to tranform a list into a set 
 
>>> some_set 
set(['foo', 'bar'])                         # notice how a dupe elem got removed 
-------------------------- 
 
 
## 
##  set operation 
## 
 
------------------------ 
some_set.add('gatech')       #  adds a new elem. (does nothing if it already exists) 
some_set.remove('gatech')    #  removes an elem.  (raises a KeyError if the elem doesn't exist in the set) 
some_set.discard('gatech')   #  removes an elem if it exists. i.e. if 'gatech' in some_set: some_set.remove('gatech') 
some_set.pop()               #  removes a random elem. (raises a KeyError if the elem doesn't exist in the set) 
some_set.clear()             #  empties a set.  same as  some_set = set() 
new_set = some_set.copy()    #  creates a shallow copy. still better than an equal sign = assignment which only creates a pointer. 
 
set_size = len(some_set)     #  find the size of the set 
 
some_set = {'a','b','c'} 
other_set = {'a','b','e'} 
diff_set = some_set.difference(other_set)   #  returns {'c','e'} 
diff_set = some_set - other_set             #  same as difference() 
 
union_set = some_set.union(other_set)              #  creates a union 
intersect_set = some_set.intersection(other_set)   #  creates an intersection 
 
if some_set.isdisjoint(other_set):         #  returns True, if intersection is empty 
if some_set.issubset(other_set):           #  returns True, if some_set is a subset of other_set 
if some_set.issuperset(other_set):         #  returns True, if some_set is a superset of other set 
----------------------- 
 
 
## 
##  frozenset 
## 
 
some_frozenset = frozenset(['foo','bar']) 
 
some_frozenset.add('gatech')      #  raises AttributeError: 'frozenset' object has no attribute 'add' 
 
 
 
##################### 
####    dict     #### 
##################### 
 
(ref) https://www.python-course.eu/dictionaries.php 
 
## 
##  initialize a dict variable 
## 
 
some_dict = {}      # an empty dict. notice it's curly brackets. 
 
>>> print some_dict 
{} 
 
some_dict = {"english":"yes", "spanish":"no", "french":"yes"}     # some init values 
 
>>> print some_dict 
{"english":"yes", "spanish":"no", "french":"yes"} 
 
 
note: any data type can be "key", but it MUST be immutable. 
 
 
### 
###   accessing value by key 
### 
 
some_dict["english"] = "no"       # changing existing elem 
some_dict["russian"] = "yes"      # setting a new key-value pair 
 
 
### 
###  nested dict 
### 
 
two ways to do it. 
 
(1) raw 
 
some_dict = {} 
if "english" not in some_dict.keys(): 
   some_dict["english"] = {}    # so key is english, and value is an empty dict. without this init, we get errors in next line. 
some_dict["english"]["british"] = "yes" 
some_dict["english"]["american"] = "no" 
 
 
 
(2) defaultdict 
 
import defaultdict from collections 
some_dict = defaultdict(dict) 
some_dict['english']['british'] = 'yes'     # notice, here we didn't have to  some_dict['english'] = {} 
some_dict = dict(some_dict)                 # casting defaultdict to dict type 
 
>>> print some_dict 
{'english' : {'british' : 'yes'}} 
 
 
### 
###  dict operations 
### 
 
some_dict.clear()     # same thing as  some_dict = {} 
len(some_dict)        # gives the number of (k,v) pairs 
 
for k in some_dict.keys():   # gives a list of keys 
   print some_dict[k] 
 
some_dict.values()    # gives a list of values (dupe values can appear of course) 
 
some_dict.items()     # gives a list where each elem is a tuple (k,v) 
item_list = some_dict.items()      # you can easily reconstruct original dictionary from items list 
some_dict = dict(item_list) 
 
food = ['pizza', 'sushi', 'tacos']    # suppose you want to create a dict of food allergy 
allergy = ['no', 'yes', 'no']         # and you have these two lists 
 
food_allergy_list = zip(food, allergy)        # produces [('pizza','no'),('sushi','yes'),('tacos','no')]     yes it's an item list 
food_allergy_dict = dict(food_allergy_list)   # so constructing a dict is trivial 
 
# or if you have two lists, keys and values, then it's trivial to create a dict like below also. 
 
some_dict = {} 
 
for i in range(len(key_list)): 
   some_dict[key_list[i]] =  val_list[i] 
 
 
 
if some_key in some_dict.keys():    # can be simply written as  if some_key in some_dict: 
   some_dict[some_key] = 'yes' 
 
if some_val not in some_dict.values():   #  you can negate the check like this also 
 
 
del some_dict[some_key]    # remove a (k,v) entry completety 
 
 
 
######################### 
###     namespace     ###   (sometimes aka context) 
######################### 
 
namespace in python is just a dictionary. (global names of a module, local names of function/methods, build-in function names, etc) 
 
## 
##  global VS local VS nonlocal 
## 
 
global: the most outer scope. i.e. main (usually) 
local: any var created/changed inside functions is local 
nonlocal: 
 
==> see examples below. some are not always intuitive. 
 
## 
##  scope 
## 
- a variable is strictly local to its scope by default. 
- inner most scope is searched first. 
 
e.g. 
----------------- 
def foo(): 
   s = "monday" 
   print(s) 
 
s = "tuesday" 
foo()            # this will print "monday" 
print(s)         # this will print "tuesday" 
----------------- 
 
e.g. 
----------------- 
def foo(): 
   print(s)      # UnboundLocalError: local var 's' referenced before assignedment 
   s = "monday" 
   print(s) 
 
s = "tuesday" 
foo()            # prints "monday" 
print(s)         # prints "tuesday" 
----------------- 
 
e.g. 
----------------- 
def foo(): 
   s = "monday" 
   print(s) 
 
foo()            # this will print "monday" 
print(s)         # NameError: 's' not defined 
----------------- 
 
## 
##  global variable 
## 
 
use "global" cast. basically global makes a var defined as if in the main. 
 
e.g. 
----------------- 
def foo(): 
   global s     # "global" casting 
   print(s) 
   s = "monday" 
   print(s) 
 
s = "tuesday" 
foo()            # this will print "tuesday" then "monday" 
print(s)         # this will print "monday" 
----------------- 
 
e.g. 
--------------- 
def foo(): 
   global x 
   x = 123 
   print(x) 
 
foo()      # 123 
print(x)   # 123 
-------------- 
 
e.g. 
--------------- 
def foo(): 
   global x 
   print(x) 
 
x = 123 
foo()      # 123 
-------------- 
 
NOTE: global only refers to the outer most scope, not any other intermediate enclosing scopes. 
e.g. 
-------------------- 
def foo(): 
   x = 123 
   def bar(): 
      global x 
      x = 456 
   print("foo:" + str(x))    # 123 as expected 
   bar() 
   print("bar:" + str(x))    # 123, NOT 456, because it's foo()'s scope, and x in foo() scope is not global 
                             # solution to this is nonlocal 
foo() 
print("main:" + str(x))     # 456, because here in the most outer scope, bar() scope's x is made global 
--------------------- 
 
 
## 
##  nonlocal          # new in python3 
## 
 
nonlocal is used within nested functions. it cannot make a var global 
 
e.g. 
------------- 
def foo(): 
   nonlocal x 
   print(x) 
 
x = 123 
foo()            # SyntaxError: no binding for nonlocal 'x' found 
------------- 
 
e.g. 
-------------------- 
def foo(): 
   x = 123 
   def bar(): 
      nonlocal x 
      x = 456 
   print("foo:" + str(x))    # 123 as expected 
   bar() 
   print("bar:" + str(x))    # 456  !! 
 
x = 777 
foo() 
print("main:" + str(x))     # 777 
--------------------- 
 
e.g. 
-------------------- 
def foo(): 
   #  x = 123        # here, commented out x def in foo() scope 
   def bar(): 
      nonlocal x     # SyntaxError: no binding for nonlocal 'x' found 
      x = 456        # because nonlocal really expects you to define it in the outer scope of a nested function 
   bar() 
   print("bar:" + str(x)) 
 
x = 777 
foo() 
print("main:" + str(x)) 
--------------------- 
 
 
### 
### 
### 
 
__str__ is only called when a string representation is required of an object 
 
e.g. 
p1 = Person() 
str(p1) 
print p1 
print "%s" % p1 
 
 
 
 
 
 
 
########################### 
###    OOP in python    ### 
########################### 
 
## 
##  define/instantiate a class 
## 
 
---------------------------------// Person.py 
class Person: 
    def __init__(self,name,age=0): 
        self.name = name 
        self.age = age 
    def getName(self):       # recall we call a function defined within a class "a method" 
        return self.name 
    def addAge(self,n): 
        self.age += n 
 
p1 = Person("ken",27) 
 
p1.addAge(1) 
 
print p1.getName()   # ken 
print p1.age         # 28 
 
p1.age = p1.age + 3 
---------------------------------- 
 
recall 3 principles of OOP 
(1) encapsulation           # aka data protection, private variable, data abstraction # because only relevant data is made accessible to users 
(2) inheritance 
(3) polymorphism 
 
 
## 
## (1) encapsulation 
## 
 
recall in C++, 
 
public      # everybody can access/change 
protected   # users cannot access it from an instantiated object, but child class who inherits it can access. 
private     # only accessible within the class that defines it. (so users cannot access it from instantiated object. and child class who inherits the class cannot access it) 
 
 
in python, we embrace the same spirit, but protected is actually accessible like public. 
 
public     #  defined textually, e.g. foo 
protected  #  defined with an underscore _  e.g. _foo  but it is actually publicly accessible. so it's only symbolic. 
private    #  defined with double underscore __  e.g. __foo  and cannot be accessed. (but there is a way, see below) 
 
note: as below, you often get getter() and setter() methods for the private attrib __age, and getter/setter is the right way in java, but the "pythonic" way is to simply make the attrib public if you are gonna allow getter/setter. 
      and yes, it is totally fair you want to implement some sanity check (like cannot set a negative number age), then it is reasonable to control only via setter() 
------------------------------------ 
class Person(object): 
   def __init__(self, name, age): 
      self.name = name 
      self.__age = age      # so __age is private 
   def setAge(self, n): 
      if n >= 0: 
         self.__age = n 
   def getAge(self): 
      return self.__age 
   def __foo(self):        # a private method. the same deal as private attributes. you can only access it inside the class 
      pass 
 
p1 = Person('ken', 27) 
p1.__age = 28              # illegal.   AttributeError: Person instance has no attribute '__age' 
p1._Person__age = 28       # this is a hack way to access a private attribute. add an underscore and the class name e.g. "_Person" 
                           # because of this, people say python has no private encapsulation, unlike C++/Java. 
p1.__foo()                 # illegal.   AttributeError: Person instance has no attribute '__foo' 
p1._Person__foo()          # this works. 
 
 
## 
## (2) inheritance, (3) polymorphism 
## 
 
e.g. 
------------------------------------ 
class Person(object): 
   def __init__(self, name, age): 
      self.name = name 
      self.__age = age      # private 
   def getAge(self): 
      return self.__age 
   def __str__(self): 
      return self.name + " " + self.__age 
 
Class Language(object): 
   def __init__(self, country): 
      self.country = country 
   def ___str__(self): 
      return self.country 
 
class Musician(Person, Language):                     # inherited two classes 
   def __init__(self, name, age=0, country, music): 
      Person.__init__(self, name, age) 
      language.__init__(self, country) 
      self.music = music 
   def __str__(self): 
      return Person.__str__(self) + " " + Language.__str__(self) + " " + self.music 
 
 
p1 = Musician('ken', 27, 'USA', 'guitar') 
p1.getAge() 
p1.country = 'japan' 
print p1 
------------------------------------ 
 
 
note: when you inherit multiple classes who have the same attribute names, they collide, and can be a trouble. 
 
 
### 
###    override  VS  overload 
### 
 
override   #  a child class redefines the same-name function of parent class. 
overload   #  defining the same-name function with different input arguments. 
 
note:  in the above Musician class, __init__ and __str__ methods are override examples. 
note:  overload in python, unlike C++, is done with star. 
 
e.g. 
------------------------ C++ 
int foo(int n){ 
   return n + 123; 

int foo(int n, int m){ 
   return n + m + 777; 

------------------------ 
 
------------------------  python 
 
def foo(*x): 
   if len(x) == 1: 
      return x[0] + 123 
   else: 
      return x[0] + x[1] + 777 
 
------------------------ 
 
 
(ref) https://www.python-course.eu/python3_inheritance.php 
 
 
### 
###   class attributes  VS  object attributes 
### 
 
class attributes     #  class level attrib, shared by ALL instances of the class 
object attributes    #  instance level attrib 
 
note: attributes == variables 
note: object attributes == instance attributes 
 
e.g. 
------------------------------ 
class Person(object): 
   counter = 0              # defined outside member methods 
                            # usually at the top like this 
   def __init__(self, age, name): 
      self.age = age 
      self.name = name 
      Person.counter += 1 
 
   def __del__(self): 
      Person.counter -= 1 
 
 
p1 = Person(27, 'ken') 
print (Person.counter)     #  1 
 
p2 = Person(32, 'jon') 
print (Person.counter)     #  2 
 
del p1 
print (Person.counter)     #  1 
 
del p2 
print (Person.counter)     #  0 
----------------------------- 
 
 
## 
##  constructor and destructor 
## 
 
programmers don't deal with it in python. but essentially, __init__ and __del__ let you define actions at construction/destruction of an instance of a class. 
note __init__ and __del__ are methods that get called by instance, so they are not construcors/destructor to be pricise. 
 
 
## 
##  static method 
## 
 
now remember the population counter class variable example. 
let's make it private, so people don't manipulate that variable. 
and we will implement getter() for it. 
e.g. 
------------------------------------ 
class Person(object): 
   __counter = 0 
   def __init__(self, age, name): 
      self.age = age 
      self.name = name 
      Person.__counter += 1 
 
   def __del__(self): 
      Person.__counter -= 1 
 
   def getPopulation(self):          #  WRONG! because you need an instance to invoke this method 
      return Person.__counter        #  ideally, you wanna be able to run a static method like Person.getPopulation() 
 
   def getPopulation():              #  WRONG! here you can now run Person.getPopulation() 
      return Person.__counter        #  but calling this method from an instance will raise an error 
                                     #  TypeError:  getPopulation() takes no argument (1 given) 
   @staticmethod 
   def getPopulation():              #  VALID.  now you can call Person.getPopulation() and also call the method from an instance 
      return Person.__counter        #  notice the magic decorator @staticmethod 
 
p1 = Person(27, 'ken') 
>>> p1.getPopulation()           # these both work, returning 1 
>>> Person.getPopulation() 
 
------------------------------------ 
 
 
(ref) https://www.python-course.eu/python3_class_and_instance_attributes.php 
 
### 
###  class method 
### 
 
(ref) https://www.python-course.eu/python3_class_and_instance_attributes.php 
 
 
 
 
 
### 
###  decorator 
### 
 
https://www.python-course.eu/python3_decorators.php 
 
 
 
### 
###  slots 
### 
 
imagine a simple class Foo. 
 
------------------------------------------------ 
class Foo(object): 
   pass 
 
f1 = Foo() 
f1.x = 777 
f1.y = "dynamically created attribute" 
 
>>> f1.__dict__ 
{'x': 777, 'y': 'dynamically created attribute'} 
------------------------------------------------ 
 
===> we wanna restrict users from dynamically adding attributes after instantiation. 
===> use __slots__ 
 
e.g. 
------------------------------------------ 
class Person(object): 
   __slots__ = ['age','name']            # define a static list of all possible attributes you wanna allow in this class 
   def __init__(self, age, name): 
      self.age = age 
      self.name = name 
 
p1 = Person('ken',27) 
p1.height = 177               # AttributeError: 'Person' object has no attribute 'height' 
------------------------------------------ 
 
 
(ref) https://www.python-course.eu/python3_slots.php 
 
 
### 
###   new style class   # python2 
### 
 
in python 2, we have new style vlass and classic(old) style class. 
the new style has more local attributes like __init__, __str__, __sizeof__, etc which old style doesn't have. 
(also other new features in new style) 
in general, always use new stule class. 
in python 3, all classes are new style class by default. 
 
------------------------- 
class Fruit(object):      # new style class 
   pass 
 
class Fruit:              # old class 
   pass 
------------------------- 
 
note: even if you inherit, like below, if your Fruit is old class, then your Apple is also old class. 
class Apple(Fruit): 
   pass 
 
 
### 
###  metaclass 
### 
 
duh 
 
 
 
 
 
###################### 
####     regex    #### 
###################### 
 
https://www.python-course.eu/python3_re.php 
 
## 
## matching 
## 
 
if "bar" in "foobartas":    # simplest regex 
   print "yay" 
 
# note: recall our raw string representation 
print "foo\"bar"         # backslash is an escape char in string 
print 'C:\\base\dir'     # but it can be annoyingly clumsy 
print "C:\\\\base\\dir"  # here is an example 
print r"C:\\base\dir"    # here is a solution. this still evaluate regex 
 
# so we will use r"" format. 
# otherwise, in general, python regex syntax is the same as other language. 
 
import re    # you need this module in python 
 
filename = "20180103.html" 
if re.search(r"^\d.*\.html", ):  checks if a filename starts with a number, then followed by at least one char, then ends with .html 
   print filename 
 
name = "John Meyer" 
if re.search(r"M[ae][iy]er",name):   [] is a char class 
   print name 
 
# note: "-" and "^" within [] has meaning only used as expected. 
# e.g. [a-z] [^0-9] otherwise they work as themselves. 
# e.g. [ab^c] this catches a b c and "^" 
# e.g. [-a-c] this catches a b c and "-" 
 
\d     # any decimal, same as [0-9] 
\D     # complement of \d. same as [^0-9] 
\s     # any white space char. same as  [ \t\n\r\f\v] 
\S     # complement of \s. any non-white space char. same as [^ \t\n\r\f\v] 
\w     # matches any alphanumeric char and an underbar. same as [a-zA-Z0-9_] 
\W     # complements of \w. 
\\     # backslash 
 
^   # beginning 
$   # end 
*   # quantifier. (0 or more occurence of the prev char) 
+   # 1 or more occurence of the prev char 
?   # makes the preceding char optional (0 or 1 occurrence of the prev char) 
()  # group 
{}  # repeater. {4} denotes 4 times. {3,5} denotes 3 to 5 times. {3,} denotes 3 to more times. {,5} denotes {0,5} 
 
e.g. 
month = "Feb" 
if re.search(r"Feb(ruary)?",month): 
   print month 
 
if re.search(r"^\d{8}$",yyyymmdd):   # if you are looking for 8 digit date 
   print yyyymmdd 
 
## 
##  grouping and "matching object" mo 
## 
 
# suppose you want to extract date and time 
timestamp = "blah blah 20180103 foo 12:30:00 bar" 
mo = re.search(r"(\d{8}) .*(\d\d:\d\d:\d\d)",timestamp)     # returns None if no match 
if mo != None: 
   print mo.group()   # returns the entire substring matched. not just parenthesis parts. '20180103 foo 12:30:00' 
   print mo.group(1)  # 20180103 
   print mo.group(2)  # 12:30:00 
 
 
e.g. 
----------------------//  suppose you have a text file a.txt 
<name>kenics</name> 
<date>20180103</date> 
<color>green</color> 
---------------------- 
# and you want to print like below 
name:kenics 
date:20180103 
color:green 
 
-------// then you can write code like this 
import re 
infile = open("a.txt",'r') 
for line in infile: 
   mo = re.search(r"<(\w+)>(.*)</1>",line)      # here \1 refers to the first ()   yes it's neat 
   if mo != None; 
      print (mo.group(1) + ":" + mo.group(2)) 
--------- 
 
 
## 
##  altenations 
## 
 
as seen above, parenthesis is used for grouping. but it is also used to offer logical OR of certain keywords. 
suppose you have an archive of emails, and want to extract emails exchanged between Tom & Jerry 
--------------------- 
for email in email_archive: 
   if re.search(r"(^To:|^From:) (Tom|Jerry)", email): 
      print email 
--------------------- 
 
## 
##  regex split() 
## 
 
split() method in string class doesnt let you use regex as delimiter. 
use re.split() which returns a list of string as delimited by regex 
-------------------- 
import re 
str = "foo??bar tom((cat" 
str_list = re.split(r"\W+",str)     # notice how this lets you neatly get rid of chars you don't want. 
print str_list                      # ['foo','bar','tom','cat'] 
-------------------- 
 
another example 
-------------------- 
import re 
str_list = ['first_name:tom, last_name:hagen, middle_name:NA', 'first_name:foo, last_name:bar, middle_name:keio'] 
# suppose you want to remove the tags 
for str in str_list: 
   print re.split(r",? ?\w+:",str)   #  this will print 
                                     #  ['', 'tom', 'hagen', 'NA'] 
                                     #  ['', 'foo', 'bar', 'keio'] 
 
# of course you can get smart with slicing 
for str in str_list: 
   print re.split(r",? ?\w+:",str)[1:]   #  this will print 
                                         #  ['tom', 'hagen', 'NA'] 
                                         #  ['foo', 'bar', 'keio'] 
-------------------- 
 
 
## 
##  findall 
## 
 
a neat function to get a list of all matches. (if one or more matches) 
returns None if no match. 
 
-------------------- 
import re 
str = "cat eats rats beating foo bar" 
mo = re.findall(r"[a-z]at", str) 
if mo != None: 
   print(mo)            #  ['cat','eat','rat','eat'] 
-------------------- 
 
obviously you can then do stuff like: 
print len(mo)        # how many matches 
print len(set(mo))   # how many uniq items 
 
## 
## substitution 
## 
 
---------------// very simple 
import re 
str = "Hello world hello" 
str = re.sub(r"[Hh]ello","goodbye",str)   # replaces every match and returns the new str 
print str                                 # goodbye world goodbye 
---------------- 
 
note: for non-regex simple sub, then string class has its own replace() 
e.g. 
 
str = "foo bar foo foo" 
print str.replace("foo","bar")    #  replaces all occurrences of foo with bar, and returns the new str 
print str.replace("foo","bar",2)  #  does replacement only the first 2 occurrences 
 
 
############################################## 
####   star : multiple input parameters   #### 
############################################## 
 
stackoverflow explains perfectly. I will quote the best answer from the below link. (only minor code/wording modifition) 
 
(ref) 
http://stackoverflow.com/questions/2921847/python-once-and-for-all-what-does-the-star-operator-mean-in-python 
https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument-lists 
 
 
The single star * unpacks the sequence/collection into positional arguments, so you can do this: 
 
----------------------------- # single star example 
def sum(a, b): 
    return a + b 
 
values = (1, 2) 
 
s = sum(*values)   #  This will unpack the tuple so that it actually executes as: s = sum(1, 2) 
 
----------------------------- 
 
 
The double star ** does the same, only using a dictionary and thus named arguments: 
 
----------------------------- # double star example 
 
values = { 'a': 1, 'b': 2 } 
s = sum(**values) 
 
----------------------------- 
 
You can also combine like below: 
 
----------------------------- 
 
def sum(a, b, c, d): 
    return a + b + c + d 
 
values1 = (1, 2) 
values2 = { 'c': 10, 'd': 15 } 
s = sum(*values1, **values2)       # this will execute as:  s = sum(1, 2, c=10, d=15) 
 
------------------------------ 
 
 
 
Additionally you can define functions to take *x and **y arguments, this allows a function to accept any number of positional and/or named arguments that aren't specifically named in the declaration. 
 
------------------------------  # single star as input arg 
def sum(*values): 
    s = 0 
    for v in values: 
        s = s + v 
    return s 
 
s = sum(1, 2, 3, 4, 5) 
------------------------------ 
 
------------------------------  # double star as input arg 
def get_a(**values): 
    return values['a'] 
 
s = get_a(a=1, b=2)      # returns 1 
 
----------------------------- 
 
 
====> as above, you can allow you to specify a large number of optional parameters without having to declare them. 
 
 
--------------------------------  # single/double star as input arg 
 
def sum(*values, **options): 
    s = 0 
    for i in values: 
        s = s + i 
    if "neg" in options: 
        if options["neg"]: 
            s = -s 
    return s 
 
s = sum(1, 2, 3, 4, 5)            # returns 15 
s = sum(1, 2, 3, 4, 5, neg=True)  # returns -15 
s = sum(1, 2, 3, 4, 5, neg=False) # returns 15 
 
-------------------------------- 
 
 
########################## 
####    formatting    #### 
########################## 
 
(ref) https://pyformat.info/ 
 
 
 
 
######################################## 
####   shallow copy  VS  deepcopy   #### 
######################################## 
 
like C++, must do deepcopy if inner objects contain reference to other objects. 
 
 
--------------------------- 
from copy import deepcopy  #  import statement 
 
arr1= [1,2,3,4,5,6] 
arr2 = deepcopy(arr)       #  manipulating arr2 contents will not corrupt arr contents 
 
--------------------------- 
 
 
################################# 
####    __name__ variable    #### 
################################# 
 
lets say you have three .py files. A.py B.py C.py 
 
$ python A.py   # B.py and C.py are imported within A.py  as in import B 
 
python interpreter sets the variable __name__ = __main__ within A.py, and sets __name__ to "B" and "C" respectively within B.py and C.py 
 
This lets the programmer define the segment of code that gets executed only when the code is run as the main file. 
 
if __name == '__main__': 
   <your main code here> 
 
(ref) 
http://stackoverflow.com/questions/419163/what-does-if-name-main-do 
http://ibiblio.org/g2swap/byteofpython/read/module-name.html 
 
 
### 
###  how to avoid global variables 
### 
 
https://augmentedtrader.com/2016/01/29/how-to-avoid-accidental-global-variables-in-python/ 
 
basically anything defined outside function definitions are global. it's not surprising if you think about it. 
 
 
################################## 
####   arithmetic operators   #### 
################################## 
 
+ - * /     # these are easy 
x**y        # x to the power of y.  exponentiation 
x^y         # xor bitwise operator like java 
x%y         # modulo aka remainder 
x//y        # integer division 
 
e.g. 
11 % 5 = 1 
11 // 5 = 2 
 
in other words,   a == (a // b)*b + (a % b) 
 
e.g. 
a = 13 
a += 2    # gives 15 
 
 
############################ 
###    error handling    ### 
############################ 
 
(ref) https://docs.python.org/3/tutorial/errors.html 
 
think about a simple process that accepts a numeric input from user. 
you let user type in a number, if it's invalid, then try again, until he/she does it right. 
 
e.g. 
------------------------ 
x = 0 
while True: 
   try: 
      x = int(input("enter a number: ")) 
      break 
   except ValueError: 
      print("you didnt enter a number. please try again") 
 
do_something_with_the_input_num(x) 
------------------------ 
 
 
try: 
  foobar() 
except(RuntimeError, TypeError,NameError):   # if you wanna specify multiple error types 
  do_something() 
except(ValueError): 
  pass 
except:                   # this means catch any other error 
  do_someting_else() 
else:                     # this runs only when try() doesn't raise any exception 
  do_whatever() 
finally:                  # executes always, regardless of any error or not 
  do_some_magic() 
 
 
 
### 
###  raise 
### 
 
(ref) https://stackoverflow.com/questions/13957829/how-to-use-raise-keyword-in-python 
 
two purposes 
 
(1)  raise your own error 
 
e.g. 
 
if (start_date > end_date): 
   raise ValueError("start_date cannot be later than end_date") 
 
 
(2)  raise an error further up in the call stack 
 
try: 
   do_something() 
except ValueError as e: 
   if can_handle(e): 
      handle(e) 
   else: 
      raise 
 
 
 
 
######################################## 
#####      build-in functions      ##### 
######################################## 
 
(ref) 
https://docs.python.org/2/library/functions.html 
 
abs()         divmod()     input()       open()       staticmethod() 
all()         enumerate()  int()         ord()        str() 
any()         eval()       isinstance()  pow()        sum() 
basestring()  execfile()   issubclass()  print()      super() 
bin()         file()       iter()        property()   tuple() 
bool()        filter()     len()         range()      type() 
bytearray()   float()      list()        raw_input()  unichr() 
callable()    format()     locals()      reduce()     unicode() 
chr()         frozenset()  long()        reload()     vars() 
classmethod() getattr()    map()         repr()       xrange() 
cmp()         globals()    max()         reversed()   zip() 
compile()     hasattr()    memoryview()  round()      __import__() 
complex()     hash()       min()         set()        apply() 
delattr()     help()       next()        setattr()    buffer() 
dict()        hex()        object()      slice()      coerce() 
dir()         id()         oct()         sorted()     intern() 
 
 
lets look at some of them below. 
 
### 
###  isinstance(<data>, <type>) 
### 
 
the thing with implicit type system is you lose track of the type of variables. hence the isinstance() 
 
print isinstance(123,int)        #  True 
print isinstance(123,str)        #  False 
print isinstance(123.456,float)  #  True 
 
 
## 
##  del(a_variable_namee) 
## 
 
foo = 1234 
del foo       # better than foo = None, because del removes the variable name from (local or global) namespace 
 
 
### 
###  eval(str) 
### 
 
>> "1+1" 
"1+1" 
>> eval("1+1") 

 
 
as above, eval() is very useful. in practice, jason often returns things all in str form. so often we have to do dict1 = eval(data). 
e.g. 
 
dict1 = {'ken':123,'foo':456,'bar':789} 
data = str(dict1) 
dict2 = eval(data) 
 
===> obviously, be caseful about using eval() in prod env because it is prone to code injection hack. 
 
 
### 
###  round(number,decimalPlace) 
### 
 
foo = 12.777 
print(round(foo,2))    #  12.78 
 
# alternatively 
print("%.2f" % foo)           # bar = "%.2f" % foo 
print("{:.2f}".format(foo)) 
 
 
### 
###  sqrt(x) 
### 
 
x ** 0.5 
x ** (1.0/2.0)    #  if you write x**1.0/2.0, you only get x/2.0 
 
# or equivalently 
 
import math 
math.sqrt(x) 
 
### 
###  sleep(number_of_seconds) 
### 
 
import time 
time.sleep(5)    # sleep 5 seconds 
 
 
### 
###   lambda arg1,arg2,arg3,,,argN : expression 
### 
 
lambda func == anonymous func 
 
def multiply(x): 
   return x*x 
 
foo = multiply(7) 
print(foo)               # 49 
 
foo = lambda x: x*x 
print(foo(7))            # 49 
 
 
# a morerealistic use case is inside another function 
 
def addN(n): 
   return lambda a: a+n 
 
add3 = addN(3)         # now you can create a derivative off of addN() 
add999 = addN(999) 
 
print add3(123)        # 126 
print add999(1)        # 1000 
 
 
# another powerful use case is inside map/reduce/filter functional paradigm, as we will see below. 
 
 
### 
###   map(func_to_apply, a_list_of_input) 
### 
 
alist = [12, -34, 56, -78] 
blist = map(abs, alist)           # [12, 34, 56, 78] 
 
# traditional procedural/imperative code looks like this. 
 
blist = [] 
for i in alist: 
   blist.append(abs(i)) 
 
# or slightly neat way is to use list comprehension 
 
blist = [ abs(x) for x in alist ] 
 
 
# suppose you want to add two lists pair-wise 
 
>>> [1,2,3] + [4,5,6] 
[1, 2, 3, 4, 5, 6]        # not what you wanted to do 
 
>>> np.array([1,2,3]) + np.array([4,5,6])       # many people just use numpy, which is ok 
array([5, 7, 9]) 
 
>>> map(lambda a,b: a+b, [1,2,3,4], [5,6,7,8])      # functional way 
[6, 8, 10, 12] 
 
 
# here comes a powerful feature of map(), input can be function also. 
 
def multiply(x): 
   return x*x 
def add(x): 
   return x+x 
 
fList = [add,multiply] 
 
for i in range(5): 
   print map(lambda a: a(i), fList]    # prints below 
[0, 0] 
[2, 1] 
[4, 4] 
[6, 9] 
[8, 16] 
 
 
### 
###   reduce(a_func, a_list_of_input) 
### 
 
apply the func in each elem of the list in a rolling fashion. 
 
 
# suppose you want to compute the sum of all elements in a list 
 
>>> sum(range(10))      # how do you imeplement this ? 
45                      # sure you have a built-in func sum() but how about product() ? 
 
>>> reduce(lambda a,b: a+b, range(10)) 
45 
 
>>> reduce(lambda a,b: a*b, range(1,6))    # product([1,2,3,4,5])  =   1*2*3*4*5 = 120 
120 
 
>>> reduce(lambda a,b: a if a>=b else b, [34,11,56,17])       # max(x) 
56 
 
>>> reduce(lambda a,b: a if a<=b else b, [34,11,56,17])       # min(x) 
11 
 
 
### 
###   filter(func_that_evaluates_to_True_or_False, a_list_of_input) 
### 
 
>>> filter(lambda a: a%2 == 0, range(10)) 
[0, 2, 4, 6, 8] 
 
 
 
 
######################## 
####     numpy     ##### 
######################## 
 
import numpy as np 
 
L = range(5)        # [0, 1, 2, 3, 4] 
a = 3 
np.std(L) 
np.mean(L) 
np.median(L) 
np.multiply(L, 3)   # [0, 3, 6, 9, 12]        # similarly you can do np.{add,subtract,divide} 
np.multiply(L, L)   # [0, 1, 4, 9, 16]        # note, when you divide, make sure you force cast float. e.g. np.divide(L, a * 1.0) 
np.sqrt([1,4,9])    # [1,2,3] 
 
 
## 
##  numpy.random     # https://docs.scipy.org/doc/numpy/reference/routines.random.html 
## 
 
np.random.randint(0,100)      # returns an integer [0,99] 
 

  1. 2015-02-05 23:54:27 |
  2. Category : python
  3. Page View:

Google Ads