PYTHON PROGRAMMING FOR BEGINNERS A CRASH COURSE WITH HANDS-ON PROJECTS TO LEARN PYTHON CODING, GAME PROGRAMMING WITH NO CODING... (Mike Kernell)
PYTHON PROGRAMMING FOR BEGINNERS A CRASH COURSE WITH HANDS-ON PROJECTS TO LEARN PYTHON CODING, GAME PROGRAMMING WITH NO CODING... (Mike Kernell)
PYTHON PROGRAMMING FOR BEGINNERS A CRASH COURSE WITH HANDS-ON PROJECTS TO LEARN PYTHON CODING, GAME PROGRAMMING WITH NO CODING... (Mike Kernell)
BEGINNERS
A CRASH COURSE WITH HANDS-ON PROJECTS TO
LEARN PYTHON CODING, GAME PROGRAMMING
WITH NO CODING EXPERIENCE IN 7 DAYS TO
MASTER MACHINE LEARNING & BIG DATA
ANALYSIS
MIKE KERNELL
CONTENTS
Author Biography
Introduction
1. Introduction to Python
1.1: Python and its History
1.2: How to Install the Interpreter
1.3: How to Use the Python Shell, IDLE, and Write Your First Program
2. Variables and Operators
2.1: What are Variables?
2.2: Naming a Variable
2.3: The Assignment Operator
2.4: Basic Operators
2.5: More Assignment Operators
3. Data Types in Python
3.1: Integers
3.2: Float
3.3: String
3.4: Type Casting in Python
3.5: List
3.6: Array
3.7: Tuple
3.8: Dictionary
4. How to Make Your Program Interactive?
4.1: Input()
4.2: Print()
4.3: Triple Quotes
4.4: Escape Characters
5. Condition Statements
5.1: If statement
5.2: Inline If
6. Loops
6.1: For loop
6.2: While loop
6.3: Break
6.4: Continue
6.5: Try, Except
7. Functions and Modules
7.1: What are Functions?
7.2: Built-In Functions
7.3: Defining Your Functions
7.4: Recursive Functions
8. Variable Scope
8.1: Default Parameters Values
8.2: Variable-Length Argument List
9. Importing Modules
9.1: Creating your Own Module
10. Working with Files
10.1: Opening and Reading Text Files
10.2: Using a For Loop to Read Text Files:
10.3: Writing to a Text File
10.4: Opening & Reading Text Files by Buffer Size
10.5: Opening, Reading, and Writing Binary Files
10.6: Deleting and Renaming Files
11. Object-Oriented Programming
11.1: Classes
11.2: Objects
11.3: Polymorphism
11.4: Encapsulation
11.5: Inheritance
11.6: Multiple Inheritance
11.7: Operator Overloading
12. Data Structures and Algorithms
12.1: Asymptotic Analysis
12.2: Linear Data Structures
12.3: Non-Linear Data Structures
13. Python Gaming Project
13.1: Mario Game In Python With Source Code
13.2: Stages on how to make a Mario video game in Python
13.3: Code For Importing Libraries
13.4: Code For The Initialization & Declaration of Functions
13.5: Code For The Game Starting
13.6: Code For The Game Level
13.7: Code For The Game Main Module
Afterword
© Copyright 2022 by Mike Kernell - All rights reserved.
This document provides exact and reliable information concerning the topic and issues covered.
- From a Declaration of Principles which was accepted and approved equally by a Committee of the
American Bar Association and a Committee of Publishers and Associations.
In no way is it legal to reproduce, duplicate, or transmit any part of this document in either electronic
means or printed format. All rights reserved.
The information provided herein is stated to be truthful and consistent. Any liability, in terms of
inattention or otherwise, by any usage or abuse of any policies, processes, or directions contained
within is the solitary and utter responsibility of the recipient reader. Under no circumstances will any
legal responsibility or blame be held against the publisher for any reparation, damages, or monetary
loss due to the information herein, either directly or indirectly.
Respective authors own all copyrights not held by the publisher.
The information herein is offered for informational purposes solely and is universal as so. The
presentation of the information is without a contract or any type of guaranteed assurance.
The trademarks that are used are without any consent, and the publication of the trademark is without
permission or backing by the trademark owner. All trademarks and brands within this book are for
clarifying purposes only and are owned by the owners themselves, not affiliated with this document.
AUTHOR BIOGRAPHY
The following dialogue box will ask you to disable the path length limit.
By selecting this option, Python will exceed the 260-character MAX PATH
limit. In practice, this allows Python to utilizing symbolic path names.
The option to Disable the route length limit does not affect any other
system settings. The possible name length problems with Python projects will
be resolved by enabling it.
Additionally, the Python 3.9 package will launch a new Finder window.
Python may be accessed through the command line. Open the Terminal
application from the Applications -> Utilities -> Terminal. Once open,
execute python3 on the command line to invoke the Python interpreter. When
you see the prompt >>>, you know it is functioning. To verify, write
print("Hello, World").
1.3: HOW TO USE THE PYTHON SHELL, IDLE, AND
WRITE YOUR FIRST PROGRAM
Python Shell
Once open, execute python3 on the command line to invoke the Python
interpreter. When the prompt >>> appears, you know it is functioning. Type
print("Hello, World") to confirm. Python is a coding dialect that runs on an
interpreter. That is, it runs the code line by line. Python includes a Python
Shell that may perform a single Python command and show the result.
Additionally, it is referred to as REPL (Read, Evaluate, Print, Loop) since
it reads the command, evaluates it, publishes the result, and then loops back
to read the command again. To start the Python Shell, open the power shell or
command prompt on Windows or a terminal window on Mac, type python,
and then press enter. As seen below, a Python Prompt with three greater-than
symbols >>> displays.
Now, you can submit a single statement and get the output. For instance,
input a basic formula such as 3 + 2 and hit enter; the result will appear on the
next line, as seen below.
Python IDLE
Python IDLE's default mode of operation is the shell. When you double-
click the program's icon to launch it, the shell is the very first thing you see.
This is a new Python interpreter window with no content. You may use it
instantly to begin interacting with Python. You may verify it with the
following piece of code:
You used print() to print the string "Hello, from IDLE!" on the screen in
this case. This is the simplest method of interacting with Python IDLE. You
enter commands one by one, and Python returns the results of each
command. Following that, examine the menu bar. You'll see many choices
for interacting with the shell:
This menu allows you to restart the shell. If you choose that option, the
shell's state will be cleared. It will behave as though you've launched a new
instance of Python IDLE. The shell will completely forget about its initial
state:
In the example shown above, you define a variable, x = 5. When you use
print(x), the shell outputs the proper value, which is 5. However, when the
shell is restarted, and print(x) is attempted again, the shell produces a
traceback. This error message tells the user that the variable x is undefined.
The shell has forgotten everything that occurred before being restarted.
Additionally, you may pause the shell's execution from this menu. This
will terminate any program or statement that is currently executing in the
shell. Consider the following when you send an interrupt from the keyboard
to the shell:
At the bottom of your window, a Keyboard Interrupt error notice is
shown in red text. The program has halted execution as a result of the
interrupt.
Writing Your First Program
Here “+” is the addition operator. 2 and 3 are the operands, whereas 5 is
the operation's outcome.
There are different kinds of operators in Python, which are listed below:
Arithmetic Operators:
Arithmetic operators are used to performing mathematical operations
such as addition, subtraction, multiplication, etc.
Example:
# Examples of Arithmetic Operator
a=9
b=4
# Addition of numbers
add = a + b
# Subtraction of numbers
sub = a - b
# Multiplication of number
mul = a * b
# Division(float) of number
div1 = a / b
# Division(floor) of number
div2 = a // b
# Modulo of both number
mod = a % b
# Power
p = a ** b
# print results
print(add)
print(sub)
print(mul)
print(div1)
print(div2)
print(mod)
print(p)
Output:
Comparison Operators:
Relational operators perform comparisons on values. It yields either True
or False depending on the criteria.
Example:
# Examples of Relational Operators
a = 13
b = 33
# a > b is False
print(a > b)
# a < b is True
print(a < b)
# a == b is False
print(a == b)
# a != b is True
print(a != b)
# a >= b is False
print(a >= b)
# a <= b is True
print(a <= b)
Output:
Logical Operators:
Logical operators execute the operations Logically AND, Logical OR,
and Logical NOT. It is used to group conditional statements.
Example:
# Examples of Logical Operator
a = True
b = False
# Print a and b is False
print(a and b)
# Print a or b is True
print(a or b)
# Print not a is False
print(not a)
Output:
Bitwise Operators:
Bitwise operators operate on bits and execute actions bit by bit. These are
used to perform binary number operations.
Example:
# Examples of Bitwise operators
a = 10
b=4
# Print bitwise AND operation
print(a & b)
# Print bitwise OR operation
print(a | b)
# Print bitwise NOT operation
print(~a)
# print bitwise XOR operation
print(a ^ b)
# print bitwise right shift operation
print(a >> 2)
# print bitwise left shift operation
print(a << 2)
Output:
2.5: MORE ASSIGNMENT OPERATORS
Assignment Operators are used to specify the values to be assigned to
variables. Here are some assignment operators listed below:
+=
Add and Assign: Add the right and left operands and then assign them to
the left operand.
Syntax: a += b
Example:
x=7
y=9
#x=x+y
x += y
# Output
print(x)
Output:
-=
Subtract and Assign: The right operand is subtracted from the left
operand, and the result is assigned to the left operand.
Syntax: x -= y
Example:
x=7
y=5
#x=x-y
x -= y
# Output
print(x)
Output:
*=
Multiply and Assign: The right operand is multiplied by the left operand,
and the result is assigned to the left operand.
Syntax: x *= y
Example:
x=3
y=5
#x=x*y
x *= y
# Output
print(x)
Output:
/=
Divide and Assign: This operator divides the left operand by the right
operand and returns the remainder to the left operand.
Syntax: x /= y
Example:
x=3
y=5
#x=x/y
x /= y
# Output
print(x)
Output:
%=
Divide (Floor) and Assign: This operation divides the left and right
operands and then assigns the result to the left operand.
Syntax: x //= y
Example:
x = 10
y=5
# x = x // y
x //= y
# Output
print(x)
Output:
**=
&=
Bitwise AND and Assign: This operator performs Bitwise AND on both
inputs before assigning the output to the left operand.
Syntax: x &= y
Example:
x=3
y=5
#x=x&y
x &= y
# Output
print(x)
Output:
|=
^=
>>=
Bitwise Right Shift: The operator performs a bitwise right shift upon
values before assigning the answer to the left operand.
Syntax: x >>= y
Example:
x=3
y=5
# x = x >> y
x >>= y
# Output
print(x)
Output:
<<=
Bitwise Left Shift: Operator executes a bitwise left shift upon operands
before appointing the outcome to the left operand.
Syntax: x <<= y
Example:
x=3
y=5
# x = x << y
x <<= y
# Output
print(x)
Output:
CHAPTER 3
DATA TYPES IN PYTHON
3.1: INTEGERS
A ndecimals,
integer is a numeric value that may be positive or negative, without
and of any length. In Python, integers are zero, positive, or
negative whole numbers that lack a fractional portion and have an unbounded
precision, for example, 0, 100, -10. The following are valid Python integer
literals.
>>> 0
0
>>> 100
100
>>> -10
-10
>>> 1234567890
1234567890
>>>
y=5000000000000000000000000000000000000000000000000000000
5000000000000000000000000000000000000000000000000000000
>>> x=1234567890
>>> type(x)
<class 'int'> # type of x is int
>>> y=5000000000000000000000000000000000000000000000000000000
In the program above, x, y, and z are initialized. Int() and float() are used
in this program to see how explicit type conversion occurs. It can be checked
how the data type changes by running this application.
3.5: LIST
Python lists are among the most flexible data formats because they enable the
simultaneous manipulation of numerous components.
Creating Lists:
A list is generated in Python by enclosing entries in square brackets [],
separated using commas.
Example:
# list of integers
my_list = [1, 2, 3]
A list may include any number of items and may contain objects of
varying categories (float, integer, string, etc.).
Example:
# empty list
my_list = []
# list with mixed data types
my_list = [1, "Hello", 3.4]
Additionally, a list may include an item from another list. This is referred
to as a nested list.
Example:
# nested list
my_list = ["mouse", [8, 4, 6], ['a']]
Delete List Elements:
Through Python del statement, one or more entries from a list can be
removed. It is even capable of deleting the list completely.
Example:
# Deleting list items
python_list = ['p', 'r', 'o', 'b', 'l', 'e', 'm']
# delete one item
del python_list[2]
print(python_list)
# delete the entire list
del python_list
# Error: List not defined
print(python_list)
Output:
Deleting a Tuple:
A tuple's elements cannot be changed. Deleting or removing entries from
a tuple is not possible. However, the term del allows for the complete
deletion of a tuple.
Example:
# Deleting tuples
myfirst_tuple = ('p', 'r', 'o', 'g', 'r', 'a', 'm', 'i', 'z')
# can't delete items
# TypeError: 'tuple' object doesn't support item deletion
# del myfirst_tuple[3]
# Can delete an entire tuple
del myfirst_tuple
# NameError: name 'myfirst_tuple' is not defined
print(myfirst_tuple)
Output:
3.8: DICTIONARY
A dictionary is an unsorted set of data values that is similar to a map. Unlike
other Data Types that include just a single value as an element, a dictionary
contains key: value pairs. To optimize the dictionary, a key-value pair is
included.
Example:
# Creating a Dictionary
# with Integer Keys
Dict = {1: 'My', 2: 'Name', 3: 'is', 4: 'John'}
print("\nDictionary with the use of Integer Keys: ")
print(Dict)
# Creating a Dictionary
# with Mixed keys
Dict = {'Name': 'June', 1: [1, 2, 3, 4]}
print("\nDictionary with the use of Mixed Keys: ")
print(Dict)
Output:
Syntax:
The syntax of input() function is:
Syntax: input ( [prompt] )
Parameters:
input() function gets a single optional argument:
Optional: Prompt - a string that is printed to standard output (often
screen) without including the trailing newline.
Example:
# get input from the user
inputString = input('Enter a string:')
print('The inputted string is:', inputString)
Output:
4.2: PRINT()
The print() method outputs the specified object to either the standard output
terminal (screen) or a text stream file.
Example:
message = 'Python is fun'
# print the string message
print(message)
# Output: Python is fun
Output:
Syntax:
The complete syntax of print() is as follows:
Syntax: print ( *objects, sep = ‘ ‘, end = ‘\n’, file = sys.stdout, flush =
False)
Parameters:
Example:
print("Python is fun.")
a=5
# Two objects are passed
print("a =", a)
b=a
# Three objects are passed
print('a =', a, '= b')
Output:
4.3: TRIPLE QUOTES
Python's triple quotes can be used to span strings across many lines. It may
also be used in code for extended comments. Within the triple quotations,
special characters such as TABs, verbatim, & NEWLINEs can be used. Its
syntax is made up of three single or double quotes in a row, as the name
indicates.
Syntax: “” string”” or ”’” string”’”
Triple Quotes for Multi-Line Strings:
Example:
""" This is a long comment that will make the code seem unattractive and
difficult to read on a tiny screen. Thus it should be divided up into multi-line
strings using double triple-quotes"""
print("hello Geeks")
Output:
Example:
txt = 'It\'s alright.'
print(txt)
Output:
Backslash ( \\ )
Example:
txt = "This will insert one \\ (backslash)."
print(txt)
Output:
New Line ( \n )
Example:
txt = "Hello\nWorld!"
print(txt)
Output:
Carriage Return ( \r )
Example:
txt = "Hello\rWorld!"
print(txt)
Output:
Tab ( \t )
Example:
txt = "Hello\tWorld!"
print(txt)
Output:
Backspace ( \b )
Example:
#This example erases one character (backspace):
txt = "Hello\tWorld!"
print(txt)
Output:
CHAPTER 5
CONDITION STATEMENTS
5.1: IF STATEMENT
I f Statement:
One of the most often used "conditional statements" in computer
languages is the "if statement" in Python. It determines whether or not
particular assertions must be performed. It tests for a specific condition, and
if it is true, the code within the "if" block will be performed; otherwise, it will
not. The if condition analyses a Boolean expression & only runs the block of
code if the expression is TRUE.
Syntax:
if expression
Statement
The condition will be converted to a "Boolean expression" in this step
(true or false). If the condition is fulfilled (true), the statement or program
inside the "if" block is run; if the condition becomes false, the statements or
program inside the "otherwise" block is executed.
Example:
num = 5
if (num < 10):
print("Num is smaller than 10")
print("This statement will always be executed")
Output:
If "a" is greater than "b" in the following code, the statements in the "if"
block will be executed, but the ones in the "otherwise" block will be skipped.
Elif Statements:
Another conditional statement in Python is the "elif" statement. If the
supplied condition is false, the "elif" statement is being used to check several
conditions. It's identical to an "if-else" statement, with the exception that in
"else," the condition won't be verified, but in "elif," it will be verified. Elif
statements are identical to if-else statements, except that they examine several
conditions.
Syntax:
if (condition):
#If condition is true, execute the following statements:
elif (condition):
#When the if condition is false & the elif condition is true, a set of
statements is performed.
else:
#When both the if & elif conditions are false, a set of statements is
performed.
Example:
num = 10
if (num == 0):
print("Number is Zero")
elif (num > 5):
print("Number is greater than 5")
else:
print("Number is smaller than 5")
Output:
In the example above, a variable named 'num' has been defined with a
value of 10, and the condition in the "if" statement is verified to see whether
it becomes true. The piece (block) of code included within the "if" condition
will then be executed. If condition is false, the "elif" condition is checked. If
the condition is met, a block of code contained within the "elif" expression is
executed. If true, a block of code included within the "else" expression will
be executed.
Nested If-Else Statement:
An "if" or "if-else" statement nested inside another if/if-else block is
referred to as nested "if-else" statements. This capability is also available in
Python, which allows us to verify several conditions in a single application.
An "if" statement is included within another "if" statement, which is
contained within yet another "if" statement, and so on.
Syntax:
if(condition):
#Statements to execute if condition is true
if(condition):
#Statements to execute if condition is true
#end of nested if
#end of if
According to the aforementioned grammar, the if block will include
another if block, and so on. If block can have as many as 'n' if blocks inside
it.
Example:
i = 10
if (i == 10):
if (i < 20):
print(i, "is smaller than 20")
if (i < 21):
print(i, "is smaller than 21")
Output:
Elif Ladder:
A program with a ladder of "elif" statements or "elif" statements arranged
in the shape of a ladder, as the name indicates. Multiple expressions are
tested with this statement.
Syntax:
if (condition):
# If the condition is true, the following set of statements will be
executed:
elif(condition):
# If the if condition is false & the elif condition is true, a set of
statements will be performed.
elif(condition):
# When both the if and first elif conditions are false and the
second elif condition is true, a set of statements is performed.
elif(condition):
# If the first & second elif conditions are false, and the third elif
statement is true, a set of statements will be performed.
else:
#Set of statements to be executed when all if and elif conditions are
false
Example:
my_marks = 90
if (my_marks < 35):
print("Sorry!, You failed the exam")
elif(my_marks > 60 and my_marks > 100):
print("Passed in First class")
else:
print("Passed in First class with distinction")
Output:
5.2: INLINE IF
In Python, the if-else expression is logical. Inline if statements in Python do
not employ the ternary operator like they do in other languages. Instead, if the
condition is true, it provides just one code to analyze the first expression.
Otherwise, the second phase is evaluated.
Simple If Statement:
In a basic, if statement, a condition is specified, and the if block is
performed depending on that condition.
Syntax:
if condition: statement
if condition:
block
An "inline if statement" is one in which the expression is performed if the
condition is True.
Example:
data = 21
if data < 22: print("It's cool")
Output:
randomList = ['a', 0, 2]
KeyboardInterrupt
>>> raise MemoryError("This is an argument")
def MyFunction(parameters):
function_block
return expression
7.2: BUILT-IN FUNCTIONS
The Python interpreter comes pre-loaded with a handful of methods and types
that are always accessible. When using the Python interpreter, you may
utilize a variety of preset functions that are easily accessible. You don't have
to declare these functions to utilize them; instead, you can call them by name.
Built-in functions are already present in the program. A module is a
collection of built-in functions that are bundled together. These modules are
bundled together to produce a library of information.
Following is the list of some built-in functions in Python:
In this case, the dir() function produces a list of all the properties and
methods of the supplied object but does not return any values. This method
even returns built-in properties, the default properties for all objects, useful
for debugging.
7.3: DEFINING YOUR FUNCTIONS
Normally programs are developed to solve some issue or provide some
feature in programming. These functions might be general or customized to
applications. For general problems, created functions are adequate since they
are meant to handle universal challenges to every application. But, for special
demands, you need to create your code, which may be modularized as
functions, generally known as client functions.
Functions that you develop yourselves to execute particular jobs are
termed user-defined functions. Functions that come with Python are termed
built-in functions. If you employ functions created by others in the library,
they may be described as library functions. All other functions that you
develop on your own go under user-defined functions. So, your user-defined
function might be a library function to someone else. Built-in functions are a
component of the Python package; however, user-defined functions are
written by the developers as per necessity.
Code:
def sum_numbers(x,y):
sum = x + y
return sum
number1 = 5
number2 = 6
print("The addition of two numbers is", sum_numbers(number1,
number2))
Output:
Enter a number: 2.4
Enter another number: 6.5
The sum is 8.9
This section defines the function sum numbers(), which helps to add two
numbers and yields the sum of the two numbers. This is a sample of a user-
defined function. Alternatively, the two integers might be divided inside our
function (the choice is all ours). On the other hand, this technique would be
incompatible with the function's name and avoided. As a result, there would
be some uncertainty. It is advisable to title functions following the job they
are responsible for doing.
7.4: RECURSIVE FUNCTIONS
It is the technique that an application goes through when one of the phases in
that application includes calling the application itself (also known as
recursion). In this case the technique is repeated inside the method itself. A
process that runs via recursion is a 'recursive' procedure. To put it another
way, recursive functions are functions that call themselves. A recursive
function must always be able to determine when it should cease reproducing
itself.
They may be divided into two categories: indirect recursion and direct
recursion.
Code:
def recursive_function():
recursive_function()
Code:
def A_func():
B_func()
def B_func():
A_func()
A recursive function may be broken down into two types:
Code:
def factorial(number):
if number == 1:
return 1
else:
return (number * factorial(number-1))
num = 3
print("The factorial of", num, "is", factorial(num))
Output:
The factorial of 3 is 6
CHAPTER 8
VARIABLE SCOPE
8.1: DEFAULT PARAMETERS VALUES
Y ou may give a default value for each argument when you define a
function. The following syntax is used to set default values for
parameters:
def function_name (param1, param2=value2, param3=value3, ...):
The assignment operator (=) is used to specify the default values (value2,
value3,...) for each argument in this syntax. When you call a function & send
an argument to a parameter with a default value, that argument is used rather
than the default value. If the parameter isn't given, the function will use the
default value. You must position them after other options with default values
to utilize default parameters. You'll get a syntax error if you don't. You can't
do anything like this, for example:
def function_name (param1=value1, param2, param3):
This causes syntax errors.
The welcome() method, which returns a greeting message, is defined in
the following example. The name and message arguments of the greet()
function are defined below. The message argument is set to 'Hi' by default.
The following code invokes the greet() method with the following two
arguments:
Example:
def greet(name, message='Hi'):
return f"{message} {name}"
greeting = greet('John', 'Hello')
print(greeting)
Output:
The greet() method utilizes the second parameter rather than the default
value since it is given as the second argument. The greet() method is called
without the second parameter in the following example:
Example:
def greet(name, message='Hi'):
return f"{message} {name}"
greeting = greet('John')
print(greeting)
Output:
Assume you want the greet() method to produce something along the
lines of Hello there. You may create a function call like this:
Example:
def greet(name='there', message='Hi'):
return f"{message} {name}"
greeting = greet('Hello')
print(greeting)
Output:
Regrettably, it produces an unexpected result. Because the welcome()
method takes the 'Hello' parameter as the first, not the second, argument
when you supply it.
To fix this, use keyword parameters like this when using the greet()
function:
Example:
def greet(name='there', message='Hi'):
return f"{message} {name}"
greeting = greet(message='Hello')
print(greeting)
Output:
8.2: VARIABLE-LENGTH ARGUMENT LIST
Non – Keyworded Arguments (*args):
The (*) in *args denotes that in Python, you can give a variable no. of
arguments to a function. During the function call, you can supply any number
of parameters.
Example:
#program to demonstrate *args in Python
def my_func(*argp):
for i in argp:
#printing each element from the list
print(i)
#passing the parameters in function
my_func("Let","us","study","Data Science","and","Blockchain")
Output:
Python comes with a large no. of standard modules. These files may be
found in the "Lib directory" of the Python installation path. Standard modules
could be imported in the same way that user-defined modules are imported.
Importing modules can be done in a variety of ways. They are as follows:
Import Statement:
You may use the import statement to import a module and the dot
operator to access the definitions within it, as explained before.
Example:
import math
print("pi value ", math.pi)
Output:
All of the definitions from the math module have been imported here.
Except for those that begin with an underscore, this contains all names visible
in the scope (private definitions). Using the asterisk (*) sign to import
everything is not a smart programming practice. This can result in several
identifier definitions. It also makes our code harder to read.
Module Search Path:
Python searches in numerous locations when importing a module. The
interpreter looks for the built-in module first. Python then searches a list of
directories specified in sys. Path if a built-in module also isn't found. The
following is the order of the search:
To add our own path, you may add to and alter this list.
Reloading a Module:
During a session, the Python interpreter only imports a module once.
Things become more efficient as a result of this. To see how this works,
consider the following example. Assume the following code is in a module
called my module:
# This module shows the effect of
# multiple imports and reload
print("This code got executed")
You can now see the result of several imports.
>>> import my_module
#Output
This code got executed
>>> import my_module
>>> import my_module
You can see that our code was only run once. This means that our module
was only imported once. You'd have to reload your module if it changed
during the course of the application. Restarting the interpreter is one method
to achieve this. However, this is of little use. Python offers a more efficient
method of accomplishing this. To reload a module, you may use the imp
modules reload() function. You can accomplish it in a variety of ways:
>>> import imp
>>> import my_module
>>> import my_module
>>> imp.reload(my_module)
Dir() Built-in Function:
The Dir() method can be used to locate names declared within a module.
For example, in the module instance from before, a method called add() was
written. In the sample module, Dir can be used in the following way:
Example:
>>> dir(example)
#Output
['__builtins__',
'__cached__',
'__doc__',
'__file__',
'__name__',
'__initializing__',
'__loader__',
'__package__',
'add']
You may view a sorted list of the names here (along with add). All the
other names that start with just an underscore are the module's default Python
attributes (not user-defined). The __name__ element, for example, includes
the module's name.
Example:
>>> import example
>>> example.__name
The dir() method can be used without any parameters to find all the
names declared in our current namespace.
Example:
>>> a = 1
>>> b = "hello"
>>> import math
>>> dir()
Output:
CHAPTER 10
WORKING WITH FILES
10.1: OPENING AND READING TEXT FILES
H ow toYouOpen a Text File:
must use the built-in "open" function to open a file. The Python
files open function provides a file object with methods and properties that
may be used to conduct different file operations in Python. The open file
method in Python has the following syntax:
Syntax:
file_object = open ("filename", "mode")
Here, “filename” gives the name of the file that the file object has opened,
and “mode” is the attribute of a file object that tells you which mode a file
was opened in.
How to Read Files:
In Python, you may read a file by calling.txt file in "read mode" (r).
Step 1:
Open file in read mode:
f=open("myfile.txt", "r")
Step 2:
The mode function is utilized in the code to verify if the file is in open
mode. If that's the case, you can go on to the next step:
if f.mode == 'r':
Step 3:
For accessing files in Python, use f.read to read data from a file and put it
in a variable called content.
contents =f.read()
Step 4:
For a Python read text file, print the contents.
Example:
def main():
f=open("myfile.txt","r")
if f.mode=="r":
contents=f.read()
print(contents)
if __name__=="__main__":
main()
Output:
When you run code (f1=f.readlines()) in Python to read a file line by line,
it separates each line and displays the file legibly; because the line is short &
readable in our scenario, the output will resemble the read mode, this piece of
code, however, might be beneficial if there is a complicated data file that is
not understandable.
10.2: USING A FOR LOOP TO READ TEXT FILES:
When the open() procedure is used to start a file, it returns an iterable object.
Iterating through a file object in for loop is the ultimate method of reading
in a file line by line. You're utilizing a built-in Python method that allows us
to iterate through file object implicitly using for loop in conjunction with the
iterable object in this way. This method requires fewer lines of code, which is
usually a good habit to follow.
Example:
# Python program to
# demonstrate reading files
# using for loop
L = ["Python\n", "Text\n", "File\n"]
# Writing to file
file1 = open('myfile.txt', 'w')
file1.writelines(L)
file1.close()
# Opening file
file1 = open('myfile.txt', 'r')
count = 0
# Using for loop
print("Using for loop")
for line in file1:
count += 1
print("Line{}: {}".format(count, line.strip()))
# Closing files
file1.close()
Output:
10.3: WRITING TO A TEXT FILE
To write into a file in Python, you must open it in write "w," append "a,"
and exclusive creation "x" mode. Because the "w" mode will overwrite a file
that already exists, it should be used with caution. As a consequence, all
previous information is erased. To produce a string/series of bytes, use the
write() method. This function returns the no. of characters written to the file.
Example:
with open("test.txt",'w',encoding = 'utf-8') as f:
f.write("my first file\n")
f.write("This file\n\n")
f.write("contains three lines\n")
#Output
'my first file\nThis file\n\ncontains three lines\n'
If the file "test.txt" does not exist in the current directory, this application
will create it. If it exists, it has been overwritten. To separate the different
lines, you must insert the newline characters ourselves.
10.4: OPENING & READING TEXT FILES BY BUFFER
SIZE
By setting buffer size in the read function, you may read a file with a
restricted buffer. It reads the no. of bytes you require from the pointer's
current location in the file.
Example:
with open('test.txt', 'r') as f:
print(f.read(10)) # Read and print 10 bytes
Output:
10.5: OPENING, READING, AND WRITING BINARY
FILES
Write a Binary File:
You must first write a file before you can read it. The file gets opened
using file = open("document.bin","wb"), and the binary file is written using
the "wb" mode. The name of the file is document.bin. "This is nice" has been
assigned to a variable in the form of a sentence. sentence = bytearray("This is
excellent") is used to decode the sentence. The function encodes ("ASCII")
has been used. The file.write() function was used to save the sentence to the
file. The write() method is used to save a file with the provided text. The
file.close() function was then used to close the file.
Example:
file = open("document.bin","wb")
sentence = bytearray("This is good".encode("ascii"))
file.write(sentence)
file.close()
Read a Binary File:
To read the file, take the document.bin file that has already been prepared
& read the binary file using the "rb" mode. The file name is document.bin.
The read() function is also utilized. The read() function reads a specified
no. of bytes from a file and returns them.
Example:
file = open("document.bin","rb")
print(file.read(4))
file.close()
Output:
10.6: DELETING AND RENAMING FILES
The OS module in Python offers methods for performing file-processing
activities, including renaming and removing files. To utilize this module, you
must first import it before using any associated functions.
The rename() Method:
The current filename & the new filename are sent to the rename()
function.
Syntax:
os.rename (current_file_name, new_file_name)
The following is an instance of how to rename a file called test.txt that
already exists:
Example:
#!/usr/bin/python
import os
# Rename a file from test.txt to test2.txt
os.rename( "test.txt", "test1.txt" )
Class
Object
Method
Inheritance
Encapsulation
Polymorphism
Data Abstraction
11.1: CLASSES
Data and functions can be organized into classes in Python. It allows for the
creation of data structures that can contain any data and are, as a result, more
openly accessible.
A bank employee, for example, might go into the bank's website and click
on the customer class to see all of the client's properties, such as transaction
information and withdrawal and deposit records.
There is no doubt that classes are indeed a pattern or blueprint for
creating things. In another way, we create a class that contains the properties
and methods of several objects. Variables represent attributes, whereas
methods carry out operations. There are two types of variables and methods
in classes. When you construct objects from a class, you have access to all
the same attributes and methods. To make them stand out from other data in
the instance, they are termed instance variables' (i.e., object). A method is not
a function; they are two distinct concepts.
The overall structure of a class may be summarized thusly:
Class NameOfClass(object):
attributes def __init__(self):
def procedure1():
def procedure2():
11.1.1: Class Creation
Writing the Classname after the keyword class creates a new kind of
class. The word 'object' is inserted within the Classname after the word
'Classname.' In Python, all classes are descended from a basic class called
object. We even have our classes derived from the object' class. Thus, the
parentheses need to include a reference to the 'object'. To avoid confusion, it
is unnecessary to use the word "object."
Code example for class creation and instantiation is as follows:
class Student:
# Class attribute
type = "student"
# Instance attribute
def __init__(self, name, age):
self.name = name
self.age = age
When you use functions, they are placed at the top of your code,
and the data you provide to the functions may be located
anywhere throughout the program. When a program grows too
lengthy, it becomes difficult to supervise. Classes allow you to tie
specific data to specific functions, allowing you to keep
everything in one place.
The fundamental premise of object orientation is that types
(classes) serve as the focal point of modularity, instead of
procedures or functions, rather than processes and functions.
The fact that it is very adaptable is one of its advantages. The type
is represented, but there are no members in it. Any function has
the authority to determine which fields should be included.
Different invocations of this class may generate objects of this
kind, populated in various ways.
11.2: OBJECTS
11.2.1: Introduction to Objects
When it comes to Python, classes are merely logical entities that act as a
prototype or template for creating objects, whereas an object is a group of
variables and Python methods. Parameters and functions are declared inside a
class and are accessible via object references. Attributes are a term used to
refer to a collection of variables and functions. Objects are simple collections
of data (parameters) and ways (functions) that operate on the data in a
collection of variables. Class definitions are similar to that of an object
definition.
To better comprehend the notion of Python objects and classes, let's look
at an example. One way to think about an object is to be an ordinary
everyday item, such as a vehicle. As previously described, we know that a
class has data and functions specified inside it. These data and functions may
be deemed characteristics and behaviors of the object, respectively, based on
their placement within the class. The characteristics (data) of the automobile
(object) include its color, price, number of doors, etc. Car (object) actions
(functions) include moving at a certain speed, using the brakes, and so on. An
object class allows for creating several objects, each having its own set of
data and methods associated with it.
Previously, we learned that class objects could be used to retrieve various
characteristics.
It may also be used to generate new object instances (instantiations) of a
class that has been defined before. The technique for creating an object is
identical to calling a function.
Tom = Dog ()
This will result in creating a new individual object with the name Tom.
The characteristics of objects may be accessed by using the prefix of the
object's name.
Data or a procedure may be used as attributes. An object's procedures
correspond to the equivalent functionalities of the object's class.
11.2.2: Object Instantiation
Whenever we declare a class, we create a representation or a blueprint for
the described thing. There are no modes until we construct the object that will
be allocated. Actual information or data is included inside the objector
instance. A class may be thought of as a template. The ability to construct
data structures based on the properties and methods that you describe is
provided by this feature.
Instantiation is nothing more than the process of producing a new object
or instance of a given class.
You might think of it as a cookie-cutter that you can customize to create
the ideal cookies, each with specific attributes such as shape, size, and other
qualities that you specify.
Code:
class Cookie:
pass
cookie1=Cookie ()
cookie2=Cookie ()
On the other hand, there are some examples. An instance of a class is a
single object belonging to a class with a distinct memory address.
11.2.3: Creating an Object
To access the characteristics of a class, an object with the same identity as
the class is used. But that is not the only thing that the class object can be
used for; it could also be used to construct new objects, but then those objects
may be used to access the attributes, as seen in the following example:
Code:
class A:
a=5
def functionA(self):
print('Welcome to Class A')
object1 = A()
object1.functionA()
Output:
However, while calling the function, we are not giving any value to it
since we use a self-defined parameter when declaring it in the class. When a
function is called with an object, the object itself is immediately supplied to
the function as an argument, making object1.functionA() equal to
object1.functionA() (object1). As a result, the very first parameter in the
method must be the item itself, which is referred to as the 'self' argument in
most cases. It is possible to call it anything else as well. However, naming
itself is a tradition, and following this convention is regarded as great
programming training.
11.2.4: Modifying and Deleting Objects
In addition to creating, it is possible to modify and remove objects once
they have been created as follows:
The object can be deleted using the "del" keyword
class A:
a=5
def functionA(self):
print("Welcome to Class A")
del a
object1 = A()
del object1
#The object can be modified as:
class Apple:
a=5
def functionApple(self):
print('Welcome to Class Apple')
Apple.functionApple(1)
print(Apple.a)
Apple.a=10
print(Apple.a)
Output:
11.2.5: Advantages of Objects
In the static binding, the overloaded functions are invoked based on the
type and number of arguments that match the corresponding type and number
of arguments.
Because all of this data is accessible throughout the compilation process,
the compiler finds the most suited function for the situation.
It is accomplished by function overloading, which is sometimes referred
to as static or early binding in certain circles.
class A:
def Say(self):
pass
class B(A):
def Say(self):
print("I am class B")
class C(A):
def Say(self):
print("I am class C")
a1 = B()
a1.Say()
a1 = C()
a1.Say()
Output:
The bike is the main base class in the preceding code, while the electric
bike and petrol bike are the children classes in the same code. And the
methods fuel() and capacity() are passed down to the child classes Electric
bike and petrol bike, respectively. Currently, we can alter the functionality of
the methods as needed, and we've actually implemented the fuel() method
inside the electric bike class, and we've done the same thing in the petrol bike
class to make the fuel() function more accessible.
Examples include the code ebike. fuel(), which prints "Electric bikes
operate on a battery," and pbike.fuel(), which prints "Petrol bikes run on
gasoline."
11.3.5: Implementing Method Overloading
Python does not offer method overloading in the same way other
programming languages do. It will just overwrite the previously defined
function with the most recent definition. On the other hand, we may attempt
to obtain a result comparable to overloading by utilizing *args or optional
arguments.
class OptionalArgument:
def addNumbers(self, a, b, c=0):
return a + b + c
o = OptionalArgument()
print(o.addNumbers(2,3))
print(o.addNumbers(2,3,4))
Output:
11.3.6: Implementing Method Overriding
Method Overriding or Runtime polymorphism is the overriding of
methods. It functions in conjunction with inheritance. In method overriding,
even if the name of the method and the arguments supplied are the same, the
method's behavior varies depending on the kind of object being overridden.
class Animal:
def sound (self):
pass
class Cat(Animal):
def sound (self):
print("Meoooowwwww")
class Dog(Animal):
def sound (self):
print("Woohoo")
a = Cat()
a.sound()
a = Dog()
a.sound()
Output:
We constructed the Cat and Dog classes in the preceding example, which
derive from the Animal class. After that, we added the Sound method to both
the Cat and Dog classes. As you can see in the preceding example, sound
publishes various results on the same Animals reference depending on how it
is configured in sound.
At runtime, it determines the kind of object to be created and runs the
appropriate function.
11.3.7: Why Should one use Polymorphism?
Single Inheritance
When a child class becomes a parent class for another child class.
Code:
class Parent:
def ParentFunction1(self):
print("This is parent class 1")
class Child(Parent):
def ChildFunction1(self):
print("This is child class 1")
ob = Child()
ob.ParentFunction1()
ob.ChildFunction1()
Output:
Multiple-Inheritance
It is that a child class inherits from more than one parent class.
Code:
class Parent:
def Parentfunction1(self):
print("This is parent class 1")
class Parent2:
def Parentfunction2(self):
print("This is parent class 2")
class Child(Parent , Parent2):
def ChildFunction1(self):
print("This is child class 1")
ob = Child()
ob.Parentfunction1()
ob.Parentfunction2()
ob.ChildFunction1()
Output:
Multilevel Inheritance
When a child class becomes a parent class for another child class.
Code:
class Parent:
def ParentFunction1(self):
print("This is parent class 1")
class Child(Parent):
def ChildFunction1(self):
print("This is child class 1")
class Child2(Child):
def ChildFunction2(self):
print("This is child class 2")
ob = Child2()
ob.ParentFunction1()
ob. ChildFunction1()
ob. ChildFunction2()
Output:
11.5.2: Parent Class Creation
The parent class is often referred to as the base class. Parent classes
provide a pattern on which children or subclasses may be built, reusing them.
This class may have the capability of creating a child class via inheritance,
eliminating the need to rewrite the same code every time.
As an illustration: To create a bank account, we will use the term "bank
account" as a personal account that contains the child classes "personal
account" and "business account." Several ways between personal and
commercial accounts will be identical, such as ways to withdraw and deposit
money; thus, such methods may be grouped under the parent class of bank
account for convenience.
11.5.3: Child Class Creation
Children are categories that are descended from the base class in some
way. It simply implies that each child's class will utilize the procedures and
variables available in the parent class. For example, business_account is a
child class of bank_account.
Class account(Bank_account)
pass
Remember that the 'pass' keyword is used when you do not add more
attributes or functions to the class.
This step will create a subclass that will inherit the methods and
properties from its parent class.
Instead of passing the 'pass' keyword to the child class, the __int__ ()
function is sent.
Super() allows you to have a child class inherit all of the procedures and
characteristics from its parent class, which is very useful when dealing with
inheritance.
11.5.4: Syntax Inheritance
Inheritance is the ability for a new class category to inherit the attributes
and behaviors of an existing class. The class from which inheritance is
derived is referred to as the parent class. A child class is any class that derives
from a base class in the Java programming language.
Child classes not only inherit all of their parent class's properties and
methods, but they also have the ability to expand or rewrite them.
The following is the standard syntax for class Inheritance:
class Base_Class:
#Base class body
class Derived_Class(Base_Class):
#Derived class body
11.5.5: Advantages of Inheritance
Code reusability; There are many ways available to you that will
allow you to use the same functions and attributes across your
code.
It is a good representation of real-world relationships between
parent and child classes.
In nature, it has a transitive property. If a subclass class gets
attributes from a base class, then all of the child class's subclasses
will likewise receive the characteristics of the parent class, as will
all of the child class's subclasses.
Code reusability is the frequent usage of code that has only been
written once.
A single superclass may represent the number of subclasses within
a chain.
Inheritance eliminates duplication and redundancy in data.
Inheritance is being used to reduce the amount of space and time
required.
There are no modifications to be made in any of the base classes;
only changes need to be made in the parent class.
The ability to pass on inheritance in order to develop more
dominating items.
The use of inheritance forces subclasses to adhere to a common
interface.
Inheritance aids in the reduction of code duplication and the
facilitation of code extension.
The use of inheritance makes it easier to create class libraries.
TL = TeamLeader('Jake',5000,'Master')
Output:
This is because the methods called are from class B rather than class A in
the preceding example due to the Method Resolution Order (MRO). The
above-given example is how the classes are listed in the code above: class B
and then class A.
When there are multiple inheritances, the procedures are run in the order
in which they were indicated when the classes were inherited. The sequence
in which procedures are resolved is referred to as the resolution order. Not
important for languages that offer single inheritance, but for languages that
enable multiple inheritances, the order in which methods are resolved is quite
important. This arrangement is referred to as Linearization of a subclass, and
the collection of rules used to achieve it is referred to as MRO (Method
Resolution Order). You may acquire the MRO of a class by using either the
__mro__ property or the mro() method. Both of these methods are available
in Java. In contrast to the __mro__ attribute, the mro() function produces a
python list instead of a tuple.
Method Resolution Order (MRO) is a programming language term that
refers to the order in which a method or property is resolved. The Python
programming language permits classes that derive from other classes. The
class that is being inherited is referred to as the Base or Superclass, whereas
the class that is being inherited is referred to as the Child or Subclass. When a
method is executed in Python, the resolution order specifies the sequence in
which the parent classes are looked for and found. To find the method or
attribute, it must first be searched inside a class, and then it must follow the
inheritance order set while inheriting. This arrangement is also known as
Linearization of a class, and the collection of rules that govern it is known as
MRO (Method Resolution Order). Even though the interpreter is deriving
from another class, it still has to be able to fix the functions that are being
invoked via an instance. As a result, we need the technique resolution order.
11.6.4: Advantages of Multiple Inheritance
These operators have been made to work with int and str classes to be
used with both.
11.7.1: Need for Operator Overloading?
Because the compiler doesn't fully understand how well to multiply the
operands, it will give us a compiler error if we try to multiply them with the
Operator *.
Here, let's look at an example of a class we've made ourselves called
Graph. It has two attributes called "X" and "Y." Now, items of this class
would be different points, and adding + to these points (objects) would be an
error.
Code:
class Graph:
def __init__(self, x, y):
self.x = x
self.y = y
p1 = Graph(1, 2)
p2 = Graph(2, 3)
print(p1+p2)
Output:
In this case, the compiler doesn't understand what p1+p2 stands for.
We can write a method to override the + Operator to be used differently
to solve this problem.
11.7.2: Preforming Operator Overloading
Python has a special method or magic function automatically called when
that Operator is used to do operator overloading.
For example, when we use the * operator, the magic method __mul__ is
instantly called. This method already has the operation for the * operator set
up.
To make the '+' operator work in a different way, we will use the __add__
magic method to do it.
Code:
class Graph:
def __init__(self, a,b):
self.a = a
self.b=b
def __add__(self, o):
a=self.a+o.a
b=self.b+o.b
ss=Graph(a,b)
return ss
p1=Graph(30,40)
p2=Graph(70,80)
ss=p1+p2
#sum of the a coordinates of graph
print(ss.a)
#sum of the b coordinates of graph
print(ss.b)
Output:
We have added the __add()__ method to the Graph object and called it.
We ended up getting the sum of the coordinates, which was the Graph object.
11.7.3: Overloading Arithmetic Operator
Let us overload the "+" arithmetic operator. To implement the __add__()
method in the class, we will need to overload the + Operator. When you have
enormous power, you also have immense responsibility. Within this function,
we have complete freedom to do anything we want. However, it is more
logical to give a Point object representing the coordinate sum.
Code:
class Coordinates:
def __init__(self, a=0, b=0):
self.a = a
self.b = b
def __str__(self):
return "({0},{1})".format(self.a, self.b)
def __add__(self, other):
a = self.a + other.a
b = self.b + other.b
return Coordinates(a, b)
Now let's try the addition operation again:
Code:
class Coordinates:
def __init__(self, a=0, b=0):
self.a = a
self.b = b
def __str__(self):
return "({0},{1})".format(self.a, self.b)
def __add__(self, other):
a = self.a + other.a
b = self.b + other.b
return Coordinates(a, b)
point1 = Coordinates(10, 20)
point2 = Coordinates(20, 30)
print(point1+point2)
Output:
Addition: p1+p2
Subtraction: p1-p2
Multiplication: p1*p2
Power: p1 ** p2
Division: p1/p2
Floor Division: p1//p2
Remainder: p1%p2
Bitwise NOT: ~p1
Bitwise XOR: p1^p2
Bitwise OR: p1|p2
Bitwise AND: p1&p2
Bitwise Left Shift: p1<<p2
Bitwise Right Shift: p1>>p2
D ata Structure is a method for gathering and classifying the data in such a
manner that actions on them may be performed efficiently. Data
Structures is the process of representing data pieces in terms of a connection
in order to facilitate organization and storage. For instance, we include some
data indicating the client's name is "Eras," and her age is 19. Here, "Eras" is a
String, and 19 is an integer.
We can arrange this data by creating a record called Client, which will
include both the clients' names and ages. Now, as a data structure, we may
gather and store clients' records in a database file. For instance, "Daryl" is 10,
"Joline" is 11, and "Lennie" is 13.
If you are accustomed to Object-Oriented programming standards, a class
does the same thing; it aggregates several types of data into a single entity.
The main distinction is that data structures include ways for effectively
accessing and manipulating data.
In basic terms, Data Frameworks are built to hold ordered data in a
manner that facilitates the execution of different operations on it. It is a
representation of the knowledge associated with the material to be arranged
in memory. It ought to be designed and executed in such an approach that
complexity is minimized and efficiency is maximized.
12.1: ASYMPTOTIC ANALYSIS
An asymptotic analysis of a procedure is a way to figure out the math behind
how well it works at running. Asymptotic analysis can help us figure out the
best case, the average case, and the worst case of an algorithm.
This type of analysis is called "input bound," which means that if there is
no input to the method, it is thought that it will work in an endless amount of
time. Other than "input," all other components are recognized to be the same.
Asymptotic analysis is the process of figuring out how long an operation
will take in terms of mathematic units of time. For example, for one
operation, the running time is f(n), and for another, it is g(n) (n2). As the
amount of operations grows, so does the first operation's running time. The
second operation's running time will grow exponentially as the number of
operations increases. Both operations will run for about the same amount of
time if n is very small.
Most of the time, an algorithm takes falls into three groups. −
Best Case: This is when the program runs in the shortest amount of time.
Average Case: The average time it takes to run a program.
Worst Case: The longest time it will take to run the program.
Asymptotic notations are used to figure out how long an algorithm takes
to run. These are the most common ones.
constant
Ο(1)
polynomial
n Ο(1)
logarithmic
Ο(log n)
linear
Ο(n)
exponential
2 Ο(n)
quadratic
Ο(n 2)
cubic
Ο(n 3)
n log n
Ο(n log n)
12.2: LINEAR DATA STRUCTURES
In this section, the linear type of data structures like stacks, queues, and so on
are discussed.
12.2.2: Stack
A linear data structure that uses the First-In and Last-Out (FILO) or Last-
In and First-Out (LIFO) ordering to store objects. A new mechanism is added
to one end of a stack, while an element is withdrawn from the other end.
Insert and delete processes are sometimes referred to as push and pop.
Stack is connected with the following functions:
Implementation
In Python, a stack may be implemented in a variety of ways. This article
discusses how to create a stack using Python data structures and modules.
In Python, the stack may be implemented in the following ways:
List
queue.LifoQueue
Collections.deque
Code:
from queue import LifoQueue
stack = LifoQueue(maxsize=4) #initialize stack at 4
print(stack.qsize()) #display size
stack.put('1')#push onto stack
stack.put('2')
stack.put('3')
stack.put('4')
print("Full Stack: ", stack.full())
print("Size Stack: ", stack.qsize())
print('\nElements popped from the stack')
print(stack.get())#LIFO order get top and pop
print(stack.get())
print(stack.get())
#now one remaining
print("\nNon empty: ", stack.empty())
Output:
12.2.3: Queues
Like a stack, a queue is a sequential data model that holds items in a
(FIFO) First In First Out order, just like the stack. To get rid of something
from a queue, start with the item that was last added. Queue: Any line of
people waiting to get something where the person who came first has
functioned first.
Operations Used:
1. queue.Queue
2. collections.deque
3. list
Queue Implementation
As described in Section' 12.2.2: Stack Implementation through
Queues', the implementation of queues using:
from queue import Queue
; is the same as described in section 12.2.2.
Collections Implementation
The deque class through the collection modules may be used to create a
queue in Python. When we require faster append and pop actions from both
ends of a container, the deque is chosen over the list because deque has an
O(1) computation time for add and remove operations, whereas the list has an
O(n) time complexity. The operations append(), and popleft() is used rather
than enqueue and deque.
Code:
from collections import deque #imports collections through deque
q = deque() #initializes queue through deque
# Adding elements 1,2,3 to queue (enqueue)
q.append('1')
q.append('2')
q.append('3')
print("Queue at start: ")
print(q)
# Removing elements from a queue
print("\nelements popped: ")
print(q.popleft())
print(q.popleft())
print(q.popleft())
print("\nUpdated Queue: ")
print(q)
#if we use q.popleft() now, it will raise an index error as list is now empty
Output:
Lists Implementation
The list is a built-in data structure in Python that can be utilized as a
queue, and it is called a list. Rather than enqueue() and dequeue(), the
append() and pop() functions are used to add and remove items from a queue,
instead. Lists, on the other hand, are very slow for this because it takes a lot
of time to add or remove an attribute at the beginning.
Code:
# Initializing
queue = [] #queue as list
# enqueue 1,2,3
queue.append('1')
queue.append('2')
queue.append('3')
print("Queue 1: ")
print(queue)
# Removing elements from the queue from head, (FIFO)
print("\nElements dequeued: ")
print(queue.pop(0))
print(queue.pop(0))
print(queue.pop(0))
print("\nQueue after removal")
print(queue) #queue now empty
Output:
There are a number of types of linked lists that can be used, the one
shown over is known as a singly linked list.
For example, suppose we have a sorted collection of IDs in an array
called list1[].
List1[] = [2000, 2020, 2050,3000, 3040]
And because you want to add a new element of List1 2005, we'll have to
shift all the components after 1000 to keep the sorted order (excluding 2000).
Code:
# Node class defined
class Node:
def __init__(self, data):
self.Nodedata = data
self.nextNode = None
# next is initialized as none
class LinkedList: #linked list class
def __init__(self):
self.Listhead = None
Output:
No output as this is only creating classes, not objects, nor is it returning
anything.
You can create a linked list object by the following:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
# Main Code Begins:
if __name__=='__main__':
# Create object of empty list
list1 = LinkedList()
list1.head = Node(1)
second = Node(2)
third = Node(3)
'''
Three nodes have been created. But is not yet a linked list because the
nodes aren't linked
References to three blocks as defined as head, second and third
'''
list1.head.next = second; # this linked first head to second node
second.next = third; # Link second node to third
Output:
This also shows no output but creates a linked list of 3 nodes.
Traversal
We generated a basic linked list with 3 nodes in the previous program.
Let's go over the list and display the info for each node. Let's create a
generalized printList() that displays any provided list for traversal.
Code:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def display(self): #Here add the display function
temp = self.head #initialize head as the temp node
while (temp): #while the node temp exists (is not none)
print (temp.data) #display data of node
temp = temp.next #move to next node
if __name__=='__main__':
list1 = LinkedList() #object created
list1.head = Node(1)
second = Node(2)
third = Node(3)
list1.head.next = second; #link
second.next = third; #link
list1.display() #call display method
Output:
Code:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
# Function to initialize the Linked List object
def __init__(self):
self.head = None
def display(self): #display function
temp = self.head
while (temp):
print (temp.data)
temp = temp.next
def push(self, new_data): #insert add
new_node = Node(new_data) #add the new data in a new node
new_node.next = self.head #link the next pointer of new node to
current head
self.head = new_node #make the new node the new head
linkedL=LinkedList()
linkedL.push(5)
linkedL.push(3)
linkedL.push(1)
linkedL.display()
Output:
linkedL=LinkedList()
linkedL.push(5)
linkedL.push(3)
linkedL.push(1)
linkedL.insertAfter(3,9)#insert 9 after 3
linkedL.display()
Output:
1. At the conclusion
Code:
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
# Function to initialize the Linked List object
def __init__(self):
self.head = None
def display(self): #display function
temp = self.head
while (temp):
print (temp.data)
temp = temp.next
def push(self, new_data): #insert at head
new_node = Node(new_data) #add the new data in a new node
new_node.next = self.head #link the next pointer of new node to
current head
self.head = new_node #make the new node the new head
# This function is explained in Linked List class definition
# Appends a new element at the end of the list. This operation is
# defined inside the LinkedList class displayed above */
def append(self, new_data):
new_node = Node(new_data)
if self.head is None:
self.head = new_node
return
last = self.head
while (last.next):
last = last.next
last.next = new_node
linkedL=LinkedList()
linkedL.push(5)
linkedL.push(3)
linkedL.push(1)
linkedL.append(0)#insert 9 at the end
linkedL.display()
Output:
Deletion of a Node
To comprehend the deletion process, let's develop a problem statement:
Remove the first instance of a 'key.'
Assume a linked list with a small number of entries. Our goal is to create
a function that removes the specified node from the collection. So, if the list
starts with 1 3 5 7 9, after eliminating 3, it will be 1 5 7 9.
Consider the pointer 'node,' which points to the node to be destroyed. To
delete the node, we must do the following procedures.
node.next.val = node.val
node.next.next = node.next.next
Code:
class node:#create node class
def __init__(self, data, next = None):
self.value = data
self.nextPtr = next
#function make a list
def make(nodes):
head = node(nodes[0])
for nodes in nodes[1:]:
ptr = head
while ptr.nextPtr:
ptr = ptr.nextPtr
ptr.nextPtr = node(nodes)
return head
#traverse list
def printL(head):
ptr = head
print('Linked List: [', end = "")
while ptr:
print(ptr.value, end = ", ")
ptr = ptr.nextPtr
print(']')
class deletionclass(object):#class for deletion
def deleteNode(self, node, data):#void type function
while node.value is not data:
node = node.nextPtr
node.value = node.nextPtr.value
node.nextPtr = node.nextPtr.nextPtr
LL = make([0,34,1,4,9,10])#pass 0, 34, 1, 4, 9, 10 as a linked list
printL(LL) #traverse initial list
delHere = deletionclass() #create object for deletionclass called delHere
delHere.deleteNode(LL, 4) #pass the linked list LL and the value to
delete, 4, to a method deleteNode
printL(LL) #traverse new list
Output:
Data
Pointer to the right child
Pointer to left child
The root of the tree is the highest node. The components just underneath
an element are referred to as its offspring. Its parent is the element that sits
exactly above it. For instance, 'a' is a child of 'f,' and 'f' is 'a's' parent. Finally,
no-child components are referred to as leaves.
Tree Class Code:
class Node:
def __init__(self,key):
self.left = None #left node
self.right = None #right node
self.val = key
root = Node(2) #create object
root.left = Node(9);
root.right = Node(1);
root.left.left = Node(4);
''' 2
/ \
9 1
/ \ / \
4 None None None
/ \
None None'''
Types of Binary Trees
Full Binary
Binary Tree in its Full Form, if each node has 0 or 2 offspring, it is called
a complete binary tree. A whole binary tree is shown in the examples below,
where all nodes have two offspring except the leaf nodes.
Code:
class Node:
def __init__(self, item):
self.item = item
self.leftnode = None
self.rightnode = None
def FullTree(root):
# Tree in empty case
if root is None:
return True
# Check if child present
if root.leftnode is None and root.rightnode is None:
return True
if root.leftnode is not None and root.rightnode is not None:
#recursively call to check for every node
return (FullTree(root.leftnode) and FullTree(root.rightnode))
return False
root = Node(2) #creating tree
root.rightChild = Node(4)
root.leftChild = Node(3)
root.leftChild.leftChild = Node(5)
root.leftChild.rightChild = Node(6)
root.leftChild.rightChild.leftChild = Node(7)
root.leftChild.rightChild.rightChild = Node(8)
if FullTree(root): #if true returned
print("tree is a full binary tree")
else: #if false returned
print("tree is not full binary tree")
Output:
Complete Binary
When each and every level is entirely filled, with the exception of the
lowest, which is possibly filled from the left, it is similar to a full binary tree,
but there are two significant distinctions.
A complete binary tree is not always a full binary tree because the
last leaf element may not have the right sibling.
The leaf components must all slant to the left.
Code:
# Checking if complete
class Node:
Perfect Binary
A perfect binary tree is one in which each internal node has precisely two
child nodes, and all leaf nodes would be at the same level. A degree of 2 is
assigned to all internal nodes.
A perfect binary tree can be accurate and useful information as recursion:
Code:
# if a binary tree is perfect
class newNode:
def __init__(self, k):
self.key = k
self.right = self.left = None
# To calculate depth
def calcDepth(node):
a=0
while (node is not None):
a += 1
node = node.left
return a
# Check if perfect binary tree
def perfect(root, d, level=0):
# in empty tree case
if (root is None):
return True
# presence of trees
if (root.left is None and root.right is None):
return (d == level + 1)
if (root.left is None or root.right is None):
return False
return (perfect(root.left, d, level + 1) and
perfect(root.right, d, level + 1))
root = None
root = newNode(2)
root.left = newNode(3)
root.right = newNode(4)
root.left.left = newNode(5)
root.left.right = newNode(6)
if (perfect(root, calcDepth(root))):
print("The tree is perfect binary tree")
else:
print("The tree not perfect")
Output:
Balanced Binary
The height is balanced if it is O(log n), where n is the total number of
nodes. The AVL tree, for example, maintains O(log n) height by ensuring
that the height difference between the left and right subtrees is no more than
1. Red-Black trees keep their height constant by ensuring that the proportion
of nodes on each root-to-leaf path is the same and that no neighboring red
nodes exist. Even Binary Search trees provide high performance since they
search, insert, and delete in O(log n) time.
The criteria for a height-balanced binary tree are as follows:
The left subtree's nodes are all smaller than the root node.
The root node is greater than all nodes in the right subtree.
Each node's subtrees are likewise BSTs, the same two attributes as
the node.
To demonstrate that a tree with a right subtree for one value smaller than
the root is not a legitimate binary search tree, a tree with a right subtree for
one value smaller than the root is displayed.
Operation of Search
The approach is based on the BST characteristic that each left subtree has
values lower than the root, and each right subtree has data higher than the
root.
If the number is below the root, we can be confident it is not in the right
subtree; we only need to look in the left subtree, and if the value is over the
root, we can be sure it is not in the left subtree; we only need to look in the
right subtree.
Algorithm Used:
If root == NULL
return NULL;
If number == root->data
return root->data;
If number < root->data
return search(root->left)
If number > root->data
return search(root->right)
Insert Node
The goal is to use a queue to iteratively traverse the supplied tree in level
order. If a node's left child is null, we create a new key as the node's left
child. If the right child of a node is empty, we find the new key the right
child. We continue to traverse the tree until we locate a node with an empty
left or right child.
Code:
# program to inject an element in the binary tree
class newNode():
def __init__(self, data):
self.key = data
self.left = None
self.right = None
#Inorder traversal binary tree
def inorder(temp):
if (not temp):
return
inorder(temp.left)
print(temp.key,end = " ")
inorder(temp.right)
#insertion of new node
def insert(temp,key):
if not temp:
root = newNode(key)
return
q = []
q.append(temp)
while (len(q)):
temp = q[0]
q.pop(0)
if (not temp.left):
temp.left = newNode(key)
break
else:
q.append(temp.left)
if (not temp.right):
temp.right = newNode(key)
break
else:
q.append(temp.right)
# Driver code
if __name__ == '__main__':
root = newNode(11)
root.left = newNode(12)
root.left.left = newNode(8)
root.right = newNode(10)
root.right.left = newNode(16)
root.right.right = newNode(9)
print("Traversal before insertion:", end = " ")
inorder(root)
key = 12
insert(root, key)
print()
print("Traversal after insertion:", end = " ")
inorder(root)
Output:
Delete a Node
Remove a node from a binary tree by ensuring that the tree declines from
the bottom up (i.e., the deleted node is replaced by the leaf and rightmost
node). This is not the same as removing BST. Because there is no order
among the items, in this case, we replace it with the last item.
1. Begin at the root and locate the lowest and rightmost element in
the binary tree, as well as the node that we wish to remove.
2. Replace the data of the node to be eliminated with the data of the
deepest rightmost node.
3. Delete the lowest rightmost node after that.
Code:
class Node:
def __init__(self,data):
self.data = data
self.left = None
self.right = None
def inorder(temp):
if(not temp):
return
inorder(temp.left)
print(temp.data, end = " ")
inorder(temp.right)
def deleteDeepest(root,d_node): #delete deepest node
q = [] #create empty list
q.append(root) #append root
while(len(q)): #until end of list
temp = q.pop(0)
if temp is d_node:
temp = None
return
if temp.right:
if temp.right is d_node:
temp.right = None
return
else:
q.append(temp.right)
if temp.left:
if temp.left is d_node:
temp.left = None
return
else:
q.append(temp.left)
#deletion of node
def deletion(root, key):
if root == None :
return None
if root.left == None and root.right == None:
if root.key == key :
return None
else :
return root
key_node = None
q = []
q.append(root)
temp = None
while(len(q)):
temp = q.pop(0)
if temp.data == key:
key_node = temp
if temp.left:
q.append(temp.left)
if temp.right:
q.append(temp.right)
if key_node :
x = temp.data
deleteDeepest(root,temp)
key_node.data = x
return root
# Driver code
if __name__=='__main__':
root = Node(11)
root.left = Node(12)
root.left.left = Node(8)
root.left.right = Node(13)
root.right = Node(10)
root.right.left = Node(16)
root.right.right = Node(9)
print("before the deletion:")
inorder(root)
key = 12
root = deletion(root, key)
print()
print("after the deletion:")
inorder(root)
Output:
If the entity to be removed is the innermost node itself, shown above code
will not work, so after the task deletDeepest(root, temp) accomplishes
operation, the key node is deleted (as the key node is equal to temp), and then
replacing key node's data with the deepest node's data(temp's data) tosses a
runtime error.
CHAPTER 13
PYTHON GAMING PROJECT
13.1: MARIO GAME IN PYTHON WITH SOURCE
CODE
T his Mario Game is created in Python interpreter. This Game Code is
patterned in Graphical User Interface that works with the
PyGame library. Telling regarding the gameplay, it is a one-player Python
game, where the participant (Mario) has to escape fireballs getting out from
the flying dragon. Every level arrives with more troubles. The region gets
smaller & smaller as early as there is a rise in level. In this great Mario
Python lesson, you could discover how to create a great Mario video game in
Python.
This Mario video game program in Python easy & clean Graphical User
Interface is offered for simple gameplay. The gameplay layout is so minimal
that the user will not discover it hard to use & understand. Various images are
utilized in the advancement of this video game design. The gaming
atmosphere is just like the Mario video game.
Anyhow if you like to rank up your expertise in programming,
particularly video games in Python, try this project.
To begin creating this Mario video game in Python, be sure that you
got PyCharm IDE downloaded on your pc.
13.2: STAGES ON HOW TO MAKE A MARIO VIDEO
GAME IN PYTHON
Phase 1: Create your project name.
Initially, open PyCharm IDE & then create your “project name” after
creating the project name, tap on the “create” icon.
Next, after making a python file, Name the Python file after clicking “enter. “