0% found this document useful (0 votes)
5 views33 pages

Module 3

The document provides an overview of Python dictionaries, detailing their characteristics, creation, access, modification, and iteration methods. It explains how dictionaries store data in key-value pairs, emphasizing the importance of immutable keys and the use of hashing for efficient operations. Additionally, the document introduces NumPy, highlighting its capabilities for numerical computing, including ndarray objects, broadcasting, and integration with other libraries.

Uploaded by

ashvini297
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views33 pages

Module 3

The document provides an overview of Python dictionaries, detailing their characteristics, creation, access, modification, and iteration methods. It explains how dictionaries store data in key-value pairs, emphasizing the importance of immutable keys and the use of hashing for efficient operations. Additionally, the document introduces NumPy, highlighting its capabilities for numerical computing, including ndarray objects, broadcasting, and integration with other libraries.

Uploaded by

ashvini297
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Python Programming [1BPLC105B] Module 3

Dictionaries
Dictionaries are yet another kind of compound type. They are Python’s built-in mapping
type. They map keys, which can be any immutable type, to values, which can be any type
(heterogeneous), just like the elements of a list or tuple. In other languages, they are called
associative arrays since they associate a key with a value.

Python dictionary is a data structure that stores the value in key: value pairs. Values in a
dictionary can be of any data type and can be duplicated, whereas keys can't be repeated and
must be immutable.

 Keys are case sensitive which means same name but different cases of Key will be
treated distinctly.

 Keys must be immutable which means keys can be strings, numbers or tuples but not
lists.

 Duplicate keys are not allowed and any duplicate key will overwrite the previous
value.

 Internally uses hashing. Hence, operations like search, insert, delete can be performed
in Constant Time.

 From Python 3.7 Version onward, Python dictionary are Ordered.

How to Create a Dictionary

One way to create a dictionary is to start with the empty dictionary and add key:value pairs.
The empty dictionary is denoted {}:

Dictionary can be created by placing a sequence of elements within curly {} braces, separated
by a 'comma'. Each pair contains a key and a value separated by a colon.

As an example, we will create a dictionary to translate English words into Spanish. For this
dictionary, the keys are strings.

>>> english_spanish = {}
>>> english_spanish["one"] = "uno"
>>> english_spanish["two"] = "dos"

Dept. of CSE (Data Science) 1


Python Programming [1BPLC105B] Module 3

>>> print(english_spanish)
{"two": "dos", "one": "uno"}

d1 = {1: ‘Python’, 2: 'Programming', 3: 'Class'}


print(d1)
output: {1: ‘Python’, 2: 'Programming', 3: 'Class'}

We can create a dictionary using dict().


# create dictionary using dict() constructor
d2 = dict(1= ‘Python’, 2='Programming', 3= 'Class')
print(d2)

Accessing Dictionary Items

We can access a value from a dictionary by using the key within square brackets
or get() method.

d = { "name": "Prajjwal", 1: "Python", (1, 2): [1,2,4] }


# Access using key
print(d["name"])
# Access using get()
print([Link]("name"))
Output: Prajjwal
Prajjwal

Adding and Updating Dictionary Items

We can add new key-value pairs or update existing keys by using assignment.

d = {1: 'Python', 2: 'Programming', 3: 'Class'}


# Adding a new key-value pair
d["age"] = 22
# Updating an existing value
d[1] = "Python dict"

Dept. of CSE (Data Science) 2


Python Programming [1BPLC105B] Module 3

print(d)
Output

{1: 'Python dict', 2: 'Programming', 3: 'Class', 'age': 22}

Removing Dictionary Items

We can remove items from dictionary using the following methods:

del: Removes an item by key.

pop(): Removes an item by key and returns its value.

clear(): Empties the dictionary.

popitem(): Removes and returns the last key-value pair.

d = {1: 'Python', 2: 'Programming', 3: 'Class', 'age': 22}


# Using del to remove an item
del d["age"]
print(d)
# Using pop() to remove an item and return the value
val = [Link](1)
print(val)
# Using popitem to removes and returns
# the last key-value pair.
key, val = [Link]()
print(f"Key: {key}, Value: {val}")
# Clear all items from the dictionary
[Link]()
print(d)

Output
{1: 'Python', 2: 'Programming', 3: 'Class'}
Python
Key: 3, Value: ‘Class’
{}

Iterating Through a Dictionary

Dept. of CSE (Data Science) 3


Python Programming [1BPLC105B] Module 3

We can iterate over keys [using keys() method] , values [using values() method] or both
[using item() method] with a for loop.
d = {1: 'abc', 2: 'For', 'age':22}

# Iterate over keys


for key in d:
print(key)

# Iterate over values


for value in [Link]():
print(value)

# Iterate over key-value pairs


for key, value in [Link]():
print(f"{key}: {value}")
Output
1
2
age
abc
For
22
1: abc
2: For
age: 22

Hashing
The order of the pairs may not be what was expected. Python uses complex algorithms,
designed for very fast access, to determine where the key:value pairs are stored in a
dictionary. For our purposes we can think of this ordering as unpredictable. We also might
wonder why we use dictionaries at all when the same concept of mapping a key to a value
could be
implemented using a list of tuples:

>>> {"apples": 430, "bananas": 312, "oranges": 525, "pears": 217}


{'pears': 217, 'apples': 430, 'oranges': 525, 'bananas': 312}
>>> [('apples', 430), ('bananas', 312), ('oranges', 525), ('pears', 217)]
[('apples', 430), ('bananas', 312), ('oranges', 525), ('pears', 217)]

The reason is dictionaries are very fast, implemented using a technique called hashing, which
allows us to access a value very quickly. By contrast, the list of tuples implementation is

Dept. of CSE (Data Science) 4


Python Programming [1BPLC105B] Module 3

slow. If we wanted to find a value associated with a key, we would have to iterate over every
tuple, checking the 0th element. What if the key wasn’t even in the list? We would have to get
to the end of it to find out.

Another way to create a dictionary is to provide a list of key:value pairs using the same
syntax as the previous output:
>>> english_spanish = {"one": "uno", "two": "dos", "three": "tres"}
It doesn’t matter what order we write the pairs. The values in a dictionary are accessed with
keys, not with indices, so there is no need to care about ordering.

Here is how we use a key to look up the corresponding value:


>>> print(english_spanish["two"])
'dos'
The key "two" yields the value "dos".

Lists, tuples, and strings have been called sequences, because their items occur in order.

Dictionary operations

The del statement removes a key:value pair from a dictionary. For example, the following
dictionary contains the names of various fruits and the number of each fruit in stock:

>>> inventory = {"apples": 430, "bananas": 312, "oranges": 525, "pears": 217}
>>> print(inventory)
{'pears': 217, 'apples': 430, 'oranges': 525, 'bananas': 312}

If someone buys all of the bananas, we can remove the entry from the dictionary:

>>> del inventory["bananas"]


>>> print(inventory)
{'apples': 430, 'oranges': 525, 'pears': 217}
If we then try to see how many bananas we have, we get an error (because, yes, we have no
bananas).

If we’re expecting more bananas soon, we might just change the value associated with
bananas:

>>> inventory["bananas"] = 0
>>> print(inventory)
{'pears': 217, 'apples': 430, 'oranges': 525, 'bananas': 0}

A new shipment of bananas arriving could be handled like this:

>>> inventory["bananas"] += 200


>>> print(inventory)
{'pears': 0, 'apples': 430, 'oranges': 525, 'bananas': 512}

The len function also works on dictionaries; it returns the number of key:value pairs:
>>> len(inventory)
4

Dept. of CSE (Data Science) 5


Python Programming [1BPLC105B] Module 3

Dictionary methods
Dictionaries have a number of useful built-in methods. The keys method returns what Python
3 calls a view of its underlying keys.

for key in english_spanish.keys(): # The order of the k's is not defined


print("Got key", key, "which maps to value", english_spanish[key])
keys = list(english_spanish.keys())
print(keys)

This produces this output:


Got key three which maps to value tres
Got key two which maps to value dos
Got key one which maps to value uno
['three', 'two', 'one']

It is so common to iterate over the keys in a dictionary that we can omit the keys method call
in the for loop —iterating over a dictionary implicitly iterates over its keys:

for key in english_spanish:


print("Got key", key)

The values method is similar; it returns a view object which can be turned into a list:
>>> list(english_spanish.values())
['tres', 'dos', 'uno']

The items method also returns a view, which promises a list of tuples— one tuple for each
key:value pair:
>>> list(english_spanish.items())
[('three', 'tres'), ('two', 'dos'), ('one', 'uno')]

Tuples are often useful for getting both the key and the value at the same time while we are
looping:
for (key,value) in english_spanish.items():
print("Got",key,"that maps to",value)

This produces:
Got three that maps to tres
Got two that maps to dos
Got one that maps to uno

The in and not in operators can test if a key is in the dictionary:


>>> "one" in english_spanish
True
>>> "six" in english_spanish
False
>>> "tres" in english_spanish # Note that 'in' tests keys, not values.
False
Dept. of CSE (Data Science) 6
Python Programming [1BPLC105B] Module 3

This method can be very useful, since looking up a non-existent key in a dictionary causes a
runtime error:
>>> english_spanish["dog"]
Traceback (most recent call last):
...
KeyError: 'dog'

Aliasing and copying

As in the case of lists, because dictionaries are mutable, we need to be aware of aliasing.
Whenever two variables refer to the same object, changes to one affect the other.

If we want to modify a dictionary and keep a copy of the original, use the copy method. For
example, opposites is a dictionary that contains pairs of opposites:

>>> opposites = {"up": "down", "right": "wrong", "yes": "no"}

>>> alias = opposites

>>> copy = [Link]() # Shallow copy

alias and opposites refer to the same object; copy refers to a fresh copy of the same
dictionary. If we modify alias, opposites is also changed:

>>> alias["right"] = "left"

>>> opposites["right"]

'left'

If we modify copy, opposites is unchanged:

>>> copy["right"] = "privilege"

>>> opposites["right"]

'left'

Counting letters

We have seen a Function that counted the number of occurrences of a letter in a string. A
more general version of this problem is to form a frequency table of the letters in the string,
that is, how many times each letter appears. Such a frequency table might be useful for
compressing a text file. Because different letters appear with different frequencies, we can

Dept. of CSE (Data Science) 7


Python Programming [1BPLC105B] Module 3

compress a file by using shorter codes for common letters and longer codes for letters that
appear less frequently.

Dictionaries provide an elegant way to generate a frequency table:

>>> letter_counts = {}

>>> for letter in "Mississippi":

letter_counts[letter] = letter_counts.get(letter, 0) + 1

>>> letter_counts

{'M': 1, 's': 4, 'p': 2, 'i': 4}

We start with an empty dictionary. For each letter in the string, we find the current count
(possibly zero) and increment it. At the end, the dictionary contains pairs of letters and their
frequencies. It might be more appealing to display the frequency table in alphabetical order.
We can do that with the items and sort methods (more precisely, sort orders
lexicographically):

>>> letter_items = list(letter_counts.items())

>>> letter_items.sort()

>>> print(letter_items)

[('M', 1), ('i', 4), ('p', 2), ('s', 4)]

Notice in the first line we had to call the type conversion function list. That turns the promise
we get from items into a list, a step that is needed before we can use the list’s sort method.

Dept. of CSE (Data Science) 8


Python Programming [1BPLC105B] Module 3

Numpy
NumPy (Numerical Python) is a fundamental Python library for numerical computing,
particularly known for its efficient handling of large, multi-dimensional arrays and matrices.

Key Features of NumPy:

 ndarray object:

This is the core of NumPy, providing a high-performance, fixed-size, homogeneous multi-


dimensional array object. Unlike Python lists, all elements in an ndarray must be of the same
data type, which enables efficient storage and operations.

 Broadcasting:

NumPy's broadcasting mechanism allows operations on arrays of different shapes and sizes
by automatically "stretching" the smaller array to match the larger one, provided their
dimensions are compatible.

 Vectorized Operations (Universal Functions - ufuncs):

NumPy provides a rich set of universal functions (ufuncs) that enable element-wise
operations on arrays without explicit Python loops, leading to significant performance gains.

 Mathematical Functions:

It offers a comprehensive collection of mathematical functions (e.g., linear algebra, Fourier


transforms, trigonometric functions, basic arithmetic) optimized for ndarray objects.

 Indexing and Slicing:

NumPy arrays support powerful and flexible indexing and slicing, similar to Python lists but
extended for multi-dimensional access.

Dept. of CSE (Data Science) 9


Python Programming [1BPLC105B] Module 3

 Random Number Generation:

NumPy includes a robust module for generating various types of random numbers, essential
for simulations and statistical analyses.

 Integration with other Libraries:

NumPy integrates seamlessly with other scientific computing libraries in Python, such as
SciPy, Matplotlib, and Pandas, forming the backbone of the data science ecosystem.

 Performance:

NumPy operations are often implemented in optimized C/C++ or Fortran code, resulting in
significantly faster execution compared to native Python list operations, especially for large
datasets.

Installation of NumPy Using PIP:

Open your Command Prompt or terminal and run the following code

pip install numpy

The standard Python data types are not very suited for mathematical operations. For example,
suppose we have the

list a = [2, 3, 8]. If we multiply this list by an integer, we get:

>>> a = [2, 3, 8]

>>> 2 * a

[2, 3, 8, 2, 3, 8]

And float’s are not even allowed:

>>> a = [2, 3, 8]

>>> 2 * a

>>> 2.1 * a

TypeError: can't multiply sequence by non-int of type 'float'

In order to solve this using Python lists, we would have to do something like:

values = [2, 3, 8]

Dept. of CSE (Data Science) 10


Python Programming [1BPLC105B] Module 3

result = []

for x in values:

[Link](2.1 * x)

because Python list’s are not designed as mathematical objects. Rather, they are purely a
collection of items. In order to get a type of list which behaves like a mathematical array or
matrix, we use Numpy.

>>> import numpy as np

>>> a = [Link]([2, 3, 8])

>>> 2.1 * a

array([ 4.2, 6.3, 16.8])

>>> import numpy as np

>>> a = [Link]([2, 3, 8])

>>> a * a

array([ 4, 9, 64])

>>> a**2

array([ 4, 9, 64])

Why Use NumPy?

In Python we have lists that serve the purpose of arrays, but they are slow to process.

NumPy aims to provide an array object that is up to 50x faster than traditional Python lists.

The array object in NumPy is called ndarray, it provides a lot of supporting functions that
make working with ndarray very easy.

Arrays are very frequently used in data science, where speed and resources are very
important.

Why is NumPy Faster Than Lists?

Dept. of CSE (Data Science) 11


Python Programming [1BPLC105B] Module 3

NumPy arrays are stored at one continuous place in memory unlike lists, so processes can
access and manipulate them very efficiently.

This behavior is called locality of reference in computer science.

This is the main reason why NumPy is faster than lists. Also it is optimized to work with
latest CPU architectures.

Which Language is NumPy written in?

NumPy is a Python library and is written partially in Python, but most of the parts that require
fast computation are written in C or C++.

Import NumPy

Once NumPy is installed, import it in your applications by adding the import keyword:

import numpy

Now NumPy is imported and ready to use.

import numpy
arr = [Link]([1, 2, 3, 4, 5])
print(arr)

NumPy is usually imported under the np alias.

Create an alias with the as keyword while importing:

import numpy as np

import numpy as np
arr = [Link]([1, 2, 3, 4, 5])
print(arr)

Checking NumPy Version

The version string is stored under __version__ attribute.

Example

import numpy as np
print(np.__version__)

Dept. of CSE (Data Science) 12


Python Programming [1BPLC105B] Module 3

Create a NumPy ndarray Object

NumPy is used to work with arrays. The array object in NumPy is called ndarray.

We can create a NumPy ndarray object by using the array() function.

import numpy as np
arr = [Link]([1, 2, 3, 4, 5])
print(arr)
print(type(arr))

To create an ndarray, we can pass a list, tuple or any array-like object into the array() method,
and it will be converted into an ndarray:
Example
Use a tuple to create a NumPy array:
import numpy as np
arr = [Link]((1, 2, 3, 4, 5))
print(arr)

Dimensions in Arrays
A dimension in arrays is one level of array depth (nested arrays).

0-D Arrays
0-D arrays, or Scalars, are the elements in an array. Each value in an array is a 0-D array.
Example
Create a 0-D array with value 42
import numpy as np
arr = [Link](42)
print(arr)

1-D Arrays
An array that has 0-D arrays as its elements is called uni-dimensional or 1-D array.
These are the most common and basic arrays.
Example
Create a 1-D array containing the values 1,2,3,4,5:
Dept. of CSE (Data Science) 13
Python Programming [1BPLC105B] Module 3

import numpy as np
arr = [Link]([1, 2, 3, 4, 5])
print(arr)
2-D Arrays
An array that has 1-D arrays as its elements is called a 2-D array.
These are often used to represent matrix or 2nd order tensors.
Create a 2-D array containing two arrays with the values 1,2,3 and 4,5,6:
import numpy as np
arr = [Link]([[1, 2, 3], [4, 5, 6]])
print(arr)

Check Number of Dimensions?


NumPy Arrays provides the ndim attribute that returns an integer that tells us how many
dimensions the array have.
Example
Check how many dimensions the arrays have:
import numpy as np

a = [Link](42)
b = [Link]([1, 2, 3, 4, 5])
c = [Link]([[1, 2, 3], [4, 5, 6]])

print([Link])
print([Link])
print([Link])

NumPy Array Indexing:


Access Array Elements
Array indexing is the same as accessing an array element. We can access an array element by
referring to its index number. The indexes in NumPy arrays start with 0, meaning that the first
element has index 0, and the second has index 1 etc.
Example
Get the first element from the following array:
import numpy as np
arr = [Link]([1, 2, 3, 4])
print(arr[0])

Dept. of CSE (Data Science) 14


Python Programming [1BPLC105B] Module 3

import numpy as np
arr = [Link]([1, 2, 3, 4])
print(arr[1])

import numpy as np
arr = [Link]([1, 2, 3, 4])
print(arr[2] + arr[3])

Access 2-D Arrays


To access elements from 2-D arrays we can use comma separated integers representing the
dimension and the index of the element. Think of 2-D arrays like a table with rows and
columns, where the dimension represents the row and the index represents the column.
Access the element on the first row, second column:
import numpy as np
arr = [Link]([[1,2,3,4,5], [6,7,8,9,10]])
print('2nd element on 1st row: ', arr[0, 1])

Access the element on the 2nd row, 5th column:


import numpy as np
arr = [Link]([[1,2,3,4,5], [6,7,8,9,10]])
print('5th element on 2nd row: ', arr[1, 4])

Shape
One of the most important properties an array is its shape. We have already seen 1
dimensional (1D) arrays, but arrayscan have any dimensions you like. Images for example,
consist of a 2D array of pixels. But in color images everypixel is an RGB tuple: the intensity
in red, green and blue. Every pixel itself is therefore an array as well. This makes a color
image 3D overall.
To get the shape of an array, we use shape:
>>> import numpy as np
>>> a = [Link]([2, 3, 8])
>>> [Link]
(3,)

>>> b = [Link]([
[2, 3, 8],
Dept. of CSE (Data Science) 15
Python Programming [1BPLC105B] Module 3

[4, 5, 6],
])
>>> [Link]
(2, 3)

Slicing
Slicing in python means taking elements from one given index to another given index.
We pass slice instead of index like this: [start:end].
We can also define the step, like this: [start:end:step].
If we don't pass start its considered 0
If we don't pass end its considered length of array in that dimension
If we don't pass step its considered 1

Slice elements from index 1 to index 5 from the following array:

import numpy as np
arr = [Link]([1, 2, 3, 4, 5, 6, 7])
print(arr[1:5])

Slice elements from index 4 to the end of the array:

import numpy as np
arr = [Link]([1, 2, 3, 4, 5, 6, 7])
print(arr[4:])

Slice elements from the beginning to index 4 (not included):

numpy as np
arr = [Link]([1, 2, 3, 4, 5, 6, 7])
print(arr[:4])

Slice from the index 3 from the end to index 1 from the end:

import numpy as np
arr = [Link]([1, 2, 3, 4, 5, 6, 7])
print(arr[-3:-1])

Return every other element from index 1 to index 5:

import numpy as np
arr = [Link]([1, 2, 3, 4, 5, 6, 7])
print(arr[1:5:2])

Return every other element from the entire array:

Dept. of CSE (Data Science) 16


Python Programming [1BPLC105B] Module 3

import numpy as np
arr = [Link]([1, 2, 3, 4, 5, 6, 7])
print(arr[::2])

Slicing 2-D Arrays

From the second element, slice elements from index 1 to index 4 (not included):
import numpy as np
arr = [Link]([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
print(arr[1, 1:4])

From both elements, return index 2:


import numpy as np
arr = [Link]([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
print(arr[0:2, 2])

From both elements, slice index 1 to index 4 (not included), this will return a 2-D array:

import numpy as np
arr = [Link]([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
print(arr[0:2, 1:4])

>>> a = [Link]([2, 3, 8])


>>> a[2]
8
>>> a[1:]
[Link]([3, 8])

>>> b = [Link]([
[2, 3, 8],
[4, 5, 6],
])
>>> b[1]
array([4, 5, 6])
>>> b[1][2]
6

Masking

Masking in NumPy refers to the process of selectively operating on or extracting elements


from an array based on a boolean condition. This is achieved by creating a "mask" – a
boolean array of the same shape as the original data array, where True indicates elements that
satisfy the condition and False indicates those that do not.
There are several ways to perform masking in NumPy:
1. Boolean Indexing:

Dept. of CSE (Data Science) 17


Python Programming [1BPLC105B] Module 3

This is the most common and straightforward method. A boolean array (the mask) is used
directly to index another array, returning only the elements where the mask is True.

import numpy as np
arr = [Link]([10, 20, 30, 40, 50])
mask = arr > 25 # Create a boolean mask for values greater than 25
filtered_arr = arr[mask]
print(filtered_arr)

2. Using [Link]():
The [Link]() function allows conditional selection of elements from two arrays or
conditional modification of an array. It takes a condition, a value to use if the condition
is True, and a value to use if the condition is False.

import numpy as np
arr = [Link]([1, 2, 3, 4, 5])
modified_arr = [Link](arr % 2 == 0, arr * 10, arr) # Multiply even numbers by 10
print(modified_arr)

3. Masked Arrays ([Link] module):


For handling missing or invalid data, NumPy provides the [Link] module, which offers
masked arrays. A masked array combines a data array with a boolean mask, allowing
operations to automatically ignore masked elements.

import [Link] as ma
data = [Link]([1, 2, [Link], 4, 5])
masked_arr = ma.masked_invalid(data) # Mask NaN values
print(masked_arr)
print(masked_arr.mean()) # The mean will ignore the masked NaN value

Suppose we have an array, and we want to throw away all values above a certain cutoff:
>>> a = [Link]([230, 10, 284, 39, 76])
>>> cutoff = 200
>>> a > cutoff
[Link]([True, False, True, False, False])

Simply using the larger than operator lets us know in which cases the test was positive. Now
we set all the values above 200 to zero:
>>> a = [Link]([230, 10, 284, 39, 76])
>>> cutoff = 200
>>> a[a > cutoff] = 0
>>> a
[Link]([0, 10, 0, 39, 76])

Dept. of CSE (Data Science) 18


Python Programming [1BPLC105B] Module 3

The crucial line is a[a > cutoff] = 0. This selects all the points in the array where the test was
positive and assigns 0 to that position. Without knowing this trick we would have had to loop
over the array:
>>> a = [Link]([230, 10, 284, 39, 76])
>>> cutoff = 200
>>> new_a = []
>>> for x in a:
>>> if x > cutoff:
>>> new_a.append(0)
>>> else:
>>> new_a.append(x)
>>> a = [Link](new_a)

Broadcasting
arrays of different shapes. For instance
>>> a = [Link]([
[0, 1],
[2, 3],
[4, 5],
])
>>> b = [Link]([10, 100])
>>> a * b
array([[ 0, 100],
[ 20, 300],
[ 40, 500]])
The shapes of a and b don’t match. In order to proceed, Numpy will stretch b into a second
dimension, as if it were stacked three times upon itself. The operation then takes place
element-wise.

One of the rules of broadcasting is that only dimensions of size 1 can be stretched (if an array
only has one dimension, all other dimensions are considered for broadcasting purposes to
have size 1). In the example above b is 1D, and has shape (2,). For broadcasting with a,
which has two dimensions, Numpy adds another dimension of size 1 to b. b now has shape
(1, 2). This new dimension can now be stretched three times so that b’s shape matches a’s
shape of (3, 2).
The other rule is that dimensions are compared from the last to the first. Any dimensions that
do not match must be stretched to become equally sized. However, according to the previous
rule, only dimensions of size 1 can stretch. This means that some shapes cannot broadcast and
Numpy will give you an error:

>>> c = [Link]([
[0, 1, 2],
[3, 4, 5],
])
>>> b = [Link]([10, 100])
>>> c * b
ValueError: operands could not be broadcast together with shapes (2,3) (2,)
Dept. of CSE (Data Science) 19
Python Programming [1BPLC105B] Module 3

What happens here is that Numpy, again, adds a dimension to b, making it of shape (1, 2).
The sizes of the last dimensions of b and c (2 and 3, respectively) are then compared and
found to differ. Since none of these dimensions is of size 1 (therefore, unstretchable) Numpy
gives up and produces an error.

The solution to multiplying c and b above is to specifically tell Numpy that it must add that
extra dimension as the second dimension of b. This is done by using None to index that
second dimension. The shape of b then becomes (2, 1), which is compatible for broadcasting
with c:
>>> c = [Link]([
[0, 1, 2],
[3, 4, 5],
])
>>> b = [Link]([10, 100])
>>> c * b[:, None]
array([[ 0, 10, 20],
[300, 400, 500]])
dtype

A commonly used term in working with numpy is dtype - short for data type. This is typically
int or float, followed by some number, e.g. int8. This means the value is integer with a size of
8 bits.

As an example, let’s discuss the properties of an int8. Each bit is either 0 or 1. With 8 of
them, we have 28 = 256 possible values. Since we also have to count zero itself, the largest
possible value is 255. The data type we have now described is called uint8, where the u
stands for unsigned: only positive values are allowed. If we want to allow negative numbers
we use int8. The range then shifts to -128 to +127.

An int64 for example is a 64 bit unsigned integer with a range of -


9223372036854775808 to 9223372036854775807

>>> import numpy as np


>>> a = [Link]([200], dtype='uint8')
>>> a + a
array([144], dtype=uint8)

If you add two uint8, the result of 200 + 200 cannot be 400, because that doesn’t fit in a
uint8. In standard Python, Python does a lot of magic in the background to make sure the
result is the 400 you would expect. But numpy doesn’t, and will return 144. To fix this, we
should make sure that our numbers where not stored as uint8, but as something larger; uint16
for example. That way the resulting 400 will fit.
>>> import numpy as np
>>> a = [Link]([200], dtype='uint16')
>>> a + a
array([400], dtype=uint16)
Dept. of CSE (Data Science) 20
Python Programming [1BPLC105B] Module 3

Changing dtype
To change the dtype of an existing array, you can use the astype method:
>>> import numpy as np
>>> a = [Link]([200], dtype='uint8')
>>> [Link]('uint64')

FILES
File handling refers to the process of performing operations on a file, such as creating,
opening, reading, writing and closing it through a programming interface. It involves
managing the data flow between the program and the file system on the storage device,
ensuring that data is handled safely and efficiently.
Why do we need File Handling
 To store data permanently, even after the program ends.
 To access external files like .txt, .csv, .json, etc.
 To process large files efficiently without using much memory.
 To automate tasks like reading configs or saving outputs.

While a program is running, its data is stored in random access memory (RAM). RAM is fast
and inexpensive, but it is also volatile, which means that when the program ends, or the
computer shuts down, data in RAM disappears. To make data available the next time the
computer is turned on and the program is started, it has to be written to a non-volatile storage
medium, such a hard drive, usb drive, or CD-RW. Data on non-volatile storage media is
stored in named locations called files. By reading and writing files, programs can save
information between program runs.

Python has many built in functions for file handling.

Opening a File
To open a file, we can use open() function, which requires file-path and mode as arguments:
Syntax:
file = open('[Link]', 'mode')
 [Link]: name (or path) of the file to be opened.
 mode: mode in which you want to open the file (read, write, append, etc.).

Dept. of CSE (Data Science) 21


Python Programming [1BPLC105B] Module 3

Note: If we don’t specify the mode, Python uses 'r' (read mode) by default.

f = open('[Link]')
When you specify the filename only, it is assumed that the file is located in the same folder as
Python. If it is somewhere else, you can specify the exact path where the file is located.

f = open(r'C:\Python33\Scripts\[Link]')

While specifying the exact path, characters prefaced by \ (like \n \r \t etc.) are interpreted
as special characters. We can escape them using:
 raw strings like r'C:\new\[Link]'
 double backslashes like 'C:\\new\\[Link]'

Specify File Mode

Here are five different modes you can use to open the file:
Character Mode Description

‘r’ Read (default) Open a file for read only

‘w’ Write Open a file for write only (overwrite)

‘a’ Append Open a file for write only (append)

‘r+’ Read+Write open a file for both reading and writing

‘x’ Create Create a new file

We can also specify how the file should be handled.


Characte
Mode Description
r

Text
‘t’ Read and write strings from and to the file.
(default)

Read and write bytes objects from and to the [Link] mode
‘b’ Binary is used for all files that don’t contain text (e.g. images).

# Open a file for reading


f = open('[Link]')

# Open a file for writing


f = open('[Link]', 'w')

# Open a file for reading and writing


f = open('[Link]', 'r+')

Dept. of CSE (Data Science) 22


Python Programming [1BPLC105B] Module 3

# Open a binary file for reading


f = open('[Link]', 'rb')

Because read mode ‘r’ and text mode ‘t’ are default modes, you do not need to specify them.

Read a File
Suppose you have the following file.

[Link]
First line of the file.
Second line of the file.
Third line of the file.

To read its contents, you can use read() method.

# Read entire file


f = open('[Link]')
print([Link]())

# Prints:
#
First line of the file.
# Second line of the file.
# Third line of the file.

By default, the read() method reads the entire file. However, you can specify the maximum
number of characters to read.

f = open('[Link]')
print([Link](3))
# Prints Fir
print([Link](5))
# Prints First

Read Lines
To read a single line from the file, use readline() method.
f = open('[Link]')
print([Link]())
# Prints First line of the file.

# Call it again to read next line


print([Link]())
# Prints Second line of the file.

You can loop through an entire file line-by-line using a simple for loop.

f = open('[Link]')
Dept. of CSE (Data Science) 23
Python Programming [1BPLC105B] Module 3

for line in f:
print(line)

# Prints:
# First line of the file.
# Second line of the file.
# Third line of the file.

If we want to read all the lines in a file into a list of strings, use readlines() method.
# Read all the lines in a file into a list of strings
f = open('[Link]')
print([Link]())

# Prints:
# ['First line of the file.\n', 'Second line of the file.\n', 'Third line of the file.']

Write a File
Use the write() built-in method to write to an existing file. Remember that you need to open
the file in one of the writing modes (‘w’, ‘a’ or ‘r+’) first.

Write mode ‘w’

In ‘w’ mode the entire contents of the file are overwritten:


f = open('[Link]', 'w')
[Link]('Overwrite existing data.')

[Link]
Overwrite existing data.

Append mode ‘a’


In ‘a’ mode, text is added to the end of the file:
f = open('[Link]', 'a')
[Link](' Append this text.')

[Link]
First line of the file.
Second line of the file.
Third line of the file. Append this text.

Read-write mode ‘r+’

In ‘r+’ mode, the file is partially overwritten:


f = open('[Link]', 'r+')
[Link]('---Overwrite content---')

[Link]
Dept. of CSE (Data Science) 24
Python Programming [1BPLC105B] Module 3

---Overwrite content---
Second line of the file.
Third line of the file.

Write Multiple Lines


To write multiple lines to a file at once, use writelines() method. This method accepts list of
strings as an input.
f = open('[Link]', 'w')
lines = ['New line 1\n', 'New line 2\n', 'New line 3']
[Link](lines)

[Link]
New line 1
New line 2
New line 3

Flush Output Buffer


When you write to a file, the data is not immediately written to disk instead it is stored
in buffer memory. It is written to disk only when you close the file or manually flush the
output buffer.
# Flush output buffer to disk without closing
f = open('[Link]', 'a')
[Link]('Append this text.')
[Link]()

Close a File
It’s a good practice to close the file once you are finished with it. You don’t want an open file
running around taking up resources!
Use the close() function to close an open file.
f = open('[Link]')
[Link]()

# check closed status


print([Link])
# Prints True

There are two approaches to ensure that a file is closed properly, even in cases of error. The
first approach is to use the with keyword, which Python recommends, as it automatically
takes care of closing the file once it leaves the with block (even in cases of error).

with open('[Link]') as f:
print([Link]())

The second approach is to use the try-finally block:


f = open('[Link]')
try:
# File operations goes here
Dept. of CSE (Data Science) 25
Python Programming [1BPLC105B] Module 3

finally:
[Link]()

Create a New File


If you try to open a file for writing that does not exist, Python will automatically create the
file for you.
# Create a file and open it for writing

# write mode
f = open('[Link]', 'w')

# append mode
f = open('[Link]', 'a')

# read + write mode


f = open('[Link]', 'r+')
There is another way to create a file. You can use open() method and specify exclusive
creation mode ‘x’.
# Create a file exclusively
f = open('[Link]', 'x')
Note that when you use this mode, make sure that the file is not already present, if it is,
Python will raise the error.

Delete a File
You can delete a file by importing the OS module and using its remove() method.
import os
[Link]('[Link]')

Check if File Exists


If you try to open or delete a file that does not exist, an error occurs. To avoid this, you can
precheck if the file already exists by using the isfile() method from the OS module.

import os
if [Link]('[Link]'):
f = open('[Link]')
else:
print('The file does not exist.')

Random Access
Sometimes you need to read from the record in the middle of the file at that time you can use
the seek(offset, from_what) method. This function moves the file pointer from its current
position to a specific position.
The offset is the number of characters from the from_what parameter which has three
possible values:
 0 – indicates the beginning of the file (default)

Dept. of CSE (Data Science) 26


Python Programming [1BPLC105B] Module 3

 1 – indicates the current pointer position


 2 – indicates the end of the file

Suppose you have the following file.


[Link]
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Here’s how you can use the seek() method to randomly access the contents of a file.

f = open('[Link]', 'rb+')

# go to the 7th character and read one character


[Link](6)
print([Link](1))
# Prints G

# go to the 3rd character from current position (letter G)


[Link](3, 1)
print([Link](1))
# Prints K

# go to the 3rd character before the end


[Link](-3, 2)
print([Link](1))
# Prints X

If you want to check the current position of the file pointer, use the tell() method.

f = open('[Link]')

# initial position
print([Link]())
# Prints 0

# after reading 5 characters


[Link](5)
print([Link]())
# Prints 5

with open("[Link]", "w") as myfile:


[Link]("My first file written from Python\n")
[Link]("---------------------------------\n")

[Link]("Hello, world!\n")

with block make sure that the file get close even if an error occurs (power outages excluded).
Dept. of CSE (Data Science) 27
Python Programming [1BPLC105B] Module 3

Reading a file line-at-a-time

with open("[Link]", "r") as my_new_handle:


for the_line in my_new_handle:
# Do something with the line we just read.
# Here we just print it.
print(the_line, end="")

Turning a file into a list of lines

with open("[Link]", "r") as input_file:


all_lines = input_file.readlines()

all_lines.sort()

with open("[Link]", "w") as output_file:


for line in all_lines:
outut_file.write(line)

Reading the whole file at once

with open("[Link]") as f:
content = [Link]()
words = [Link]()
print("There are {0} words in the file.".format(len(words)))

An example
Here is a filter that copies one file to another, omitting any lines that begin with #:
def filter(oldfile, newfile):
with open(oldfile, "r") as infile, open(newfile, "w") as outfile:
for line in infile:
# Put any processing logic here
if not [Link]('#'):
[Link](line)

Directories

Files on non-volatile storage media are organized by a set of rules known as a file system.
File systems are made up of files and directories, which are containers for both files and other
directories. When we create a new file by opening it and writing, the new file goes in the
current directory (wherever we were when we ran the program). Similarly, when we open a
file for reading, Python looks for it in the current directory. If we want to open a file
somewhere else, we have to specify the path to the file, which is the name of the directory
(or folder) where the file is located:
>>> wordsfile = open("/usr/share/dict/words", "r")
Dept. of CSE (Data Science) 28
Python Programming [1BPLC105B] Module 3

>>> wordlist = [Link]()


>>> print(wordlist[:6])
['\n', 'A\n', "A's\n", 'AOL\n', "AOL's\n", 'Aachen\n']

This (Unix) example opens a file named words that resides in a directory named dict, which
resides in share, which resides in usr, which resides in the top-level directory of the system,
called /. It then reads in each line into a list using readlines, and prints out the first 5 elements
from that list. A Windows path might be "c:/temp/[Link]" or "c:\\temp\\[Link]".
Because backslashes are used to escape things like newlines and tabs, we need to write two
backslashes in a literal string to get one! So the length of these two strings is the same!
We cannot use / or \ as part of a filename; they are reserved as a delimiter between directory
and filenames. When working with files in directories it is a good idea to let Python deal with
all the slashes and escaping them. The [Link] module does this for different operating
systems. Using [Link]. join("directory", "filename") will automatically return
"directory/filename" on Unix/Linux, and "directory\\filename" on Windows. This can not
only be of great help when moving code from one system to another, or when sharing with
colleagues. It also means that you do not have to take care of it yourself, and it might save
you some issues with string handling. You can also explore the [Link] module for other
handy features that will help you handling files. The file /usr/share/dict/words should exist on
Unix-based systems, and contains a list of words in alphabetical order.

What about fetching something from the web?

The Python libraries are pretty messy in places. But here is a very simple example that copies
the contents at some web URL to a local file.
import [Link]
url = "[Link]
destination_filename = "[Link]"
[Link](url, destination_filename)
The urlretrieve function— just one call— could be used to download any kind of content
from the Internet.

import requests
url = "[Link]
response = [Link](url)
print([Link])

import requests
url = "[Link]
response = [Link](url)
for line in response:
print(line)

Working with binary files

Dept. of CSE (Data Science) 29


Python Programming [1BPLC105B] Module 3

Binary file handling in Python involves working with files that store data in a raw,
uninterpreted format, rather than as human-readable text. This includes files like images,
audio, video, or serialized Python objects.

Common examples of binary files include:


 Images: .jpg, .png, .gif
 Audio/Video: .mp3, .mp4, .wav
 Compiled Code: .exe, .dll, .pyc
 Compressed Archives: .zip, .gz
 Serialized Data: Python pickle files, database files

The Key: Binary Mode ('b')


To work with binary files, you must append a 'b' to your file mode string. This tells Python to
make no assumptions about the file’s content—it will not attempt to encode or decode the
data, nor will it translate newline characters. It will simply read and write raw bytes.
 'rb': Read Binary. Opens for reading in binary mode.
 'wb': Write Binary. Opens for writing in binary mode (erases or creates).
 'ab': Append Binary. Opens for appending in binary mode.
Binary files and text files differ fundamentally in their content representation and the
operations performed on them.
Content:
 Text Files:
Store data as a sequence of human-readable characters, typically encoded using schemes like
ASCII or Unicode (e.g., UTF-8). Each character corresponds to a specific numerical value,
and the file often includes special characters like newline (\n) to indicate line breaks.
 Binary Files:
Store data as raw bytes, directly representing the underlying data structure or content (e.g.,
images, audio, executables). These bytes are not necessarily human-readable and require
specific programs to interpret their meaning. Newline characters may or may not have a
special meaning depending on the file format.

Operations:
 Text Files:
Can be opened and read by any text editor, allowing for easy viewing and modification of the
character content. Operations typically involve reading and writing character strings, with the
system handling character encoding and newline conversions.
 Binary Files:
Require specialized software or code to interpret and manipulate their content. Operations
involve reading and writing raw bytes, often in chunks or according to a defined data
structure. Direct modification with a text editor can corrupt the file as the text editor might
misinterpret byte sequences or alter them during saving.

# Writing to a text file


with open("[Link]", "w") as f:
[Link]("Hello, World!\n")
[Link]("This is a text file.")

Dept. of CSE (Data Science) 30


Python Programming [1BPLC105B] Module 3

# Reading from a text file


with open("[Link]", "r") as f:
content = [Link]()
print(content)

Dept. of CSE (Data Science) 31


Python Programming [1BPLC105B] Module 3

Dept. of CSE (Data Science) 32


Python Programming [1BPLC105B] Module 3

Dept. of CSE (Data Science) 33

You might also like