Saturday, April 28, 2012

Computer Engineer should Know

Communication costs/memory access times could affect a program in so many ways 

- L1 cache reference: 0.5 ns

- Branch mispredict: 5 ns

- L2 cache reference: 7 ns

- Mutex lock/unlock: 100 ns

- Main memory reference: 100 ns

- Compress 1K bytes with Zippy: 10,000 ns

- Send 2K bytes over 1 Gbps network: 20,000 ns

- Read 1 MB sequentially from memory: 250,000 ns

- Round trip within same datacenter: 500,000 ns

- Disk seek: 10,000,000 ns

- Read 1 MB sequentially from network: 10,000,000 ns

- Read 1 MB sequentially from disk: 30,000,000 ns

- Send packet CA->Netherlands->CA: 150,000,000 ns

(note that 1 ns = 1 * 10^-9 s)

Note: The large difference between I/O access (from disk) and main memory access (from RAM) i.e. Reading from main memory is 120 times faster !

Sunday, April 22, 2012

painless python for python enthusiasts

# Usage
- Email Spell Checker, spams and viruses from Emails
- python is good at data objects and memory managements
- One high level programming language
- Run programs on command-line or IDE
- By default in Mac,unix,linux
./configure; make; make install

#SEGMENT 1
- Source files with .py file extension; .pyc those are the byte code compiled version of the source code
- Intergrated Development Environments (IDEs)
- provides source code editing
- Execution framework
- Tools such as debuggers, analyzers etc
- Various IDE: IDLE, SPE, PyDev/Eclipse
- Ipython is another Interactive cmd-line has much features than the default
Interactive mode
- 3 greater than signs
- To exit: Ctrl-D in IDLE

print 'Hello World!'
print ('Hello World!') print by default add new lines
or
import sys
sys.stdout.write('Hello World!\n')

# SEGMENT 2
Python:
Object-oriented programming language
Can write scripts, applications, APIs
python is good for system capabilities
History: Invented in Holland (1989-1991)
Marketing/Executive Summary
- Robust: system support, datatypes, functionality
- Simple: simpler than VB
- Modular: import features that you need db, networking
- Flexible: java Jython extend into
- Intuitive:

"Batteries Included"
- Standard library provides core functionality

Execution Style
- Interpreted but byte-compiled ( python is interpreted but byte-compiled for performance )
like jave it also byte-compiled, if the source code is not edited it will execute the byte-compiled code directly which makes it little faster
simple arthimetic 5+4*8 = 37
2***3 = 8
s = ' python '
t = ' is cool '
s +' ' + t
python is cool
s * 2
pythonpython
s[0]= p, s[1]=y, s[-1]=n, s[3:6]='hon'
data = [43,'foo', 3.14]
data.append('bar')
data
o/p: [43, 'foo', 3.140000, 'bar']
str(data[2])
'3.14'

# Dictionary is a hash table, key followed by the value
d = {'title': 'Python Fundamental'}
d['year'] = 2009
d
o/p: {'year': 2009, 'title': 'Python Fundamentals'}
for item in data:
print item
42
foo
3.14
bar
for k in d:
print 'key:', k, 'value:', d[k]

Key: year Value: 2009
Key: title Value: Python Fundamentals
i =0
while i 5:
print i
i += 1
0
1
2
3
4
print i
5
if i == 5:
print 'i is equal to five'
i is equal to five
# Files
f = open(r'c:\windows\temp\test.txt','w')
f.write('line 1\n')
f.close()
f = open(r'c:\windows\temp\test.txt', 'r')
for line in f:
print line, # print (line, end='')
line 1
f.close()

# Functions
def foo(x):

- Use '#' to start a comment
- One statement per line
Unless semicolon(;)
- Code blocks delimited by indentation (white space)
- Use '\' to break up long lines

Block Delimitation
# foo() displays & logs its argument
def foo(x):
print "argument is ", x
f = open('log.txt','w')
if isinstance(x, str):
f.write('%s\n' %x)
else:
f.write('%s\n' % str(x))
f.close()
Statements
- simple statements fit on one line
There is no code block following e.g. print
- Compound statements have code block
First line called a header
Indented sub-block of code called a suite
Header plus ':' followed by indented suite
Indentation allows any whitespace
Use spaces not TABs E.g. TAB in Unix platform is 8 spaces whereas in Windows platform 4 characters
Recommended indentation is 4 white spaces
Use same # of spaces for each line

Syntax Elements
# Process weather check on multiple cities
checked = 0 # number of cities checked
cities = ('x','y','z','a',
'b','c')
for city in cities:
condition, wind, temp = get_weather(city)
print "Temp:", temp; checked += 1
if condition == WINDY and wind 10 \
and temp 45:
send_surfing_alert(city)

#SEGMENT 4
- Variables and Assignment
Dynamic Typing... variables not declared
- Type inferred on assignment
- var = expression

Flexible assignment syntax
- var1 = var2 = expression
- var1, var2 = expr1, expr2

Assignment operators
- primary assignment operator: =
- Augmented assignment
+=, *=, ...
- No increment/decrement
++, -- are not permitted instead we have to use += , -=

Identifier Rules
Similar to other languages
- First Character must be alphabetic
- Any others can be alphanumeric
Treat underscores (_) as alphabetic
Case-sensitive: "None" is not "none"

Style
- Variable naming guidelines
similar to other languages
- Names longer than 1 character
- Normal data in lowercase
- Class names should be Titlecases e.g. First letter should be Capital - India,Ganga
- Constants should be in CAPs
Python Gotchas
- Special names begin/end with underscores
- Do not use built-in function/data names
- Reserved words, or keywords, can't be used

Python Keywords
and,as,assert,break,class,continue,def,del,elif,else,except,exec,finally,for,from,global,finally,for,from,global,if,import,in,is,lambda,nonlocal,not,or
pass,print,raise,return,try,while,with,yield
Constants: True, False

Built-In's
def: A _____ is a special predefined(pre-build) python interpreter identifier
Built-ins are either data attributes or functions - usually the latter

Common Build-ins
Some useful built-in functions:
-informational:
dir(), help(), type() - These all will give the information about the objects
-Operational:
int(){conversion to int}, str(), range(). raw_input(), input()

#SEGMENT 5
Function Syntax
Introducing Functions
- Declared using def keyword:
def func_name ([arg1[,arg2[,...argn]...]):
func_body
def add2tome (number):
return number + 2

Functions
- Declarations:
Header line and at least one for body
Can have any number of arguments
- If no value explicitly returned...
Python returns None
None: Python's NULL or void
None: constant Boolean False

Importing & Modules
What is Importing?
Allows use of outside code
In other words to bring in the functionality, suck in some functionality into ur code.
What are Modules?
- Self-contained Python code // plug and play methodology like database import database modules things like that.
- Bring in new functionality/objects
- Import only features that you need

Import Syntax
Two different ways to access module attributes
- Use module elements with name
import os
os.getcwd() // call procedure os module followed by getcwd function
'/tmp'

- Can import individual elements into 'namespace'
from os import getcwd
getcwd() // We can call directly its just like a variable
'/tmp'

#SEGMENT 6
Keyboard Input
- How to get keyword input from user
Use python's raw_input() function
Renamed to input()
Syntax
var = raw_input(prompt)
Example
name = raw_input('Enter name: ')
Enter name: Gyani Pillala
name
'Gyani Pillala

#SEGMENT 7
400a
Introduce standard data types
- Numbers
- Sequences - Starting with index0
- Hashing - Starting with hashing key-value pair

#Standard Types

Standard Types: Numbers, Strings, Lists, Tuples, Dictionaries, Sets
Other Types: None, Funtions and Methods, Modules, Types/Classes, Iterators

Boolean Values
- Every object has an intrinsic boolean value
- Any numeric zero or empty container is False
False bool " " str
0 int [] list
0L long () tuple
0.0 float {} dict
0.0+0.0j complex None None
- All other values are True

Operators
- Apply to most data types
- Object Value Comparison
= = == !=
- Object Identity Comparison
is , is not
E.g. If x=some object, y=some object , if both happen to be pointing to the same object where "is " and "is not " can be compared against two
is , is not
- Boolean
not , and , or

Built-in Functions
- Apply to most data types
dir() object's attributes
help() show help text
type() object type
isinstance() check object type
cmp() compare 2 objects
str() string rep of object

#Numbers
- Integers (int)
No size limit
Decimal, hexadecimal,octal,binary
42, 0xAE, 0237/0o237, 0b1110
- Long intergers (long)
Merged with and replaced by integers
42L, 0xDEACADEEFABDE
- Floating-Point Numbers (float)
IEEE 754 double-precision
3.14, -6e2, 0.1
-1.1 == 1.100000000000000001
Bits do not like repeating fractions
Use round() + string formatting
Or use decimal.Decimal type
http://docs.python.org/tut/node16.html
Others Numbers
Other numeric types
complex (complex)
Boolean (bool)
Other numeric type modules
decimal
fractions
numbers
Numeric Operators
Arithmetic Operators
+ - * / // %(modulus) **(exponential)
// - Classic Division How it is different from normal division(/)
1/2 - The answer is 0 or 1.0/2.0 - The answer is 0.5 whereas
1//2 - The answer is 0.5 or 1.0//2.0 - The answer is 0.5
Unary Operator
+ -
Bit Operators ( int only )
& (bitwise and ) | (bitwise or) ^(Bitwise exclusive OR) (Left shift) (Right Shift) ~(Uniary Bitwise operator- compliment)

Numeric Built-ins
Factory
int() - When we call int we are creating integer object
float() -
complex() -
Note: Factory function works, Example when we pass a floating-point to interger function, the output is a interger itself but it won't change the floating
point number whereas it create a interger from the scratch. In other words the two format are still available
Not "casting" nor "conversion..."

Operational
abs() - absolute value
pow() - Exponential value
round() - round up the floating point value to significant figures
divmod() - It is a combination of division and the modulus operator. E.g. If you want to find out what is the Quotient and the Reminder we can get it
chr() - In python 3 all strings are unicode, you can pass the ascii value or unicode then it will turn u the apropriate string
data = []
if data:
print 'data has element in it'
else:
print 'data is empty'
o/p: data is empty
if len(data) 0:
print 'data has stuff in it'
else:
print 'data is empty'
o/p: data is empty
Note: In second case we are calling len function call. Whenever we have any funtion calls some kind of overload is associated with it.
In first case with boolen values itself we can do the purpose
dir(data) # This takes an object and tells more about it, different attributes of list
isinstance(data, list)
True
isinstance(data, int)
False
type(data)
type 'list'
1 + 2 = 3, 5 % 2 = 1, 2 ** 3 = 8, 9 ** 0.5 = 3.0, 1 / 2 = 0, 1.0/2 = 0.5, 1.0/2.0=0.5, 1.0//2.0 = 0.0
int(3.4) = 3, float(1)=1.0, round(1.185, 2) = 1.18999, '%.2f' %round(1.185, 2) = '1.19', str(round(1.185,2)) = '1.19'

#Sequences
Strings(str,unicode) # Python 2
Bytes(bytes,bytearray)
Lists(list)
Tuples(tuple)
Sequences are ...
- Array-like collections/containers
- Heterogeneous(except strings)
- Accessed by index ( starts at 0 )
Accessing the sequence elements phenomenon are called slicing
Access element(s) by "slicing"
Single-elements slice: seq[i]
Return item i for sequence seq
Where 0 = i len(seq)
Negative indices also allowed, so:
--len(seq) = i len(seq) Note: If you mention -1, it is the last element of the array

Slicing Example
S = " p y t h o n "
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
String example above
Works for all sequence types
s[2]=t, s[0]=p, s[-2]=o, s[len(s)]=Error

Multi-Element Slicing
-Access multiple element(s) with ":"
Syntax: seq[i:j]
-From i up to but not including j
Missing indices also allowed
-Means from beginning or to end
S = " python"
s[2:5] = tho
s[3:] = hon
s[:2] = py
s[-4:-1] = tho
s[:] = python

Sequence Operators
- Membership : ( in , not in )
- Concatenation : ( + )
- Repetition/Duplication ( * )

Sequence Built-ins
- Factory
str(), list(), tuple(), unicode(), bytes(), bytearray()
- Operational
len(), max(), min()

Strings
- Line an array of characters...
No char(acter) type in Python
- Immutable, as are numbers
Value cannot be changed
- Flexible string formatting
% operator or format() method
- Triple quotes allow special chars

String demo
s = 'Python'
s * 2
'PythonPython'
s
'PythonPython'
s[1]
'y'
s[-1]
'n'
s[:4]
'pyth'
s[2:6]
'thon'
s[-4:-1]
'tho'
s[:6] + ' is cool '
'Python is cool'
'-' * 20
'----------------'
'ton' is s
False
'thon' is s
True
'thon' not in s
False
hi = '''hi
there!'''
hi
'hi\nthere!'
print hi
hi
there!

String Formatting
"Name: %s, age: %d" % ('John', 35)
'Name: John, age:35'
"Name: {0}, age: {1}".format('John',35) # Quite Flexible
'Name: John, age:35'
d = { 'user': 'wes', 'page': 42 }
'http://web/%(user)s/%(page)d.html' %d
'http://web/wes/42.html'
'http://web/{user}/{page}.html'.format(**d)
'http://web/wes/42.html'

String Methods
- Built-in String Method Sampler
split() split on delimiter to list e.g. pass in the delimiter will split, password file delimiter (:)
join() join list with delimiter e.g. pass lists of substing will give new string
find() substring search
strip() remove leading/trailing WS // remove at the begin and end
lower() lowercased version of string
replace() search and replace (not RE)
ljust() create left-justified string

Demo
s = 'Python is cool.'
s
'Python is cool.'
s.find('is not')
-1
s.find('is')
7
s.rfind('o')
12
s.center(25)
' Python is cool. '
s.center(25).strip()
'Python is cool.'
s.split()
['Python', 'is', 'cool.']
'::'.join(s.split())
'Python::is::cool.'
'.'.join(reversed(s.split()))
'cool..is.Python'
s.title()
'Python Is Cool.'
s.upper()
'PYTHON IS COOL.'
s.title().swapcase()
'pYTHON iS cOOL.'
s.isalpha() # It chech the entrie string is all about alphabetic but in our case it has space and fullstop
False
s.endswith('.')
True
s.replace('.','!')
'Python is cool!'

String Miscellany
- Operators and Operational Built-in Functions
raw_input() user input
ord() ASCII/Unicode value
r'c:\tmp\new' raw string # Message to the Interpreter don't do any special conversions like \t tab or \n new line
u'n\xe9' Unicode string
b'n\xc3\xa9' bytes string

Strings and Bytes
- Unicode default string type in 3
- Introduce byte types for 8-bit chars
2. x 3.x Mutalbe
str("") bytes(b"") no
unicode(u"") str("") no
N/A bytearray yes

Lists and Tuples
- Ordered heterogeneous containers
- Lists
Mutable, resizable
Feature many helper methods
- Tuples
Immutable
Transport data to/from functions
Not truly meant for user manipulation

List Methods
- Built-in Methods
append() add object to end
insert() add object anywhere
remove(), pop() delete objects
reverse() reverse in-place
sort() sort in-place
extend() merge another list
*count() number of occurrences
*index() first index of value

Demo
m = ['core', 'programming',9,2007]
m
['core', 'programming', 9 2006 ]
m.append('prentice Hall')
m
['core', 'Programming', 9, 2007, 'prentice Hall']
m.insert(1,'pytho')
m
['core', 'Pytho', 'Programming', 9, 2006, 'Prentice Hall']
2006 in m
True
m.pop(3)
9
m
['core','python','programming',2006,'prentice hall']
m[2:4] = ['Fundamentals', 2008 ]
m
['core','python','Fundamentals', 2008, 'Prentice Hall']
m.remove('core')
m
['Python','Fundamentals',2008, 'Prentice Hall']
m.remove('c')
error

List Comprehensions
- Lists:
Highly-used data type
Most common operations:
choose elements that fit criteria
Apply function to each element
- List Comprehensions("listcomps")
construct lists using logic
Basic syntax:
[ expr for var in iterable ]

Demo
range(10)
[0,1,2,3,4,5,6,7,8,9]
[ i for i in range(10)]
[0,1,2,3,4,5,6,7,8,9]
[i for i in range(10) if i%2 ==0]
[0,2,4,6,8]
[i*3 for i in range(10) if i%2 ==0]
[0,6,12,18,24]
[i//3 for i in range(10) if i % 2 == 0]
[0,0,1,2,2]

- Generator Expressions
List Comprehensions
Not as efficient with memory
Entire list must be created
Generator Expressions
Alternative to list comprehensions
"Generate" Successive values
Nearly identical basic sytax
- (expr for var in iterable )

Hashing Types
- Dictionaries (dict)
- Mutable Sets (set)
- Immutable Sets ( frozenset )

- Hashed collection/container objects
- Accessed by iterator ( or key for dicts )
- Heterogeneous
- Unordered by definition

Dictionaries
- Python's only mapping type
Map keys to values
Mutable, resizable hash tables
- Heterogeneous
Values are arbitrary Python Objects
- Keys are scalar ( must be hashable )
Strings, numbers, etc
- No( key ) collisions allowed

Dictionary Methods
Common Built-in Methods
get() get value given key
update() merge another dict
setdefault() return value, set if nec
pop() remove & return value
items() all key-value pairs
clear() clear dictionary
fromkeys() make new dict w/keys

Dictionary Operations
General Usage
- Number of key-value pairs:
len()
- Key membership:
if k in d: # or not in
- Loop through all keys:
for k in d:
Hashing works pretty faster than the normal list

Demo
d = { 'title': ' Core Python Programming'}
d
{ 'year': 2006, 'title': 'Core Python Programming'}
'year' in d
True
'pub' in d
False
d['title']
'Core Python Programming'
d['pub']
Error, Boc the key pub is not existing
d. get ('pub', 'N/A')
'N/A'
d.setdefault('pub', 'prentice Hall')
'Prentice Hall'
d
{ 'year': 2006, 'pub': "Prentice Hall', 'title': "Core Python Programming'}
d['pub']
'Prentice Hall'
for k in d:
print k.ljust(8), d[k]

year 2006
pub Prentice Hall
title Core Python Programming

for k, v in d.items():
print k.ljust(8), v

year 2006
pub Prentice Hall
title Core Python programming
d.items()
[('year', 2006), ('pub', 'Prentice Hall'), ('title', 'Core PYthon Programming')]
d.iteritems() # Belongs to python 3
dictionary-itemiterator object at 0x11abfa0

Sets and Frozensets
- def: a set is a finite collection of objects
- Mutable(set) or immutable (frozenset)
- No key-value pairs, just values
- Unordered and heterogeneous
- Hashed, like dictionary keys
- No collisions means no duplicates
- Remember Venn diagrams ?

Sets Avoids the same numbers repetition
Demo
a = [1, 4, 6, 3]
b = (9, 5, 2, 7, 5, 3)
a, b
([1, 4, 6, 3], (9, 5, 2, 7, 5, 3))
c = set(a)
d = set(b)
c
set ([1, 3, 4, 6])
d
set ([9, 2, 3, 5, 7])
c.intersection(d)
set([3])
c & d # Intersection
set([3])
c | d # Union of C and D
set([1, 2, 3, 4, 5, 6, 7, 9])
c |= d # Assigning the value of C and D
c
set([1, 2, 3, 4, 5, 6, 7, 9])
c.add(8)
c
set ([1, 2, 3, 4, 5, 6, 7, 8, 9])
c - d # Substract the value from the set
set ([8, 1, 4, 6])

# Set Operations
- in,not in, =, =, &, |, -, ^
- for: len().max(),min()
- Augmented assignments (&=, etc )
- Set Literals {1, ...} ({} is empty dict)
- Set comprehensions { x for x in...}

= All set types have methods
- Only sets can be modified

We gave you very high level overview
Picked up some hands on work

#Summary
- Overview of standard Data types
- Operations & built-in/factory functions
- Usage examples
Next: Objects and Memory Model

#Objects and Memory Model
Objects and Memory Model

- Introducing object references
- Tracking the reference count
- Categorizing the standard types

Python manages the memory with object references... reference count
object are the primary abstraction in python


#Objects

- def: each unit of data or logic in Python is an object, the primary abstraction
All objects will be having 3 attributes mandatory

- Attributes that all objects have
- Identity
- Type
- Value
- All read-only except perhaps value
There is no way we can change the objects Identity and Type

Objects are tagged with garbage collection , when the reference count goes to 0... That basically help python manages memory

# References
- Objects created when requested/needed and (generally*) assigned as a reference
- Variables merely references to objects
- References also called aliases
- Memory management: reference count
- Count in/decrements based on usage
- Objects GC'd when "refcount" goes to 0

# More on References
x = 1
y = x
x === 1 === y
Both are looking/referencing at single object
Objects are most important thing, variables are just referencing...

- Variables...
- Don't "hold" data per se
- Just names that "point" to objects
- Can create additional aliases to objects
- Be aware of cyclic references
It's really not a problem b'cos python will be having inbuilt references manager, but keep in mind when u create a complex program object relationship

#Refcount Increment

- Object's reference count incremented when:
- It ( the object ) is created ( and assigned )
foo = 'Python is cool!'
- Additional aliases for it are created
bar = foo
- Passed to a function ( new local reference )
spam (foo) # function local variable will be pointing..
- Becomes part of a container object
lotsaFoos = [123, foo, 'xyz']

# Refcount Decrement
- Object's reference count decremented when:
- A local reference goes out-of-scope
i.e. when spam() ends
- Alias explicitly destroyed
del bar # or del foo
- Alias reassigned to different objects
bar = 42
- Object removed from container/collection
lotsaFoos.remove(foo)
- Container itself is deallocated
del lotsaFoos # or out-of-scope

#Categorizing Types
- Why categorize the standard types ?
- Make you learn them faster
- Have you understand them better
- Be able to "see" how they work internally
- Encourage more proficient programming
- Three Models
- Storage
- Update
- Access

# Storage Model
- How data is stored in an object
- Can it hold single or multiple objects ?

Model Category Standard Type(s)

literal/scalar numbers, strings
container lists,tuples, dicts, sets

English keywords
This is not like rocket science
That's all i wanted to say in the storage model
I am just trying to put myself into your shoes

Sets:
mutable sets : sets
Immutable sets : frozen sets

# Update Model
- Can an object's value be updated?
- Mutable == yes and immutable == no
- There is one of each set type
- The 'bytearray' type is mutable

Model Category Standard Type(s)

mutable lists, dicts
immutable numbers, strings, tuples

# Access Model
- How data is accessed in an object
- Directly, via index, or by key
- Primary model for type differentiation

Model Category Standard Type(s)

direct numbers, sets
sequence strings,lists,tuples
mappings dicts

# Combining All Models
Data Type Storage Model Update Model Access Model

numbers literal/scalar immutable direct
strings literal/scalar mutable sequence
lists container mutable sequence
tuples container immutable sequence
dicts container mutable mapping
sets(Two types ) container im/mutable direct

# Interning of Objects
- Exception to the general rule
- Some strings and integers are "interned"
- Integers in range (-5, 257 ) [ currently ]
- Oft-used, single-character, or empty strings
- Primarily for performance reasons

x = 4
y = 4
x == 4 == y
x = 4.3
y = 4.3
x == 4.3
y == 4.3

#What is the output here ( and WHY )?

x = ['foo', [1,2,3], 1.2 ]
y = list(x) # copy x; or x[:]

y[1][0] = 4
print x
print y

# Explanation
- Create list object x
- Make a copy and assign to y
- Use y to reference & change value

x = ['foo',[1,2,3], 1.2 ]
y = x[:]
y[1][0] = 4
print x
print y

x == ['foo', [1,2,3], 1.2 ]
y == ['foo', [1,2,3], 1.2 ]


#Answer
Unfortunately we get 4 2 3 in both cases
We just copied the references

x [ , , ] === [ 'foo', [4,2,3], 1.2 ] === y [ , , ]

Both x and y are looking at the same list, that why the data change in the list effected both the objects x & y

#Copied References
- You did copy the list, but you also
- Copied its references and changed one that is mutable (objs not copied )

" Shallow copy " -- It just copies the references it won't copy the objects

English
That is the punch line here
you swear the code is correct, but still it's not working the way you wanted it to work

# Copying Objects
- Always tricker with mutable objects
- Let's copy a list x as list y:
- Creates an alias not a copy
y = x # Conditions Checking ... - x == y and x is y ( It gives True )

- Create a shallow copy ( Copies the references ... )
y = x[:] # Condition Checking .. x == y but x is not y

- Create a deep copy ( Copies the objects ... ) [ both x and y no longer points to the same objects ]
y = copy.deepcopy(x)

## Summary
# References and "Refcounting"
# Storage, Update, & Access Models
# Interning and Copying Objects
# Eye-Opening Quizzes
# Eye-opening Quizzes
# Next: Loops and Conditionals

# Loops and Conditionals
- Syntax Considerations
- Conditional Statements
- Looping Mechanisms
- Loop "Helpers"

#Syntax Considerations
- Code delimitation by indentation
- Code blocks called "suites"
- Indentation must be consistent
- Try to use only spaces (no TABs )
- First "dedented" line not part of block
- Major players likely to be "compound"
- Helpers either BIFs or "simple" statements

# if Statement
- Conditionally execute code
- Parentheses not required

Syntax:
if conditional expression:
# If true, execute this suite
# now outside of it clause

- Example:
if i 100:
print "greater then 100"
print "always see output here "

English :
If you have experience in other programming languages, it should be fairly straight forward.

# if-else Statement
- else used with if for opposing condition

- Example:
if i 100:
print " Greater than 100"
else:
print " Less than or Equal to 100"
print "Execution Resumes Here "

# if-elif-else
- Python's "else-if" spelled elif
- Example:
# prompt, get, and check input
data = raw_input("Enter 'y' or 'n' :") # python 2
data = input("Enter 'y' or 'n' :") # python 3

if data[0] == 'y' :
print "You typed 'y'." # 'y' key
elif data[0] == 'n':
print "You typed 'n'." # 'n' Key
else:
print 'Invalid key!' # other key

Note:
python 3 , the print turning out into function...
It's mandatory that the string should be in double quotes

Demo
def demo():
data = raw_input('Enter "y" or "n": ').stip() or .lower()
if data[0].lower() == 'y': or if data[0] == 'y' or data[0] == 'n':
print 'you typed "y"'
elif data[0] == 'n':
print "you typed "n"'
elif data == 'gooj':
print "you got out of jail free.'
else:
print 'You entered invalid key.'
demo()
Enter "y" or "n": YES
You typed "Y"
demo()

# Ternary Operator
- Ternary operator aka conditional expression
- Syntax in other languages:
C ? T : F

- In python:
- 2.5+: T if C else F
- 2.5: (C and [T] or [F]) [0]
- Example:
x, y = 1, 2
max_xy = x if x y else y
max_xy

# Looping Mechanisms

- def: a_ executes a block of code...
- For a specific number of times
- Iterates over a (not nec. finite) dataset, or
- Until a condition is no longer satisfied
- Looping Statements
- Primarily used to iterate over data(for)
- Primarily used as a counting loop (while)
- Helpers
- Built-in Functions (BIFs)
- Auxiliary (simple) statements

# for Loops
- The python for loop is its most powerful
- The most commonly-used Python loop
- It traverses an "iterable," setting the loop variable to each successive value
- Syntax:
for variable in iterable:
# body of loop (suite)

# Iterables
- def: an iterable is any data structure that supports simple element traversal
- Sequence (strings, lists, tuples )
- Sequence-like objects:
- Iterators, lines of a file, keys of a dictionary, generators, sets, etc.

# range() Built-in
- range(): helper for Python for loops
- Python for more like shell foreach
- Iterating rather than traditional counting
- range() morphs counting into iterating
- range() returns list (2.x) or iterator (3.x)

- Full and Short Syntax (int arguments):
range(start, end[, step])
range([start,] end )

Demo
my_str = 'Python is cool.'
my_list = [3.14,'foo',42]

for c in my_str:
print c
print (c) # python 3
p
y
t
h
o
.... # It just prints character by character
for item in my_list:
print item
3.14
foo
42

for i in range(1, 10):
print i
1
2
3
4
... # prints upto 9

English:
This is just a very high level overview

for i in range(1, 10, 2):
print i
1
3
5
7
9
range(1, 10 )
[1,2,3,....9]

# More on range()
- Examples:
range(5) [0,1,2,3,4]
range(6, 9) [6,7, 8]
range(2, 12, 3) [2,5,8,11]

- 2.x: use xrange() to get iterator version
- Lazier, more memory-friendly
- Raplaces and renamed as range() in 3.x
- range() lets for loops iterate over index:
for i in range(len(data)):
print data[i]

# Item or Index
music = ('Poe', 'Gaudi', 'Freud')
for i in range(len(music)):
print 'album %d: %s' %(i, music[i])

album 0: Poe
album 1: Gaudi
album 2: Freud

- In the above, we iterate by index
- We can also iterate by item/element as usual:
- for album in music: print album
- But there is no access to the index above:
sometimes we want bothe the item and the index

# enumerate() Built-in
- enumerate(): another helper for Python for loops
- Returns a special-purpose iterator
- Iterator emits both index and item!!!
- Example:
music = ('Poe', 'Gaudi', 'Freud')
for i, album in enumerate(music):
print 'album %d: %s' % (i, album)

album 0: Poe
album 1: Gaudi
album 2: Freud

# while Loops
- while loops are conditionals, like a looping if
- Suite executed until condition no longer satisfied
- Suite not executed if condition was never True
- Test performed before each loop interation
- Common use cases:
- A counting loop
- An infinite loop
- Syntax:
while conditional_expression:
# body of loop

Demo
while i 5:
print i
i += 1
0
1.... # prints till 4

# Infinite while loop
not_done = True
while not_done:
# Some block of code to do something
# when finished hopefully call "break"
break
range and enumerate are built-in functions

# break statement
- break terminates a loop, regardless of conditional

- Syntax:
# inside the body of a loop
break
- Example:
while True: # infinite loop
:
if error: # break out of loop
break

# continue statement
- continue terminates current loop iteration
- It does not necessarily start the next loop
- Syntax:
# inside the body of a loop
continue

- Example:
while Ture: # infinite loop
:
if skip_reminder: # skip rest of loop
continue
# code which may be skipped

# pass statement ( Python specific )
- pass performs no action
- Python's "no operation" (NOP) statement
- Used when statement required syntactically
- Good as placeholder for code to be written
- Syntax:
# inside my suite
pass

- Example:
class NetworkError(IOError):
pass

# else Statement
- else can also be used for loops
- Unique compared to other lanugages
- Executed if loop not broken out of

- Syntax:
loop: #While or for
suite1 # normal loop block
else:
suite2 # only w/o break

# Loop else Example
- Prime numbers and the search for a divisor:

value = int(raw_input("Enter #: "))
counter = int(value ** 0.5) # sq root

while counter 1: # stop at 2
if value % counter == 0:
print(value, "is composite")
break
counter -= 1
else:
print (value, " is prime ")

# Summary
- Review indentation as delimitation
- Introduce family of if statements
- Python's Looping Types: for and while
- Define iterables
- Explore roles of loop helpers
- Next Lesson: Files and Input/Output

Painless Python for proficient programmers

 == Painless Python for Proficient Programmers

- the interactive shell displays non-None expression results
- the print statement does elementary I/O to standard output
    use comma to separate the values you want to emit
    print uses space separators and newline at the end
- In real programs, you'll use very different tools:
    the logging package for logging purposes
    add strings to a HTML response object
    GUI widgets and their methods

==  Some trivial examples

print 'Hello, world!' # classic !-)
x = 23 # name x now means 23
print x # emits 23
x = 'foo' # now  x means 'foo' instead
print x # emits foo
del x # name x reverts to undefined
print x # raises an error ("exception")

y = None # name y gets bound ot None
print y # emits None

== Similarities with Java
- Both typically compiled -- bytecode (python got a  make engine built in )
    But: Python compiles implicitly ( like a built-in make ! )
- "Everygthing" inherits from object
    But: in Python, also numbers, functions, classes, ...
    "Everything is a first-class object", no " boxing/unboxing"
- uniform object-reference semantics
    assignment, argument-passing, return
- garbage collection ( but: CPython also uses RC...)
- Key "marginalia": vast standard library ( + thind party packages & tools ) , introspection, serialization, threads

Examples:
In c when you say a = b , then lot of bits copying happens
Whereas in java and python, b refers exactly the same object as a refered to
java/python both got garbage collector


== Similarities with C++
- Multi-paradigm (not just "forced" OOP )
    OOP, procedural, generic, a little FP
- Multiple inheritance
- Operator overloading
    but: not for simple assignment ( not an operator )
- "Signature-based" polymorphism
    As if "everything was a template" ( but: nicer syntax )
- abundant choices for most all "side issues"
    - GUI, Web & other networking , DB , IPc, distributed processing...

Examples
In C++ we can overload assignment operators whereas in python we cannot overload assignment operators
python exactly have the same java symentics of assignment operators

Assignment is a object reference in python. Assignment is not an operator in python
In python everything we write is a template implicitly

== Deep connection with C

"Spirit of C" @87% ( More than java or C++ despite surface syntax...), according to ISO C standard "Rationale".
1. trust the programer
2. don't stop the programmer from doing what need to be done
3. keep the lanugage small and simple
4. provide only one way to perform an operation
5. (be fast, even if not guaranteed to be portable)
  ( this is the one point out of five that's not at 100% in python]

== The Zen of Python
import this
Beautiful is better than ugly.
Explicit is better than implicit
Simple is better than complex
Complex is better than complicated
Flat is betten than nested
Sparse is better than dense
Readability counts
...
In the face of ambiguity, refuse the temptation to guess.
There should be one, preferably only one, abvious way to do it.

== Python vs Java/C++/C: Syntax
- spare syntax, no ornamentation
    - "no wasted pixels" ( Tufle )
    - no {} around blocks, just indent
    - no {} around conditions in if and while
    - generally little punctuation

Every Pixel is important
Don't put a pixel there, unless it communicates a pixel there...
(), {} - wasting a pixel

== Python vs Java/C++/C: semantics
-types: strong but dynamic
    - names have no types ( objects have types )
    - " duck typing" ( if it walks like a duck , &c )
- No "declarations", just statements
- "everything" is a first-class object
    - classes, functions, methods, modules, packages...
- The focus is no high and very high levels
    though lower levels are decently supported too

Everything is a object
module, package these are objects

== Duck Typing
Takes some work to teach the ducks to type, but the returns in productivity are quite worthwhile:-)

==Flow Control
- if :
    - O+ elif :
    - optionally: else:
- while :
    - block can contain break, continue
    - optionally: else:
        - executes if no break terminated the loop
- for in :
    - break, continue, else: like in while
- with as :
    - in 2.5, requires: from __future__ import with_statement

== Built-in simple types ( all immutable )
- numbers: int, long, float, complex
    - 23 434343434343 ox17 2.3 4.5+6.7j
    - operators: + - * ** / // % ~ & | ^ << >>
    - built-in functions: abs min max pow round sum
- Strings: plain and Unicode
    - 'single' "double" r`aw` u"nicode" \n&\c
    - operators: + (cat), * (rep), %(format)
        - rich "format language" (akin to C's printf)
    - Built-in functions: chr ord unichr
    - are immutable sequences: len, [] (index/slice), for
        - each item is a "character" ( actually: a length-1 sting )
    - tons and tons of methods: capitalize, center, ...

== Discovering methods
dir('anystring')
........
........
........
........
........

You will be getting huge numbers of methods, attributes of that object
 

== > Getting help about a method

>>> help(''.center)
Help on builtin function center:

center(...)
 S.center(width[, fillchar]) -> string

Returns S centered in a string of length withd. Padding is done using the specified fill character ( default is a space )
(END)
>>>

==> ... and then, experiment

>>> 'ciao'.center(10, '+')
'+++ciao+++'
>>> 'ciao'.center(3, '+')
'ciao'
>>> 'ciao'.center(9, '+' )
'+++ciao++'

Note: learn by doing....

== > Built-in container types

- tuple: immutable sequence
    - () (23,) (23, 45) tuple('ciao')
- list: mutable sequence ( a "vector")
    - [] [23] [23, 45] list('ciao')
- set, frozenzet: simple hashtables
    -set () set((23,)) set('ciao')
- dict: map key -> value by hashtable
    - {} {2:3} {4:5, 6:7} dict(ci='oo')
- all containers support: len(c), looping (for x in c), membership testing ( if x in c )
    - and , generally , many methods ( sets also support operators )

==> Sequences

- stings, tuples and lists are sequences (other squence types are in the standard library )
- repetition ( c*N), catenation ( C1 + C2 )
- indexing: c[i], slicing: c[i:j] and c[i:j:k]:
    - 'ciao'[2] =='a', 'ciao'[3:1:-1] =='oa'
    - always: start included, end excluded ( per koenig...)
- lists are mutable sequences ( can assign to item or slice )
    - assigning to a slice can change the length
- dicts and sets are not sequences ( though they are iterables )
    - ordering "arbitrary" ( as befits hash tables), no slicing

== > More about Containers

- mutating vs non-mutating methods
    - most mutating methods return None
    - e.g. alist.append(...), aset.add(...), adict.update(...)
- a few mutating methods return non-None:
    -alist.pop(...), adict.pop(...), adict.setdefault(...)
- set has an immutable variant (frozenset)
- dict has a variant defaultdict ( in module collections )
- also iin collections: deque( sequence with added methods... left, clear, rotate; no slicing, no sort )
- no heap type, but rather heap functions on lists(module heapq)

==> Example: making a heap ( priority-queue type )
import heapq
class heap(object):
    def __inti__(self, content=()):  // Initializer
        self._L = list (content)
        heapq.heapify(self._L)
    def push(self, item): heapq.heappush(self._L, item)
    def pop(self): return heapq.heappop(self._L)
    def replace(self, item):
        return heapq.heapreplace(self._L, item)
    def __len__(self): return len(self._L)
    def __iter__(self): return iter(self._L)
    def __repr__(self): return 'heap(%r)' % self._L

== > Comparisons, tests, truth ( or, rather, "truthiness")
- equality, identity: == !=, is , is not
- order: < > <= >=
- membership: in, not in
- "chaining": 3 <= x < 9
- falsy: numbers == 0, "", None, empty containers, False ( aka bool(0))
- truthy: anything else, True ( aka bool(1))
- not x == not bool(x) for any x
- and, or "short-circuit" (-> return an operand)
- same for built-ins any, all (-> return a bool )

==> Exceptions
- Errors( and other "anomalies" )"raise exceptions" (instances of Exception or any subtype of Exception )
- Statement raise explicitly raises an exception
- Exceptions propagate " along the call stack", terminating functions along the way, until they're "caught"
- If uncaught, an exception terminates the program
- Statement try/except can catch exceptions (also: try/finally, and elegant with to implement "RAAI" [ in 2.5, needs from __future__ import with_statement at start of module )]

==> Some RAAI examples
from __future__ import with_statement

with open('afile.txt') as f:
    for aline in f: print aline[3],
with some_lock do: a_critical_section()

import contextlib, mysqldb
with contextlib.closing(mysqldb.connect()) as db:
    with contextlib.closing(db.cursor()) as c:
    c.execute("SELECT * FROM t WHERE t.zap< 23")
    for record in c.fetchall(): ...

==> iterators and for loops

for i in c:
    ===>
_t = iter(c)
while True:
    try: i = _t.next()
    except StopIteration: break
   
also:
( for i in c ) ("genexp")
[ for in in c ("list comprehension")

==> Some examples of genexp use (w/" accumulators")
def countall(it): return sum ( 1 for x in it )
print countall(x for x in range(99) if x%5==x%7) #15

if any(x>5 for x in xs): ...

if all(x>y>z for x, y, z in zip(xs, ys, zs)): ...
# or, better(since zip makes a list...):
from itertools import izip
if all(x>y>z for x, y, z in izip(xs, ys, zs)): ...

print max(i for i, x in in enumerate(xs) if x>0)
And... We're halfway through!

=== Rapid Development with Python Django and Google App Engine
Talk Overview
- This is not a plug for Python, Django or Google App Engine
    - Except implicitly :)
- Best practices for using Django with App Engine
    - project setup
    - The "Google App Engine Django Helper" module
    - Using App Engine's db.Model instead of Django's Model Class
    - Writing unit tests
python is a Great Language
Django is a Great Web FrameWork
Google App Engine - Is a great Application Development Platform
What i am trying to tell here is , to use some of the best practices of using Django with Appengine

Today i am going to bore you to Depth Briefly...

i hope there will be plenty of time for Q&A

=== Google App Engine Recap

- Does one thing well: run web apps
- Simple Configuration
- Request handlers
- Accelerators and shortcuts

=== App Engine Does One Thing Well

- App Engine handlers HTTP requests, nothing else
    - Think RPC: request in , processing, response out
    - Works well for the web and AJAX; also for other services
- Resources are scaled automatically
    - Requests may go to the same process, serially
    - Requests may go to different processes, in parallel or serially
- Highly scalable datastore based on Bigtable (Google internal database )
    - Not SQL: no joins

Ajax webapplication

=== Configuring an App Engine Application
- An application is a directory with everything underneath it
    symbolic links are followed
- Single file app.yami in app root directory
    Defines application metadata
    Maps URL patterns ( regular expressions) to request handlers
    Separates static files from program files
- Dev server (SDK) emulates deployment environment
They have special API's

==== Request Handlers
- URL patterns are mapped to request handlers by app.yami
    yami = is a markup language similar to python
- Handler is invoked like a CGI script
- Environment variables give request parameters
    E.g. PATH_INFO, QUERY_STRING, HTTP_REFERER
- Write response to stdout
    Status (optional), headers, blank line, body

==== Request Handler Acclerators and Shortcuts
- CGI doesn't mean slow!
- Define a main() function
    Module will remain loaded, main() called for each requests
    Can use module globals for caching
    Must use "if __name__##'__main__':main()" boilerplate
- CGI doesn't mean clumsy !
- WSGI support layered on top of CGI: util.run_wsgi_app(app)
    Web services Gateway Interface, little much resemblance of CGI(Common Gateway Interface )
Interface to the web server

==== Django Project Setup for App Engine

- Django is a bit finicky about project structure
    - code in one or more 'app' (application) subdirectories
        - cannot have the same name as the project
    - Must have a single settings.py file
            - found via DJANGO_SETTINGS_MODULE environment variable
- App Engine Vs Django
    - No SQL: must use App Engine's own database
    - Top-level directoy appended at end of sys.path
    - Django 0.96.1 preloaded, which is pretty old
    - Slight differences between dev_appserver and real deployment

=== Boilerplate Files, Standard Project Lay-out

- Boilerplate files
    - These hardly  vary between projects
    - app.yami: direct all non-static requests to main.py
    - main.py: initialize Django and send it all request
    - settings.py: change only a few settings from defaults
- Project lay-out
    - static/*: static files: serverd directly by App Engine
    - myapp/*.py: app-specific python code
        urls.py, views.py, models.py, tests.py and more
    - templates/*.html: templates ( or myapp/templates/*.html)

=== Minimal app.yaml

application: myapp         # .appspot.com
version: 1

runtime: python
api_version: 1

handlers:
- url: /static
    static_dir: static
- url: .*
    script: main.py

=== The Most Minimal main.py
import os
from google.appengine.ext.webapp import util

os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from django.core.handlers import wsgi

def main():
    app = msgi.WSGIHandler()
    util.run_wsgi_app(app)

if __name__ == '__main__':
main()

=== BARE Minimal Settings.py
import os
DEBUG = os.environment['SERVER_SOFTWARE'].startswith('Dev')
INSTALLED_APPS( 'myapp', )
MIDDLEWARE_CLASSES = ()
ROOT_URLCONT = 'myapp.urls'
TEMPLATE_CONTEXT_PROCESSORTS = ()
TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), 'template'),)
TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.load.template.source',)
T2 = 'UTC'

AppEngine application always runs in UTC

=== Google App Engine Django Helper

- Separate Open source project
    By two Googlers, Matt Brown and Andy smith
    http://code.google.com/p/google-app-engine-django
- Takes care of monkey-patching Django
    Loads newer version of Django if available in app root dir
- Enables using standard Django project management tool
    For unit tests and fixture loading ( development only )
- Comes with boilerplate app.yaml, main.py, settings.py

=== Getting Started

- Download and unzip appengine_helper_for_django_rN.zip
- Rename directory to 'mysite' or whatever you like
- This  becomes your project root; contents;
    COPYING, KNOWN_ISSUES, Makefile, README
- __init__.py        (empty)
- app.yaml        (edit application: only )
- appengine_django/...    (helper code lives here )
- main.py        (generic bootstrap )
- manage.py        (Django management script )
- settings.py        ( edit settings here )
- urls.py        ( edit URL mappings here )

=== Changing the Standard Set-up

- Edit app.yaml to set your application id ( can do this later )
- Create subdirectory myapp
- Edit settings.py, adding 'myapp' to INSTALLED_APPS
- In myapp, create:
- __init__.py        (empty)
- views.py        (add your view code here )
- models.py        (add your model definitions here )
- tests.py        ( add your unit tests here )
To use Django HEAD, copy the django packages here
/usr/local/google_appengine must be your App Engine SDK

=== Your First View

- Edit urls.py:
    from django.conf.urls.defaults import *
    urlpatterns = patterns('myapp.views',(r'^$', 'index'),
        # ...more here later...
    )
- Edit myaap/views.py:
    from django.httpo import HttpResponse
    def index(request):
        return HttpResponse('Hello World')
- Run it: ./manage.py runserver
- Point your browser to: http://localhost:8080

=== Using Models

- Edit models.py:
    from google.appengine.ext import db
    from appengine_django.models import BaseModel
    class Shout(BaseModel):       # subclass of db.Model
        title = db.StringProperty(required=True)
        test = db.TextProperty()
        mtime = db.DateTimeProperty(auto_now_add=True)
        user = db.UserProperty()

- Up next:
    - write views to use models
    - Use forms derived from your models with templates
   
=== Using Forms
- I tend to put forms in views.py; do as you please
 from django.shortcuts import render_to_response
 from google.appengine.ext.db import djangoforms
 import models
 class ShoutForms(djangoforms.ModelForm):
    class Meta:
        model = models.Shout
        exclude = ['mtime'm, 'user']
    query = models.Shout.gql("ORDER BY mtime DESC")
   
    def index(request):
        return render_to_response('index.html', { 'shouts': query.run(),'form': ShoutForm()})

=== Using Templates

- Put this in templates/index.html
    {% for shout in shouts %}
   
{{ shout.user }} ; {{ shout.title }}
    {{ shout.text }}
    {{ shout.mtime | timesince }}
    { % endfor %}
        {{ form }}

=== The post() Method

- Add to urls.py:
    (r'^post/$', 'post');
- Add to views.py:
    from google.appengine.api import users
    from django.http import HttpResponseRedirect
   
    def post(request):
        form = ShoutForm(request.POST)
        if not form.is_valid():
            return render_to_response('index.html', {'form':form})
    shout = form.save(commit=False)
    shout.user = users.get_current_user()
    shout.put()
    return HttpResponseRedirect('/')

=== Writing Tests

- Python has two test frameworks:
- doctest.py
    - Tests are interactive sessions captured in doc stings
    - Really easy to get started
    - Some caveats (output must be reproducible)
   
- unitest.py
    - Tests are methods in classes derived from unittest TestCase
    - Modeled after JUnit

=== Running Tests

- Use whichever test framework you like
    ./manage.py test myapp
- Runs all tests found in myapp
    - Specifically:
        - looks for doctest and unittest tests
        - looks in models.py and tests.py

=== Example Doc Tests

- Put this in myapp/tests.py
r"""
 from django.test.client import Client
 from models import *
 c = Client()
 r = c.get('/')
 r.status_code
200
 r.content
'\n\n
\n'
 s = Shout(title='yeah', text='hello world')
 key = s.put()
 r = c.get('/')
 r.stauts_code
200
assert 'yeah' in r.content
"""

=== Test Fixtures
- ./manage.py: manages the datastore used
- ./manage.py runserver: uses a persistent datastore in /tmp
- ./manage dumpdata: writes datastore contents to stdout
    - Format can be JSON (default) or XML ( not fully supported yet )
- ./manage loaddata: loads datastore from a file
- Fixtures can also be added to TestCase classes:
   
    from django.test import TestCase
    class MyTestCase(TestCase):
        fixtures = ['test_data.json', 'more_test_data']
        def testSomething(self):
            ...

Painless Python for Proficient Programmers Part II

== Function definition and calling
- def ():
    - compiled, not executed
- call name() executes the body
- last 0+ parms may have "default values", = (expr evaluates once, at def time), then the args are optional in the call
- last O+ args may be "named", =
- may end with * (tuple of 0+ positional args) and/or ** (dict of 0+ named args )

=== Example: sum of squares
- def sumsq(a, b): return a*a+b*b
  print sumsq(23, 45)

More general, higher-abstraction:
  def sumsq(*a): return sum(x*x for x in a )

Lower-abstraction, slower but still OK:
  def sumsq(*a):
    total = 0
    for x in a: total += x*x
    return total

=== Generators
- functions with 'yield' instead of return
- each call builds and returns an iterator ( object with a next method, suitable for iterating-on e.g in a for loop )
- end of funtion raises StopIteration

def enumerate(seq):    # actually a built-in...
    n = 0
    for item in seq:
        yield n, item
        n += 1
def enumerate2(seq):    # higher-abstraction variant:
    from itertools import izip, count
    return izip(count(), seq)


=== An endless generator
def fibonacci():
    i = j = 1
    while True:
        r, i, j = i, j, i + j
        yield r
for rabbits in fibonacci():
    print rabbits,
    if rabbits > 100: break

1 1 2 3 5 8 13 21 34 55 89 144

=== Closures
- def is an executable statement ( each execution creates  a new function object), and scoping is lexical, so...

def makeAdder(addend):
    def adder(augend):
        return augend + addend
    return adder
a23 = makeAdder(23)
a42 = makeAdder(42)
print a23(100), a42(100), a23(a42(100))
123 142 165

=== Decorators
@
def etc, etc

- is like:
    def etc, etc
    = ()
- Handy syntax to apply a Higher-Order-Function(HOF);
    may be a name or a call (HOF2 ...!)


=== Classes ("new-style")

class ():
 - is usually a series of def and assignment statements; names defined or assigned become attributes of new class object (functions become "methods")
- attributes of any base are also attributes of the new class, unless "overridden" (assigned or defined in the body)

=== Instantiating a class
To create an instance, just call the class:
class eg(object):
    cla = []            # class attributes
    def __init__(self):     # initializer
        self.ins = {}   # instance attributes
    def meth1(self, x ):    # a method
        self.cla.append(x)
    def meth2(self, y, z):  # another method
        self.ins[y] = z
es1 = eg()
es2 = eg()

=== Classes and instances
 print es1.cla, es2.cla, es1.ins, es2.ins
[] [] {} {}

es1.meth1(1); es1.meth2(2,3)
es2.meth1(4); es2.meth2(5,6)
print es1.cla, es2.cla, es1.ins, es2.ins
[1,4] [1,4] { 2: 3} {5: 6}

print es1.cla is es2.cla
True
print es1.ins is es2.ins
False
=== Look-up Mechanics
inst.method(arg1, arg2)
    == type(inst).method(inst, arg1, arg2)
    inst.name [[whether it later gets called, or not ...!]]
    === ("descriptors" can change this behavior...)
1. first try inst.__dict__['name']
2. else try type(inst).__dict__['name']
3. else try each of type(inst).__bases__
4. finally try type(inst).__getattr__(inst, 'name')
5. if all else fails, raise AttributeError

=== Subclassing

class sub(eg):
    def meth2(self, x, y=1): # override
        eg.meth2(self,x,y)    # super-call
        # or: super(sub, self).meth2(x,y)
class repeater(list):
    def append(self,x):
        for i in 1, 2:
            list.append(self, x)
class data_overrider(sub):
    cla = repeater()

=== Properties

class blah(object):
    def getter(self):
        return ...
    def setter(self, value): ...
        name = property(getter, setter)
    inst = blah()
Now ...

    print inst.name # like inst.getter()
    inst.name = 23  # like inst.setter(23)

=== Why properties matter:

- never "hide" attributes behind getters/setters "for flexibility"
- instead, expose interesting attributes directly
- if/when in a future release you need a getter and/or a setter ...
- write the new needed methods
- wrap them up into a property
- and all client-code of the class need NOT change!
- down with boilerpalte! NEVER code like:
    def getFoo(self): return self._foo
    def setFoo(self, foo): self._foo = foo
just name the attribute foo ( not_foo ) so it's directly available !

=== Operator Overloading

"special methods" have names starting and ending with __ ( double-underscore AKA "dunder"):
__new__, __init__, __del__  # ctor, init, finalize
__repr__, __str__, __int__  # convert
__lt__, __gt__, __eq__ ...  # compare
__add__, __sub__, __nul__ ... # arithmetic
__call__, __hash__, __nonzero__ ...
__getattr__, __setattr__, __delattr__
__len__, __iter__, __contains__
__get__, __set__, __enter__ , __exit__ ...

Python calls a type's special methods appropriately when you perform operations on instances of the type

=== An endless iterator

class Fibonacci(object):
    def __init__(self): self.i = self.j = 1
    def __iter__(self): return self
    def next(self):
        r, self.i = self.i, self.j
        self.j += r
        return r
    for rabbits in Fibonacci():
        print rabbits,
        if rabbits > 100: break

1 1 2 3 5 8 13 21 34 55 89 144

=== Built-in Functions

- Don't call special methods directly; let built-in functions and operators do it right !
    e.g: abs(x), neverx.__abs__()
- many interesting built-in functions:

  abs any all chr cmp compile dir enumerate eval getattr hasattr hex id intern isinstance iter len max min oct open ord pow range repr reversed round setattr sorted sum unichr xrange zip

- many, MANY other important types and functions in standard library modules (array, bisect, cmath, collections, contextlib, copy, functools, heapq, inspect, intertools, operator, pprint, Queue, random, re, StringIO, struct weakref, ...)

=== Example: indexing a textfile

# Build map word -> [ list of line #s containing it ]
indx = {}
with open(filename) as f:
    for n, line in enumerate(f):
        for word in line.split():
            indx.setdefualt(word, []).append(n)
# emit it in alphabetical order
for word in sorted(indx):
    print "%s:" % word,
    for n in indx[word]: print n,
    print

=== Or, a bit simpler, with a little stdlib help...

import collections
indx - collections.defaultdict(list)
with open(filename) as f:
    for n, line in enumerate(f):
        for word in line.split():
            indx[word].append(n)
    for word in sorted(indx):
        print "%s:" %word,
        for n in indx[word]: print n,
        print

=== Other possibilities given the indx map
# the 7 most popular words in the textfile
import heapq
for w in heapq.nlargest(7, indx, key=indx.get):
    print w
# lines that contain N given words
def enwhack(*words):
    words = list(words)
    r = set(indx[words.pop()])
    for w in words: r &= set(indx[w]) # intersection
    return sorted(r)

=== Importing modules
- import modulename
- from some.given.package import modulename
    - then, in either case, use modulename.blah
    - some abbreviations ( not necessarily recommended...):
        - alias module name with an 'as' clause:
        - import thisnameisfartoolong as z
            - then use z.blah
    - from thisnameisfartoolong import blah
    - from thisnameisfartoolong import * # not recommended

=== Import example
import math
print math.atan2(1, 3)
# emits 0.321750554397
print atan2(1, 3)
# raises a NameError exception
from math import atan2
# injects atan2 into current namespace
# handy for interactive use, often confusing in "real" programs
# and, always avoid (except for interactive use)...
from math import *

=== Coding your own modules
- any python source wot.py is a module
- just import wot
    - file must be in a directory (or zip file) listed in sys.path
    - also importable: the bytecode file(wot.pyc) which the python compiler created the first time you import the source
- also importable: binary native-code extension files(wot.pyd) coded in c  and using python's C API (or other compiled-to-native-code languages and tools: pyrex, Cython, SWING,...)
- Note: Google App Engine only Supports .py modules !
Every python program is a module

=== What's a module?
- a module is a simple object with attributes  -- the attributes are the modules's "top-level" names
- bound by assignment, or assigning-statements: class, def, import, from
- a modules's attributes are also known as "global variables" of the module ( there are no "global" globals!)
- a module's attribues can also be bound/unbound/rebound "from the outside" (also known as "monkey patching")
    - not good practise, but sometimes useful for testing with Mock and similar design patterns
    - do however consider the Dependency injection DP alternative

=== Modules are singletons
- the most natural and Pythonic form (automatic singletons)
- the first import loads the module ( compiling if needed ) and executes it, every other import just accesses it, specifically by using sys.modules[modulename]
- if you really need a class ( for overloading, getattr, &c)...
    import sys
    class _hidden(object): ...
    sys.modules[__name__] = _hidden()

=== Packages
- a package is a module containing other modules ( and maybe sub-packages &c )
- lives in a directory containing a file named __init__.py:
    __init__.py is the "module body"
    often empty (just "tagging" the directory as a package)
    a package's module are the dir's .py files
    subpackages are subdirs which need to contain __init__.py
- the parent directory must be on sys.path
- import foo.bar or from  foo import bar

=== " Batteries included "
    - The standard python library has > 200 modules ( plus many, many more for unit-tests, encoding/decoding, demos)
    - some are pure Python modules, some are C-coded ones
    - The App engine supports Any pure-Python modules
    - and MOST standard library C-coded modules
        -( with very few specific execptions, such as, sockets, threads)
    - plus, some specific API's ( Datastore, users, urlfetch, mail)
    - also, any pure-python modules you include with your app

=== A peculiar consequence
    - time needed for an expert programmer to learn well...
    - python itself ( the python language): 1-3 days
    - built-ins, special methods, metaprogramming, &c: 2-4 days
    - standard library (absolutely-crucial modules): 10-15 days
    - all the standard library: 30-50 days
    - all third-party offerings: ..

=== To find more nifty modules...
- http://cheeseshop.python.org/pypi: 4000+ packages, and counting!
- It's always fun to roll your own, but...:-)
- time to learn all about 4000+ packages: well, hmmmmm

=== Online resources ( to get started )
- www.python.org
- www.diveintopython.org
- (usenet) comp.lang.python
- (Mailing list) help @ python.org
- Any good search engine !

python good material


Python
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Python Tips, Tricks, and Hacks

1 Quick Tricks
Tell you pain to inspire people not to share the pain.
1.1  Four kinds of Quotes
Python uses single quotes for one thing and double quotes for another. Python lets you use both, although not interchangeably. A triple Quote, ‘’’(three single quotes) “””(three double quotes)

Code:
 print """I wish that I'd never heard him say, '''She said, "He said, 'Give me five dollars'"'''"""
o/p: I wish that I'd never heard him say, '''She said, "He said, 'Give me five dollars'"'''

1.2  Truthfulness of Various Objects
Unlike some programming languages, Python types are false if empty, and true if not. That means you don’t have to check, for example, that the length of a string, tuple, list or dist is 0 or is equal to an empty one. It is enough to just check the truthfulness of the object

For example, the following expressions are equivalent. Here, ‘my_object’ is a string, but it could easily be another python type
Example
my_object  = ‘Test’ # True example
# my_object = ‘’      # False example

If len(my_object) > 0:     # Not required to check like this
            Print  ‘my_object is not empty’ 
If my_object !=’’;
            Print ‘my_object is not empty’
If my_object: # an empty string will evaluate to False
            Print ‘my_object is  not empty’

Conclusion: there’s really no need to check lengths or quality if you’re only interested in if the object is empty or not

1.3  Checking if a String Contains a Substring
We can test if a list, tuple or dict contains an item by testing the expression ‘item in list’ or ‘item not in list’. I never realized that this would work for strings as well.

Ugly Code
String = ‘Hi there’ # True example
# string = ‘Good bye’           # False example
if string.find(‘Hi’) != -1:
            print success

Smart Code (simpler,cleaner)
String = ‘Hi there’ #True example
#string = ‘Good bye’ #False example
If ‘Hi’ in string:
            Print ‘success!’

1.4  Pretty-Printing a List
Using ‘join’ method we can print the string nicely

String = [‘xamma’,’yamma’,’zamma’]
Print ‘The three most recent presidents were: %s.’ % ‘,’.join(string)
#prints ‘The three most recent presidents were: xamma,yamma,zamma

The ‘join’ method turns the list into a string by casting each item into a string and connecting them with the string that ‘join’ was called on. It’s even smart enough to not put one after the last element

As an added advantage, this is pretty fast, running in linear time. Don’t ever create a string by ‘+’ing list items together in a for loop; not only is it ugly, but it takes much longer.

1.5  Integer vs. Float Division
By default, if you divide one integer, the result will be truncated into an integer. For example
Executing 5/2 returns 2

There are two was to fix this. The first and simplest way is to just turn one of the integers into a float. If the values are static, you can just append a .0 to one to make it a float: 5.0/2 returns 2.5. Alternatively, you can just cast one of the values: float(5) / 2 returns 2.5

The other way will result in cleaner code, but you must make sure none of you code is relying on this truncation. You can do a from __future__import division to change python to always return a float as the result of a division. After such an import, 5/2 will return 2.5. If you still need to use the truncating integer division somewhere, you can then use the // operator: 5//2 will always return 2

Examples
5/2      #Returns 2
5.0/2   # Returns 2.5
Float(5)/2 # Returns 2.5
5//2        # Returns 2

From __future__import division
5/2                   #returns 2.5
5.0/2                #Returns 2.5
Float(5)/2       # Returns 2.5
5//2                  # Returns 2

If you want your code to be future-proof, use the // operator if you want truncating division, no matter if you are doing a from __future__import division or not

1.6  Lambda Fuctions
Sometimes you need to pass a function as an argument, or you want to do a short but complex operation multiple times.  You could define your function the normal way, or you could make a lambda function, a mini-function that returns the result of a single expression. The two definitions are completely identical

def add(a,b): return a+b

lambda way  -> add2 = lambda a,b: a+b

The advantage of the lambda function is that it is in itself an expression, and can be used inside another statement. Here’s an example using the ‘map’ function, which calls a function on every element in a list, and returns a list of the results.

Example:
squares = map(lambda a: a*a, [1,2,3,4,5])
#squares is now [1,4,9,16,25]

Without a lambda, you’d have to define the function separately. You’ve just saved a line of code and a variable name

Syntax: Lambda Functions
A lambda function has the syntax: lambda variable(s) : expression
Variable(s) – a comma-separated list variable or variables that the function can receive. You can’t use keywords, and you don’t want these to be in parentheses (a mistake I started making for a couple of months and wondered why my lambdas never workd)
Expression – an inline python expression. Scope includes local scope and variable(s). This is what the function returns.

Lists
a)      List Comprehensions
List can fit in a for loop, an if statement, and an assignment all in one line. In other words, you can map and filter a list in one expression
a.1  Mapping the List
Trying to square every element

Numbers = [1,2,3,4,5]
Squares = []
For number in numbers:
            Squares.append(number*number)
#Now, squares should have [1,4,9,16,25]

Map function, can be done something like below
Numbers = [1,2,3,4,5]
Squares = map(lambda x: x*x, numbers)
#Now, squares should have [1,4,9,16,25]

The cleaner way !
Numbers = [1,2,3,4,5]
Squares = [ number*number for number in numbers]
# Now, squares should have  [1,4,9,16,25]
This does the exact same thing as the previous two examples
b)     Filtering the List
Example, we want to remove every element with a value equal to or greater that 4?

Numbers = [1,2,3,4,5]
Numbers_under_4 = []
For number in numbers:
            If number < 4:
                        Numbers_under_4.append(number)
# Now, numbers_under_4 contains [1,4,9]

Better one
Numbers = [1,2,3,4,5]
Numbers_under_4 = filter(lambda x: x <4, numbers)
#now, numbers_under_4 contains [1,2,3]

Filter accepts a function and a list. It evaluates for every list element and if the function evaluates evaluates to true, that list element is included in the final list.

Numbers = [ 1,2,3,4,5]
Numbers_under_4 = [number for number in numbers if number < 4]
# now, numbers_under_4 contains [1,2,3]

c)      Map and filter at Once
Example:  ‘map’ and ‘filter’ a list at the same time.

Numbers = [1,2,3,4,5]
Squares = []
For number in numbers:
      If number < 4:
                  Squares.append(number*number)
#squares is now [1,4,9]

Numbers = [1,2,3,4,5]
Squares = map(lambda x: x*x, filter(lambda x: x < 4, numbers))
# squares is now [1,4,9]

Numbers = [1,2,3,4,5]
Squares = [ number*number for number in numbers if number < 4]
# square is now [1,4,9]

d)     Generator Expressions
There is a downside to list comprehensions: the entire list has to be stored in memory at once. Eventually this becomes pretty inefficient

Generator expressions are newish in python 2.4, generator expressions do not load the whole list into memory at once, but instead create a ‘generator object’ so only one list element has to be loaded at any time. If you’re just passing it off to something that takes any iterable object – like a for loop – you might as well use a generator function

Generator expressions have the same syntax as list comprehensions, but with parentheses around the outside instead of brackets

Numbers = (1,2,3,4,5) # Since we’re going for efficiency, I’m using a tuple instead of a list
Squares_under_10 = (number*number for number in numbers if number*number < 10)
#squares_under_10 is now a generator object, from which each successive value can gotten by calling next()
For square in squares_under_10:
      Print square
#prints ‘1 4 9’

This is ever so slightly more efficient than using a list comprehension. Use list comprehensions if you need the entire list at once for some reason. If neither of these is true, just do whatever you want. It’s probably good practice to use generators expressions unless there’s some reason not to, but you’re not going to see any real difference in efficiency unless the list is very large

As a final note, generator expressions only need to be surrounded by one set of parentheses. So, if you’re calling a function with only a generator expression, you only need one set of parentheses. This is valid python: some_function(item for item in list)

Nested ‘for’ Statements
List comprehensions and generators expressions can be used for more than just mapping and filtering

    for y in (0,1,2,3):
        if x < y:
            print (x, y, x*y),
# prints (0, 1, 0) (0, 2, 0) (0, 3, 0) (1, 2, 2) (1, 3, 3) (2, 3, 6)
 
Better Example
print [(x, y, x * y) for x in (0,1,2,3) for y in (0,1,2,3) if x < y]
# prints [(0, 1, 0), (0, 2, 0), (0, 3, 0), (1, 2, 2), (1, 3, 3), (2, 3, 6)
 
Print [(x, y, x * y) for x in (0,1,2,3) for y in (0,1,2,3) if x < y ]
# prints [(0,1,0), (0,2,0), (0,3,0), (1,2,2), (1,3,3), (2,3,6)]
 
Syntax: List Comprehensions and Generator Expressions
A list comprehension has the syntax: [ element for variable(s) in list if condition ]
A generator expression has the syntax: ( element for variable(s) in list if condition )
 
List                        anything has can be treated as a list or iterator
Variable(s)           variable or variables to assign the current list element to, just like in a regular for loop
Condition             an inline python expression. Scope again includes local scope and variable(s). If this evaluates to true, item will be included in result
element                an inline python expression. Scope includes the local scope and variables(s). This is the actual element that will be included in the result
 
The for variable(s) in list bit can be repeated indefinitely
 
Reducing a List
 
Numbers = [1,2,3,4,5]
Result = 1
For number in numbers:
               Result *= number
# result is now 120
 
Use the built-in function ‘reduce’, which accepts a function that takes two arguments
Numbers = [1,2,3,4,5]
Result = reduce(lambda a,b: a*b, numbers)
#result in now 120
 
Iterating over a List: range, xrange and enumerate
Passing a value to ‘range’ gives you a list of counting integers from 0 to the value -1, inclusive. In other words, it gives you the index values of a list with that length. ‘xrange’ does the same thing, except a bit more efficiently: it doesn’t load the whole list into memory at once
 
Strings = [‘a’,’b’,’c’,’d’,’e’]
For index in xrange (len(strings)):
               Print index
# prints ‘0  1 2 3 4 ‘
Python has a really awesome built-in function called ‘enumerate’ that will give you both. Enumerate-ing a list will return an iterator of index, value pairs
 
Strings = [‘a’,’b’,’c’,’d’,’e’]
For index, string in enumerate(strings):
               Print index,string
#prints ‘0 a 1 b 2 c 3 d 4  e 5’
 
As an added advantage, enumerate is quite a bit cleaner and more readable than xrange(len()). Because of this, ‘range’ and ‘xrange’ are probably only useful if you need to create a list of values from scratch for some reason, instead of from an existing list
 
Checking a Condition on Any or Every List Element
Numbers = [1,10,100,1000,10000]
If [ number for number in numbers if number < 10]:
               Print ‘At least one element is over 10’
#Output: ‘At least one element is over 10’
If none of the elements satisfy the condition, the list comprehension will create an empty list which evaluates as false. Otherwise, a non-empty list will be created, which evaluates as true
 
Build-in ‘any’ function
Numbers = [1,10,100,1000,10000]
If any(number < 10 for number in numbers):
               Print ‘Success’
# output : ‘Success!’
 
Numbers = [1,2,3,4,5,6,7,8,9]
If len(numbers) == len([number for number in numbers if number < 10]):
               Print ‘success’
#Output: ‘Success’
 
The built-in ‘all’ function. As you might expect, it’s smart enough to bail after the first element that doesn’t match, returning ‘False’
 
Numbers = [1,2,3,4,5,6,7,8,9]
If all (number < 10 for number in numbers):
               Print ‘Success’
#Output: ‘Success!’
 
Combining Multiple Lists, item by item 
The built-in ‘zip’ function can be used, well , to zip lists together. It returns a list of tuples, where the nth tuple contains the nth item from each of the passed in lists

Letters = [‘a’,’b’,’c’]
Numbers = [1,2,3]
Squares = [1,4,9]
Zipped_list  = zip(letters, numbers, squares)
#zipped_list contains [(‘a’,1,1),(‘b’,2,4),(‘c’,3,9)]

A Few More List Operators
The following are all built-in functions that can be called on any list or iterable

Max – Returns the largest element in the list
Min – Returns the smallest element in the list
Sum – Returns the sum of all elements in the list

Advanced Logic With Sets
Sets differ from lists in that they enforce uniqueness (they can’t contain more than one of the same item) and are unordered. The most common thing I want to do is to make sure my list is unique. This is easy; I just have to convert it to a set and check if the length is the same

Numbers = [1,2,3,3,4,1]
Set (numbers)
# returns set ([1,2,3,4])
If len (numbers) == len(set(numbers)):
            Print ‘List is unique!`
#In this case, doesn’t print anything
Of course, you can convert the set back into a list, but remember that ordering is not preserved.  http://docs.python.org/library/stdtypes.html#types-set

Dictionaries
Constructing Dictionaries with Keyword Arguments
Dict(a=1, b=2, c=3)
#returns {‘a’:1, ‘b’:2,’c’:3}
This might be a bit cleaner than a ‘regular’ dictionary creation depending on your code; there are less quotes floating around

Dicts to Lists
Turning a dictionary into a list or an iterator is easy. To get a list of keys, you can just case the dict into a list. It’s cleaner, though to call .keys() on the dictionary to get a list of the keys, or .iterkeys() to get an iterator. Similarly, you can call .values() or .itervalues() to get a list or iterator of dictionary values.
To preserve both keys and values, you can turn a dict into a list or iterator of 2-item tuples by using .items() or .iteritems().

Dictionary = {‘a’:1,’b’:2,’c’:3}
Dict_as_list = dictionary.items()
#dict_as_list now contains [(‘a’,1), (‘b’,2),(‘c’,3)]

Lists to Dicts
You can reverse the process, turning a list of 2-element lists or tuples into a dict
Dict_as_list = [[‘a’,1],[‘b’,2],[‘c’,3]]
Dictionary = dict(dict_as_list)
#dictionary now contains {‘a’:1,’b’:2,’c’:3}

With the ‘keyword arguments’ method
Dict_as_list = [[‘a’,1],[‘b’,2],[‘c’,3]]
Dictionary = dict(dict_as_list, d=4, e=5)
#dictionary now contains {‘a’:1,’b’:2,’c’:3,’d’: 4,’e’: 5}

Dictionary Comprehensions
Emails = {‘Rama’: ‘x@example.com’,’Gyan’:’y@example.com’,’mady’:’z@example.net’}
Email_at_dotcom = dict([name,’.com’ in email] for name, email in emails.iteritems())
#email_at_dotcom now is {‘x’:True, ‘y’:True,’z’:False}

Selecting Values
The Right Way
Python now supports the syntax ‘value_if_true if test else value_if_false’
Test  = True
#test = False
Result = ‘Test is True’ if test else ‘Test is False’
#result is now ‘Test is True’

Test1 = False
Test2 = True
Result = ‘Test1 is True’ if test1 else ‘Test1 is False, test2 is True’ if test2 else ‘Test1 and Test2 are both False’
O/p: Test1 is False, test2 is True
The first if/else is evaluated first, and if test1 is false the second if/else is evaluated.

The and/or Trick
In python, ‘and’ and ‘or’ are complex creatures. ‘and’ returns the first false value, or the last value if all are true. In other words, if the first value is false it is returned, otherwise the last value is returned. The result of this is something you would expect: if both are true, the last value is returned, which is true and will evaluate to True in a Boolean test. If one is false, that one is returned and will evaluated to False in a Boolean test

Or-ing two expressions, if the first value is true it is returned, otherwise the last value is returned. So, if both are false, the last value is returned, which is false and will evaluate to False in a Boolean test. If one is true, that one is returned and will evaluate to True in a Boolean test

Test = True
#test = false
Result = test and ‘test is true’ or ‘test is false’
#result is now ‘Test is true’

Explanation:
If test is true, the and statement skips over it and returns its right half, here ‘Test is True’ or ‘Test is False’. As processing continues left to right, the or statement returns the first true value, ‘Test is True’

If test if false, the and statement returns test. As processing continues left to right, the remaining statement is test or ‘Test is False’. Since test is false, the or statement skips over it and returns its right half, ‘Test is False’

Using True and False as Indexes
Another way to select values is to use True and False as list indexes, taking advantage of the fact that False == 0 and True ==1
Test = True
#test = False
Result = [‘Test is False’,’Test is True’][test]
#result is now ‘Test is True’

Functions
Default Argument Values are Only Evaluated Once

def function(item, stuff = []):
            stuff.append(item)
            print stuff
function(1)
#print ‘[1]’
Function(2)
#print ‘[1.2]’ !!!
The default value for a function argument is only evaluated once, when the function is defined. Python simply assigns this value to the correct variable name when the function is called.
Python doesn’t check if that value (that location is memory) was changed. It just continues to assign that value to any caller that needs it. So, if the value is changed, the change will persist across function calls. The solutions- don’t use mutable objects as function defaults.

Better Code !
Def function(item, stuff = None):
            If stuff is None:
                        Stuff = []
Stuff.append(item)
Print stuff
Function(1)
#prints ‘[1]’
Function(2)
#prints ‘[2]’, as expected
None is immutable, so we’re safe from accidently changing value of the default.

Force Default Arguments to be Evaluated Each Time
From copy import deepcopy
Def resetDefaults(f):
            Defaults = f.func_defaults
            Def resetter(*args, **kwds):
                        f.func_defaults = deepcopy(defaults)
                        return f(*args, **kwds)
            resetter.__name__ = f.__name__
            return resetter
Simply apply this decorator to your function to get the expected results

@resetDefaults #This is how you apply a decorator
Def function(item, stuff = []):
            Stuff.append(item)
            Print stuff
Function(1)
#prints ‘[1]’

Function(2)
#prints ‘[2]’ , as expected

Arbitrary Numbers of Arguments
Python lets you have arbitrary numbers of arguments in your functions. First define any required arguments, then use a variable with a ‘*’ prepended to it. Python will take the rest of the non-keyword arguments, put them in a list or tuple, and assign them to this variable:

Def do_something(a,b,c, *args):
            Print a, b, c, args
Do_something(1,2,3,4,5,6,7,8,9)
#prints ‘1,2,3, (4,5,6,7,8,9)’
After you’ve defined all other arguments, use a variable with ‘**’ prepended to it. Python will take the rest of the keyword arguments, put them in a dictionary, and assign them to this variable

Def do_something_else(a, b, c, *args, **kwargs):
            Print a, b, c, args, kwargs
Do_something_else(1,2,3,4,5,6,7,8,9, timeout=1.5)
#prints ‘1,2,3, (4,5,6,7,8,9), {“timeout”: 1.5}’

Caveat
def do_something(a, b, c, actually_print, *args):
            If actually_print:      
                        print a, b, c, args
do_something(1, 2, 3, True, 4, 5, 6)

The only way to pass ‘actually_print’ in this situation is to pass it as a non-keyword argument
do_something(1, 2, 3, True, 4, 5, 6)
#Result is ‘1, 2, 3, (4, 5, 6)’

Passing a List or Dictionary as Arguments
Since you can receive arguments as a list or dictionary, you can send arguments to a function from a list or dictionary

To send a list as non-keyword arguments, just prepend it with a ‘*’
args = [5,2]
pow(*args)
# returns pow(5,2), meaning 5^2 which is 25

To send a dictionary as keyword arguments (this is probably more common), prepend it with ‘**’
def do_something(actually_do_something=True, print_a_bunch_of_numbers=False):
            if actually_do_something:
                        print ‘something has been done’
            if print_a_bunch_of_numbers:
                        print range(10)
kwargs = {‘actually_do_something’: True, ‘print_a_bunch_of_numbers’: True}
do_something(**kwargs)
#prints ‘Something has been done’, then ‘[0,1,2,3,4,5,6,7,8,9]’

Decorators
A decorator is a function that wraps another function: the main function is called and its return value is passed to the decorator. The decorator then returns a function that replaces the wrapped function: the main function is called and its return value is passed to the decorator. The decorator then returns a function that replaces the wrapped function as far as the rest of the program is concerned.

Def decorator1(func):
            Return lambda: func() + 1
def decorator2(func):
            def print_func():
                        print func()
            return print_func
@decorator2
@decorator1
def function():
            return 41
function()
#prints ‘42’

In this example, ‘function’ is passed to ‘decorator1’. ‘decorator1’ returns a function that calls ‘function’ and adds 1. This function is then passed to ‘decorator2’, which returns a function that calls the function returned by ‘decorator1’ and prints the result. This last function is the function you are actually calling when you call ‘function’

This example does the exact same thing, but more verbosely and without decorators:
def decorator1(func):
            return lambda: func() + 1
def decorator2(func):
            def print_func():
                        print func()
            return print_func
def function():
            return 41
function = decorator2(decorator1(function))
function()
#prints ‘42’

Switch Statements’ using Dictionaries of Functions
For example, say you’re handling keystrokes and you need to call a different function for each keystroke

def key_1_pressed():
            print ‘Key 1 pressed’
def key_2_pressed():
            print ‘key 2 pressed’
def key_3_pressed():
            print ‘key 3 pressed’
def unknown_key_pressed():
#          print ‘unknown key pressed’

In python, you would typically use elif’s to choose a function
Keycode = 2
If keycode == 1:
            Key_1_pressed()
elif keycode == 2:
            Key_2_pressed()
elif number == 3:
            Key_3_pressed()
else:
            Unknown key pressed()
# prints ‘key 2 pressed’

But you could also throw all the functions in a dictionary, and key them to the value you’re switching on. You could even check see if the key exists and run some code if it doesn’t

Keycode = 2
functions = {1: key_1_pressed, 2: key_2_pressed, 3: key_3_pressed }
functions.get(keycode, unknown_key_pressed) ()

Classes
Passing ‘self’ Manually
Methods are just regular functions that when called from an instance are passed that instance as the first argument (usually called self ). If for some reason you’re not calling the function from an instance, you can always pass the instance manually as the first argument.

Class Class:
            def a_method(self):
                        print ‘Hey a method’
instance = Class()
instance.a_method()
#prints ‘Hey a method’, somewhat unsurprisingly. You can also do:
Class.a_method(instance)
#prints ‘Hey a method’
Internally, these statements are exactly the same

Checking for Property and Method Existence
Need to know if a particular class or instance has a particular property or method? You can use the built-in ‘hasattr’ function to check; it accepts the object and the attribute (as a string) to check for. You use similarly to the dict ‘has_key’ method

class Class:
            answer = 42
hasattr(Class, ‘answer’)
#returns True
Hasattr(Class, ‘question’)
#returns False

You can also check for existence of and access the property in one step using the built-in function ‘getattr’. Getattr also accepts the object and the attribute, as a string, to check for.

class Class:
            answer = 42
getattr(Class, ‘answer’)
#returns 42
getattr(Class, ‘question’,’What is six times nine?’)
#returns ‘What is six times nine?’
getattr(Class, ‘question’)
#raises AttributeError

Don’t overuse ‘hasattr’ and ‘getattr’. If you’ve written your class in manner where you need to keep checking to see it a property exists, you’ve written it wrong. Just always have the value exist and set it to ‘None’ if it’s not being used. These functions are best used for handling polymorphism, that is, allowing your function/class/whatever to support different kinds of objects

Modifying Classes After Creation
You can add, modify or delete a class property or method long after the class has been created, and even after it has been instantiated. Just access the property or method as Class.attribute. No matter when they were created, instances of the class will respect these changes

class Class:
            def method(self):
                        print ‘Hey a method’
instance = Class()
instance.method()
#prints ‘Hey a method’

def new_method(self):
            print ‘New method wins!’
Class.method = new_method
Instance.method()
#prints ‘New method wins!’
Pretty awesome. But don’t get carried away

Creating Class Methods
Occassionally when writing a class you want to include a function that is called from the class, not the instance. Perhaps this method creates new instances, or perhaps it is independent of any properties of any individual instance. Python actually gives you two ways to do this, depending if your method needs to (or should) know about which class called it. both involves applying decorators to your methods

A ‘class method’ receives the class as the first argument, just as a regular instance method receives the instance as the first argument. So, the method is aware if it is being called from its own class or from a subclass.
A ‘static method’ receives no information about where it is called; it is essentially a regular function, just in a different scope.
Class and static methods can be called straight from the class, as Class.method(), or from an instance as Class().method(). The instance is ignored except for its class. Here’s an example of each , along with a regular instance method

class Class:
            @classmethod
            Def a_class_method(cls):
                        Print ‘I was called from class %s’ % cls
            Def an_instance_method(self):
                        Print ‘I was called from the instance %s’  % self
Instance = Class()
Class.a_class_method()
Instance.a_class_method()
#both print ‘I was called from class __main__.Class’
Class.a_static_method()
Instance.a_static_method()
#both print ‘I have no idea where I was called from’
Class.an_instance_method()
#raises TypeError
Instance.an_instance_method()
#prints something like ‘I was called from the instance <__main__.Class instance at 0x2e80d0>’

References

Good Book
http://tomayko.com/writings/dynamic-superclassing-in-python   


Dynamic Superclassing in Python
I would like to make it possible for people to extend the base objects with custom methods for doing whatever weird stuff people like to do

Let us have a module, biz.py, with the following class definition
class A:
            def __init__(self):
                        self.x = 5
                        self.y = 10
            def foo(self):
                        print self.x
Now, let’s say we want to add a special ‘bar’ method that would be kind of like the ‘foo’ method but would print x * 3.14. We want to be able to do this outside the original ‘biz’ module; let’s say nuge.py:

from biz import A
def bar(self):
            print self.x *3.14
A.bar = bar

Let’s give it a try:
>>> import biz, nuge
>>> a = biz.A()
>>>a.foo()
5
>>>a.bar()
15.70000001

Note that we never actually use anything from ‘nuge’ but we need to import it so that it can molest biz.A. Remember that module level statements are executed when the module is imported.

It’s also kind of interesting that you can modify the base classes of a class at anytime. Instead of adding a single method, it’s possible to add an entire class (or set the classes) into the **bases** chain, effectively grafting two (or more) classes together. Or, more precisely, dynamically superclassing A with B.

Let us redine nuge.py as follows :
Class B:
            def bar(self):
                        print self.x * 3.14
            def baz(self):
                        print self.x ** 2
# this magic moment..
A.__bases__ = (B,)

This is equivalent to specifying B as superclass when we define A:
Class A(B):

The advantage is that we can do this at runtime without modifying A’s source. The effect is that B becomes a superclass of A and B’s methods are thus available on all A instances

>>>import biz, nuge
>>>a = biz.A()
>>>a.foo()
5
>>>a.bar()
15.7
>>>isinstance(a,B)
True
I should note that assigning the tuple(B,) to A. bases overwrites the original, declared superclass(es). It is much wiser to combine the original bases value with the new class as follows:
A.__bases__ += (B,)
This appends B to the existing set of bases instead of just destroying them

Code
Note that you will never find documentation that tells you all this, you have to play around
class A:
            def __init__(self):
                        self.x = 5
def foo(self):
            print self.x
def bling(self):
            print self.x – self.y
class B:
            def bar(self):
                        print self.x * 3.14
def baz(self):
            print self.x ** 2
A.__bases__ += (B,)
a = A()
a.foo()
a.bling()
a.bar()
a.baz()
print isinstance(a,B)

Module: The most basic unit of code reusability in Python. What you usually ‘import’ Typically a single file

Package: A group of modules and other packages. Typically a folder on the filesystem, distinguished by an __init__.py file inside

Distribution: A package or group of packages meant to be installed at the same time. What you are releasing here. Source distributions are usually represented folder, called a ‘root package’, with a setup.py file inside.

Site-packages directory: The place in your filesystem where all of the installed distributions live

NOTE: Only one __init__.py file will be loaded for each virtual package, and which one is not determined until runtime. Therefore it is important to either put nothing but these lines in the file or have each file be exactly the same.

Decorators modify functions. Beginning with the basics, learn how to use decorators in a variety of ways. Execute code when a function is parsed or called. Conditionally call functions and transform inputs and outputs. Write customizable decorators that accept arbitrary arguments. And, if necessary, easily make sure your decorated function has the same signature as the original

Decorators modify functions. More specifically, a decorator is a function ‘that transforms another function’

Without decorators (code)
def  decorator_function(target):
            #Do something with target function
target.attribute = 1
return target
def target(a,b):
            return a + b
#This is what the decorator actually does
target = decorator_function(target)          

Using decorator (code)
def decorator_function(target):
            # Do something with the target function
            target.attribute = 1
            return target
#Here is the decorator, with the syntax ‘@function_name’
@decorator_function
def target(a,b):
            Return a + b
As you can see, you need to put the decorator function’s name, prefaced with a ‘@’ on the line before the ‘target function’ definition. Python internally will transform the ‘target’ by applying the decorator to it and replacing it with the returned value
>>> target(1,2)
3
>>>target.attribute
1

Does a decorator function have to return a function
No. The decorator function can return absolutely anything, and python will replace the ‘target’ function with that return value. Example

def decorator_evil(target)
            return False
@decorator_evil
def target(a,b):
            return a + b
print target   #o/p – False
print target(1,2) #o/p TypeError: ‘bool’ object is not callable

The Wrapper Function
Remember, your ‘decorator function’ can return an arbitrary function. We’ll call it the wrapper function, for reasons which will become clear in a second. The trick here is to define the wrapper function inside the ‘decorator function’, giving it access to the decorator function’s variable scope, including the target function

def decorator(target):
            def wrapper():
                        print ‘Calling function “%s”’ % target.__name__
                        return target()
#Since the wrapper is replacing the target function, assigning an attribute to the target function
#We need to assign it to the *wrapper function*.
wrapper.attribute = 1
return wrapper

@decorator
def target():
            print ‘I am the target function’

>>> target()
Calling function “target”
I am the target function
>>> target.attribute
1
As you can see, the ‘wrapper function’ can do whatever it wants to the target function, including the simple case of returning the target’s return value

Getting the Arguments (Arguments passed to the target functions)
Since the returned ‘wrapper function’ replaces the target function, the wrapper function will receive the arguments intended for the target function. Assuming you want your decorator to work for any target function, your wrapper function then should accept arbitrary non-keyword arguments and arbitrary keyword arguments, add, remove, or modify arguments if necessary, and pass the arguments to the target function

def  decorator(target):
            def wrapper(*args, **kwargs):
                        kwargs.update({‘debug’: True}) #Edit the keyword arguments – here, enable debug mode no matter what
                        print ‘Calling function “%s” with arguments %s and keyword arguments %s’ % (target.__name__, args, kwargs)
                        return target(*args, **kwargs)
            wrapper.attribute = 1
            return wrapper

@decorator
def target(a, b, debug=False):
            if debug: print ‘[Debug] I am the target function’
            return a + b
>>> target(1,2)
Calling function “Target” with arguments (1,2) and keyword arguments {‘debug’: True}
[Debug] I am the target function
3
>>>target.attribute
1

Note: you can also apply a decorator to a ‘class method’. If you decorator is always going to be used this way, and you need access to the current instance, you ‘wrapper function’ can assume the first argument is always self:

def wrapper(self, *args, **kwargs):
            #Do something with ‘self’
            print self
            return target(self, *args, **kwargs)