Thursday, June 25, 2015

Python Crash Course - part two



Lecture 1

"""
1. Functions declaration

- Basic function definition

def name(parameter1, parameter2, . . .):
''' Function documentation (optional) '''
    body
"""

# STYLE: It’s a standard practice for multi-line documentation strings to give a synopsis
# of the function in the first line (brief), follow this with a blank second line, and end
# with the rest of the information.

# You can obtain documentation string with: fact.__doc__
def fact(n):
    """Return the factorial of the given number."""
    r = 1
    while n > 0:
        r = r*n
        n = n - 1
    return r

'''
A function that doesn’t return a value is called a procedure. All Python procedures are
functions; if no explicit return is executed in the procedure body, then the special
Python value None is returned.
'''

# Assign the result
x = fact(4)

'''
2. Function parameter options

The simplest way to pass parameters to a function in Python is by position. In the first
line of the function, you specify definition variable names for each parameter; when the
function is called, the parameters used in the calling code are matched to the function’s
parameter variables based on their order.
'''

# This method requires that the number of parameters used by the calling code exactly
# match the number of parameters in the function definition, or a TypeError exception will
# be raised:

def power(x, y):
    r = 1
    while y > 0:
        r = r*x
        y = y - 1
    return r

'''
2.1 Default values

Function parameters can have default values, which you declare by assigning a default
value in the first line of the function definition, like so:

def fun(arg1, arg2=default2, arg3=default3, . . .)

Any number of parameters can be given default values.

NOTE: Parameters with default values must be defined as the _last_ parameters in the
parameter list.
'''

# STYLE: See there is not space in default parameters assignment
def power(x, y=2):
    r = 1
    while y > 0:
        r = r * x
        y = y - 1
    return r

'''
2.2 Passing arguments by parameter name

This type of argument passing is called key- word passing.
'''

power(y=2, x=3)

# Keyword passing, in combination with the default argument capability of Python
# functions, can be highly useful when you’re defining functions with large numbers of
# possible arguments, most of which have common defaults.

# Suppose you have:

# def list_file_info(size=False, create_date=False, mod_date=False, ...):
#     ...get file names...
#     if size:
#         # code to get file sizes goes here
#         if create_date:
#             # code to get create dates goes here
#         ...
#     ...
#     ...
#     return file_info_structure

# Hey do not worry - you do not need to remember all argument positions
#
# file_info = list_file_info(size=True, mod_date=True)

'''
2.3 Variable numbers of arguments

- One way handles the relatively familiar case where you wish to collect an unknown number
of arguments at the end of the argument list into a list.

- Also you can collect an arbitrary number of keyword-passed arguments, which have no
correspondingly named parameter in the function parameter list, into a dictionary.
'''

# Prefixing the _final_ parameter name of the function with a * causes all excess non-
# keyword arguments in a call of a function to be collected together and assigned as a
# tuple to the given parameter.

def maximum(*numbers):
    if len(numbers) == 0:
        return None
    else:
        maxnum = numbers[0]
    for n in numbers[1:]:
        if n > maxnum:
            maxnum = n
    return maxnum

# Here is how we call it:
maximum(2, 3, 4, 5)

# If the _final_ parameter in the parameter list is prefixed with **, it will collect all
# excess keyword-passed arguments into a dictionary. The index for each entry in the
# dictionary will be the keyword (parameter name) for the excess argument.

def example_fun(x, y, **other):
    print("x: {0}, y: {1}, keys in 'other': {2}".format(x, y, list(other.keys())))
    other_total = 0
    for k in other.keys():
        other_total = other_total + other[k]
        print("The total of values in 'other' is {0}".format(other_total))


# Here is an example call:
example_fun(2, y="1", foo=3, bar=4)

'''
3. Mutable objects as arguments

REMEMBER: Arguments are passed in by object reference!

- Immutable objects (such as tuples, strings, and numbers)
What is done with a parameter has no effect outside the function.

- Mutable objects (for example, a list, dictionary, or class instance),
Any change made to the object will change what the argument is referencing outside the
function.
'''

# Example is always better:
def f(n, list1, list2):
    list1.append("add new value")
    list2 = ["a", "completely" , "new", "value"]
    n = n + 1

x = 5         # for n
y = [1, 2]    # for list1
z = [3, 4]    # for list2. Be careful!!

f(x, y, z)
print x, y, z

'''
At the begining:
z                list2
\                 /
 \               /
  \             /
   +-----------+
   |  [3, 4]   |
   +-----------+

'''

'''
4. Local and global variables
'''

# REMEMBER: Functions define scope!

# Any variables in the parameter list of a function, and any variables created within a
# function by an assignment (like r = 1 in fact), are local to the function.

# You can explicitly make a variable global by declaring it so before the variable is
# used, using the _global_ statement.

def fun():
    global a # use top level
    a = 1
    b = 2

# Let's test it:

a = "one"
b = "two"

fun()
print a
print b


''''
5. Assigning functions to variables

Functions are first class objects!
'''


# Functions can be assigned, like other Python objects, to variables, as shown in the fol-
# lowing example:

def f_to_kelvin(degrees_f):
    return 273.15 + (degrees_f - 32) * 5 / 9

def c_to_kelvin(degrees_c):
    return 273.15 + degrees_c


abs_temperature = f_to_kelvin
abs_temperature(32)

abs_temperature = c_to_kelvin
abs_temperature(0)

# You can place them in lists, tuples, or dictionaries:
t = {'FtoK': f_to_kelvin, 'CtoK': c_to_kelvin}
t['FtoK'](32)

'''
6. lambda expressions (aka mini functions)

Taken directly from LISP!
lambda expressions are anonymous little functions that you can quickly define inline.

lambda argument1, argument2,... argumentN :expression using arguments

Why?
Often, a small function needs to be passed to another function.
'''

# Explain with examples:
import math
def square_root(x): return math.sqrt(x)

# with lambda (one parameter)
square_root = lambda x: math.sqrt(x)

# direct call
(lambda x: math.sqrt(x))(4)

# See more examples in next lecture be patient...

'''
7. Generator(or coroutine) functions

Why?
Generators functions allow you to declare a function that behaves like an iterator,
i.e. it can be used in a loop.

'''

# REMEMBER: Generators are memory efficient! Laziness helps for that :)

# Compare thies two implementations

def firstn(n):
    num, nums = 0, []
    while num < n:
        nums.append(num)
        num += 1
    return nums

sum_of_first_n = sum(firstn(1000000))

def firstn(n):
    num = 0
    while num < n:
        yield num
        num += 1

sum_of_first_n = sum(firstn(1000000))

# How could you define function that return all nonnegative integers?

def all_naturals():
    x = 0
    while True:
        yield x
        x += 1

33 in all_naturals()

'''
8. Functions in functions - dynamically creating a function (aka lexical closures)

'''

# LEGB Rule - order matters

# L. Local. Names assigned in any way within a function (def or lambda)), and not
#    declared global in that function.

# E. Enclosing function locals. Name in the local
#    scope of any and all enclosing functions (def or lambda), form inner to outer.

# G. Global (module). Names assigned at the top-level of a module file, or declared global
#    in a def within the file.

# B. Built-in (Python). Names preassigned in the built-in names
#    module: Python "kernel"

# Do you remember that functions creates scope?

def make_adder(n=1):
    def action(x):    # inner functions could use all enclosing variables
        return x + n
    return action

# using lambda
def make_adder(n=1):
    return lambda x: x + n

one_adder = maker_adder() #=> one_adder = lambda x: x + 1
one_adder(1)

# nested lambdas
one_adder = (lambda n: lambda x: x + n)(1)

# NOTE: You can't reference inner function directly

# With nested functions (closures) you create a function with state (initial value)

two_adder = make_adder(2)
two_adder(1)

'''
9. Decorators

A decorator is just a callable that takes a function as an argument and returns a
replacement function.
'''

def logger(func):
    def inner(*args, **kwargs):        # all kind of parameters
        print "Arguments were: %s, %s" % (args, kwargs)
        return func(*args, **kwargs)   # call 'real' function!
    return inner

# Here is how to use it:
@logger
def foo(x, y=1):
    return x * y # logger(foo(30))

foo(30)

'''
10. Multi-value return
'''

def divide(x, y):
    quotient = x / y
    remainder = x % y
    return quotient, remainder

all = divide(22, 7)
all, _ = divide(22, 7)
q, r = divide(22, 7)

'''
11. __ and __{some}__ functions

Naming convention:

_  for protected

__ for private

'''

Python Crash Course - part one

Lecture 2
Lecture 3 (functional programming)



"The quality of our thoughts is bordered on all sides
by our facility with language."

           --J. Michael Straczynski

# How to comment?

# What is a data type?

'''
1. Variables, assignments and expressions

- Neither a variable type declaration nor an end-of-line delimiter is necessary.
- The line is ended by the end of the line.
- Variables are created automatically when they're first assigned.
- A new assignment overrides any previous assignments.
- Assignment do not return value.
'''

x = "Hello"
print x

del x
# print x and read the traceback

# Expressions return values
x = 3
y = 5
z = (x + y) / 2


"""
2. Indentation and block structuring

Python doesn't use braces to indicate code structure; instead,
the indentation itself is used.

- It's impossible to have missing or extra braces.
- Easy to grasp the skeleton of code just by looking at it.
- Python coding styles are mostly uniform – no flavour wars!

"""

# NOTE: With assignment you include time!
# You say: "That is the value at *this* moment". This is dangerous - SICP for more details.
n = 9
r = 1
while n > 0:
    r = r * n
    n = n - 1

"""
3. Strings

Like most other programming languages, indicates strings through
the use of " or '

- You can't split a normal string across lines - use triple-quoted strings.

"""

# Backslashes can be used to escape characters, to give them special meanings.
#
# \n means the newline character
# \t means the tab character
# \\ means a single normal backslash character
# \" is a plain double-quote character

# Use 'print x' do not type only x

x = "\tDon't need a backslash\n"
x = 'Can\'t get by without a backslash'
x = "Backslash your \" character!"
x = 'You can leave the " alone'

"""
4. Numbers

- Python offers four kinds of numbers: integers, floats, complex numbers, and Booleans.
- Integers can be arbitrarily large
- The division of two integers results in a float
- Built-in numeric functions:

abs, divmod, cmp, coerce, float, hex, int, long, max, min, oct, pow, round

"""

# This is impossible integer in Java
x = 30000000000
x = x / 2.3

# Build in numeric functions
round(2.3)

# Booleans: True, False

# Most Python objects can be used as Booleans!

# The numbers 0, 0.0, and 0+0j are all False; any other number is True.
# The empty string "" is False; any other string is True.
# The empty list [] is False; any other list is True.
# The empty dictionary {} is False; any other dictionary is True.
# The empty set set() is False; any other set is True.
# The special Python value None is always False.

"""
5. 'None' value

- Like zero in arithmetic

This is enough for now.
"""

"""
6. Lists are like arrays

- Ordered collection of objects
- Lists can contain different types of elements

NOTE: Lists are recursive structure - list = element | list
"""

# Note that you don't have to worry about declaring the list
# or fixing its size ahead of time. Following example creates the list
# as well as assigns it, and a list automatically grows or shrinks in size as needed.

# empty one
x = []

# This assigns a three-element list to x
x = [1, 2, 3]

# First element is a number, second is a string, third is another list.
x = [2, "two", [1, 2, 3]]

# Python indexing is more flexible than C indexing; if indices are negative
# numbers, they indicate positions counting from the end of the list,
# with –1 being the last position in the list, –2 being the second-to-last position,
# and so forth.

x = ["first", "second", "third", "fourth"]
a = x[-1]
b = x[-2]

help([]) # or help(list)


"""
7. List slicing
"""

# Can extract or assign to an entire sublist at once, an operation known as slicing.
# Instead of entering list[index] to extract the item just after index,
# enter list[index1:index2] to extract all items including index1
# and up to (but not including) index2 into a new list.

x = ["first", "second", "third", "fourth"]
x[1:-1]
x[0:3]
x[-2:-1]

# When slicing a list, it's also possible to leave out index1 or index2.
# Leaving out index1 means "go from the beginning of the list,"
# and leaving out index2 means "go to the end of the list":

x[:3]
x[2:]

# What about x[:]?

"""
8. Modifying lists

- You can use list index notation to modify a list as well as to extract
an element from it.
- You can also use slicing
"""

x = [1, 2, 3, 4]
x[1] = "two"

# slicing
x = [1, 2, 3, 4]
x[len(x):] = [5, 6, 7]

# NOTE: len() is generic function for all type of sequences

# append at the beginning
x[:0]

# append at the end
x = [1, 2, 3]
x.append("four")

# if append list?
y = [5, 6, 7]
x.append(y)

x = [1, 2, 3]
x.extend(y)

# or use '+'
z = [1, 2, 3] + [4, 5]

# insertion
x = [1, 2, 3]
x.insert(2, "hello")
x.insert(0, "start")

# The 'del' statement is the *preferred* method of deleting list items or slices
x = ['a', 2, 'c', 7, 9, 11]
del x[1]
del x[:2]

# As a homework read about 'remove'

"""
9. List membership with the in operator

- To test if a value is in a list using the 'in' operator, which returns a Boolean value.
"""

3 in [1, 3, 4, 5]
3 not in [1, 3, 4, 5]
3 not in ["one", "two", "three"]

"""
10. List initialization with the * operator
"""
z = [None] * 4
z = [3, 1] * 2 # list multiplication operator


"""
11. Tuples

Tuples are data structures that are very similar to lists, but they
can't be modified. They can only be created.

- The main difference between tuples and lists is that tuples are immutable.
"""

x = ('a', 'b', 'c')

# REMEMBER: One-element tuples need a comma!

x = 3
y = 4
(x+y)    # adds x and y
(x + y,) # Including a comma indicates the parentheses denote a tuple

"""
12. Packing and unpacking tuples

"""

(one, two, three, four) = (1, 2, 3, 4)

# even simpler
one, two, three, four = 1, 2, 3, 4


"""
13. Converting between lists and tuples

It is important to stay immutable!
"""

list((1, 2, 3, 4))
tuple([1, 2, 3, 4])

# 'list' is a convenient way to break a string into characters
list("Hello")


"""
14. Sets

A set in Python is an unordered collection of objects used in situations where member-
ship and uniqueness in the set are main things you need to know about that object.

ATTENTION: Just as with dictionary keys (as you'll see later), the items in a set
must be immutable and hashable. This means that ints, floats, strings, and tuples can be
members of a set, but lists, dictionaries, and sets themselves can't
"""

# sets also have several set-specific operations
x = set([1, 2, 3, 1, 3, 5])
y = set([1, 7, 8, 9])

# union
x|y

# intersection
x&y

# not in both - symmetric difference
x^y

# Frozensets - Because frozensets are immutable and hashable, they can be members of other
# sets:
x = set([1, 2, 3, 1, 3, 5])
z = frozenset(x)
x.add(z)


"""
15. Strings

Strings can be considered sequences of characters, which means you can use index or slice
notation.

REMEMBER: Strings are immutable!
"""

x = "Hello"
x[0]
len(x)
8 * "Победа! "

"""
16. String methods
"""

" ".join(["join", "puts", "spaces", "between", "elements"])
x = "You\t\t can have tabs\t\n \t and newlines \n\n mixed in"
x.split()

help(split) # error
help("".split()) # something different

help("".split)

# Legacy code: string.split(text)

# Converting strings to numbers
float('123.456')

# Getting rid of extra whitespace
x = " Hello, World\t\t "
x.strip()
x.lstrip()
x.rstrip()

# String searching
x = "Mississippi"

# 'find' takes one required argument: the substring being searched for. 'find' returns the
# position of the first character of the first instance of substring in the string object,
# or –1 if substring doesn't occur in the string
x.find("ss")

help("".find)

# with optional parameter
x.find("ss", 3)

# count is used identically to any of the previous four functions but returns the number
# of non-overlapping times the given substring occurs in the given string
x.count("ss")

x.startswith("Miss")
x.endswith("pi")

"""
17. Modifying strings?!

Strings are immutable, but string objects have a number of methods that can operate on
that string and return a new string that's a modified version of the original string.
"""

x.replace("ss", "+++")

# Cool - Modifying strings with list manipulations

text = "Hello, World"

# Make it mutable list
wordList = list(text)
wordList[6:] = []
wordList.reverse()
text = "".join(wordList)
print text

"""
18. Using the format method

The format command is a powerful string-formatting mini-language and offers almost endless
possibilities for manipulating string formatting.
"""

# The format method and positional parameters
"{0} is the {1} of {2}".format("Ambrosia", "food", "the gods")

# The format method and named parameters
"{food} is the food of {user}".format(food="Ambrosia", user="the gods")

# ... it is powerful
"{0} is the food of {user[1]}".format("Ambrosia", user=["men", "the gods", "others"])

# The format specifier lets you control the fill character, alignment, sign, width,
# precision, and type of the data when it's substituted for the replacement field.

# will skip format specifiers...

# Formatting strings with %
"%s is the %s of %s" % ("Ambrosia", "food", "the gods")


"""
19. Dictionaries

Dictionaries are also called associative arrays or hashtables in other languages.
"""

# Empty dictionary is created much like an empty list, but with curly braces instead of
# square brackets

x_list = []
y_dict = {}

help(dict)

# Keys
x = {0: 'zero', 1: 'one'}

# Whereas list indices must be integers, dictionary keys are much less restricted -
# they may be numbers, strings, or one of a wide range of other Python objects.

y = {}
y["two"] = 2
y["pi"] = 3.14
y["two"] * y["pi"]

len(y)

english_to_french = {'red': 'rouge', 'blue': 'bleu', 'green': 'vert'}

# keys in a list
list(english_to_french.keys())

# values in a list
list(english_to_french.values())

# both
list(english_to_french.items())

# 'in' checks in keys
'red' in english_to_french

# Attempting to access a key that isn't in a dictionary is an error in Python!

# Alternatively, you can use the 'get' function. It returns the value associated with a key,
# if the dictionary contains that key, but returns its second argument if the dictionary
# doesn't contain the key:

print english_to_french.get('chartreuse', 'No translation')

# The difference between 'get' and 'setdefault' is that after the setdefault call, there
# is a key in the dictionary 'chartreuse' with the value 'No translation'.

print english_to_french.setdefault('chartreuse', 'No translation')

# What can be used as a key?

# Any Python object that is immutable and hashable can be used as a key to a dictionary!

"""
20. Control flow
"""

# WHILE LOOP

# while condition:    <-- : means that control structure continues
#     body
# else:               <-- difference is here (optional)
#     post-code

# 'condition' is an expression that evaluates to a true or false value. As long as it's
# True, the 'body' will be executed repeatedly. If it evaluates to False, the while loop
# will execute the 'post-code' section and then terminate.

# The break and continue statements in body or pass

# The IF-ELIF-ELSE statement

# if condition1:
#     body1
# elif condition2:
#     body2
# elif condition3:
#     body3
# .
# .
# elif condition(n-1):
#     body(n-1)
# else:
#    body(n)

# The FOR loop

# for item in sequence:
#     body
# else:
#     post-code     <-- optional

x = [1, 3, -7, 4, 9, -5, 4]
for i in range(len(x)):          # range function
    if x[i] < 0:
        print "Found a negative number at index: %s" % i

# enumerate function to loop over both the items and their index
x = [1, 3, -7, 4, 9, -5, 4]
for i, n in enumerate(x):        # enumerate
    if n < 0:
        print "Found a negative number at index: %s " % i

# Comparison and Boolean operators: <, <=, >, >=, ==, !=,  <>, or, and

# The big example :)
def contains_even_number(l):
  "Prints whether or not the list l contains an even number."
  for elt in l:
    if elt % 2 == 0:
      print "list contains an even number"
      break
    else:
      print "list does not contain an even number"

algorithms (1) cpp (3) cv (1) daily (4) emacs (2) freebsd (4) java (3) javascript (1) JSON (1) linux (2) Lisp (7) misc (8) programming (16) Python (4) SICP (1) source control (4) sql (1) думи (8)