GE3151 Unit IV
GE3151 Unit IV
Lists: list operations, list slices, list methods, list loop, mutability, aliasing, cloning lists, list
parameters; Tuples: tuple assignment, tuple as return value; Dictionaries: operations and
methods; advanced list processing - list comprehension; Illustrative programs: simple sorting,
histogram, Students marks statement, Retail bill preparation.
4.1 Lists
A list is a sequence of values. In a string, the values are characters; in a list, they can be any
type. The values in a list are called elements or sometimes items. There are several ways to
create a new list; the simplest is to enclose the elements in square brackets ([ and]):
The elements of a list don’t have to be the same type. The following list contains a string, a
float, an integer, and another list:
['spam', 2.0, 5, [10, 20]]
A list within another list is called nested list. A list that contains no elements is called an
empty list; we can create one with empty brackets, [].
Creating a list:
To create a list, add a number of elements, separated by comma within a square bracket.
Syntax:
list_name = [element1, element2, … element n]
Indexing:
An element in the list can be accessed through index operator.
Syntax:
list_name[index]
Python allows negative indexing to access the elements. Index -1 refers the last element on the
list, -2 refers the second last element and so on.
Slicing:
List slice is same of string slice. From the list slice we can extract sub part of list based on user
requirements. We can use index values to create a sub list from list.
Syntax:
Var_name = list_name[start value: end value: increment/ decrement step value]
Here start value and end value may be omitted or optional. Default value for start is zero.
Default value for last is last index or -1. Default step value is 1.
Concatenation:
To concatenate or combine two or more lists “+” operator is used.
Repetitions:
Lists can be repeated or repeatedly concatenated with the asterisk operator “*”. The * operator
repeats a list in given number of times.
Membership:
We can determine whether an element is present in the list by using in or not in operator. The
in operator returns true if particular element is present, else it returns false. The not in operator
returns true if particular element is not present, else it returns false.
Here total is initialized to 0. Each time through the loop, x gets one element from the list. The
+= operator provides a short way to update a variable. This augmented assignment statement,
total += x
is equivalent to
total = total + x
As the loop runs, total accumulates the sum of the elements; a variable used this way is
sometimes called an accumulator.
def capitalize_all(t):
res = []
for s in t:
res.append(s.capitalize())
return res
Here “res” is initialized with an empty list; each time through the loop, we append the next
element. So “res” is another kind of accumulator. An operation like capitalize_all is sometimes
called a map because it “maps” a function (in this case the method capitalize) onto each of the
elements in a sequence.
Filter - select some of the elements from a list and return a sublist
Example: Function takes a list of strings and returns a list that contains only the uppercase
strings:
def only_upper(t):
res = []
for s in t:
if s.isupper():
res.append(s)
return res
Here “isupper” is a string method that returns True if the string contains only upper-case letters.
An operation like only_upper is called a filter because it selects some of the elements and filters
out the others.
Deleting elements
There are several ways to delete elements from a list.
pop modifies the list and returns the element that was removed. If an index is not given, it
deletes and returns the last element.
If we don’t need the removed value, we can use the del operator:
>>> t = ['a', 'b', 'c']
>>> del(t[1])
>>> t
['a', 'c']
If you know the element we want to remove (but not the index), we can use remove:
>>> t = ['a', 'b', 'c']
>>> t.remove('b')
>>> t
['a', 'c']
The return value from remove is None.
To remove more than one element, we can use del with a slice index:
>>> t = ['a', 'b', 'c', 'd', 'e', 'f']
>>> del t[1:5]
>>> t
['a', 'f']
As usual, the slice selects all the elements up to but not including the second index.
Syntax:
Listname[start:stop]
Listname[start:stop:steps]
If we omit the first index, the slice starts at the beginning. If we omit the second, the slice goes
to the end. So, if we omit both, the slice is a copy of the whole list. i.e [:] this will print the
entire list
>>> t[:]
['a', 'b', 'c', 'd', 'e', 'f']
A slice operator on the left side of an assignment can update multiple elements:
>>> t = ['a', 'b', 'c', 'd', 'e', 'f']
>>> t[1:3] = ['x', 'y']
>>> t
['a', 'x', 'y', 'd', 'e', 'f']
Syntax
Listname.methodname(element/index/list)
List:
To convert from a string to a list of characters, we can use list:
>>> s = 'spam'
>>> t = list(s)
>>> t
['s', 'p', 'a', 'm']
The list function breaks a string into individual letters.
Split:
If we want to break a string into words, we can use the split method:
>>> s = 'pining for the fjords'
>>> t = s.split()
>>> t
['pining', 'for', 'the', 'fjords']
Delimiter:
An optional argument called a delimiter specifies which characters to use as word boundaries.
The following example uses a hyphen as a delimiter:
>>> s = 'spam-spam-spam'
>>> delimiter = '-'
>>> t = s.split(delimiter)
>>> t
['spam', 'spam', 'spam']
Join
join is the inverse of split. It takes a list of strings and concatenates the elements. join is a string
method, so we have to invoke it on the delimiter and pass the list as a parameter:
>>> t = ['pining', 'for', 'the', 'fjords']
>>> delimiter = ' '
>>> s = delimiter.join(t)
>>> s
'pining for the fjords'
In this case the delimiter is a space character, so join puts a space between words. To
concatenate strings without spaces, we can use the empty string, '', as a delimiter.
Traversing a list
List using for loop:
The most common way to traverse the elements of a list is with a “for” loop.
• The for loop in Python is used to iterate over a sequence (list, tuple, string) or other
iterable objects.
• Iterating over a sequence is called traversal.
• Loop continues until we reach the last item in the sequence.
Syntax
for <item> in <iterable>:
<body>
Eg:
>>> names = ["Neha","John","Mary","Janice","Johan"]
>>> for name in names:
... print("Hi "+ name +"!")
...
Hi Neha!
Hi John!
Hi Mary!
Hi Janice!
Hi Johan!
To write or update the elements of the list, combine the built-in functions range and len as
below:
for i in range(len(numbers)):
numbers[i] = numbers[i] * 2
This loop traverses the list and updates each element. len returns the number of elements in the
list. range returns a list of indices from 0 to n - 1, where n is the length of the list. Each time
through the loop i gets the index of the next element. The assignment statement in the body
uses i to read the old value of the element and to assign the new value.
for x in []:
print('This never happens.')
Although a list can contain another list, the nested list still counts as a single element. The
length of this list is four: ['spam', 1, ['Brie', 'Roquefort', 'Pol le Veq'], [1, 2, 3]]
Syntax:
while (condition):
body of while
a = [1,2,3,4,5]
i=0
sum = 0
while i<len(a):
sum = sum + a[i]
i=i+1
print(sum)
Output: 15
4.1.5 Mutability:
• Lists are mutable. (Can be changed)
• Mutability is the ability for certain types of data to be changed without entirely
recreating it.
• An item can be changed in a list by accessing it directly as part of the assignment
statement.
• Using the indexing operator (square brackets []) on the left side of an assignment, one
of the list items can be updated.
The syntax for accessing the elements of a list is the same as for accessing the characters of a
string—the bracket operator. The expression inside the brackets specifies the index. Remember
that the indices start at 0:
Unlike strings, lists are mutable. When the bracket operator appears on the left side of an
assignment, it identifies the element of the list that will be assigned.
Figure below shows the state diagram for cheeses, numbers and empty:
Example Description
>>> a = [1,2,3,4,5] changing single element
>>> a[0] = 100
>>> a
[100, 2, 3, 4, 5]
>>> a = [1,2,3,4,5] changing multiple element
>>> a[0:3] = [100,100,100]
>>> a
[100, 100, 100, 4, 5]
>>> a = [1,2,3,4,5] The elements from a list can also be removed
>>> a[0:3] = [ ] by assigning the empty list to them.
>>> a
[4, 5]
>>> a = [1,2,3,4,5] The elements can be inserted into a list by
>>> a[0:0] = [20,30,45] squeezing them into an empty slice at the
>>> a desired location.
[20, 30, 45, 1, 2, 3, 4, 5]
a = 'banana'
b = 'banana'
We know that a and b both refer to a string, but we don’t know whether they refer to the same
string. There are two possible states, shown in Figure.
In one case, a and b refer to two different objects that have the same value. In the second
case, they refer to the same object.
To check whether two variables refer to the same object, we can use the is operator.
>>> a = 'banana'
>>> b = 'banana'
>>> a is b
True
In this example, Python only created one string object, and both a and b refer to it. But when
we create two lists, we get two objects:
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False
In this case we would say that the two lists are equivalent, because they have the same elements,
but not identical, because they are not the same object. If two objects are identical, they are
also equivalent, but if they are equivalent, they are not necessarily identical.
4.1.6 Aliasing
Creating a copy of a list is called aliasing. When we create a copy both lists will be having
same memory location. Changes in one list will affect another list. Aliasing refers to having
different names for same list values. If a refers to an object and we assign b = a, then both
variables refer to the same object:
>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
The association of a variable with an object is called a reference. In this example, there are two
references to the same object. An object with more than one reference has more than one name,
so we say that the object is aliased.
If the aliased object is mutable, changes made with one alias affect the other. When the first
element of the list named “a” is replaced, the first element of the list named “b” is also replaced.
>>> b[0] = 42
>>> a
[42, 2, 3]
This type of change is known as a side effect. This happens because after the assignment b=a,
the variables a and b refer to the exact same list object. They are aliases for the same object.
This phenomenon is known as aliasing. To prevent aliasing, a new object can be created and
the contents of the original can be copied which is called cloning.
In python, arguments are passed by reference. When we pass a list to a function, the function
gets a reference to the list. If the function modifies the list, the caller sees the change. If any
changes are done in the parameter which refers within the function, then the changes also reflect
back in the calling function.
Passing a list as an argument actually passes a reference to the list, not a copy of the list. Since
lists are mutable, changes made to the elements referenced by the parameter change the same
list that the argument is referencing.
For example, delete_head removes the first element from a list:
def delete_head(t):
del t[0]
The parameter t and the variable letters are aliases for the same object. The state diagram
looks like,
It is important to distinguish between operations that modify lists and operations that create
new lists. For example, the append method modifies a list, but the + operator creates a new
list.
>>> t1 = [1, 2]
>>> t2 = t1.append(3)
>>> t1
[1, 2, 3]
>>> t2
None
>>> t3 = t1 + [4]
>>> t1
[1, 2, 3]
>>> t3
[1, 2, 3, 4]
The result of the operator is a new list, and the original list is unchanged. For example, this
function does not delete the head of a list:
def bad_delete_head(t):
t = t[1:]
The slice operator creates a new list and the assignment makes t refer to it, but that doesn’t
affect the caller.
>>> t4 = [1, 2, 3]
>>> bad_delete_head(t4)
>>> t4
[1, 2, 3]
At the beginning of bad_delete_head, t and t4 refer to the same list. At the end, t refers to a
new list, but t4 still refers to the original, unmodified list.
An alternative is to write a function that creates and returns a new list. For example, tail
returns all from the first element of a list:
def tail(t):
return t[1:]
This function leaves the original list unmodified. Here’s how it is used:
Example 1: Output
def remove(a): [2, 3, 4, 5]
a.remove(1)
a = [1,2,3,4,5]
remove(a)
print(a)
Example 2: Output
def insidefun(a):
for i in range(0,len(a),1):
a[i]=a[i]+10
print("inside",a) inside [11, 12, 13, 14, 15]
a = [1,2,3,4,5]
insidefun(a)
print("outside",a) outside [11, 12, 13, 14, 15]
Example 3: Output
def insert(a): [30, 1, 2, 3, 4, 5]
a.insert(0,30)
a = [1,2,3,4,5]
insert(a)
print(a)
4.2 TUPLES
>>> t2 = ('a')
>>> type(t2)
<type 'str'>
Another way to create a tuple is the built-in function tuple. With no argument, it creates an
empty tuple:
>>> t = tuple()
>>> print t
()
If the argument is a sequence (string, list or tuple), the result is a tuple with the elements of
the sequence:
>>> t = tuple('lupins')
>>> print t
('l', 'u', 'p', 'i', 'n', 's')
Because tuple is the name of a built-in function, we should avoid using it as a variable name.
Most list operators also work on tuples. The bracket operator indexes an element:
But if we try to modify one of the elements of the tuple, we get an error:
we can’t modify the elements of a tuple, but we can replace one tuple with another:
Benefits of Tuple:
• Tuples are faster than lists.
• If the user wants to protect the data from accidental changes, tuple can be used.
• Tuples can be used as keys in dictionaries, while lists can't.
>>> temp = a
>>> a = b
>>> b = temp
>>> a, b = b, a
The left side is a tuple of variables; the right side is a tuple of expressions. Each value is
assigned to its respective variable. All the expressions on the right side are evaluated before
any of the assignments.
The number of variables on the left and the number of values on the right have to be the
same:
>>> a, b = 1, 2, 3
ValueError: too many values to unpack
More generally, the right side can be any kind of sequence (string, list or tuple). For example,
to split an email address in to a user name and a domain, we could write:
The return value from split is a list with two elements; the first element is assigned to uname,
the second to domain
A function can only return one value, but if the value is a tuple, the effect is the same as
returning multiple values. For example, if we want to divide two integers and compute the
quotient and remainder, it is inefficient to compute x/y and then x%y. It is better to compute
them both at the same time.
The built-in function divmod takes two arguments and returns a tuple of two values, the
quotient and remainder. We can store the result as a tuple:
>>> t = divmod(7, 3)
>>> print t
(2, 1)
Or use tuple assignment to store the elements separately:
def min_max(t):
return min(t), max(t)
max and min are built-in functions that find the largest and smallest elements of a sequence.
min_max computes both and returns a tuple of two values.
Example1: Output:
def div(a,b):
r=a%b
q=a//b
return(r,q)
a=eval(input("enter a value:")) enter a value:4
b=eval(input("enter b value:")) enter b value:3
r,q=div(a,b)
print("reminder:",r) reminder: 1
print("quotient:",q) quotient: 1
Example2: Output:
def min_max(a):
small=min(a)
big=max(a)
return(small,big)
a=[1,2,3,4,6]
small,big=min_max(a)
print("smallest:",small) smallest: 1
print("biggest:",big) biggest: 6
Functions can take a variable number of arguments. A parameter name that begins with *
gathers arguments into a tuple. For example, printall takes any number of arguments and prints
them:
def printall(*args):
print args
The gather parameter can have any name we like, but args is conventional. Here’s how the
function works:
>>> t = (7, 3)
>>> divmod(t)
TypeError: divmod expected 2 arguments, got 1
>>> divmod(*t)
(2 , 1)
>>> max(1,2,3)
3
>>> sum(1,2,3)
TypeError: sum expected at most 2 arguments, got 3
Write a function called sumall that takes any number of arguments and returns their sum.
zip is a built-in function that takes two or more sequences and “zips” them into a list of tuples
where each tuple contains one element from each sequence. In Python 3, zip returns an iterator
of tuples, but for most purposes, an iterator behaves like a list. This example zips a string and
a list:
>>> s = 'abc'
>>> t = [0, 1, 2]
>>> zip(s, t)
[('a', 0), ('b', 1), ('c', 2)]
The result is a list of tuples where each tuple contains a character from the string and the
corresponding element from the list.
If the sequences are not the same length, the result has the length of the shorter one.
Each time through the loop, Python selects the next tuple in the list and assigns the elements
to letter and number. The output of this loop is:
0 a
1 b
2 c
If we combine zip, for and tuple assignment, we get a useful idiom for traversing two (or more)
sequences at the same time. For example, has_match takes two sequences, t1 and t2, and returns
True if there is an index i such that t1[i] == t2[i]:
If we need to traverse the elements of a sequence and their indices, we can use the built-in
function enumerate:
As we should expect from a dictionary, the items are in no particular order. In Python3, items
return an iterator, but for many purposes, iterators behave like lists. Going in the other direction,
we can use a list of tuples to initialize a new dictionary:
The dictionary method update also takes a list of tuples and adds them, as key-value pairs, to
an existing dictionary. Combining items, tuple assignment and for, we get the idiom for
traversing the keys and values of a dictionary:
It is common to use tuples as keys in dictionaries (primarily because we can’t use lists). For
example, a telephone directory might map from last-name, first-name pairs to telephone
numbers. Assuming that we have defined last, first and number, we could write:
directory[last,first] = number
The expression in brackets is a tuple. We could use tuple assignment to traverse this dictionary.
for last, first in directory:
print first, last, directory[last,first]
This loop traverses the keys in directory, which are tuples. It assigns the elements of each tuple
to last and first, then prints the name and corresponding telephone number. There are two ways
to represent tuples in a state diagram. The more detailed version shows the indices and elements
just as they appear in a list.
Comparing tuples
The relational operators work with tuples and other sequences; Python starts by comparing the
first element from each sequence. If they are equal, it goes on to the next elements, and so on,
until it finds elements that differ. Subsequent elements are not considered ( even if they are
really big).
The sort function works the same way. It sorts primarily by first element, but in the case of a
tie, it sorts by second element, and so on. This feature lends itself to a pattern called DSU for
Decorate a sequence by building a list of tuples with one or more sort keys preceding the
elements from the sequence, Sort the list of tuples, and Undecorate by extracting the sorted
elements of the sequence.
For example, suppose you have a list of words and you want to sort them from longest to
shortest:
def sort_by_length(words):
t = []
for word in words:
t.append((len(word), word))
t.sort(reverse=True)
res = []
for length, word in t:
res.append(word)
return res
The first loop builds a list of tuples, where each tuple is a word preceded by its length.
sort compares the first element, length, first, and only considers the second element to break
ties.
The keyword argument reverse=True tells sort to go in decreasing order.
The second loop traverses the list of tuples and builds a list of words in descending order of
length.
Tuple Methods
Methods Example Description
a.index(tuple) >>> a=(1,2,3,4,5) Returns the index of the first
>>> a.index(5) matched item.
4
a.count(tuple) >>>a=(1,2,3,4,5) Returns the count of the
>>> a.count(3) given element.
1
len(tuple) >>> len(a) return the length of the
5 Tuple
min(tuple) >>>min(a) return the minimum element
1 in a Tuple
max(tuple) >>>max (a) return the maximum element
5 in a Tuple
del(tuple) >>>del (a) Delete the entire tuple
4.3 DICTIONARY
Python dictionary is an unordered collection of items. While other compound data types have
only value as an element, a dictionary has a key: value pair.
4.3.1 Operations
How to create a dictionary?
Creating a dictionary is as simple as placing items inside curly braces {} separated by
comma.
An item has a key and the corresponding value expressed as a pair, key: value. While values
can be of any data type and can repeat, keys must be of immutable type (string, number or
tuple with immutable elements) and must be unique.
# Empty dictionary
my_dict = {}
# Dictionary with integer keys
my_dict = {1: 'apple', 2: 'ball'}
# Dictionary with mixed keys
my_dict = {'name': 'John', 1: [2, 4, 3]}
# using dict()
my_dict = dict({1:'apple', 2:'ball'})
Example:
marks = {}.fromkeys(['Math','English','Science'], 0) {'Math': 0, 'English': 0, 'Science': 0}
print(marks) ('Math', 0)
for item in marks.items(): ('English', 0)
print(item) ('Science', 0)
list(sorted(marks.keys()))
Function Description
all() Return True if all keys of the dictionary are true (or if the dictionary is empty).
any() Return True if any key of the dictionary is true. If the dictionary is empty,
return False.
len() Return the length (the number of items) in the dictionary.
cmp() Compares items of two dictionaries.
sorted() Return a new sorted list of keys in the dictionary.
Here are some examples that uses built-in functions to work with dictionary.
squares = {1: 1, 3: 9, 5: 25, 7: 49, 9: 81}
print(len(squares)) 5
print(sorted(squares)) [1, 3, 5, 7, 9]
Syntax
list = [ expression for item in list if conditional ]
Here is an example to make a list with each item being increasing power of 2.
Programs on matrix:
Matrix addition Output
a=[[1,1],[1,1]] [3, 3]
b=[[2,2],[2,2]] [3, 3]
c=[[0,0],[0,0]]
for i in range(len(a)):
for j in range(len(b)):
c[i][j]=a[i][j]+b[i][j]
for i in c:
print(i)
Matrix multiplication Output
a=[[1,1],[1,1]] [3, 3]
b=[[2,2],[2,2]] [3, 3]
c=[[0,0],[0,0]]
for i in range(len(a)):
for j in range(len(b)):
for k in range(len(b)):
c[i][j]=a[i][j]+a[i][k]*b[k][j]
for i in c:
print(i)
Matrix transpose Output
a=[[1,3],[1,2]] [1, 1]
c=[[0,0],[0,0]] [3, 2]
for i in range(len(a)):
for j in range(len(a)):
c[i][j]=a[j][i]
for i in c:
print(i)
Simple Sorting
Output
Enter Number of Elements in the Array: 9
Enter the Element 1 :26
Enter the Element 2 :54
Enter the Element 3 :93
Enter the Element 4 :17
Enter the Element 5 :77
Enter the Element 6 :31
Enter the Element 7 :44
Enter the Element 8 :55
Enter the Element 9 :20
[17, 20, 26, 31, 44, 54, 55, 77, 93]
becomes
with each element greater than x copied to the right as it is compared against x.
alist = []
print('Insertion Sort :')
n = int(input('Enter Number of Elements in the Array: '))
for i in range(0, n):
x = int(input('Enter the Element %d :' %(i+1)))
alist.append(x)
insertionSort(alist)
print(alist)
Output:
Insertion Sort :
Enter Number of Elements in the Array: 9
Enter the Element 1 :54
Enter the Element 2 :26
Enter the Element 3 :93
Enter the Element 4 :17
Enter the Element 5 :77
Enter the Element 6 :31
Enter the Element 7 :44
Enter the Element 8 :55
Enter the Element 9 :20
[17, 20, 26, 31, 44, 54, 55, 77, 93]
Example
The following figure shows the fifth pass in detail. At this point in the algorithm, a sorted
sublist of five items consisting of 17, 26, 54, 77, and 93 exists. We want to insert 31 back into
the already sorted items. The first comparison against 93 causes 93 to be shifted to the right.
77 and 54 are also shifted. When the item 26 is encountered, the shifting process stops and 31
is placed in the open position. Now we have a sorted sublist of six items.
Output
Merge Sort :
Enter Number of Elements in the Array: 9
Enter the Element 1 :54
Enter the Element 2 :26
Enter the Element 3 :93
Enter the Element 4 :17
Enter the Element 5 :77
Enter the Element 6 :31
Enter the Element 7 :44
Enter the Element 8 :55
Enter the Element 9 :20
Original Array :
[54, 26, 93, 17, 77, 31, 44, 55, 20]
Intermediate s :
Splitting [54, 26, 93, 17, 77, 31, 44, 55, 20]
Splitting [54, 26, 93, 17]
Splitting [54, 26]
Splitting [54]
Splitting [26]
Splitting [93, 17]
Splitting [93]
Splitting [17]
Merging [17, 26, 54, 93]
Splitting [77, 31, 44, 55, 20]
Splitting [77, 31]
Splitting [77]
Splitting [31]
Splitting [44, 55, 20]
Splitting [44]
Splitting [55, 20]
Splitting [55]
Splitting [20]
Merging [20, 44, 55]
Merging [20, 31, 77, 44, 20]
Merging [20, 31, 77, 44, 55]
Merging [26, 54, 93, 20, 77, 31, 44, 55, 20]
Merging [26, 54, 93, 20, 31, 31, 44, 55, 20]
Merging [26, 54, 93, 20, 31, 77, 44, 55, 20]
Merging [26, 54, 93, 20, 31, 77, 44, 55, 20]
Merging [26, 54, 93, 20, 31, 77, 44, 55, 20]
Sorted Array is:
[26, 54, 93, 20, 31, 77, 44, 55, 20]
The following figure shows how the list as it is being sorted by merge sort.
Splitting
Merging
def histogram(nums):
for x in nums:
output = ''
while x > 0:
output = output + "x"
x=x-1
print(output)
histogram([2, 3, 6, 5])
Explanation
The histogram function loops through a list of numbers (nums) in order: for x in nums with
each number in the list it creates a string (output) containing "x". It then subtracts one from the
number x = x - 1, and joins another "x" to the output string. This continues until the number
reaches a value of 1 when the loop is finished and the number gets printed.
So histogram([2, 3, 6, 5]) would produce:
xx
xxx
xxxxxx
xxxxx
mark = []
tot = 0
Grade=0
print("Enter Number of Subjects: ")
subNo = int(input())
print("Enter Marks Obtained in " + str(subNo) + " Subjects: ")
for i in range(subNo):
print("Enter Marks Obtained in",i+1,"Subjects: ")
mark.append(input())
for i in range(subNo):
tot = tot + int(mark[i])
avg = tot/subNo
if avg==100:
Grade = "O"
elif avg>=90 and avg<=99:
Grade = "A+"
elif avg>=80 and avg<=89:
Grade = "A"
elif avg>=70 and avg<=79:
Grade = "B+"
elif avg>=60 and avg<=69:
Grade = "B"
elif avg>=50 and avg<=59:
Grade = "C"
elif avg>=49 and avg<0:
Grade = "RA"
else:
print("Invalid Input!")
print ("\nThe Grade is: \t", Grade)
output