Download as pdf or txt
Download as pdf or txt
You are on page 1of 61

PYCODING

DATE CREATED: 20/02/2023


Python Introduction
Python is a high-level, interpreted programming
language that is widely used for a variety of
applications, including web development, scientific
computing, data analysis, artificial intelligence, and
more. It was first released in 1991 by Guido van
Rossum and has since become one of the most
popular programming languages in the world.

One of the reasons for Python's popularity is its


simplicity and ease of use. Python is known for its
readable and concise syntax, which makes it easy to
learn and use. It also has a large and active
community, which means there are many resources
available for learning and troubleshooting.

Python is an interpreted language, which means that


the code is executed directly without the need for
compilation. This allows for rapid development and
testing, as changes to the code can be quickly made
and tested without having to go through a lengthy
compile cycle.

Python also has a wide range of built-in libraries and


modules, which makes it a powerful tool for data
analysis and scientific computing.
Additionally, Python has many third-party packages
available for a wide range of applications, which makes
it a versatile language for a variety of use cases.

Overall, Python's simplicity, ease of use, and versatility


make it a great choice for both beginners and
experienced developers.

In Simpler terms,
Python is a widely used, high-level programming
language that is popular for its simplicity and
versatility. Its easy-to-learn syntax and broad range of
applications, including web development, data
analysis, artificial intelligence, and more, make it a
valuable tool for developers of all skill levels. Whether
you're just starting out in tech or you're a seasoned
programmer, Python is definitely a language worth
learning.

Keywords

In Python, keywords are reserved words that have a


specific meaning and purpose in the language. They
cannot be used as variable names, function names, or
any other identifier. Here's a brief explanation of some
of the most commonly used Python keywords:
"and, as, assert, break, class, continue, def, del, elif,
else, except, False, finally, for, from, global, if,
import, in, is, lambda, None, nonlocal, not, or, pass,
raise, return, True, try, while, with, yield."

Here's an explanation of all the Python keywords:


"and": A logical operator used to combine multiple
conditions in a statement. It returns True if all
conditions are true.
"as": Used to create an alias for a module or
namespace.
"assert": Used for debugging purposes. It ensures
that a condition is true, otherwise it raises an
assertion error.
"break": Used to exit a loop or switch statement.
"class": Used to define a class in object-oriented
programming.
"continue": Used to skip the current iteration of a
loop and continue with the next one.
"def": Used to define a function.
"del": Used to delete a variable or object.
"elif": Used in conditional statements ("if"
statements) to define an additional condition and
what to do if the conditions are false.
"else": Used in conditional statements to define what
to do if the conditions are false.
"except": Used in a try/except block to define the
code to execute if an exception is raised.
"finally": Used in a try/except block to specify a
block of code that will always be executed,
regardless of whether an exception is raised.
"for": Used to create a loop that iterates over a
sequence.
"from": Used to import a specific module or object
from a module.
"global": Used to modify a variable outside the
current scope.de depending on whether a condition
is true or false.
"if": Used to create a conditional statement that
executes different code depending on whether a
condition is true or false.
"import": Used to import a module into the current
code.
"in": Used to check if a value is in a sequence.
"is": Used to check if two objects are the same
object.
"lambda": Used to define an anonymous function.
"nonlocal": Used to modify a variable in an outer
scope.
"not": A logical operator used to negate a condition.
"or": A logical operator used to combine multiple
conditions in a statement. It returns True if any of
the conditions are true.
"pass": Used as a placeholder when you need to
define a function, loop, or conditional statement
without any code inside.
"raise": Used to raise an exception.
"return": Used to return a value from a function.
"try": Used to wrap a block of code that may raise an
exception, and define what to do if an exception is
raised.
"while": Used to create a loop that continues as long
as a condition is true.
"with": Used to create a context manager that
automatically handles setup and teardown of
resources.
"yield": Used in a generator function to yield a value
to the caller.

Operators
Arithmetic operators: These operators are used to
perform arithmetic operations, such as addition (+),
subtraction (-), multiplication (*), division (/), and
modulo (remainder) (%).
Comparison operators: These operators are used to
compare values and return a boolean value (True or
False). Examples include "==" (equal to), "!=" (not
equal to), ">" (greater than), "<" (less than), ">="
(greater than or equal to), and "<=" (less than or
equal to).

Logical operators: These operators are used to


combine boolean values and return a boolean value.
Examples include "and" (returns True if both
conditions are true), "or" (returns True if either
condition is true), and "not" (returns the opposite
boolean value).

Bitwise operators: These operators perform bitwise


operations on integer values. Examples include "&"
(bitwise AND), "|" (bitwise OR), "^" (bitwise XOR), "~"
(bitwise NOT), "<<"" (left shift), and ">>" (right shift).

Assignment operators: These operators are used to


assign values to variables. Examples include "="
(simple assignment), "+=" (add and assign), "-="
(subtract and assign), "*=" (multiply and assign), "/="
(divide and assign), and "%=" (modulo and assign).
Identity operators: These operators compare the
memory locations of two objects. Examples include
"is" (returns True if the objects are the same) and "is
not" (returns True if the objects are not the same).

Comments
Single-line comments: Single-line comments begin with
the "#" symbol and are used to provide a brief
explanation or annotation for a single line of code.
Anything after the "#" symbol is ignored by the Python
interpreter.

# This is a single-line comment


x = 5 # This is also a single-line comment

Multi-line comments: Multi-line comments are enclosed


in triple quotes (""" """) or single quotes (''' ''') and can
span multiple lines of code. These comments are
typically used to provide more detailed explanations or
documentation for a block of code.

"""
This is a multi-line comment.
It can span multiple lines of code.
This comment is enclosed in triple quotes.
"""
Docstrings: Docstrings are special comments that
provide documentation for a module, function, class, or
method. They are also enclosed in triple quotes and
can span multiple lines of code.

def my_function():
"""
This function does something.
It takes no arguments and returns nothing.
"""
print("Hello, world!")

Numbers in Python
Integers: Integers are whole numbers (positive,
negative, or zero) that do not have a fractional
component. They are represented in Python using
the "int" data type.

Example: x = 5

Floats: Floats are numbers with a fractional


component. They are represented in Python using
the "float" data type.

Example: y = 3.14
Complex numbers: Complex numbers are numbers
with a real and imaginary component. They are
represented in Python using the "complex" data
type.

Example: z = 2 + 3j

Booleans: Booleans are binary values that can be


either "True" or "False". They are represented in
Python using the "bool" data type.

Example: a = True

Data Types

In Python, there are several built-in data types,


including:
1. Numeric Types: Python supports several numeric
types including int, float, and complex.
Integers (int) are whole numbers without a decimal
point.
Floats (float) are numbers with a decimal point.
Complex numbers (complex) have a real and an
imaginary component.
2. Boolean Type: Boolean data type (bool) has only two
possible values: True or False.
3. Sequence Types:
Strings (str) are a sequence of characters.
Lists (list) are mutable, ordered sequences of
elements.
Tuples (tuple) are immutable, ordered sequences of
elements.
4. Sets: A set (set) is an unordered collection of unique
elements.
5. Dictionaries: A dictionary (dict) is an unordered
collection of key-value pairs.

Variables

Variables are names that represent values, and they are


created using the "=" operator. They are used to store
and manipulate data throughout a program.

Rules for Naming a Variable


Naming convention: Variables should start with a
letter or underscore, and can be followed by letters,
digits, or underscores. They should not start with a
digit.
Case-sensitive: Python is case-sensitive, so "my_var"
and "My_Var" are considered two different variables.
Reserved words: Variables cannot have the same
name as a reserved word in Python, such as "if",
"else", or "for".
No spaces: Variable names cannot have spaces.
Instead, use underscores or capitalize each word to
make it more readable (e.g. "my_variable" or
"MyVariable").
Best practice: Use meaningful names for variables to
make the code more readable and easier to
understand.

Strings
String is a sequence of characters. Strings are a built-in
data type and are defined by enclosing characters in
quotes. Python supports single quotes ('...') and double
quotes ("...") to define a string.

my_string = "Hello, world!"

Strings in Python are immutable, meaning that once a


string is created, its contents cannot be changed.
However, you can perform operations on strings to
create new strings with modified content.
Common Python String Methods
1. len(): Returns the length of a string.
my_string = "Hello, world!"
print(len(my_string)) # Output: 13
2. upper(): Converts a string to uppercase.
my_string = "Hello, world!"
print(my_string.upper()) # Output: HELLO, WORLD!
3. lower(): Converts a string to lowercase.
my_string = "Hello, world!"
print(my_string.lower()) # Output: hello, world!
4. replace(): Replaces a substring with another
substring.
my_string = "Hello, world!"
new_string = my_string.replace("world", "Python")
print(new_string) # Output: Hello, Python!
5. split(): Splits a string into a list of substrings based
on a delimiter.
my_string = "Hello, world!"
new_list = my_string.split(", ")
print(new_list) # Output: ['Hello', 'world!']
6. join(): Joins a list of substrings into a single string
using a delimiter.
my_list = ['Hello', 'world!']
new_string = ", ".join(my_list)
print(new_string) # Output: Hello, world!
Lists
List is a built-in data structure that is used to store a
collection of items. Lists are defined by enclosing a
comma-separated sequence of items in square
brackets. The items in a list can be of any data type,
including other lists.

my_list = ["apple", "banana", "cherry"]

Python lists are mutable, meaning that you can modify


the contents of a list after it has been created. You can
add, remove, or modify items in a list as needed.
Common Python List Methods
1. append(): Adds an element to the end of the list.
my_list = ["apple", "banana", "cherry"]
my_list.append("orange")
print(my_list) # Output: ['apple', 'banana', 'cherry',
'orange']
2. extend(): Adds all the elements of an iterable to the
end of the list.
my_list = ["apple", "banana", "cherry"]
other_list = ["orange", "grape"]
my_list.extend(other_list)
print(my_list) # Output: ['apple', 'banana', 'cherry',
'orange', 'grape']

3. insert(): Inserts an element at a specified position in


the list.
my_list = ["apple", "banana", "cherry"]
my_list.insert(1, "orange")
print(my_list) # Output: ['apple', 'orange', 'banana',
'cherry']
4. remove(): Removes the first occurrence of an
element from the list.
my_list = ["apple", "banana", "cherry"]
my_list.remove("banana")
print(my_list) # Output: ['apple', 'cherry']
5. pop(): Removes and returns the element at a
specified position in the list. If no position is
specified, it removes and returns the last element.
my_list = ["apple", "banana", "cherry"]
popped_element = my_list.pop(1)
print(popped_element) # Output: 'banana'
print(my_list) # Output: ['apple', 'cherry']
6. sort(): Sorts the elements of the list in ascending
order.
my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
my_list.sort()
print(my_list) # Output: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
7. reverse(): Reverses the order of the elements in the
list.
my_list = ["apple", "banana", "cherry"]
my_list.reverse()
print(my_list) # Output: ['cherry', 'banana', 'apple']

Tuples
Tuple is a collection of ordered, immutable elements
enclosed in parentheses. Once a tuple is created, it
cannot be modified. Tuples are often used to represent
fixed collections of related values.

my_tuple = (1, 2, 3, "apple", "banana")

Tuples can also be created without using parentheses,


by separating the elements with commas. This is known
as tuple packing:

my_tuple = 1, 2, 3, "apple", "banana"

To access the elements of a tuple, you can use indexing


or slicing, just like with lists.

my_tuple = (1, 2, 3, "apple", "banana")


print(my_tuple[0]) # Output: 1
print(my_tuple[3:5]) # Output: ('apple', 'banana')
Common Python Tuple Methods
1. count(): Returns the number of times a specified
value appears in the tuple.
my_tuple = (1, 2, 3, 4, 3, 2, 1)
count_2 = my_tuple.count(2)
print(count_2) # Output: 2
2. index(): Searches the tuple for a specified value and
returns the index of the first occurrence of that
value.
my_tuple = (1, 2, 3, 4, 3, 2, 1)
index_3 = my_tuple.index(3)
print(index_3) # Output: 2

Dictionaries
Dictionary is a collection of key-value pairs, enclosed in
curly braces {}. Dictionaries are unordered and mutable,
which means that you can add, remove, and modify
elements in a dictionary after it is created.

my_dict = {'apple': 2, 'banana': 4, 'orange': 1}

To access the value associated with a particular key in a


dictionary, you can use the square bracket notation:

my_dict = {'apple': 2, 'banana': 4, 'orange': 1}


print(my_dict['apple']) # Output: 2
You can also use the get() method to access the value
associated with a particular key. This is useful when
you are not sure whether the key exists in the
dictionary, because it allows you to specify a default
value to return if the key is not found:

my_dict = {'apple': 2, 'banana': 4, 'orange': 1}


print(my_dict.get('mango', 0)) # Output: 0

To add a new key-value pair to a dictionary, you can use


the square bracket notation or the update() method:

my_dict = {'apple': 2, 'banana': 4, 'orange': 1}


my_dict['mango'] = 3
print(my_dict) # Output: {'apple': 2, 'banana': 4,
'orange': 1, 'mango': 3}

To remove a key-value pair from a dictionary, you can


use the pop() method or the del statement:

my_dict = {'apple': 2, 'banana': 4, 'orange': 1}


my_dict.pop('banana')
del my_dict['orange']
print(my_dict) # Output: {'apple': 2}
Common Python Dictionary Methods
1. keys(): Returns a view object containing the keys of
the dictionary.
my_dict = {'apple': 2, 'banana': 4, 'orange': 1}
keys = my_dict.keys()
print(keys) # Output: dict_keys(['apple', 'banana',
'orange'])
2. values(): Returns a view object containing the
values of the dictionary.
my_dict = {'apple': 2, 'banana': 4, 'orange': 1}
values = my_dict.values()
print(values) # Output: dict_values([2, 4, 1])
3. items(): Returns a view object containing the key-
value pairs of the dictionary as tuples.
my_dict = {'apple': 2, 'banana': 4, 'orange': 1}
items = my_dict.items()
print(items) # Output: dict_items([('apple', 2),
('banana', 4), ('orange', 1)])
4. get(key, default=None): Returns the value
associated with the given key, or the default value if
the key is not found.
my_dict = {'apple': 2, 'banana': 4, 'orange': 1}
value = my_dict.get('apple', 0)
print(value) # Output: 2
value = my_dict.get('mango', 0)
print(value) # Output: 0
5. pop(key, default=None): Removes the key-value pair
associated with the given key from the dictionary,
and returns the value. If the key is not found, the
default value (or None) is returned.
my_dict = {'apple': 2, 'banana': 4, 'orange': 1}
value = my_dict.pop('banana')
print(my_dict) # Output: {'apple': 2, 'orange': 1}
print(value) # Output: 4
value = my_dict.pop('mango', 0)
print(value) # Output: 0
6. update(other_dict): Adds the key-value pairs from
the other dictionary to this dictionary, overwriting
any existing keys.
my_dict = {'apple': 2, 'banana': 4, 'orange': 1}
other_dict = {'banana': 5, 'mango': 3}
my_dict.update(other_dict)
print(my_dict) # Output: {'apple': 2, 'banana': 5,
'orange': 1, 'mango': 3}
Array
An array is a collection of items stored in contiguous
memory locations. Each item in the array can be
accessed using its index, which is an integer value that
represents the position of the item in the array. Python's
array module provides a way to create and manipulate
arrays of primitive data types, such as integers or
floating-point numbers.
To use the array module, you first need to import it:
import array

You can then create an array by specifying the data type


and initializing it with a sequence of values:
my_array = array.array('i', [1, 2, 3, 4])

In this example, 'i' indicates that the array should


contain integers, and [1, 2, 3, 4] is the sequence of
values to be stored in the array.

Once you have created an array, you can access its


elements using indexing, just like with a list:
print(my_array[0]) # Output: 1
print(my_array[2]) # Output: 3

You can also modify the values in the array using


indexing:
my_array[0] = 5
print(my_array) # Output: array('i', [5, 2, 3, 4])

Common Python Array Methods


1. append(): Adds a single item to the end of the array.
my_array.append(5)
2. extend(): Adds multiple items to the end of the
array.
my_array.extend([6, 7, 8])
3. insert(): Inserts a single item at a specific index in
the array.
my_array.insert(2, 9)
4. remove(): Removes the first occurrence of a
specified item from the array.
my_array.remove(5)
5. pop(): Removes and returns the item at a specified
index in the array. If no index is specified, the last
item in the array is removed and returned.
my_array.pop(3)
6. index(): Returns the index of the first occurrence of
a specified item in the array.
my_array.index(7)
7. count(): Returns the number of occurrences of a
specified item in the array.
my_array.count(9)
8. reverse(): Reverses the order of the items in the
array.
my_array.reverse()
9. sort(): Sorts the items in the array in ascending
order.
my_array.sort()
Sets
set is an unordered collection of unique elements.

You can create a set in Python by enclosing a sequence


of elements in curly braces {} or by using the set()
function.
my_set = {1, 2, 3}
my_set = set([1, 2, 3])

Note that sets can only contain hashable elements,


such as numbers, strings, and tuples. Lists and
dictionaries are not hashable and cannot be added to a
set.

You can add and remove elements from a set using the
add(), remove(), and discard() methods.

my_set.add(4) # adds the element 4 to the set


my_set.remove(2) # removes the element 2 from
the set
my_set.discard(5) # removes the element 5 if it
exists in the set

You can also perform set operations such as union,


intersection, and difference using the |, &, and -
operators, respectively.
set1 = {1, 2, 3}
set2 = {3, 4, 5}

union_set = set1 | set2 # {1, 2, 3, 4, 5}


intersection_set = set1 & set2 # {3}
difference_set = set1 - set2 # {1, 2}

Common Python Set Methods


1. union(): Returns a new set containing all the
elements from two or more sets.
set1 = {1, 2, 3}
set2 = {3, 4, 5}
union_set = set1.union(set2) # {1, 2, 3, 4, 5}
2. intersection(): Returns a new set containing the
elements that are common to two or more sets.
set1 = {1, 2, 3}
set2 = {3, 4, 5}
intersection_set = set1.intersection(set2) # {3}
3. difference(): Returns a new set containing the
elements that are in one set but not the other.
set1 = {1, 2, 3}
set2 = {3, 4, 5}
difference_set = set1.difference(set2) # {1, 2}
4. symmetric_difference(): Returns a new set
containing the elements that are in either of the
sets, but not both.
set1 = {1, 2, 3}
set2 = {3, 4, 5}
symmetric_difference_set =
set1.symmetric_difference(set2) # {1, 2, 4, 5}

Note that sets are mutable objects and can be modified


in place using the update() method or the |=, &=, and -=
operators.
Conditional Statements in Python
conditional statements allow you to perform different
actions based on whether a certain condition is true or
false.

The if statement is used to test a single condition. If the


condition is true, the code inside the block is executed.
If the condition is false, the code inside the block is
skipped.

x = 10
if x > 0:
print("x is positive")

The if-else statement is used to test a single condition.


If the condition is true, the code inside the if block is
executed. If the condition is false, the code inside the
else block is executed.
x = -5
if x > 0:
print("x is positive")
else:
print("x is negative")

The if-elif-else statement is used to test multiple


conditions. It starts with an if statement, which is
followed by one or more elif statements, and ends with
an optional else statement. The code inside the block of
the first true condition is executed, and the other blocks
are skipped.

x=0
if x > 0:
print("x is positive")
elif x < 0:
print("x is negative")
else:
print("x is zero")

Note that in Python, indentation is used to define the


scope of the code inside the conditional blocks. The
code inside the block should be indented by four spaces
or a single tab.
Loop statements in Python
Loop statements in Python allow you to execute a block
of code repeatedly, based on certain conditions. There
are two types of loops in Python: for loop and while
loop.

The for loop is used to iterate over a sequence (such as


a list, tuple, or string) and execute a block of code for
each item in the sequence.

for variable in sequence:


# code to be executed for each item in the
sequence

Example:
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)

The while loop is used to execute a block of code as


long as a certain condition is true.

while condition:
# code to be executed as long as the condition is
true
Example:
i=1
while i < 5:
print(i)
i += 1

Note that both for and while loops can be combined


with the break and continue statements.

break statement is used to exit a loop.

continue statement is used to skip over a certain


iteration of the loop.

pass is a null statement that does nothing. It is often


used as a placeholder or a stub, when a statement is
required syntactically, but no action is required or
desired.
Functions in Python

A function is a block of code that performs a specific


task. It takes input (in the form of arguments),
processes it, and then returns output. Functions can
be reused in multiple parts of a program, which
makes them a very powerful tool in programming.
Here's an example of a simple Python function that
takes two arguments and returns their sum:

def add_numbers(a, b):


return a + b

def is used to define the function, and add_numbers


is the name of the function.

The function takes two arguments (a and b), which


are used to calculate the sum of the numbers.
The return statement is used to return the result of
the calculation.

To use this function, you simply call it and pass in the


necessary arguments:

result = add_numbers(2, 3)
print(result) # Output: 5

In addition to taking arguments, functions can also


have default values for their arguments, which can be
overridden when the function is called.
For example:
def greet(name, greeting='Hello'):
return f'{greeting}, {name}!'
result1 = greet('John')
result2 = greet('Emily', 'Hi')
print(result1) # Output: Hello, John!
print(result2) # Output: Hi, Emily!

In this example, the greet function takes two arguments,


name and greeting, with a default value of 'Hello' for
greeting. If the greeting argument is not provided when
the function is called, it will default to 'Hello'.

Functions in Python can also return multiple values by


using tuples. Here's an example:

def get_name_and_age():
name = 'John'
age = 30
return name, age
result = get_name_and_age()
print(result) # Output: ('John', 30)

In this example, the get_name_and_age function returns


two values, name and age, which are packed into a tuple.
When the function is called, the tuple is unpacked and the
individual values can be assigned to variables.
In Python, parameters are the variables defined in the
function definition. Arguments, on the other hand, are
the values passed to the function when it is called.
The terms "parameter" and "argument" are often used
interchangeably, but it is important to understand the
distinction between the two.

Namescape and Scope in Python

Namespace refers to a collection of names that are


used to refer to objects in Python. Every object in
Python has a unique identifier, or memory address, and
a name that refers to that object.

A namespace is a mapping of those names to the


objects they refer to. In Python, there are several types
of namespaces, including the built-in namespace,
global namespace, and local namespace.

Scope, on the other hand, refers to the region of a


program where a namespace is directly accessible. In
Python, there are three levels of scope: global, local,
and nonlocal.
The global namespace is accessible throughout the
entire program, and it contains the names defined at the
top level of the program or in a module.

The local namespace is created when a function is


called, and it contains the names defined within that
function. The local namespace is destroyed when the
function returns.

The nonlocal namespace is used to refer to variables in


the outer, enclosing function of a nested function.

Here's an example to illustrate the concept of scope and


namespace:

x = 10 # global namespace
def my_function():
y = 20 # local namespace
print(x) # Accesses x from global namespace
print(y)
my_function()

In this example, x is defined in the global namespace,


while y is defined in the local namespace of the
my_function function. When my_function is called, it
can access x from the global namespace, but not vice
versa.
It is also worth noting that variables in the global
namespace can be accessed from within a function
using the global keyword, and variables in the nonlocal
namespace can be accessed from within a nested
function using the nonlocal keyword.

Recursion in Python
Recursion is a programming technique where a function
calls itself to solve a problem.

It's like solving a big problem by breaking it down into


smaller, similar problems until you reach the simplest,
most basic problem that can be solved easily. This
simplest problem is called the base case.

The function starts by checking if the current problem is


the base case. If it is, it solves the problem directly and
returns a value. If it's not the base case, the function
breaks down the problem into smaller subproblems that
are similar to the original problem, and calls itself with
one of the subproblems as the input. This continues until
the function reaches the base case, at which point it
solves the problem directly and returns a value.

Recursion is often used when solving problems that can


be divided into smaller, similar subproblems.
Examples of problems that can be solved using recursion
include finding the factorial of a number, searching
through a tree structure, and finding the shortest path in
a maze.

Recursion can be a powerful tool for solving certain types


of problems, but it can also lead to performance issues if
the recursion goes too deep. It's important to choose the
right base case and make sure the recursive case is
making progress towards the base case.

Examples
Factorial Calculation: The factorial of a number is the
product of all positive integers up to that number. For
example, the factorial of 5 (written as 5!) is 5 x 4 x 3 x 2 x
1 = 120. We can calculate the factorial using recursion as
follows:
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)

In this example, the base case is when n is equal to 1. If n


is equal to 1, the function returns 1. If n is greater than 1,
the function calls itself with n-1 as the argument, and
multiplies the result with n.
Fibonacci Sequence: The Fibonacci sequence is a series
of numbers where each number is the sum of the two
preceding ones. The first two numbers in the sequence
are 0 and 1. We can generate the Fibonacci sequence
using recursion as follows:
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)

In this example, the base cases are when n is equal to 0


or 1. If n is equal to 0, the function returns 0. If n is equal
to 1, the function returns 1. If n is greater than 1, the
function calls itself with n-1 and n-2 as the arguments
and adds the results.

Object-Oriented Programming

Classes and objects


Inheritance and polymorphism
Encapsulation and abstraction
Design patterns
Classes and Objects in Python
A class is a blueprint or template for creating objects. It
defines the properties and methods that an object will
have.
An object is an instance of a class. It's like a variable
that holds the properties and methods defined by the
class.
Here is an example of a simple class in Python:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def say_hello(self):
print("Hello, my name is " + self.name + " and I
am " + str(self.age) + " years old.")

In this example, we define a class called Person that


has two properties, name and age, and one method
called say_hello. The __init__ method is a special
method that is called when an object of the class is
created. It sets the initial values of the name and age
properties. The say_hello method simply prints a
message to the console using the name and age
properties.
We can create an object of the Person class as follows:
person1 = Person("Alice", 25)

This creates an object called person1 of the Person


class, with name set to "Alice" and age set to 25. We can
call the say_hello method on the person1 object as
follows:
person1.say_hello()

This will print the message "Hello, my name is Alice and


I am 25 years old." to the console.
We can create multiple objects of the same class, each
with different values for the properties. For example:
person2 = Person("Bob", 30)
person3 = Person("Charlie", 35)

In this example, we create two more objects of the


Person class with different values for the name and age
properties. We can call the say_hello method on each of
these objects to print their respective messages to the
console.

Classes and objects are a powerful concept in OOP


and allow us to organize our code in a modular and
reusable way. They are commonly used in software
development for building complex systems that
require a high level of abstraction and encapsulation.
Inheritance in Python
Inheritance is a fundamental concept in object-oriented
programming that allows one class to inherit properties
and methods from another class. In Python, inheritance is
implemented using the syntax:
class ChildClass(ParentClass):
# ChildClass properties and methods

In this syntax, ChildClass is the class that inherits from


ParentClass. The ChildClass can access all the properties
and methods of the ParentClass, as well as define its own
properties and methods.

Here is an example of a simple inheritance in Python:

class Animal:
def __init__(self, name, age):
self.name = name
self.age = age

def speak(self):
print("I am an animal.")

class Dog(Animal):
def speak(self):
print("I am a dog.")
In this example, we have two classes, Animal and Dog.
Dog is a subclass of Animal, meaning it inherits all the
properties and methods of Animal. Dog also defines its
own speak method that overrides the speak method of
Animal.
We can create an object of the Dog class as follows:
dog1 = Dog("Buddy", 5)

This creates a Dog object called dog1 with name set to


"Buddy" and age set to 5. We can call the speak method on
the dog1 object as follows:
dog1.speak()

This will print the message "I am a dog." to the console,


since we have overridden the speak method in the Dog
class.

We can also call the speak method on an object of the


Animal class:
animal1 = Animal("Spot", 3)
animal1.speak()

This will print the message "I am an animal." to the


console, since the speak method of Animal has not been
overridden.
Polymorphism in Python
Polymorphism is the ability of an object to take on many
forms. In Python, polymorphism is achieved through
method overloading and method overriding.

Method overloading is the ability of a class to define


methods with the same name but different parameters.

Method overriding is the ability of a subclass to override a


method of its superclass.

Here is an example of polymorphism in Python using


method overloading:
class Calculator:
def add(self, a, b):
return a + b

def add(self, a, b, c):


return a + b + c

In this example, we have a Calculator class that defines


two add methods with different parameters. When we call
the add method with two arguments, the first add method
will be called. When we call the add method with three
arguments, the second add method will be called.
Here is an example of polymorphism in Python using
method overriding:
class Animal:
def speak(self):
print("I am an animal.")

class Dog(Animal):
def speak(self):
print("I am a dog.")

class Cat(Animal):
def speak(self):
print("I am a cat.")

In this example, we have an Animal class and two


subclasses, Dog and Cat. Both Dog and Cat override the
speak method of Animal, so when we call the speak
method on a Dog object, it will print "I am a dog." to the
console, and when we call the speak method on a Cat
object, it will print "I am a cat." to the console.

Polymorphism allows us to write more efficient and


organized code, since we can reuse methods across
different parts of a program. It also allows us to write code
that is more readable and understandable, since we can
use the same method names across different classes and
expect them to behave in different ways.
Encapsulation in Python

Encapsulation is a fundamental concept in object-oriented


programming that refers to the idea of hiding data and
methods within a class to prevent them from being
accessed or modified directly from outside the class.

Encapsulation helps to protect the data from being


modified or corrupted accidentally and also allows for
better control over the behavior of the objects.

In Python, encapsulation is implemented by using access


modifiers to control the visibility of the class members.
The access modifiers are:
Public: Members are accessible from anywhere.
Protected: Members are accessible from the class and
its subclasses.
Private: Members are only accessible from within the
class.

The access modifiers are implemented in Python using


underscores before the name of the member variable or
method. A single underscore before the name of a
member variable or method indicates that it is protected,
while double underscores indicate that it is private.
Here is an example of encapsulation in Python:
class BankAccount:
def __init__(self, account_number, balance):
self._account_number = account_number
self._balance = balance

def deposit(self, amount):


self._balance += amount

def withdraw(self, amount):


if amount > self._balance:
raise ValueError("Insufficient balance")
self._balance -= amount

def get_balance(self):
return self._balance

In this example, we have a BankAccount class that has two


member variables, _account_number and _balance, which
are both marked as protected. The class also has three
methods, deposit, withdraw, and get_balance, which can
be used to modify or access the _balance member
variable.

Since the _balance member variable is marked as


protected, it can be accessed and modified only from
within the class and its subclasses.
This helps to protect the data from being modified
accidentally from outside the class.

Encapsulation is an important concept in OOP that allows


for better organization and control over the behavior of
objects. It also helps to improve the security and reliability
of the program by preventing the data from being modified
accidentally or maliciously from outside the class.
Abstraction in Python
Abstraction is a fundamental concept in object-oriented
programming that refers to the idea of hiding the
implementation details of a class and exposing only the
essential features to the outside world. Abstraction helps
to simplify the code by reducing the complexity and
allowing for better organization and management of the
program.

In Python, abstraction is implemented by using abstract


classes and methods. An abstract class is a class that
cannot be instantiated and is designed to be used as a
base class for other classes. An abstract method is a
method that has a declaration but no implementation and
must be implemented in the derived classes.
To define an abstract class in Python, we use the abc
module, which provides the ABC (Abstract Base Class)
class and the abstractmethod decorator.

Here is an example of abstraction in Python:


from abc import ABC, abstractmethod

class Shape(ABC):
@abstractmethod
def area(self):
pass

class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height

def area(self):
return self.width * self.height

class Circle(Shape):
def __init__(self, radius):
self.radius = radius

def area(self):
return 3.14 * self.radius ** 2
In this example, we have an abstract Shape class that
defines an abstract method area. The Shape class cannot
be instantiated, but it can be used as a base class for
other classes that implement the area method.

The Rectangle and Circle classes are derived from the


Shape class and implement the area method. The
Rectangle class calculates the area of a rectangle based
on its width and height, while the Circle class calculates
the area of a circle based on its radius.

Abstraction helps to improve the design and organization


of the program by hiding the implementation details of
the classes and providing a simple and clear interface for
the users. It also allows for better reusability and
maintainability of the code by making it easier to add new
features or modify existing ones without affecting the
other parts of the program.

Design Patterns in Python


Design patterns are proven solutions to commonly
occurring problems in software design. They provide a
structured and reusable approach to solving specific
problems and help to improve the quality, maintainability,
and extensibility of the code.
In Python, design patterns are typically implemented
using object-oriented programming (OOP) principles
and techniques. Here are some examples of commonly
used design patterns in Python:

Singleton: This pattern ensures that only one instance


of a class is created and provides a global point of
access to it. This pattern is useful for situations where
you need to ensure that there is only one instance of a
class in the system, such as a configuration manager or
a logging service.

class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance

Factory: This pattern provides an interface for creating


objects in a superclass, but allows the subclasses to
alter the type of objects that will be created. This
pattern is useful for situations where you need to create
different types of objects based on some input or
condition.
class ShapeFactory:
def create_shape(self, shape_type):
if shape_type == 'rectangle':
return Rectangle()
elif shape_type == 'circle':
return Circle()
else:
raise ValueError('Invalid shape type')

Decorator: This pattern allows you to add functionality to


an object dynamically without changing its structure. This
pattern is useful for situations where you need to add new
features or behaviors to an object without modifying its
existing code.

class Beverage:
def get_cost(self):
pass

class Coffee(Beverage):
def get_cost(self):
return 1.0

class Decorator(Beverage):
def __init__(self, beverage):
self.beverage = beverage
def get_cost(self):
return self.beverage.get_cost()

class Sugar(Decorator):
def get_cost(self):
return self.beverage.get_cost() + 0.5

class Milk(Decorator):
def get_cost(self):
return self.beverage.get_cost() + 1.0

Observer: This pattern allows one-to-many relationships


between objects, where one object changes its state and
notifies all its dependent objects automatically. This
pattern is useful for situations where you need to keep
track of changes in the state of an object and notify other
objects about those changes.

class Subject:
def __init__(self):
self._observers = []

def attach(self, observer):


self._observers.append(observer)

def detach(self, observer):


self._observers.remove(observer)
def notify(self):
for observer in self._observers:
observer.update()

class Observer:
def __init__(self, subject):
self.subject = subject
self.subject.attach(self)

def update(self):
pass

These are just a few examples of the many design


patterns that are commonly used in Python. Design
patterns help to improve the quality and structure of the
code, and they also make it easier to maintain and extend
the code over time.

Reading and Writing Files in Python


In Python, you can read and write files using built-in
functions and methods. Here's how you can do it:
Reading a file:
Open the file using the open() function. The function
takes two arguments: the name of the file and the
mode in which you want to open it. For example, to
open a file named example.txt in read mode, you would
use the following code:
file = open("example.txt", "r")

Read the contents of the file using the read() method.


This method reads the entire file and returns a string.
For example:
contents = file.read()

Close the file using the close() method. This is


important to ensure that the file is properly closed and
the system resources are released. For example:
file.close()

Here's an example that puts it all together:

file = open("example.txt", "r")


contents = file.read()
file.close()
print(contents)

Writing to a file:

Open the file using the open() function. The function


takes two arguments: the name of the file and the
mode in which you want to open it. For example, to
open a file named example.txt in write mode, you
would use the following code:
file = open("example.txt", "w")

Write to the file using the write() method. This method


writes a string to the file. For example:
file.write("Hello, world!")

Close the file using the close() method. This is


important to ensure that the file is properly closed and
the system resources are released. For example:
file.close()

Here's an example that puts it all together:

file = open("example.txt", "w")


file.write("Hello, world!")
file.close()

You can also read and write to a file in different modes,


such as "a" for appending to a file or "b" for reading and
writing binary files. In addition, you can use the with
statement to automatically close the file when you're done
with it:
with open("example.txt", "r") as file:
contents = file.read()

with open("example.txt", "w") as file:


file.write("Hello, world!")
Modes for Reading and Writing Files
Read mode ( "r" ) - This mode is used to read the
contents of a file. When a file is opened in read mode,
the file pointer is positioned at the beginning of the
file. You can read the contents of the file using the
read() method.
Write mode ( "w" ) - This mode is used to write
contents to a file. If the file already exists, it will be
truncated (i.e., all the existing content will be deleted).
If the file does not exist, a new file will be created. You
can write to the file using the write() method.
Append mode ( "a" ) - This mode is used to append
data to a file. If the file already exists, new data will be
added to the end of the file. If the file does not exist, a
new file will be created. You can append data to the
file using the write() method.
Read and Write mode ( "r+" ) - This mode is used to
read and write to a file. When a file is opened in this
mode, the file pointer is positioned at the beginning of
the file. You can read the contents of the file using the
read() method, and you can write to the file using the
write() method.
Write and Read mode ( "w+" ) - This mode is used to
write and read to a file. If the file already exists, it will
be truncated (i.e., all the existing content will be
deleted).
If the file does not exist, a new file will be created.
You can write to the file using the write() method, and you
can read the contents of the file using the read() method.

Append and Read mode ( "a+" ) - This mode is used to


append and read data to a file. If the file already exists,
new data will be added to the end of the file. If the file
does not exist, a new file will be created. You can
append data to the file using the write() method, and
you can read the contents of the file using the read()
method.

Working with input/output streams in python


Input/output streams in Python are used to handle reading
and writing of data to different sources such as files, the
console, and network sockets.

In Python, the sys module provides access to the standard


input and output streams. Here's an overview of how to
work with input and output streams in Python.

Reading input from the console: To read input from the


console, you can use the input() function in Python. Here's
an example:
name = input("What is your name? ")
print("Hello, " + name)
When you run this code, it will prompt the user to enter
their name, and then it will print a personalized message
using their input.

Writing output to the console: To write output to the


console, you can use the print() function in Python. Here's
an example:
print("Hello, world!")

This will print the message "Hello, world!" to the console.

Reading from and writing to files: To read from a file, you


can use the open() function to open the file in read mode,
and then use the read() method to read the contents of the
file. Here's an example:
file = open("example.txt", "r")
contents = file.read()
file.close()
print(contents)

This will open the file "example.txt" in read mode, read the
contents of the file, and print them to the console. To write
to a file, you can use the open() function to open the file in
write mode, and then use the write() method to write to the
file. Here's an example:
file = open("example.txt", "w")
file.write("Hello, world!")
file.close()

This will open the file "example.txt" in write mode, write


the message "Hello, world!" to the file, and then close the
file.

Reading from and writing to network sockets: To read


from a network socket, you can use the recv() method, and
to write to a network socket, you can use the send()
method. Here's an example of how to create a client
socket, connect to a server, and send a message:

import socket

client_socket = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
client_socket.connect(("localhost", 5000))
client_socket.send("Hello, server!")

This will create a client socket, connect to a server running


on the local machine on port 5000, and send the message
"Hello, server!" to the server.
Formatting Output in python
Formatting output in Python is a way to control how data is
presented when printed to the console or written to a file.
Python provides several built-in functions and methods for
formatting output, which allows you to customize the way
data is displayed. Here are some examples of how to
format output in Python:

Using the print() function: You can use the print() function
to format output by using placeholders and format
specifiers. Placeholders are used to indicate where values
should be inserted into the string, and format specifiers
control how those values are displayed. Here's an example:
name = "John"
age = 30
print("My name is {} and I am {} years
old.".format(name, age))
This will print the message "My name is John and I am 30
years old."

Using f-strings: F-strings are a newer way to format output


in Python 3.6 and above. They use placeholders in curly
braces, and allow you to include variables directly in the
string. Here's an example:
name = "John"
age = 30
print(f"My name is {name} and I am {age} years old.")
Using string formatting methods: Python strings have
built-in formatting methods that allow you to control how
data is displayed. For example, you can use the
str.format() method to format a string. Here's an example:
price = 9.99
print("The price is ${:.2f}".format(price))

This will print the message "The price is $9.99", with the
price formatted to two decimal places.

Using formatting libraries: Python also provides several


libraries for advanced formatting, such as string.Template
and jinja2. These libraries allow you to create more
complex templates and format data in a variety of ways.
Here's an example using jinja2:
from jinja2 import Template
name = "John"
age = 30
template = Template("My name is {{ name }} and I am
{{ age }} years old.")
print(template.render(name=name, age=age))

This will print the message "My name is John and I am 30


years old."
Handling exceptions and errors in python
Handling exceptions and errors is an important part of writing
reliable code in Python. Exceptions are raised when there is
an error or exceptional condition in your code, and you can
use try-except blocks to handle them. Here are some
examples of how to handle exceptions in Python:

Basic try-except block: You can use a try-except block to


catch exceptions and handle them. Here's an example:

try:
num = int(input("Enter a number: "))
result = 10 / num
print(result)
except ZeroDivisionError:
print("You can't divide by zero!")
except ValueError:
print("Please enter a valid integer.")

In this example, the try block prompts the user for a number,
divides 10 by that number, and prints the result. If the user
enters 0 or a non-integer value, the corresponding except
block will be executed instead.

Catching multiple exceptions: You can catch multiple


exceptions in the same except block, by using parentheses
and separating the exceptions with commas. Here's an
example:
try:
num = int(input("Enter a number: "))
result = 10 / num
print(result)
except (ZeroDivisionError, ValueError):
print("Invalid input.")

This is equivalent to the previous example, but the two


exceptions are caught in a single except block.

Catching all exceptions: You can catch all exceptions using a


generic except block. This can be useful for handling
unexpected errors that might not be caught by more specific
except blocks. Here's an example:
try:
num = int(input("Enter a number: "))
result = 10 / num
print(result)
except:
print("An error occurred.")

In this example, any exception that is raised in the try block


will be caught by the except block and the message "An error
occurred" will be printed.

Raising exceptions: You can raise exceptions yourself using


the raise statement. This can be useful for signaling errors or
exceptional conditions in your code. Here's an example:
def divide(num1, num2):
if num2 == 0:
raise ZeroDivisionError("You can't divide by zero!")
return num1 / num2

try:
result = divide(10, 0)
print(result)
except ZeroDivisionError as e:
print(e)

In this example, the divide function raises a ZeroDivisionError


if the second argument is 0. The error is caught in the try
block, and the error message "You can't divide by zero!" is
printed.

You might also like