Factory method

We may not always know what kind of objects we want to create in advance.
Some objects can be created only at execution time after a user requests so.

Examples when you may use a factory method:

  • A user may click on a certain button that creates an object.
  • A user may create several new documents of different types.
  • If a user starts a webbrowser, the browser does not know in advance how many tabs (where every tab is an object) will be opened.

Related Course:
Python Programming Bootcamp: Go from zero to hero

Factory method pattern

To deal with this we can use the factory method pattern.
The idea is to have one function, the factory, that takes an input string and outputs an object.

obj = Car.factory("Racecar")
obj.drive()

Key fact: a factory method returns (new) objects.

The type of object depends on the type of input string you specify. This technique could make your program more easily extensible also. A new programmer could easily add functionality by adding a new string and class, without having to read all of the source code.

Factory method example

The example below demonstrates a factory method. The factory method (named factory) returns a new object of either type depending on the input.

class Car(object):
 
def factory(type):
if type == "Racecar":
return Racecar()
if type == "Van":
return Van()
assert 0, "Bad car creation: " + type
 
factory = staticmethod(factory)
 
class Racecar(Car):
def drive(self): print("Racecar driving.")
 
class Van(Car):
def drive(self): print("Van driving.")
 
# Create object using factory.
obj = Car.factory("Racecar")
obj.drive()

Output:

Racecar driving.

Recursion

In English there are many examples of recursion:

  • “To understand recursion, you must first understand recursion”,
  • “A human is someone whose mother is human”.

You might wonder, what does this have to do with programming?

You may want to split a complex problem into several smaller ones. You are already familiar with loops or iterations. In some situations recursion may be a better solution.

In Python, a function is recursive if it calls itself and has a termination condition. Why a termination condition? To stop the function from calling itself ad infinity.

Related Course:
Python Programming Bootcamp: Go from zero to hero

Recursion examples

Recursion in with a list
Let’s start with a very basic example: adding all numbers in a list.  Without recursion, this could be:

#!/usr/bin/env python
 
def sum(list):
sum = 0
 
# Add every number in the list.
for i in range(0, len(list)):
sum = sum + list[i]
 
# Return the sum.
return sum
 
print(sum([5,7,3,8,10]))

Where we simply call the sum function, the function adds every element to the variable sum and returns.  To do this recursively:

#!/usr/bin/env python
 
def sum(list):
if len(list) == 1:
return list[0]
else:
return list[0] + sum(list[1:])
 
print(sum([5,7,3,8,10]))

If the length of the list is one it returns the list (the termination condition). Else, it returns the element and a call to the function sum() minus one element of the list. If all calls are executed, it returns reaches the termination condition and returns the answer.

Factorial with recursion
The mathematical definition of factorial is:  n! = n * (n-1)!, if n > 1 and f(1) = 1. Example:   3! = 3 x 2 x 1 = 6.  We can implement this in Python using a recursive function:

#!/usr/bin/env python
 
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)
 
print factorial(3)

When calling the factorial function n = 3.  Thus it returns n * factorial(n-1).  This process will continue until n = 1. If n==1 is reached, it will return the result.

Limitations of recursions

Everytime a function calls itself and stores some memory. Thus, a recursive function could hold much more memory than a traditional function. Python stops the function calls after a depth of 1000 calls. If you run this example:

#!/usr/bin/env python
 
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)
 
print factorial(3000)

You will get the error:

RuntimeError: maximum recursion depth exceeded

In other programming languages, your program could simply crash. You can resolve this by modifying the number of recursion calls such as:

#!/usr/bin/env python
import sys
 
sys.setrecursionlimit(5000)
 
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)
 
print factorial(3000)

but keep in mind there is still a limit to the input for the factorial function. For this reason, you should use recursion wisely. As you learned now for the factorial problem, a recursive function is not the best solution.  For other problems such as traversing a directory, recursion may be a good solution.

Logging

Python logging

We can track events in a software application, this is known as logging.  Let’s start with a simple example, we will log a warning message.

As opposed to just printing the errors, logging can be configured to disable output or save to a file. This is a big advantage to simple printing the errors.

Related course
Python Programming Bootcamp: Go from zero to hero

Logging example

import logging
 
# print a log message to the console.
logging.warning('This is a warning!')

This will output:

WARNING:root:This is a warning!

We can easily output to a file:

import logging
 
logging.basicConfig(filename='program.log',level=logging.DEBUG)
logging.warning('An example message.')
logging.warning('Another message')

The importance of a log message depends on the severity.

Level of severity

The logger module has several levels of severity. We set the level of severity using this line of code:

logging.basicConfig(level=logging.DEBUG)

These are the levels of severity:

Type Description
DEBUG Information only for problem diagnostics
INFO The program is running as expected
WARNING Indicate something went wrong
ERROR The software will no longer be able to function
CRITICAL Very serious error

The default logging level is warning, which implies that other messages are ignored. If you want to print debug or info log messages you have to change the logging level like so:

import logging
 
logging.basicConfig(level=logging.DEBUG)
logging.debug('Debug message')

Time in log

You can enable time for logging using this line of code:

logging.basicConfig(format='%(asctime)s %(message)s')

An example below:

import logging
 
logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG)
logging.info('Logging app started')
logging.warning('An example logging message.')
logging.warning('Another log message')

Output:

2015-06-25 23:24:01,153 Logging app started
2015-06-25 23:24:01,153 An example message.
2015-06-25 23:24:01,153 Another message

Python Subprocess

The subprocess module enables you to start new applications from your Python program. How cool is that?

Related Course:
Python Programming Bootcamp: Go from zero to hero

Start a process in Python:

You can start a process in Python using the Popen function call. The program below starts the unix program ‘cat’ and the second parameter is the argument. This is equivalent to ‘cat test.py’.  You can start any program with any parameter.

#!/usr/bin/env python
 
from subprocess import Popen, PIPE
 
process = Popen(['cat', 'test.py'], stdout=PIPE, stderr=PIPE)
stdout, stderr = process.communicate()
print stdout

The process.communicate() call reads input and output from the process.  stdout is the process output. stderr will be written only if an error occurs.  If you want to wait for the program to finish you can call Popen.wait().

Subprocess call():

Subprocess has a method call() which can be used to start a program. The parameter is a list of which the first argument must be the program name. The full definition is:

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
# Run the command described by args.
# Wait for command to complete, then return the returncode attribute.

In the example below the full command would be “ls -l”

#!/usr/bin/env python
 
import subprocess
subprocess.call(["ls", "-l"])

Save process output (stdout)

We can get the output of a program and store it in a string directly using check_output. The method is defined as:

 subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)
# Run command with arguments and return its output as a byte string.

Example usage:

#!/usr/bin/env python
import subprocess
 
s = subprocess.check_output(["echo", "Hello World!"])
print("s = " + s)

Threading and threads

In Python you can create threads using the thread module in Python 2.x or _thread module in Python 3.  We will use the threading module to interact with it.

A thread is an operating system process with different features than a normal process:

  • threads exist as a subset of a process
  • threads share memory and resources
  • processes have a different address space (in memory)

When would you use threading? Usually when you want a function to occur at the same time as your program.  If you create server software, you want the server not only listens to one connection but to many connections. In short, threads enable programs to execute multiple tasks at once.

Related Courses:

Python threading

Let’s create a thread program. In this program we will start 10 threads which will each output their id.

import threading
 
# Our thread class
class MyThread (threading.Thread):
 
    def __init__(self,x):
        self.__x = x
        threading.Thread.__init__(self)
 
    def run (self):
          print str(self.__x)
 
# Start 10 threads.
for x in xrange(10):
    MyThread(x).start()

Output:

0
1
...
9

Threads do not have to stop if run once. Threads could be timed, where a threads functionality is repeated every x seconds.

Timed threads

In Python, the Timer class is a subclass of the Thread class. This means it behaves similar. We can use the timer class to create timed threads. Timers are started with the .start() method call, just like regular threads. The program below creates a thread that starts after 5 seconds.

#!/usr/bin/env python
from threading import *
 
def hello():
    print "hello, world"
 
# create thread
t = Timer(10.0, hello)
 
# start thread after 10 seconds
t.start()

Repeating functionality using threads
We can execute threads endlessly like this:

#!/usr/bin/env python
from threading import *
import time
 
def handleClient1():
    while(True):
        print "Waiting for client 1..."
        time.sleep(5) # wait 5 seconds      
 
def handleClient2():
    while(True):
        print "Waiting for client 2..."
        time.sleep(5) # wait 5 seconds
 
# create threads
t = Timer(5.0, handleClient1)
t2 = Timer(3.0, handleClient2)
 
# start threads
t.start()
t2.start()

 

Python lambda

We can create anonymous functions, known as lambda functions. Lambda functions are different from normal Python functions, they origin from Lambda Calculus. It allows you to write very short functions.

Related Courses:

Lambda function example
This code shows the use of a lambda function:

#!/usr/bin/env python
 
f = lambda x : 2 * x
print f(3)

A return statements is never used in a lambda function, it always returns
something. A lambda functions may contain if statements:

#!/usr/bin/env python
 
f = lambda x: x > 10
print(f(2))
print(f(12))

map function

The definition of map is map(function,iterable). It applies a function to every item in the iteratable.  We can use map() to on a lambda function with a list:

#!/usr/bin/env python
 
list = [1,2,3,4,5]
squaredList = map(lambda x: x*x, list)
print(squaredList)

Anywhere you use lambda functions, you could use normal functions instead.  A lambda function is not a statement, it is an expression. Lambda functions do not support a block of statements.

filter function

filter(function,iterable) creates a new list from the elmeents for which the function returns True. Example:

#!/usr/bin/env python
 
list = [1,2,3,4,5,6,7,8,9,10]
newList = filter(lambda x: x % 2 == 0, list)
print(newList)

The returning list returns contains only the elements for which the lambda expression “lamba x: x % 2 == 0”  is true.

reduce function

The reduce function, reduce(function, iterable) applies two arguments cumulatively to the items of iterable, from left to right. Example:

#!/usr/bin/env python
 
list = [1,2,3,4,5]
s = reduce(lambda x,y: x+y,  list)
print(s)

In this case the expression is always true, thus it simply sums up the elements of the list. Another example:

#!/usr/bin/env python
 
list = [10,6,7,5,2,1,8,5]
s = reduce(lambda x,y: x if (x > y) else y, list)
print(s)

 

Posts navigation

1 2 3 4 5 6 7