Category: beginner
Python hosting: Host, run, and code Python in the cloud!
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) |