0% found this document useful (0 votes)
34 views12 pages

Module 5

The document discusses Python programming and its standard library. It covers topics like output formatting, templating, working with binary data, multithreading, and logging. It provides examples and explanations of using formatters, templates, and creating multiple threads in Python.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views12 pages

Module 5

The document discusses Python programming and its standard library. It covers topics like output formatting, templating, working with binary data, multithreading, and logging. It provides examples and explanations of using formatters, templates, and creating multiple threads in Python.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

Module V

Syllabus:

Python Programming, Standard Library (Part II): Output formatting , templating,


working with binary data record layouts, multithreading, logging

Output Formatting:

Python’s str.format() method of the string class allows you to do variable substitutions and value
formatting. This lets you concatenate elements together within a string through positional
formatting.

This tutorial will guide you through some of the common uses of formatters in Python, which
can help make your code and program more readable and user friendly.

Using Formatters
Formatters work by putting in one or more replacement fields or placeholders — defined by a
pair of curly braces {} — into a string and calling the str.format() method. You’ll pass into the
method the value you want to concatenate with the string. This value will be passed through in
the same place that your placeholder is positioned when you run the program.

Let’s print out a string that uses a formatter:

print("Sammy has {} balloons.".format(5))


Output
Sammy has 5 balloons.

In the example above, we constructed a string with a pair of curly braces as a placeholder:

"Sammy has {} balloons."


We then added the str.format() method and passed the value of the integer 5 to that method. This
places the value of 5 into the string where the curly braces were:

Sammy has 5 balloons.

Reordering Formatters with Positional and Keyword Arguments


When we leave curly braces empty without any parameters, Python will replace the values
passed through the str.format() method in order. As we have seen, so far, a formatter
construction with two empty curly braces with two values passed through will look like this:
print("Sammy the {} has a pet {}!".format("shark", "pilot fish"))
Output
Sammy the shark has a pet pilot fish!
The first pair of curly braces is substituted with the string value of "shark", and the second pair is
substituted with the string value of "pilot fish".

The values that exist within the method look like this:

("shark", "pilot fish")

They are essentially the tuple data type and each individual value contained in the tuple can be
called by its index number, which starts with the index number 0.

We can pass these index numbers into the curly braces that serve as the placeholders in the
original string:

print("Sammy the {0} has a pet {1}!".format("shark", "pilot fish"))


In the above example, the output will be what we get without passing index numbers into the
braces as we are calling the values in the tuple in order:

Output:

Sammy the shark has a pet pilot fish!

But, if we reverse the index numbers with the parameters of the placeholders we can reverse the
values being passed into the string:

print("Sammy the {1} has a pet {0}!".format("shark", "pilot fish"))


Output
Sammy the pilot fish has a pet shark!

Specifying Type:
We can include more parameters within the curly braces of our syntax. We’ll use the format code
syntax {field_name:conversion}, where field_name specifies the index number of the argument
to the str.format() method that we went through in the reordering section, and conversion refers
to the conversion code of the data type that you’re using with the formatter.

The conversion type refers to the the single-character type code that Python uses. The codes that
we’ll be using here are s for string, d to display decimal integers (10-base), and f which we’ll use
to display floats with decimal places. You can read more about the Format-Specification Mini-
Language through Python 3’s official documentation.
Let’s look at an example where we have an integer passed through the method, but want to
display it as a float by adding the f conversion type argument:

print("Sammy ate {0:f} percent of a {1}!".format(75, "pizza"))


Output:
Sammy ate 75.000000 percent of a pizza!

We used the syntax of {field_name:conversion} for the first curly brace replacement field to
output a float. The second curly braces only uses the first parameter {field_name}.

In the example above, there are a lot of numbers displaying after the decimal point, but you can
limit those. When you are specifying f for float values, you can additionally specify the precision
of that value by including a full stop . followed by the number of digits after the decimal you
would like to include.

If Sammy ate 75.765367% of the pizza, but we don’t need to have a high level of accuracy, we
can limit the places after the decimal to 3 by adding .3 before the conversion type f:

print("Sammy ate {0:.3f} percent of a pizza!".format(75.765367))


Output
Sammy ate 75.765 percent of a pizza!
If we just want one decimal place, we can rewrite the string and method like so:

print("Sammy ate {0:.1f} percent of a pizza!".format(75.765367))


Output
Sammy ate 75.8 percent of a pizza!

Padding Variable Substitutions


Because the placeholders are replacement fields, you can pad or create space around an element
by increasing field size through additional parameters. This can be useful when we need to
organize a lot of data visually.

We can add a number to indicate field size (in terms of characters) after the colon : in the curly
braces of our syntax:

print("Sammy has {0:4} red {1:16}!".format(5, "balloons"))


Output
Sammy has 5 red balloons !
In the example above, we gave the number 5 a character field size of 4, and the string balloons a
character field size of 16 (because it is a long string).
As we see, by default strings are left-justified within the field, and numbers are right-justified.
You can modify this by placing an alignment code just following the colon. < will left-align the
text in a field, ^ will center the text in the field, and > will right-align it.

Let’s left-align the number and center the string:

print("Sammy has {0:<4} red {1:^16}!".format(5, "balloons"))

Output:
Sammy has 5 red balloons !

Now we see that 5 is left-aligned, providing space in the field before red, and balloons is
centered in its field with space to the left and right of it.

By default, when we make a field larger with formatters, Python will fill the field with
whitespace characters. We can modify that to be a different character by specifying the character
we want it to be directly following the colon:

print("{:*^20s}".format("Sammy"))
Output
*******Sammy********

We are accepting the string being passed to str.format() in the index position of 0 since we did
not specify otherwise, including the colon, and specifying that we will use * instead of space to
fill up the field. We're centering the string with ^, specifying that the field is 20 characters in
size, and also indicating that we are working with a string conversion type by including s.

We can combine these parameters with other parameters we’ve used before:

print("Sammy ate {0:5.0f} percent of a pizza!".format(75.765367))


Output
Sammy ate 76 percent of a pizza!

Template Class in Python


In String module, Template Class allows us to create simplified syntax for output specification.
The format uses placeholder names formed by $ with valid Python identifiers (alphanumeric
characters and underscores). Surrounding the placeholder with braces allows it to be followed by
more alphanumeric letters with no intervening spaces. Writing $$ creates a single escaped $:
Below is a simple example.
# A Simple Python templaye example
from string import Template
# Create a template that has placeholder for value of x
t = Template('x is $x')
# Substitute value of x in above template
print (t.substitute({'x' : 1}))

Output:

x is 1

Following is another example where we import names and marks of students from a list and print
them using template.
# A Python program to demonstrate working of string template
from string import Template

# List Student stores the name and marks of three students


Student = [('Ram',90), ('Ankit',78), ('Bob',92)]

# We are creating a basic structure to print the name and


# marks of the students.
t = Template('Hi $name, you have got $marks marks')

for i in Student:
print (t.substitute(name = i[0], marks = i[1]))

Output:
Hi Ram, you have got 90 marks
Hi Ankit, you have got 78 marks
Hi Bob, you have got 92 marks

The substitute() method raises a KeyError when a placeholder is not supplied in a dictionary or a
keyword argument. For mail-merge style applications, user supplied data may be incomplete and
the safe_substitute() method may be more appropriate — it will leave placeholders unchanged if
data is missing:
Another application for template is separating program logic from the details of multiple output
formats. This makes it possible to substitute custom templates for XML files, plain text reports,
and HTML web reports.

Multithreading
Multiple threads can exist within one process where:
 Each thread contains its own register set and local variables (stored in stack).
 All thread of a process share global variables (stored in heap) and the program code.
Consider the diagram below to understand how multiple threads exist in memory:
Multithreading is defined as the ability of a processor to execute multiple threads concurrently.

Multithreading is defined as the ability of a processor to execute multiple threads concurrently.


Consider the diagram below in which a process contains two active threads:

Multithreading in Python
In Python, the threading module provides a very simple and intuitive API for spawning multiple
threads in a program.
Let us consider a simple example using threading module:
# Python program to illustrate the concept
# of threading
# importing the threading module
import threading

def print_cube(num):
"""
function to print cube of given num
"""
print("Cube: {}".format(num * num * num))

def print_square(num):
"""
function to print square of given num
"""
print("Square: {}".format(num * num))

if __name__ == "__main__":
# creating thread
t1 = threading.Thread(target=print_square, args=(10,))
t2 = threading.Thread(target=print_cube, args=(10,))

# starting thread 1
t1.start()
# starting thread 2
t2.start()

# wait until thread 1 is completely executed


t1.join()
# wait until thread 2 is completely executed
t2.join()

# both threads completely executed


print("Done!")

Output:
Square: 100
Cube: 1000
Done!

Let us try to understand the above code:


 To import the threading module, we do:
 import threading

 To create a new thread, we create an object of Thread class. It takes following arguments:
 target: the function to be executed by thread
 args: the arguments to be passed to the target function
In above example, we created 2 threads with different target functions:

t1 = threading.Thread(target=print_square, args=(10,))
t2 = threading.Thread(target=print_cube, args=(10,))
 To start a thread, we use start method of Thread class.
 t1.start()
 t2.start()

 Once the threads start, the current program (you can think of it like a main thread) also
keeps on executing. In order to stop execution of current program until a thread is
complete, we use join method.
 t1.join()
 t2.join()

As a result, the current program will first wait for the completion of t1 and then t2. Once,
they are finished, the remaining statements of current program are executed.
Consider the diagram below for a better understanding of how above program works:

Consider the python program given below in which we print thread name and corresponding
process for each task:
# Python program to illustrate the concept
# of threading
import threading
import os

def task1():
print("Task 1 assigned to thread: {}".format(threading.current_thread().name))
print("ID of process running task 1: {}".format(os.getpid()))

def task2():
print("Task 2 assigned to thread: {}".format(threading.current_thread().name))
print("ID of process running task 2: {}".format(os.getpid()))

if __name__ == "__main__":
# print ID of current process
print("ID of process running main program: {}".format(os.getpid()))

# print name of main thread


print("Main thread name: {}".format(threading.main_thread().name))

# creating threads
t1 = threading.Thread(target=task1, name='t1')
t2 = threading.Thread(target=task2, name='t2')

# starting threads
t1.start()
t2.start()

# wait until all threads finish


t1.join()
t2.join()
Run on IDE

ID of process running main program: 11758


Main thread name: MainThread
Task 1 assigned to thread: t1
ID of process running task 1: 11758
Task 2 assigned to thread: t2
ID of process running task 2: 11758

Let us try to understand the above code:


 We use os.getpid() function to get ID of current process.
 print("ID of process running main program: {}".format(os.getpid()))

As it is clear from the output, the process ID remains same for all threads.
 We use threading.main_thread() function to get the main thread object. In normal
conditions, the main thread is the thread from which the Python interpreter was
started. name attribute of thread object is used to get the name of thread.
 print("Main thread name: {}".format(threading.main_thread().name))

 We use the threading.current_thread() function to get the current thread object.

Logging in Python:
Logging is a means of tracking events that happen when some software runs. Logging is
important for software developing, debugging and running. If you don’t have any logging record
and your program crashes, there are very little chances that you detect the cause of the problem.
And if you detect the cause, it will consume a lot of time. With logging, you can leave a trail of
breadcrumbs so that if something goes wrong, we can determine the cause of the problem.
There are a number of situations like if you are expecting an integer, you have been given a float
and you can a cloud API, the service is down for maintenance and much more. Such problems
are out of control and are hard to determine
Python has a built-in module logging which allows writing status messages to a file or any other
output streams. The file can contain the information on which part of the code is executed and
what problems have been arisen.
Levels of Log Message
There are two built-in levels of the log message.
 Debug : These are used to give Detailed information, typically of interest only when
diagnosing problems.
 Info : These are used to Confirm that things are working as expected
 Warning : These are used an indication that something unexpected happened, or indicative
of some problem in the near future
 Error : This tells that due to a more serious problem, the software has not been able to
perform some function
 Critical : This tells serious error, indicating that the program itself may be unable to
continue running
If required, developers have the option to create more levels but these are sufficient enough to
handle every possible situation. Each built-in level has been assigned its numeric value.

Logging module is packed with several features. It has several constants, classes, and methods.
The items with all caps are constant, the capitalize items are classes and the items which start
with lowercase letters are methods.
There are several logger objects offered by the module itself.
 Logger.info(msg) : This will log a message with level INFO on this logger.
 Logger.warning(msg) : This will log a message with level WARNING on this logger.
 Logger.error(msg) : This will log a message with level ERROR on this logger.
 Logger.critical(msg) : This will log a message with level CRITICAL on this logger.
 Logger.log(lvl,msg) : This will Logs a message with integer level lvl on this logger.
 Logger.
 exception(msg) : This will log a message with level ERROR on this logger.

The Basics
Basics of using the logging module to record the events in a file are very simple.
For that, simply import the module from the library.
1. Create and configure the logger. It can have several parameters. But importantly, pass the
name of the file in which you want to record the events.
2. Here the format of the logger can also be set. By default, the file works in append mode
but we can change that to write mode if required.
3. Also, the level of the logger can be set which acts as the threshold for tracking based on the
numeric values assigned to each level.
There are several attributes which can be passed as parameters.
4. The list of all those parameters is given in Python Library. The user can choose the
required attribute according to the requirement.
After that, create an object and use the various methods as shown in the example.
#importing module
import logging

#Create and configure logger


logging.basicConfig(filename="newfile.log",
format='%(asctime)s %(message)s',
filemode='w')

#Creating an object
logger=logging.getLogger()

#Setting the threshold of logger to DEBUG


logger.setLevel(logging.DEBUG)

#Test messages
logger.debug("Harmless debug Message")
logger.info("Just an information")
logger.warning("Its a Warning")
logger.error("Did you try to divide by zero")
logger.critical("Internet is down")

Output:
The above code will generate a file with the provided name and if we open the file, the file
contains the following data.

You might also like