Python Language
- (a) can save time during program development
- (b) No compilation & linking is necessary.
- (a) makes it easy to experiment lang features
- (b) to write throw-away programs, or
- (c) to test functions during bottom-up program development.
- (a) the high-level datatypes allow you to express complex operations in a single statement;
- (b) statement grouping is done by indentation instead of beginning and ending brackets;
- (c) no variable or argument declarations are necessary.
History of Python:
Python was created by Guido van Rossum, and first released on February 20, 1991.
The Python language is named after the BBC show “Monty Python's Flying Circus” and has nothing to do with reptiles.
Python Packages / Modules:
For example, most of the Python code in scientific computing and data science is built around a group of mature and useful packages:
Python language has many uses:
Python: Install & Run
Python Installation
Installing Python and the suite of libraries that enable scientific computing is straightforward whether you use Windows, Linux, or MacOS.
(A). Python 3 by python.org
In this Python learning notes, we use the syntax of Python 3, which contains language enhancements that are not compatible with the 2.x series of Python.Though Python 3.0 was first released in 2008, adoption has been relatively slow, particularly in the scientific and web development communities. As of December 22, 2022 - Python has the version 3.11.1 (stable release version).
(B). Installation using conda
Another popular way to install Python, if you wish to eventually use the data science tools - is via the cross-platform Anaconda distribution. There are two flavors of the Anaconda distribution:
conda
which operates as a cross-platform package manager geared toward Python packages, similar in spirit to the apt
or yum
tools that Linux users might be familiar with.conda
, and additionally bundles a suite of other pre-installed packages geared toward scientific computing.Any of the packages included with Anaconda can also be installed manually on top of Miniconda.
Run Python Code
Python is a flexible and interpreted rather than compiled. It can be executed line by line, which allows a way that is not directly possible with compiled languages like C, C++ or Java.
There are four primary ways you can run Python code:
(A). Python interpreter
python
python3
or just py
at the Command Prompt application in Windows ( or look for the Terminal on Mac OS X or Unix/Linux systems):
C:\Users\Skillzam> python
Python 3.11.1 (tags/v3.11.1:a7a450f, Dec 6 2022, 19:58:39) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> 12 + 13
25
>>> 21 - 1
20
>>> num = 9
>>> num * 9
81
(B). Jupyter notebook
.ipynb
- [1]. Installing Jupyter through Anaconda Distribution
- Anaconda, the world's most popular open-source Python distribution platform will install Jupyter Notebooks by default.
- Once installed, you can launch Jupyter Notebooks from Anaconda Navigator.
- [2]. Installing Jupyter by pip
- Project Jupyter's tools are available for installation via the Python Package Index, the leading repository of software created for the Python programming language.
- JupyterLaB
- (a). Install JupyterLab with pip:
C:\Users\Skillzam> pip install jupyterlab
- (b). Once installed, launch JupyterLab with: jupyter-lab
- Jupyter Notebook
- (a). Install the classic Jupyter Notebook with:
C:\Users\Skillzam> pip install notebook
- (b). To run the notebook:
C:\Users\Skillzam> jupyter notebook
(C). Self-contained Scripts
.py
extension.
# Python Program file: main.py
msg = "Hello World!"
print(msg)
python <filename>
at the command prompt:
C:\Users\Skillzam> python main.py
Hello World!
(D). IPython interpreter
ipython
at the command prompt:
C:\Users\Skillzam> ipython
Python 3.11.1 (tags/v3.11.1:a7a450f, Dec 6 2022, 19:58:39) [MSC v.1934 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.7.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]:
>>>
by default, while IPython uses numbered commands like In [1]
:
However, we can still execute code line by line interactively:
In [1]: 55 + 2
Out[1]: 57
In [2]: myText = "Skillzam - Learn without limits!"
In [3]: print(myText)
Skillzam - Learn without limits!
Python language syntax
Syntax refers to the structure of the language, which is, what constitutes a correctly-formed program.
Observe the below code:
# Program to add two numbers
# function declaration for adding two numbers
def addNum(num1, num2):
total = num1 + num2
return (total)
value1 = 0; value2 = 0;
value1 = int(input('Enter the first number: ')) # Input first number
value2 = int(input('Enter the second number: ')) # Input second number
# Invoking the function addNum() and Printing the Output
print(f'The sum of {value1} and {value2} is {addNum(value1, value2)}')
OUTPUT
Enter the first number: 24 Enter the second number: 12 The sum of 24 and 12 is 36
This above script illustrates several of the important aspects of Python syntax.
Let's walk through it and discuss some of the syntactical features of Python.
Comments are marked by #
# Program to add two numbers
#
and anything on the line following the pound sign is ignored by the interpreter.
value1 = int(input('Enter the first number: ')) # Input first number
/* ... */
syntax used in C and C++. But, since Python will ignore string literals that are not assigned to a variable, you can add a multiline string (triple quotes) in your code, and place your comment inside it
''' This is the
demo of un-assigned
multi-line string used
as comment in Python
'''
End-of-Line terminates a statement
total = num1 + num2
total
is assigned to sum of two numbers num1 + num2
;
In Python, if you'd like a statement to continue to the next line, it is possible to use the "\
" marker to indicate this:
sumSingleDigits = 0 + 1 + 2 + 3 + 4 +\
5 + 6 + 7 + 8 + 9
It is also possible to continue expressions on the next line within parentheses ( ), without using the "\
" marker:
sumSingleDigits = (0 + 1 + 2 + 3 + 4 +
5 + 6 + 7 + 8 + 9)
Semicolon can optionally terminate a statement
Sometimes it can be useful to put multiple statements on a single line. This shows in the example, how the semicolon ;
familiar in C Language, can be used optionally in Python to put two statements on a single line.
value1 = 0; value2 = 0;
Functionally, this is entirely equivalent to writing
value1 = 0
value2 = 0
Indentation: Whitespace matters
In the function declaration, the block of code looks:
# function declaration for adding two numbers
def addNum(num1, num2):
total = num1 + num2
return (total)
This demonstrates what is perhaps the most controversial feature of Python's syntax: whitespace is meaningful!
In programming languages, a block of code is a set of statements that should be treated as a unit. In JavaScript, for example, code blocks are denoted by curly braces { }
// JavaScript code
for (int i = 0; i < 10; i++) {
// curly braces indicate code block
total = total + i;
}
In Python, code blocks are denoted by indentation. In Python, indented code blocks are always preceded by a colon (:)
on the previous line.
# Python code
for i in range(10):
# indentation indicates code block
total = total + i;
The use of indentation helps to enforce the uniform, readable style that many find appealing in Python code. But it might be confusing to the uninitiated; for example, the following two snippets will produce different results:
In the below snippet, print()
method is in the indented block, and will be executed only if mangoPrice is less than 500.
if mangoPrice < 500:
totalCost = mangoPrice * 2
print(totalCost)
In the below snippet, print()
method is outside the indented block, and will be executed regardless of the value of mangoPrice.
if mangoPrice < 500:
totalCost = mangoPrice * 2
print(totalCost)
NOTE that the amount of whitespace used for indenting code blocks is up to the user, as long as it is consistent throughout the script. By convention, most style guides recommend to indent code blocks by four spaces TAB
and that is the convention to follow.
Whitespaces within lines does not matter
While the mantra of meaningful whitespace holds true for whitespace before lines (which indicate a code block), white space within lines of Python code does not matter
For example, all three of these expressions are equivalent:
sumNumbers=12+34
sumNumbers = 12 + 34
sumNumbers = 12 + 34
Abusing this flexibility can lead to issues with code readibility - in fact, abusing white space is often one of the primary means of intentionally obfuscating code (which some people do for sport).
Using whitespace effectively can lead to much more readable code, especially in cases where operators follow each other - compare the following two expressions for exponentiating by a negative number:
squareNumber=9**2
# Check the below with SPACES
squareNumber = 9 ** 2
Observe that second version with spaces much is more easily readable at a single glance. Most Python style guides recommend using a single space around binary operators, and no space around unary operators.
Parentheses are for grouping or calling
Two major uses of parentheses. First, they can be used in the typical way to group statements or mathematical operations:
12 * (34 + 56)
# 1080
Secondly, they can also be used to indicate that a function is being invoked (called).
In the below snippet, the addNum()
is used to call the function with two arguments
. The function call is indicated by a pair of opening and closing parentheses, with the arguments to the function contained within:
addNum(value1, value2)
Some functions can be called with no arguments at all, in which case the opening and closing parentheses still must be used to indicate a function evaluation. An example of this is the upper()
method of lists:
firstString = 'Skillzam'.upper()
print(firstString)
# SKILLZAM
The "()" after upper indicates that the function should be executed, and is required even if no arguments are necessary.
print() is function NOT a statement anymore
The print()
function is one piece that has changed between Python 2.x and Python 3.x. In Python 2, print
behaved as a statement: that is, you could write
# In Python 2.x versions
>> print "Hello World!"
Hello World!
For various reasons, the language maintainers decided that in Python 3 print()
should become a function, so we now write
# In Python 3.x versions
>>> print("Hello World!")
Hello World!
This is one of the many backward-incompatible constructs between Python 2 and 3.
Style Guide for Python code
Python "style guides", which can help teams to write code in a consistent style. The most widely used style guide in Python is known as PEP8 (Python Enhancement Proposals 8). As you begin to write more Python code, it would be useful to read through this!
Python Variables & Objects
We will now understand the semantics of keywords
identifier
variables
objects
which are the main ways you store, reference, and operate on data within a Python script.
Keywords
Every programming language has special reserved words, or keywords, that have specific meanings and restrictions around how they should be used. Python is no different. Python keywords are the fundamental building blocks of any Python program.
and | continue | finally | is | raise |
as | def | for | lambda | return |
assert | del | from | None | True |
async | elif | global | nonlocal | try |
await | else | if | not | while |
break | except | import | or | with |
class | False | in | pass | yield |
Identifiers
name
given to identify a variable, function, class, module or other object.Variables
name
= object
- Pros of Dynamic Typing
- (a). very easy to work with
- (b). faster development time
- Cons of Dynamic Typing
- (a). may result in unexpected bugs
- (b). need to be aware of
type()
method
metadata
also called attributes
and methods
Assigning values to Variables
name
= object
“=”
symbol, is the operator that is used to assign values to variablesSingle value assigned to one variable
favColor = 'Blue'
Multiple values assigned to multiple variables
Make sure the number of variables matches the number of values, or else you will get an error.
aaplStockPrice, tslaStockPrice, msftStockPrice = 131.86, 123.15, 238.73
Single value assigned to multiple variables
messiGoals = neymarGoals = ronaldoGoals = "SAME"
Naming Variable
# Naming Variables & assignment
price = 120 # using '=' operator for assigning value
Price = 24 # price & Price are different as Python is case-sensitive
_interest = 2.25 # '_' is a valid usage in variable name
QTY = 3 # All-caps is valid usage in variable name
# Naming Variables : special Symbols not Allowed
$stockPrice = 123 # SyntaxError: invalid syntax
# Naming Variables : SPACES not Allowed
pin Code = 17011 # SyntaxError: invalid syntax
# Naming Variables : Cannot start with number
1stItemDiscount = 15 # SyntaxError: invalid syntax
# Naming Variables : Cannot use Keywords/Reserved words
lambda = 0.022 # SyntaxError: invalid syntax
Variable names with multiple words
1. Camel Case
Variable names where each word, except the first, starts with a capital letter:
firstName = 'Jack'
2. Snake Case
Variable names where each word is separated by an underscore ( _ )
character:
last_name = 'Sparrow'
3. Pascal Case
Variable names where each word starts with a capital letter:
MyFavoriteTeam = 'F C Barcelona'
Finding variable type
The built-in type()
method/function is used to get the type of an object/variable.
intNum = 123
type(intNum)
# int
decimalNum = 3.142
type(decimalNum)
# float
complexNum = 3 + 4j
type(complexNum)
# complex
CompanyName = "Workzam"
type(CompanyName)
# str
isGreater = True
type(isGreater)
# bool
randNum = None
type(randNum)
# NoneType
myList = ['s','k','i','l','l','z','a','m']
type(myList)
# list
tickerPrice = ('aapl', 131.86)
type(tickerPrice)
# tuple
fifaFinale = { "Argentina":4, "France": 2 }
type(fifaFinale)
# dict
teams = {"Arsenal","Barcelona","PSG"}
type(teams)
# set
Python variables are pointers
Assigning variables in Python is as easy as putting a variable name to the left of the equals =
sign:
# assign 8128 to the variable 'perfectNum'
perfectNum = 8128
# assign 3.142 to the variable 'valuePI'
valuePI = 3.142
# assign Skillzam to the variable 'academy'
academy = 'Skillzam'
# assign True to the variable 'isGreater'
isGreater = True
# assign None to the variable 'varName'
varName = None
This may seem straightforward, but if you have the wrong mental model of what this operation does, the way Python works may seem confusing. We'll briefly dig into that here.
In many programming languages, variables are best thought of as containers or buckets into which you put data.
So in C Language, for example, when you write
// C code
int perfectNum = 8128;
you are essentially defining a "memory bucket" named perfectNum
, and putting the value 8128
into it. In Python, by contrast, variables are best thought of not as containers but as pointers. So in Python, when you write
# Python code
perfectNum = 8128
you are essentially defining a pointer named perfectNum
that points to some other bucket containing the value 8128
.
Note one consequence of this: because Python variables just point to various objects, there is no need to "declare" the variable, or even require the variable to always point to information of the same type!
This is the sense in which people say Python is dynamically-typed
: variable names can point to objects of any type.
Dynamically-typed languages are those, where the interpreter assigns variables a type at runtime based on the variable's value at the time.
So in Python, you can do things like this:
varName = 789 # varName is an integer here
print('1: int',id(varName))
varName = 'Workzam' # varName is a string now
print('2: str',id(varName))
varName = [12, 34, 56] # varName is a list now
print('3: list',id(varName))
OUTPUT
1: int 2337616203024 2: str 2337615666096 3: list 2337616495808
While users of statically-typed languages might miss the type-safety that comes with declarations like those found in C,
perfectNum = 8128
this dynamic typing is one of the pieces that makes Python so quick to write and easy to read.
There is a consequence of "variable as pointer" approach in Python.
If we have two variable names pointing to the same mutable variable/object, then changing one will change the other as well! For example, let's create and modify a list:
# Python 'list' is created
listNameOne = [9, 8, 7]
listNameTwo = listNameOne
We've created two variables listNameOne
and listNameTwo
which both point to the same object. Because of this, if we modify the list via one of its names, we'll see that the "other" list will be modified as well:
print(listNameTwo)
# [9, 8, 7]
listNameOne.append(6) # append 6 to the list pointed to by listNameOne
print(listNameTwo) # listNameTwo's list is modified as well!
print('1:listNameOne',id(listNameOne))
print('2:listNameTwo',id(listNameTwo))
OUTPUT
[9, 8, 7, 6] 1:listNameOne 2337616485568 2:listNameTwo 2337616485568
This behavior might seem confusing if you're wrongly thinking of variables as buckets that contain data. But if you're correctly thinking of variables as pointers to objects, then this behavior makes sense.
Note also that if we use =
to assign another value to listNameOne
, this will not affect the value of listNameTwo
- assignment is simply a change of what object the variable points to:
listNameOne = 'Some new value'
print(listNameTwo) # listNameTwo is unchanged
print('1:listNameOne',id(listNameOne))
print('2:listNameTwo',id(listNameTwo))
OUTPUT
[9, 8, 7, 6] 1:listNameOne 2337615565616 2:listNameTwo 2337616485568
Again, this makes perfect sense if you think of listNameOne
and listNameTwo
as pointers, and the =
operator as an operation that changes what the name points to.
You might wonder whether this pointer idea makes arithmetic operations in Python difficult to track, but Python is set up so that this is not an issue. Numbers, strings, and other simple types are immutable: you can't change their value – you can only change what values the variables point to. So, for example, it's perfectly safe to do operations like the following:
x_axis = 12
y_axis = x_axis
x_axis += 4 # add 4 to x_axis' value, and assign it to x_axis
print("x-axis value =", x_axis)
print("y-axis value =", y_axis)
OUTPUT
x-axis value = 16 y-axis value = 12
When we call x_axis += 4
, we are not modifying the value of the 12
object pointed to by x_axis
; we are rather changing the variable x_axis
so that it points to a new integer object with value 16
. For this reason, the value of y_axis
is not affected by the operation.
Example to demo variables as pointers
Before you jump into understanding Python Variables, let us consider these below "Base object types" :
PyObject
, but every pointer to a Python object can be cast to a PyObject*
. Access to the members must be done by using the macros Py_REFCNT
and Py_TYPE
. For more details, refer Python common object structures.
Let us now consider the below examples:
nameOne = 'Skill'
print(id(nameOne), 'nameOne: '+ nameOne)
OUTPUT
2337616224048 nameOne: Skill
nameOne = nameOne + 'zam'
print(id(nameOne), 'nameOne: '+ nameOne)
OUTPUT
2337615651312 nameOne: Skillzam
nameTwo = nameOne
print(id(nameTwo), 'nameTwo: '+ nameTwo)
OUTPUT
2337615651312 nameTwo: Skillzam
nameOne = 'Workzam'
print(id(nameOne), 'nameOne: '+ nameOne)
OUTPUT
2337615672880 nameOne: Workzam
Everything is an Object in Python
Python is an object-oriented programming language, and in Python everything is an object.
Earlier we saw that, variables are simply pointers, and the variable names themselves have no attached type information. This leads some to claim erroneously that Python is a type-free language. But this is not the case!
Consider the following:
stockPrice = 112
type(stockPrice)
# int
inr = 'Indian Rupee'
type(inr)
# str
dollarUS = 82.82 # USD exchange rate in INR
type(dollarUS)
# float
isinstance()
function returns True
, if the specified object is of the specified type, otherwise False
isinstance(stockPrice, object)
# True
isinstance(inr, object)
# True
isinstance(dollarUS, object)
# True
Python has types; however, the types are linked not to the variable names but to the objects themselves.
In object-oriented programming languages like Python, an object
is an entity that contains data along with associated metadata and/or functionality. In Python everything is an object, which means every entity has some metadata also called attributes
and associated functionality also called methods
.
These attributes and methods are accessed via the dot syntax.
For example, before we saw that lists have an append
method, which adds an item to the list, and is accessed via the dot "."
syntax:
# Single Digit Prime Numbers
primeNumbers = [2, 3, 5]
primeNumbers.append(7)
print(primeNumbers)
isinstance(primeNumbers, object)
OUTPUT
[2, 3, 5, 7] True
While it might be expected for compound objects like lists to have attributes and methods, what is sometimes unexpected is that in Python even simple types have attached attributes and methods.
For example, numerical types have a real
and imag
attribute that returns the real and imaginary part of the value, if viewed as a complex number:
complexNumber = 9.8
print(complexNumber.real, "+", complexNumber.imag, 'i')
isinstance(complexNumber, object)
OUTPUT
9.8 + 0.0 i
Methods are like attributes, except they are functions that you can call using opening and closing parentheses.
For example, floating point numbers have a method called is_integer()
that checks whether the value is an integer:
floatNumber = 33.33
print(floatNumber.is_integer())
isinstance(floatNumber.is_integer(), object)
OUTPUT
False True
When we say that everything in Python is an object, we really mean that everything is an object – even the attributes and methods of objects are themselves objects with their own type
information:
type(intNumber.is_integer())
# bool
Python Operators
Now we'll dig into the semantics of the various operators included in Python language.
Listed below are the major Operator categories:
1. Arithmetic Operators
Python implements seven basic binary arithmetic operators, two of which can double as unary operators. They are summarized in the following table:
Operator | Name | Description |
---|---|---|
a + b | Addition | Sum of a and b |
a - b | Subtraction | Difference of a and b |
a * b | Multiplication | Product of a and b |
a / b | True division | Quotient of a and b |
a // b | Floor division | Quotient of a and b, removing fractional parts |
a % b | Modulus Integer | Remainder after division of a by b |
a ** b | Exponentiation | a raised to the power of b |
-a | Unary Negation | The negative of a |
+a | Unary plus | a unchanged (rarely used) |
These operators can be used and combined in intuitive ways, using standard parentheses ( ) to group operations. For example:
# addition, subtraction, multiplication
(12 + 34) * (12.3 - 4)
# 381.8
Floor division is true division with fractional parts truncated:
# True division
print(22 / 7)
# 3.142857142857143
# Floor division
print(22 // 7)
# 3
The floor division operator was added in Python 3.
Finally, an eighth arithmetic operator that was added in Python 3.5:
a @ b
operator, which is meant to indicate the matrix product of a
and b
, for use in various linear algebra packages.
# demonstrate a @ b operator; matrix product of a and b
import numpy as np
matrixA = np.matrix('1 2; 3 4')
print(f"matrix A = \n {matrixA}")
matrixB = np.matrix('5 6; 7 8')
print(f"matrix B = \n {matrixB}")
prodMatrix = matrixA @ matrixB # the matrix product of matrixA and matrixB
print(f"Product of matrixA and matrixB = \n {prodMatrix}")
OUTPUT
matrix A = [[1 2] [3 4]] matrix B = [[5 6] [7 8]] Product of matrixA and matrixB = [[19 22] [43 50]]
2. Bitwise Operators
Python includes operators to perform bitwise logical operations on integers.
Bitwise operators are much less commonly used than the standard arithmetic operations.
The six bitwise operators are summarized in the following table:
Operator | Name | Description |
---|---|---|
a & b | Bitwise AND | Bits defined in both a and b |
a | b | Bitwise OR | Bits defined in a or b or both |
a ^ b | Bitwise XOR | Bits defined in a or b but not both |
a << b | Bit shift left | Shift bits of a left by b units |
a >> b | Bit shift right | Shift bits of a right by b units |
~a | Bitwise NOT | Bitwise negation of a |
These bitwise operators only make sense in terms of the binary representation of numbers, which you can see using the built-in bin( )
method:
# bin() function returns the binary version of a specified integer
bin(10)
# '0b1010'
The result is prefixed with '0b'
, which indicates a binary representation. The rest of the digits indicate that the number 10 is expressed as the sum 1*23 + 0*22 + 1*21 + 0*20 = 10 .
Similarly, we can write number 9 in binary as below:
bin(9)
# '0b1001'
Now, using bitwise OR
we can find the number which combines the bits of 9 and 10:
9 | 10
# 00001001 (9 in Binary)
# | 00001010 (10 in Binary)
#___________
# 00001011 (11 in Binary)
OUTPUT
11
bin(9 | 10)
# 00001001 (9 in Binary)
# | 00001010 (10 in Binary)
#___________
# 00001011 (11 in Binary)
OUTPUT
'0b1011'
Bitwise operators are not as immediately useful as the standard arithmetic operators, but it's helpful to see them at least once to understand what class of operation they perform.
In particular, users from other languages are sometimes tempted to use XOR (i.e., a ^ b
) when they really mean exponentiation (i.e., a ** b
).
3. Assignment Operators
Already seen that variables can be assigned with the =
operator, and the values stored for later use.
assignNum = 66
print(assignNum)
# 66
We can use these variables in expressions with any of the operators mentioned earlier.
For example, to add 6 to assignNum
we write:
assignNum + 6
# 72
We might want to update the variable assignNum
with this new value; in this case, we could combine the addition and the assignment and write assignNum = assignNum + 6
. Because this type of combined operation and assignment is so common, Python includes built-in update operators for all of the arithmetic operations:
assignNum += 6 # equivalent to assignNum = assignNum + 6
print(assignNum)
# 72
There is an augmented assignment operator corresponding to each of the binary operators listed earlier; in brief, they are:
Operator | Description | Same as |
---|---|---|
a += b | Add and equal operator | a = a + b |
a -= b | Subtract and equal operator | a = a - b |
a *= b | Asterisk and equal operator | a = a * b |
a /= b | Divide and equal operator | a = a / b |
a //= b | Double divide and equal operator | a = a // b |
a **= b | Exponent and equal operator | a = a ** b |
a %= b | Modulus and equal operator | a = a % b |
a &= b | Bitwise AND Assignment Operator | a = a & b |
a|= b | Bitwise OR Assignment Operator | a = a | b |
a ^= b | Bitwise XOR Assignment Operator | a = a ^ b |
a <<= b | Bitwise LEFT shift assignment operator | a = a << b |
a >>= b | Bitwise RIGHT shift assignment operator | a = a >> b |
Each one is equivalent to the corresponding operation followed by assignment: that is,
for any operator "■"
the expression a ■= b
is equivalent to a = a ■ b
with a slight catch.
For mutable objects
like lists, arrays, or DataFrames, these augmented assignment operations are actually subtly different than their more verbose counterparts: they modify the contents of the original object rather than creating a new object to store the result.
# Demo the Add and Assignment Operators
num1 = 6
num2 = 2
num1 += num2 # num1 = num1 + num2
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 8
# Demo the Substract and Assignment Operators
num1 = 6
num2 = 2
num1 -= num2 # num1 = num1 - num2
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 4
# Demo the Multiple and Assignment Operators
num1 = 6
num2 = 2
num1 *= num2 # num1 = num1 * num2
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 12
# Demo the Divide and Assignment Operators
num1 = 22
num2 = 7
num1 /= num2 # num1 = num1 / num2
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 3.142857142857143
# Demo the Double Divide and Assignment Operators
num1 = 22
num2 = 7
num1 //= num2 # num1 = num1 // num2
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 3
# Demo the Exponent and Assignment Operators
num1 = 3
num2 = 2
num1 **= num2 # num1 = num1 ** num2
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 9
# Demo the Modulus and Assignment Operators
num1 = 7
num2 = 4
num1 %= num2 # num1 = num1 % num2
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 3
# Demo the Bitwise AND Assignment Operator
num1 = 6
num2 = 13
num1 &= num2 # num1 = num1 & num2
# 0110 (6 in binary)
# & 1101 (13 in binary)
# ________
# 0100 = 4 (In decimal)
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 4
# Demo the Bitwise OR Assignment Operator
num1 = 6
num2 = 13
num1 |= num2 # num1 = num1 | num2
# 0110 (6 in binary)
# | 1101 (13 in binary)
# ________
# 0100 = 4 (In decimal)
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 15
# Demo the Bitwise XOR Assignment Operator
num1 = 6
num2 = 13
num1 ^= num2 # num1 = num1 ^ num2
# 0110 (6 in binary)
# | 1101 (13 in binary)
# ________
# 0100 = 4 (In decimal)
# ^ 1011 = 11 (In decimal) [Negation of OR is XOR]
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 11
# Demo the Bitwise LEFT shift assignment operator
num1 = 6
num2 = 2
num1 <<= num2 # num1 = num1 << num2
# 00000110 (6 in binary) [ LEFT shift by 2]
# 00011000 (24 in binary)
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 24
# Demo the Bitwise RIGHT shift assignment operator
num1 = 19
num2 = 1
num1 >>= num2 # num1 = num1 >> num2
# 00010011 (19 in binary) [ RIGHT shift by 1]
# 00001001 (9 in binary)
print( "Value of num1 = ", num1)
OUTPUT
Value of num1 = 9
4. Comparison Operators
Python implements standard comparison operators, which return Boolean values True
and False
.
The comparison operations are listed in the following table:
Operation | Description |
---|---|
a == b | a equal to b |
a != b | a not equal to b |
a < b | a less than b |
a > b | a greater than b |
a <= b | a less than or equal to b |
a >= b | a greater than or equal to b |
Comparison operators can be combined with the arithmetic
and bitwise
operators to express a virtually limitless range of tests for the numbers.
For example, we can check if a number is odd by checking that the modulus with 2 returns 1:
# 13 is odd
13 % 2 == 1
# True
# 24 is even
24 % 2 == 0
# True
We can string-together multiple comparisons to check more complicated relationships:
# check if givenNum is between 9 and 19
givenNum = 18
9 < givenNum < 19
# True
5. Boolean Operators
When working with Boolean values, Python provides operators to combine the values using the standard concepts of "and", "or", and "not".
Predictably, these operators are expressed using the words and
, or
, not
:
testNum = 11
(testNum < 15) and (testNum > 10)
# True
(testNum > 9) or (testNum % 2 == 0)
# True
not (testNum < 7)
# True
Boolean algebra aficionados might notice that the XOR operator is not included; this can of course be constructed in several ways from a compound statement of the other operators.
Otherwise, a clever trick you can use for XOR of Boolean values is the following:
# (testNum > 1) xor (testNum < 10)
(testNum > 1) != (testNum < 10)
# True
These sorts of Boolean operations will become extremely useful when we begin discussing control flow statements such as conditionals
and loops
6. Identity & Membership Operators
Like and
, or
, not
, Python also contains prose-like operators to check for identity and membership. They are the following:
Operator | Description |
---|---|
a is b | True, if a and b are identical objects |
a is not b | True, if a and b are not identical objects |
a in b | True, if a is a member of b |
a not in b | True, if a is not a member of b |
(a). Identity Operators: is
and is not
The identity operators, "is" and "is not" check for object identity.
Object identity is different than equality
, as we can see here:
oddNumOne = [3, 5, 7]
print(id(oddNumOne))
oddNumTwo = [3, 5, 7]
print(id(oddNumTwo))
OUTPUT
2280219806976 2280219680128
oddNumOne == oddNumTwo
# True
oddNumOne is oddNumTwo
# False
oddNumOne is not oddNumTwo
# True
What do identical objects look like? Here is an example:
evenNumOne = [2, 4, 6]
evenNumTwo = evenNumOne
print(evenNumOne is evenNumTwo)
print(id(evenNumOne))
print(id(evenNumTwo))
OUTPUT
True 2280198889280 2280198889280
The difference between the two cases here is that in the first, oddNumOne
and oddNumTwo
point to different objects, while in the second they point to the same object.
As we know, Python variables are pointers. The "is"
operator checks whether the two variables are pointing to the same container (object), rather than referring to what the container contains.
With this in mind, in most cases that a beginner is tempted to use "is"
what they really mean is ==
.
(b). Membership operators: in
and not in
Membership operators check for membership within compound objects.
For example:
'Messi' in ["Messi", "Ronaldo", "Neymar"]
# True
'Messi' not in ["Messi", "Ronaldo", "Neymar"]
# False
Python Built-in Types
All Python objects have type information attached. There are two broad categories of built-in types in Python :
- 1. Scalar or Simple Types
- 2. Compound Types
1. Built-in Scalar (simple) types in Python:
integer
, floating-point
and complex
) are the obvious examples, while discrete/enumerated values can also be considered scalar.True
or False
None
Type | Mutable ? | Example | Description |
---|---|---|---|
int | Immutable | x = 96 | integers (i.e. whole numbers) |
float | Immutable | x = 3.14 | floating-point numbers (i.e. real numbers) |
complex | Immutable | x = 2 + 3j | Complex numbers (i.e. real and imaginary part) |
bool | Immutable | x = True | Boolean: True/False values |
str | Immutable | x = 'Skillzam' | String: characters or text |
NoneType | Immutable | x = None | Special object indicating null |
2. Built-in Compound types in Python:
int
, float
, complex
, bool
, str
, NoneType
.Type | Mutable ? | Example | Description |
---|---|---|---|
list | Mutable | x = ["Messi", 35, 'Forward'] | Ordered sequence of Object |
tuple | Immutable | x = (2022, "Skills", 89.99) | Ordered sequence of Objects |
dict | Mutable | x = {"Argentina":4, "France": 2} | Unordered (key,value) mapping |
set | Mutable | x = {"Arsenal","Barcelona","PSG"} | Unordered collection of unique values |
As you can see, round ( )
square [ ]
curly { }
brackets have distinct meanings when it comes to the type of collection/sequence produced.
Numbers
- 1.
int
- 2.
float
- 3.
complex
real
and imaginary
part, which are each a floating point number
. int()
, float()
, and complex()
can be used to produce numbers of a specific type.
Type | Mutable ? | Example | Description |
---|---|---|---|
int | Immutable | x = 96 | integers (i.e. whole numbers) |
float | Immutable | x = 3.14 | floating-point numbers (i.e. real numbers) |
complex | Immutable | x = 2 + 3j | Complex numbers (i.e. real and imaginary part) |
1. Integer Numbers
int()
constructor method can be used to create a integer type.Consider some examples:
# Integers includes negation whole numbers
intNum = -51
type(intNum)
OUTPUT
int
# zero is an integer as well
type(0)
OUTPUT
int
# int() constructor method to create integer variable
year = int(1947)
print(type(year))
OUTPUT
<class 'int'>
# Python integers are variable-precision
2 ** 199
OUTPUT
803469022129495137770981046170581301261101496891396417650688
up-casts
to floating-point type.
# Division will up-casts to floating-point type
22 / 7
OUTPUT
3.142857142857143
# Python 2 behavior
>>> 22 / 7
3
//
# Python 3 behavior
>>> 22 // 7
3
2. Floating-Point Numbers
decimal point ( . )
.Consider some examples:
# decimal & exponential notation
floatNumOne = 0.000000009
floatNumTwo = 9E-9
print(floatNumOne == floatNumTwo)
OUTPUT
True
e
or E
can be read "...times ten to the...", so that 9.8e7 is interpreted as 9.8 * 107 (as seen in below example).
# exponential notation
fNumOne = 98000000.00
fNumTwo = 9.8e7
print(fNumOne == fNumTwo)
OUTPUT
True
float()
constructor.int()
constructor
>>> float(-55)
-55.0
>>> int(9.8e7)
98000000
Floating-point precision:
>>> 0.1 + 0.2 == 0.3
False
Why is this, the case ?
print("0.1 = {0:.17f}".format(0.1))
print("0.2 = {0:.17f}".format(0.2))
print("0.3 = {0:.17f}".format(0.3))
OUTPUT
0.1 = 0.10000000000000001 0.2 = 0.20000000000000001 0.3 = 0.29999999999999999
EXPLANATION:
We're accustomed to thinking of numbers in decimal (base-10) notation, so that each fraction must be expressed as a sum of powers of 10:
1/8 = 0.125 = 1 * 10-1 + 2 * 10-2 + 5 * 10-3
In the familiar base-10 representation, we represent this in the familiar decimal expression: 0.125
Computers usually store values in binary notation, so that each number is expressed as a sum of powers of 2:
1/8 = 0 * 2-1 + 0 * 2-2 + 1 * 2-3
In a base-2 representation, we can write this 0.0012 where the subscript 2 indicates binary notation. The value 0.125 = 0.0012 happens to be one number which both binary and decimal notation can represent in a finite number of digits.
In the familiar base-10 representation of numbers, you are probably familiar with numbers that can't be expressed in a finite number of digits. For example, dividing 1 by 3 gives, in standard decimal notation:
1/3 = 0.333333333⋯
The 3s go on forever: that is, to truly represent this quotient, the number of required digits is infinite!
Similarly, there are numbers for which binary representations require an infinite number of digits. For example:
1/10 = (0.00011001100110011⋯)2
Just as decimal notation requires an infinite number of digits to perfectly represent 1/3 , binary notation requires an infinite number of digits to represent 1/10 .
Python internally truncates these representations at 52 bits beyond the first nonzero bit on most systems.
This rounding error for floating-point values is a necessary evil of working with floating-point numbers. The best way to deal with it is to always keep in mind that floating-point arithmetic is approximate, and never rely on exact equality tests with floating-point values.
3. Complex Numbers
A + Bj
where, A
B
are real numbers and j
is an imaginary number called “iota”.complex()
constructor method returns a complex number, when real and imaginary parts are provided, or it converts a string or number to a complex number.
>>> complex(9, 6)
(9+6j)
"j"
suffix in expressions to indicate the imaginary part:
>>> 3 + 4j
(3+4j)
# Complex Numbers
complexNum = 3 + 4j
complexReal = complexNum.real # real part of Complex number
complexImag = complexNum.imag # imaginary part of Complex number
complexConjugate = complexNum.conjugate() # conjugate of Complex number
complexAbs = abs(complexNum) # magnitude of Complex number
print("Real part of Complex Number :", complexReal)
print("Imaginary part of Complex Number :", complexImag)
print("Conjugate of Complex Number :", complexConjugate)
print("Magnitude of Complex Number :", complexAbs)
OUTPUT
Real part of Complex Number : 3.0 Imaginary part of Complex Number : 4.0 Conjugate of Complex Number : (3-4j) Magnitude of Complex Number : 5.0
opposite sign
.Strings
single quote(')
double-quote(")
or triple quote(''' or """)
.str
objects, or strings. Strings are immutable sequences of Unicode code points.("string " "literal")
== "string literal"
. - (a). Single quotes:
'allows embedded "double" quotes'
- (b). Double quotes:
"allows embedded 'single' quotes"
- (c). Triple quoted:
'''Three single quotes'''
,"""Three double quotes"""
Strings created with Single quotes:
# String in Single Quotes
academy = 'Skillzam'
print(academy)
OUTPUT
Skillzam
Strings created with Double quotes:
# String in Double Quotes
tagLine = "Learn without limits!"
print(tagLine)
OUTPUT
Learn without limits!
Strings created with Tripple quotes:
# Multi-line comments
''' This is the
Python
multi-line
comment!
'''
# String in tripple Quotes
multiLine = """
A CURE platform:
- Cross-Skill
- Up-Skill
- Re-Skill
- Expert-Skill
"""
print(multiLine)
OUTPUT
A CURE platform: - Cross-Skill - Up-Skill - Re-Skill - Expert-Skill
str
constructor.str()
function is used to create a string version of the object that would be passed as argument to it.
# string variable using str() method
techHiring = str('www.' + 'workzam' + '.com') # '+' is used for concatenation
print(techHiring)
OUTPUT
www.workzam.com
String Properties
Strings have three important properties:
# String contains characters/symbols (any Unicode Points)
strVar01 = "$killzam 2023"
strVar02 = "ಕನ್ನಡ"
print("type of strVar01 = ", type(strVar01))
print("type of strVar02 = ", type(strVar02))
OUTPUT
type of strVar01 = <class 'str'> type of strVar02 = <class 'str'>
# Length of a given string using len() String method
# len() returns number of characters contained in a string including spaces
strVar03 = ' Python '
print("length of strVar03 = ", len(strVar03))
OUTPUT
length of strVar03 = 8
String concatenation, Indexing, and Slicing
Three basic string operations:
String Concatenation : You can combine, or concatenate, two strings using the +
operator.
# String Concatenation
'Skill' + 'zam'
OUTPUT
Skillzam
# String Concatenation
fname = "Elon"
lname = 'Musk'
fullname = fname + ' ' + lname
print(fullname)
OUTPUT
Elon Musk
# Concatenation & Multiplication of string
'buz' + ('z' * 6)
OUTPUT
'buzzzzzzz'
String Indexing :
index
n
between two square brackets [ ]
immediately after the string.
# String Indexing
rhyme = "Twinkle, Twinkle, Little Star"
rhyme[4] # returns the character at index position 4
OUTPUT
'k'
# Reverse Indexing
river = "Kaveri"
river[-5]
OUTPUT
'a'
# Access an index beyond end of string, then Python throws an IndexError
rhyme = "Twinkle, Twinkle, Little Star"
try:
rhyme[100]
except:
print("IndexError: string index out of range")
OUTPUT
IndexError: string index out of range
String Slicing :
:
between two index numbers set inside square brackets [ ]
string[start : stop : step]
# String Slicing
city = "Mumbai"
city[0:3] # returns first three characters in string "Mumbai"
OUTPUT
'Mum'
# Boundaries that fall outside the beginning or ending
city = "Mumbai"
city[:10] # return the entire string
OUTPUT
'Mumbai'
empty string ("")
.
# Entire range is out of bounds
city = "Mumbai"
city[6:10] # returns the empty string ''
OUTPUT
''
# Adding 'step' to the string slicing
stadium = "Maracanã"
stadium[1::2] # start at position index 1, to end of string in step sizes of 2
OUTPUT
'aaaã'
# Reverse a string
subject = "Data Science"
subject[::-1] # same as subject[12::-1]
OUTPUT
'ecneicS ataD'
# Slicing everything : Copying the entry string
singer = "Michael Jackson"
singer[:] # Copy everything
OUTPUT
'Michael Jackson'
Escape Characters
\
followed by the character you want to insert.Code | Description |
---|---|
\' | Single Quote |
\" | Double Quote |
\\ | Backslash |
\n | New Line |
\b | Backspace |
\r | Carriage Return |
\t | Tab |
# Double quotes inside a string, which is surrounded by double quotes
sentence = "Messi became the "World Champion" in the year 2022!"
print(sentence)
OUTPUT
SyntaxError: invalid syntax
# Using escape character \" to avoid the invalid Syntax error
sentence = "Messi became the \"World Champion\" in the year 2022!"
print(sentence)
OUTPUT
Messi became the "World Champion" in the year 2022!
# Using newline escape character \n
newline = "This is to demonstrate the usuage of \n new line escape charater in Python."
print(newline)
OUTPUT
This is to demonstrate the usuage of new line escape charater in Python.
String Interpolation
String Interpolation is the process of substituting values of variables into placeholders in a string.
For instance, if you have a template for specifying user-ID like "Welcome to Skillzam! Your user ID is {uid}.", you would like to replace the placeholder for user ID with an actual value. This process is called string interpolation.
Python supports multiple ways to format text strings and these includes % Modulo
, str.format()
, f-strings
and string.Template
.
% Modulo
%s
and %r
convert any python object to a string using two separate methods: str()
and repr()
. We will learn more about these functions later on in the course, but you should note that %r
and repr()
deliver the string representation of the object, including quotation marks and any escape characters. %
operator only takes one argument, we need to wrap the right-hand side in a tuple as shown in the example below:
# Code to demonstrate % Module string interpolation
name = 'Michael Phelps'
medalNum = 28
# for single substitution
print("% s is called 'Flying Fish'!" % name)
# for single and multiple substitutions use () mandatory
print("%s is the most decorated Olympian of all time, with a total of %s medals." %(name, medalNum))
OUTPUT
Michael Phelps is called 'Flying Fish'! Michael Phelps is the most decorated Olympian of all time, with a total of 28 medals.
Padding and Precision of Floating Point Numbers: Floating point numbers use the format %5.2f
Here, 5 would be the minimum number of characters the string should contain; these may be padded with whitespace if the entire number does not have this many digits. Next to this, .2f stands for how many numbers to show past the decimal point. Let's see some examples:
# Padding and Precision of Floating Point Numbers
print('1. Floating point number: %5.2f' %(23.456))
print('2. Floating point number: %1.0f' %(23.456))
print('3. Floating point number: %1.5f' %(23.456))
print('4. Floating point number: %10.2f' %(23.456))
print('5. Floating point number: %25.2f' %(23.456))
OUTPUT
1. Floating point number: 23.46 2. Floating point number: 23 3. Floating point number: 23.45600 4. Floating point number: 23.46 5. Floating point number: 23.46
str.format()
format()
function on a string object and curly braces { }
, the string object in format()
function is substituted in place of curly braces { }
.format()
function to do simple positional formatting, just like % formatting.{ }
. This will allow us to use the parameters of format functions in any order we want.
# Code to demonstrate str.format string interpolation
name = 'Challenger Deep'
location = 'Mariana Trench'
txt = "The {} in the {}, is the deepest part of the ocean."
print(txt.format(name, location))
OUTPUT
The Challenger Deep in the Mariana Trench, is the deepest part of the ocean.
# Code to demonstrate str.format string interpolation
# use the variable name inside the curly braces {}
championName = 'Garry Kasparov'
championAge = 22
txt = "{nam} became the youngest ever undisputed World Chess Champion at {age}."
print(txt.format(age=championAge, nam=championName))
OUTPUT
Garry Kasparov became the youngest ever undisputed World Chess Champion at 22.
f-string
f
# Code to demonstrate f-string string interpolation
founderName = 'Brendan Eich'
langName = 'JavaScript'
txt = f"{founderName} is the creater of {langName} programming language."
print(txt)
OUTPUT
Brendan Eich is the creater of JavaScript programming language.
# f-strings to calculate some arithmetic operations
# Solve Quadratic Equation: x**2 - 8x + 15 = 0
a = 1
b = -8
c = 15
root1 = f"Value of root1 = {(-b + ((b**2 - 4*a*c)**0.5)) / 2*a}"
root2 = f"Value of root2 = {(-b - ((b**2 - 4*a*c)**0.5)) / 2*a}"
print("The roots of Quadratic Equation are :")
print(root1)
print(root2)
OUTPUT
The roots of Quadratic Equation are : Value of root1 = 5.0 Value of root2 = 3.0
Template string
Template
class from Python's built-in string
module to use it.$
with valid Python identifiers. Surrounding the placeholder with curly braces { }
allows it to be followed by more alphanumeric letters with no intervening spaces.
# Template string to demo string interpolation
from string import Template
name = 'Peregrine Falcon'
livingType = 'bird'
# create a template which pass two variable
txt = Template('The $value1 is the fastest $value2 in the world.')
# Pass parameters into the template string
print(txt.substitute(value2=livingType, value1=name))
OUTPUT
The Peregrine Falcon is the fastest bird in the world.
String Methods
object.method(parameters)
# Make string upper-case
academy = "Skillzam - Learn without limits!"
academy.upper()
OUTPUT
'SKILLZAM - LEARN WITHOUT LIMITS!'
# Make string lower-case
academy = "Skillzam - Learn without limits!"
academy.lower()
OUTPUT
'skillzam - learn without limits!'
# Make string Capitalize
academy = "Skillzam - Learn without limits!"
academy.capitalize()
OUTPUT
'Skillzam - learn without limits!'
# Removes any whitespace from the beginning or the end
academy = " Skillzam - Learn without limits! "
academy.strip()
OUTPUT
'Skillzam - Learn without limits!'
# replace() method replaces a string with another string
academy = "Skillzam - Learn without limits!"
academy.replace('-','=>')
OUTPUT
'Skillzam => Learn without limits!'
# Split a string by blank space and returns list
academy = "Skillzam - Learn without limits!"
academy.split()
OUTPUT
['Skillzam', '-', 'Learn', 'without', 'limits!']
# Split by a specific element and returns list (doesn't include the element that was split on)
academy = "Skillzam - Learn without limits!"
academy.split('-')
OUTPUT
['Skillzam ', ' Learn without limits!']
# Converts string into lower-case and return string
academy = "Skillzam - Learn without limits!"
academy.casefold()
OUTPUT
'skillzam - learn without limits!'
# center align the string, using a specified character & return string
academy = "Skillzam - Learn without limits!"
academy.center(50,'*')
OUTPUT
'*********Skillzam - Learn without limits!*********'
# count() method
txt = "count() string method returns the number of times the specified value occurs in the string"
txt.count('the')
OUTPUT
3
# find() & index() method returns the position of string, where it was found
vibgyor = "violet indigo blue green yellow orange red"
positionBlue = vibgyor.find('blue') # find() method
positionWhite = vibgyor.find('white') # find() method
poistionRed = vibgyor.index('red') # index() method
try:
poistionCyan = vibgyor.index('cyan') # index() method
except:
print("ValueError: substring not found")
print("Index position where 'blue' was found is ", positionBlue)
print("Index position where 'white' was found is ", positionWhite)
print("Index position where 'red' was found is ", poistionRed)
OUTPUT
ValueError: substring not found Index position where 'blue' was found is 14 Index position where 'white' was found is -1 Index position where 'red' was found is 39
Booleans
True
or False
.bool()
object constructor: values of any other type can be converted to Boolean via predictable rules.For example, any numeric type is False
if equal to zero, and True
otherwise:
# Truth value of an integer
bool(2017)
OUTPUT
True
# Truth value of zero
bool(0)
OUTPUT
False
# Truth value of a float number
bool(2.728281)
OUTPUT
True
# Truth value of None
bool(None)
OUTPUT
False
bool()
is False
for empty strings and True
otherwise:
# Truth value of an empty string
bool("")
OUTPUT
False
# Truth value of string
bool("Workzam")
OUTPUT
True
False
and for any other values, it is True
.
# Truth value of a non-empty list
bool([2, 4, 6])
OUTPUT
True
# Truth value of an empty list
bool([])
OUTPUT
False
# Truth value of an empty dictionary
bool({})
OUTPUT
False
# Truth value of an non-empty dictionary
bool({"Argentina":4, "France": 2})
OUTPUT
True
# Truth value of an empty set()
bool(set())
OUTPUT
False
# Truth value of a range(0)
bool(range(0))
OUTPUT
False
Any object can be tested for "truth value", for use in an if
or while
condition or as operand of the Boolean operations below.
By default, an object is considered True unless its class defines either a __bool__()
method that returns False or a __len__()
method that returns zero, when called with the object.
Here are most of the built-in objects considered False
:
NoneType
NoneType
which has only a single possible value i.e NoneNone
keyword is used to define a null value, or no value at all.None
can be None.For Example:
studentCount = None
type(studentCount)
OUTPUT
NoneType
print()
function in Python 3 does not return anything, but we can still catch its value.None
# print() method returns None
return_value = print('Old is Gold')
print(return_value)
OUTPUT
None
Lists
[ ]
- (1). Lists have no fixed size, meaning we don't have to specify how big a list will be.
- (2). Lists have no fixed type constraint.
For example:
# List of English Vowels
vowels = ['a', 'e', 'i', 'o', 'u']
print(vowels)
OUTPUT
['a', 'e', 'i', 'o', 'u']
# List of whole numbers in a Fibonacci series
fibo = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
print(fibo)
OUTPUT
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Lists may be constructed in several ways:
[ ]
[a], [a, b, c]
[x for x in iterable]
list() or list(iterable)
The constructor builds a list whose items are the same and in the same order as iterable's items.
iterable may be either a sequence, a container that supports iteration, or an iterator object.
If iterable is already a list, a copy is made and returned, similar to iterable[:]
.
For example, list('abc')
returns ['a', 'b', 'c']
and list( (1, 2, 3) )
returns [1, 2, 3]
.
If no argument is given, the constructor creates a new empty list, [ ]
.
# Creating list literals using square brackets
listOne = ['A', 1]
print(listOne)
OUTPUT
['A', 1]
# Creating list using built-in list() constructor method
listTwo = list("WORKZAM") # Creating list from string argument
listThree = list((8, 1, 2, 8)) # Creating list from tuple argument
listFour = list(range(11, 21)) # Creating list from range() argument
listFive = list([1, 3, 5, 7]) # Creating list from list argument
print(listTwo)
print(listThree)
print(listFour)
print(listFive)
OUTPUT
['W', 'O', 'R', 'K', 'Z', 'A', 'M'] [8, 1, 2, 8] [11, 12, 13, 14, 15, 16, 17, 18, 19, 20] [1, 3, 5, 7]
# Creating list using list comprehension
# list of single digit even number
listSix = [item for item in range(1, 10) if (item % 2 == 0)]
print(listSix)
OUTPUT
[2, 4, 6, 8]
Working with lists :
in
keyword.
# Determine if item exists in list
shoppingList = ["tea", "coffee", "milk", "eggs", "honey"]
if "eggs" in shoppingList:
print("EGGS are present in the shopping list.")
OUTPUT
EGGS are present in the shopping list.
# Modify item in a list
shoppingList = ["tea", "coffee", "milk", "eggs", "honey"]
shoppingList[4] = "bread" # Change the item from honey to bread
print(shoppingList)
OUTPUT
['tea', 'coffee', 'milk', 'eggs', 'bread']
del
# using "del" remove item from list
shoppingList = ["tea", "coffee", "milk", "eggs", "honey"]
del shoppingList[-1] # Remove the last item "honey" in the list
print(shoppingList)
OUTPUT
['tea', 'coffee', 'milk', 'eggs']
List indexing & slicing
[0]
, the second item has index [1]
etc. +
to concatenate lists, just like we did for strings. *
for a duplication method similar to stringsConside the below list example for understanding:
# list example
exampleList = ['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
exampleList[0] # access first element by indexing
OUTPUT
'S'
# Reverse Indexing of list element
exampleList = ['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
exampleList[-1] # access last element by reverse indexing
OUTPUT
'M'
You can visualize indexing & reverse-indexing this way:
Here values in the list are represented by capital letters in the squares; list indices are represented by number above and below.
In this case, exampleList[1]
returns K
, because that is the value at index 1.
Indexing is a means of fetching a single value from the list, slicing is a means of accessing multiple values in sub-lists. It uses a colon :
to indicate the start point (inclusive) and end point (non-inclusive) of the sub-array.
For example, to get the first five elements of the list, we can write:
# Slicing list Example
exampleList = ['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
exampleList[0:5] # same as exampleList[:5]
OUTPUT
['S', 'K', 'I', 'L', 'L']
Similarly, if we leave out the last index, it defaults to the length of the list. Thus, the last three elements can be accessed as follows:
# Access last three elements in list
exampleList = ['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
exampleList[-3:] # same as exampleList[-3:len(exampleList)]
OUTPUT
['Z', 'A', 'M']
Finally, it is possible to specify a third integer that represents the step size ; for example, to select every second element of the list, we can write:
# specify step size in list slicing
exampleList = ['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
exampleList[::2] # same as exampleList[0:len(exampleList):2]
OUTPUT
['S', 'I', 'L', 'A']
Reversing the list :
# Reversing the list
exampleList = ['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
exampleList[::-1]
OUTPUT
['M', 'A', 'Z', 'L', 'L', 'I', 'K', 'S']
Examples on List Indexing & Slicing :
exampleList = ['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
exampleList[0] = '$'
print(exampleList)
OUTPUT
['$', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
exampleList = ['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
exampleList[:5] = 'WORK'
print(exampleList)
OUTPUT
['W', 'O', 'R', 'K', 'Z', 'A', 'M']
exampleList = ['W', 'O', 'R', 'K', 'Z', 'A', 'M']
exampleList[:4] = ['S', 'K', 'I', 'L', 'L']
print(exampleList)
OUTPUT
['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
Use + to concatenate lists :
# use '+' to concatenate lists
exampleList + [1, 2, 3]
OUTPUT
['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M', 1, 2, 3]
Use * to duplicate lists :
# Make the list double
exampleList * 2
OUTPUT
['S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M', 'S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M']
List Nesting
Python data structures support nesting. This means we can have data structures within data structures.
For example: A list inside a list.
# Matrix like structure using lists
row1 = [1, 2, 3]
row2 = [4, 5, 6]
row3 = [7, 8, 9]
# Nesting of lists within a list
matrixOne = [row1, row2, row3]
print(matrixOne)
OUTPUT
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Access first list item in matrix list
matrixOne[0]
OUTPUT
[1, 2, 3]
# access first element of first list item in matrix list
matrixOne[0][0]
OUTPUT
1
List methods
Lists have a lot of useful built-in attributes and methods. Let us now consider them one by one:
append()
method is used to add an item to the end of the list.
# append() adds an item to end of the list
capitalCities = ["New Delhi", "New York", "London", "Istanbul"]
capitalCities.append("Tokyo")
print(capitalCities)
OUTPUT
['New Delhi', 'New York', 'London', 'Istanbul', 'Tokyo']
insert()
method inserts an item at the specified index.
# insert() adds an item at specified index
capitalCities = ["New Delhi", "New York", "London", "Istanbul"]
capitalCities.insert(0,"Tokyo")
print(capitalCities)
OUTPUT
['Tokyo', 'New Delhi', 'New York', 'London', 'Istanbul']
extend()
method is used to append elements from another list to the current list.
# extend() appends elements from one list to another
healthyFood = ['Avocado', 'Kiwi', 'Moringa']
veggies = ['Spinach', 'Kale', 'Collard']
healthyFood.extend(veggies)
print(healthyFood)
OUTPUT
['Avocado', 'Kiwi', 'Moringa', 'Spinach', 'Kale', 'Collard']
extend()
method can append not only lists but also any iterable object (tuples, sets, dictionaries etc..).
# extend() appends elements from one list to another iterables
numbers = [0, 1, 3, 5, 7, 9]
evenOdd = (2, 4, 6, 8) # Tuple Object
numbers.extend(evenOdd)
print(numbers)
OUTPUT
[0, 1, 3, 5, 7, 9, 2, 4, 6, 8]
remove()
method removes the specified item.
# remove() method removes element from list
shoppingList = ["tea", "coffee", "milk", "eggs", "honey"]
shoppingList.remove('honey')
print(shoppingList)
OUTPUT
['tea', 'coffee', 'milk', 'eggs']
pop()
method removes the specified index element.
# pop() method removes the specified index element
fishes = ['Catfish', 'Bass', 'Carp', 'Tuna', 'Salmon']
fishes.pop(3) # 'Tuna' is at the index position 3
print(fishes)
OUTPUT
['Catfish', 'Bass', 'Carp', 'Salmon']
clear()
method empties the list.
# clear() method empties the list
ranNum = [12, 34 ,76, 98, 11]
ranNum.clear()
print(ranNum)
OUTPUT
[]
sort()
method that will sort the list alphanumerically, ascending, by default.
# sort() ascending will sort list alphanumerically
colors = ['red', 'green', 'blue', 'orange', 'cyan']
colors.sort()
print(colors)
OUTPUT
['blue', 'cyan', 'green', 'orange', 'red']
sort()
descending using keyword argument reverse
= True
# sort() descending using 'reverse' argument
num = [-12, 3, 45, 8877, 222]
num.sort(reverse=True)
print(num)
OUTPUT
[8877, 222, 45, 3, -12]
sort()
customization using the keyword argument key = function
.
# sort() customization using 'key = function' argument
names = ['Raj', 'ali', 'LEO', 'eve', 'Max']
names.sort(key = str.lower)
print(names)
OUTPUT
['ali', 'eve', 'LEO', 'Max', 'Raj']
reverse()
method reverses the current sorting order of the elements.
# reverse() method reverses current sorting order
names = ['ali', 'eve', 'LEO', 'Max', 'Raj']
names.reverse()
print(names)
OUTPUT
['Raj', 'Max', 'LEO', 'eve', 'ali']
copy()
method will make a copy of the list.
# copy() method will make a copy of the list
symbols = ['INR', 'USD', 'EUR', 'JPY', 'CNY']
curSym = symbols.copy()
print(curSym)
OUTPUT
['INR', 'USD', 'EUR', 'JPY', 'CNY']
Tuples
( )
.[0]
the second item has index [1]
etc.len()
method.For Example:
# Tuple of temperature readings
tempCel = (12.5, 22, 34.5, 21, 11, 33)
print(tempCel)
OUTPUT
(12.5, 22, 34.5, 21, 11, 33)
# Tuple of tuples: stockPrices as on Jan-2023
stockPrices = (('AAPL', 135.73), ('TSLA', 130.92), ('MSFT', 238.65))
print(stockPrices)
OUTPUT
(('AAPL', 135.73), ('TSLA', 130.92), ('MSFT', 238.65))
Tuples may be constructed in a number of ways:
( )
a,
or (a,)
a, b, c
or (a, b, c)
tuple()
or tuple(iterable)
# Creating singleton tuple
tupleOne = 23, # or can also be done (23,)
print(tupleOne)
OUTPUT
(23,)
# Creating tuple using constructor method
tupleTwo = tuple("WORKZAM") # Creating tuple from string argument
tupleThree = tuple((8, 1, 2, 8)) # Creating tuple from tuple argument
tupleFour = tuple(range(11, 21)) # Creating tuple from range() argument
tupleFive = tuple([1, 3, 5, 7]) # Creating tuple from list argument
print(tupleTwo)
print(tupleThree)
print(tupleFour)
print(tupleFive)
OUTPUT
('W', 'O', 'R', 'K', 'Z', 'A', 'M') (8, 1, 2, 8) (11, 12, 13, 14, 15, 16, 17, 18, 19, 20) (1, 3, 5, 7)
Working with Tuples:
# Creating tuples without any brackets
numTuple = 12, 34, 56, 78, 90
print(numTuple)
OUTPUT
(12, 34, 56, 78, 90)
# Length of a Tuple using len() method
numTuple = (12, 34, 56, 78, 90)
len(numTuple)
OUTPUT
5
# Accessing individual elements of a Tuple
numTuple = (12, 34, 56, 78, 90)
numTuple[4]
OUTPUT
90
# IndexError: tuple index out of range
numTuple = (12, 34, 56, 78, 90)
numTuple[5] # index 5 doesnot exists
OUTPUT
IndexError: tuple index out of range
# Tuples are immutable
numTuple = (12, 34, 56, 78, 90)
numTuple[0] = 24
OUTPUT
TypeError: 'tuple' object does not support item assignment
Tuple indexing & slicing
[0]
, the second item has index [1]
etc. +
to concatenate tuples, just like we did for strings. *
for a duplication method similar to stringsConside the below tuple example for understanding:
# tuple example
exampleTuple = ('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
exampleTuple[0] # access first element by indexing
OUTPUT
'S'
# Reverse Indexing of tuple element
exampleTuple = ('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
exampleTuple[-1] # access last element by reverse indexing
OUTPUT
'M'
Indexing is a means of fetching a single value from the tuple, slicing is a means of accessing multiple values in sub-tuples. It uses a colon :
to indicate the start point (inclusive) and end point (non-inclusive) of the sub-array.
For example, to get the first five elements of the tuple, we can write:
# Slicing tuple Example
exampleTuple = ('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
exampleTuple[0:5] # same as exampleTuple[:5]
OUTPUT
('S', 'K', 'I', 'L', 'L')
Similarly, if we leave out the last index, it defaults to the length of the tuple. Thus, the last three elements can be accessed as follows:
# Access last three elements in tuple
exampleTuple = ('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
exampleTuple[-3:] # same as exampleTuple[-3:len(exampleTuple)]
OUTPUT
('Z', 'A', 'M')
Finally, it is possible to specify a third integer that represents the step size ; for example, to select every second element of the tuple, we can write:
# specify step size in tuple slicing
exampleTuple = ('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
exampleTuple[::2] # same as exampleTuple[0:len(exampleTuple):2]
OUTPUT
('S', 'I', 'L', 'A')
Reversing the tuple :
# Reversing the tuple
exampleTuple = ('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
exampleTuple[::-1]
OUTPUT
('M', 'A', 'Z', 'L', 'L', 'I', 'K', 'S')
Changing elements of a Tuple using Indexing & Slicing :
exampleTuple = ('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
exampleTuple[:5] = 'WORK'
print(exampleTuple)
OUTPUT
TypeError: 'tuple' object does not support item assignment
Use + to concatenate tuples :
# use '+' to concatenate tuples
exampleTuple = ('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
exampleTuple + (1, 2, 3)
OUTPUT
('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M', 1, 2, 3)
Use * to duplicate tuples :
# Make the tuple double
exampleTuple = ('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
exampleTuple * 2
OUTPUT
('S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M', 'S', 'K', 'I', 'L', 'L', 'Z', 'A', 'M')
Tuple Methods
Tuples have built-in methods, but not as many as lists do. Here are index()
and count()
.
index()
method finds the first occurrence of the specified value. This method raises an exception, if the value is not found.
# index() returns index of a specified value
colorCode = ('#ff4040', '#008080', '#fdbe02', '#c5aac8')
selectColor = colorCode.index('#fdbe02')
print(selectColor)
OUTPUT
2
count()
method returns the number of times a specified value appears in the tuple.
# count() returns number of times a value appears
ranNum = (12, 34, 65, 12, 67, 88, 12, 36)
selectNum = ranNum.count(12)
print(selectNum)
OUTPUT
3
Why another built-in type ?
Data integrity / immutability:
To be honest, tuples are not used as often as lists in programming, but are used when immutability is necessary.
If in your program you are passing around an object and need to make sure it does not get changed, then a tuple becomes your solution.
It provides a convenient source of data integrity.
Handle multiple return values:
A particularly common case is in a functions that have multiple return values.
For example, the as_integer_ratio()
method of floating-point objects returns a numerator and a denominator; this dual return value comes in the form of a tuple:
floatNum = 0.125
rtnVal = floatNum.as_integer_ratio()
print(rtnVal) # print a tuple o/p
OUTPUT
(1, 8)
These multiple return values can be individually assigned as follows:
floatNum = 0.125
numerator, denominator = floatNum.as_integer_ratio()
print(f'Numerator is {numerator} and Denominator is {denominator}')
OUTPUT
Numerator is 1 and Denominator is 8
Range
range()
function returns a sequence of numbers, starting from 0 by default, and increments by 1 (by default), and stops before a specified number.
Ranges implement all of the common sequence operations except concatenation and repetition (due to the fact that range objects can only represent sequences that follow a strict pattern and repetition and concatenation will usually violate that pattern).
Syntax: range(start, stop[, step])
The advantage of the range
type over a regular list
or tuple
is that a range
object will always take the same (small) amount of memory, no matter the size of the range it represents (as it only stores the start
, stop
and step
values, calculating individual items and subranges as needed).
# range() type example
num = range(6)
for n in num:
print(n, end=' ')
OUTPUT
0 1 2 3 4 5
# range() type with two arguments
num = range(1,6)
for n in num:
print(n, end=' ')
OUTPUT
1 2 3 4 5
# range() type with three arguments
num = range(2,10,2)
for n in num:
print(n, end=' ')
OUTPUT
2 4 6 8
Dictionaries
any data type
.key:value
pairs, and can be referred to by using the key name.len()
method.For Examples:
# Dictionary Example
numbers = {'Keyone':1, 'Keytwo':2, 'Keythree':3}
print(numbers)
OUTPUT
{'Keyone': 1, 'Keytwo': 2, 'Keythree': 3}
# Length of a Dictionary (Year-Make-Model of vehicle)
vehicle = {
"year": 2021,
"make": 'Mahindra',
"model": "XUV700"
}
len(vehicle)
OUTPUT
3
# Values can be of any dataType in a Dictionary
students = {
"fName": "Jasmine",
"lName": "Dsouza",
"gender": "Female", # value is string DataType
"age": 20, # value is integer DataType
"isGraduate": True, # value is boolean DataType
"cgpa": 8.4, # value is float DataType
"favSub": ["Physics","Computers","History"] # value is list DataType
}
print(students)
OUTPUT
{'fName': 'Jasmine', 'lName': 'Dsouza', 'gender': 'Female', 'age': 20, 'isGraduate': True, 'cgpa': 8.4, 'favSub': ['Physics', 'Computers', 'History']}
Dictionaries can be created by several means:
{'ravi': 4098, 'abdul': 4127}
or {4098: 'ravi', 4127: 'abdul'}
{}
, {x: x ** 2 for x in range(10)}
dict()
, dict([('BTC', 100), ('ETH', 200)])
, dict(BTC=100, ETH=200)
# Creating dictionary various ways
dictOne = {'apples':123, 'oranges':456} # using key:value pairs
dictTwo = {x: x ** 2 for x in range(6)} # dict comprehension
dictThree = dict({'Sat':23, 'Sun':22}) # dict type constructor
dictFour = dict([('BTC', 1), ('ETH', 2)]) # dict type constructor
dictFive = dict(AAPL=137.87, MSFT=240.22) # dict type constructor
print(dictOne)
print(dictTwo)
print(dictThree)
print(dictFour)
print(dictFive)
OUTPUT
{'apples': 123, 'oranges': 456} {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25} {'Sat': 23, 'Sun': 22} {'BTC': 1, 'ETH': 2} {'AAPL': 137.87, 'MSFT': 240.22}
Working with Dictionary:
# Accessing the items of a dictionary
students = {
"fName": "Jasmine",
"lName": "Dsouza",
"gender": "Female",
"age": 20,
"isGraduate": True,
"cgpa": 8.4,
"favSub": ["Physics","Computers","History"]
}
firstname = students['fName']
favSubject = students['favSub'][0]
print(f'{firstname} loves {favSubject}!')
OUTPUT
Jasmine loves Physics!
get()
method is also used to access the items of a dictionary.
# get() method to access the items of a Dictionary
vehicle = {
"year": 2021,
"make": 'Mahindra',
"model": "XUV700"
}
vehicle.get('make')
OUTPUT
'Mahindra'
Dictionary view objects :
dict.keys()
, dict.values()
and dict.items()
are view objects.keys()
method will return a list of all the keys in the dictionary. The list of the keys is a view of the dictionary, meaning that any changes done to the dictionary will be reflected in the keys list.values()
method will return a list of all the values in the dictionary. The list of the values is a view of the dictionary, meaning that any changes done to the dictionary will be reflected in the values list.items()
method will return each item in a dictionary, as tuples in a list. The returned list is a view of the items of the dictionary, meaning that any changes done to the dictionary will be reflected in the items list.
# Dictionary view objects dict.keys(), dict.values(), dict.items()
playersBio = {
'name': "Leo Messi",
'team': "Paris Saint-Germain",
'position': "Forward",
'height': 170,
'weight': 159,
'birthdate': "24/6/1987",
'age': 35,
'nationality': "Argentina",
'careerHistory': ["Barcelona","PSG","Argentina"],
'isRetired': False
}
getKeys = playersBio.keys()
getValues = playersBio.values()
getItems = playersBio.items()
print(getKeys)
print('\n')
print(getValues)
print('\n')
print(getItems)
OUTPUT
dict_keys(['name', 'team', 'position', 'height', 'weight', 'birthdate', 'age', 'nationality', 'careerHistory', 'isRetired']) dict_values(['Leo Messi', 'Paris Saint-Germain', 'Forward', 170, 159, '24/6/1987', 35, 'Argentina', ['Barcelona', 'PSG', 'Argentina'], False]) dict_items([('name', 'Leo Messi'), ('team', 'Paris Saint-Germain'), ('position', 'Forward'), ('height', 170), ('weight', 159), ('birthdate', '24/6/1987'), ('age', 35), ('nationality', 'Argentina'), ('careerHistory', ['Barcelona', 'PSG', 'Argentina']), ('isRetired', False)])
in
Keyword : is used to determine if a specified key is present in a dictionary.
# Check if a key exists 'in' the dictionary
users = {
"fname": 'Elon',
"lname": 'Musk',
"email": 'elon.musk@example.com'
}
isEmailExists = 'email' in users
print(isEmailExists)
OUTPUT
True
# Change the value of a specific item in a dictionary
users = {
"fname": 'Elon',
"lname": 'Musk',
"email": 'elon.musk@.com'
}
users['email'] = 'elon.musk@example.com'
print(users)
OUTPUT
{'fname': 'Elon', 'lname': 'Musk', 'email': 'elon.musk@example.com'}
# Adding new item (key:value) in a dictionary
users = {
"fname": 'Elon',
"lname": 'Musk',
"email": 'elon.musk@.com'
}
users['country'] = 'USA'
print(users)
OUTPUT
{'fname': 'Elon', 'lname': 'Musk', 'email': 'elon.musk@.com', 'country': 'USA'}
del
keyword removes the item with the specified key name.
# Deleting an item (key:value) in a dictionary
users = {
"fname": 'Elon',
"lname": 'Musk',
"email": 'elon.musk@example.com',
"country": 'USA'
}
del users['email']
print(users)
OUTPUT
{'fname': 'Elon', 'lname': 'Musk', 'country': 'USA'}
Nested Dictionaries
Python data structures support nesting. This means we can have data structures within data structures.
For example: A dictionary containing dictionary.
# Nested Dictionary : Example 1
team = {
"player1": {
"name": 'Leo Messi',
"position": 'Forward'
},
"player2": {
"name": 'Andres Iniesta',
"position": 'Midfield'
},
"player3": {
"name": 'Xavi Hernandez',
"position": 'Midfield'
}
}
team['player1']['name']
OUTPUT
'Leo Messi'
# Nested Dictionary : Example 2
player1 = {
"name": 'Leo Messi',
"position": 'Forward'
},
player2 = {
"name": 'Andres Iniesta',
"position": 'Midfield'
},
player3 = {
"name": 'Xavi Hernandez',
"position": 'Midfield'
}
team = {
"player1" : player1,
"player2" : player2,
"player3" : player3
}
team['player1']
OUTPUT
({'name': 'Leo Messi', 'position': 'Forward'},)
Dictionary Methods
copy()
method returns a copy of the specified dictionary.
# copy() returns a shallow copy of dictionary
student = {
"fName": "Jasmine",
"lName": "Dsouza",
"gender": "Female",
"age": 20,
"isGraduate": True,
"cgpa": 8.4,
"favSub": ["Physics","Computers","History"]
}
newStudent = student.copy()
print(newStudent)
OUTPUT
{'fName': 'Jasmine', 'lName': 'Dsouza', 'gender': 'Female', 'age': 20, 'isGraduate': True, 'cgpa': 8.4, 'favSub': ['Physics', 'Computers', 'History']}
fromkeys()
method returns a dictionary with the specified keys and value.
# fromkeys() returns dictionary with keys/value specified
allKeys = ('name','gender','age','country')
allValues = ('Rahul','Male',25,'India')
dictOne = dict.fromkeys(allKeys, allValues)
dictTwo = dict.fromkeys(allKeys) # default all values to 'None'
dictThree = dict.fromkeys(allKeys, 'xyz') # default all values to 'xyz'
print(dictOne)
print(dictTwo)
print(dictThree)
OUTPUT
{'name': ('Rahul', 'Male', 25, 'India'), 'gender': ('Rahul', 'Male', 25, 'India'), 'age': ('Rahul', 'Male', 25, 'India'), 'country': ('Rahul', 'Male', 25, 'India')} {'name': None, 'gender': None, 'age': None, 'country': None} {'name': 'xyz', 'gender': 'xyz', 'age': 'xyz', 'country': 'xyz'}
get()
method returns the value of the item with the specified key.
# get() returns the value of the key specified
vehicle = {
"year": 2021,
"make": 'Mahindra',
"model": "XUV700"
}
vehicle.get('make')
OUTPUT
'Mahindra'
pop()
method removes the specified item from the dictionary. The value of the removed item is the return value of the pop()
method.
# pop() removes the item from the dictionary
vehicle = {
"year": 2021,
"make": 'Mahindra',
"model": "XUV700"
}
vehicle.pop('year')
print(vehicle)
OUTPUT
{'make': 'Mahindra', 'model': 'XUV700'}
popitem()
method removes the item that was last inserted into the dictionary.
# popitem() removes the last inserted item
vehicle = {
"year": 2021,
"make": 'Mahindra',
"model": "XUV700"
}
vehicle.popitem()
print(vehicle)
OUTPUT
{'year': 2021, 'make': 'Mahindra'}
clear()
method removes all items from the dictionary.
# clear() removes the all items from the dictionary
vehicle = {
"year": 2021,
"make": 'Mahindra',
"model": "XUV700"
}
vehicle.clear()
print(vehicle)
OUTPUT
{}
setdefault()
method returns the value of the item with the specified key. If the key does not exist, insert the key, with the specified value.
# setdefault() returns value of the item
vehicle = {
"year": 2021,
"make": 'Mahindra',
"model": "XUV700"
}
vehicle.setdefault('country', 'India')
print(vehicle)
OUTPUT
{'year': 2021, 'make': 'Mahindra', 'model': 'XUV700', 'country': 'India'}
update()
method inserts the specified items to the dictionary. The specified items can be a dictionary, or an iterable object with key value pairs.
# update() inserts the specified item
vehicle = {
"year": 2021,
"make": 'Mahindra',
"model": "XUV700"
}
vehicle.update({"color": "Black"})
print(vehicle)
OUTPUT
{'year': 2021, 'make': 'Mahindra', 'model': 'XUV700', 'color': 'Black'}
# update() inserts items from iterable
cryptoCurrency = {}
cryptoCurrency.update([('BTC', 1), ('ETH', 2), ('ADA', 3), ('SOL', 4)])
print(cryptoCurrency)
OUTPUT
{'BTC': 1, 'ETH': 2, 'ADA': 3, 'SOL': 4}
Sets
{}
and have items with comma-separated.len()
method.
# Set Examples
primes = {2, 3, 5, 7}
odds = {1, 3, 5, 7, 9}
# set can have values of different datatypes
mixedSet = {"Skillzam", 12, True, 33.33}
# Duplicate set values will be ignored
# 'apple' will be ignored
fruits = {'apple', 'bananas', 'oranges', 'apple'}
print(fruits)
OUTPUT
{'apple', 'oranges', 'bananas'}
# len() will find the number of items in a set
fruits = {'apple', 'bananas', 'oranges'}
len(fruits)
OUTPUT
3
Sets can be created by several means:
{'male', 'female'}
{c for c in 'abracadabra' if c not in 'abc'}
set()
, set('workzam')
, set(['red', 'green', 'blue'])
# Creating sets various ways
setOne = {'apples', 'oranges', 'kiwi'} # using curly braces
setTwo = {c for c in 'abracadabra' if c not in 'abc'} # set comprehension
setThree = set(('Mon', 'Tue', 'Wed', 'Thu', 'Fri')) # set type constructor
setFour = set([('BTC', 1), ('ETH', 2), ('ADA', 3)]) # set type constructor
setFive = set("workzam") # set type constructor
print(setOne)
print(setTwo)
print(setThree)
print(setFour)
print(setFive)
OUTPUT
{'apples', 'kiwi', 'oranges'} {'d', 'r'} {'Thu', 'Tue', 'Fri', 'Wed', 'Mon'} {('ADA', 3), ('ETH', 2), ('BTC', 1)} {'w', 'z', 'o', 'a', 'm', 'k', 'r'}
Working with Sets
for
loop.
# Accessing each item in the set
cryptoCurrency = set([('BTC', 1), ('ETH', 2), ('ADA', 3), ('SOL', 4)])
print("Set is defined as ", cryptoCurrency)
for crypto in cryptoCurrency:
print(crypto)
OUTPUT
Set is defined as {('ADA', 3), ('SOL', 4), ('ETH', 2), ('BTC', 1)} ('ADA', 3) ('SOL', 4) ('ETH', 2) ('BTC', 1)
in
keyword.
# Check if a specified item is present in a set
workingDays = {'Mon', 'Tue', 'Wed', 'Thu', 'Fri'}
isItemExists = 'Sun' in workingDays
print('Sunday exits in the set? ', isItemExists)
OUTPUT
Sunday exits in the set? False
del
keyword will delete the set completely.
# del will delete the set completely
fruits = {'apples', 'oranges', 'kiwi'}
del fruits
print(fruits)
OUTPUT
NameError: name 'fruits' is not defined
Mathematics of sets
Sets can be used to peform Mathematical operations like the union, intersection, difference, symmetric difference, and others.
Python's sets have all of these operations built-in, via methods or operators.
For each, we'll show the two equivalent methods:
# union: items appearing in either
primes = {2, 3, 5, 7}
odds = {1, 3, 5, 7, 9}
primes | odds # with an operator
primes.union(odds) # equivalently with a method
OUTPUT
{1, 2, 3, 5, 7, 9}
# intersection: items appearing in both
primes = {2, 3, 5, 7}
odds = {1, 3, 5, 7, 9}
primes & odds # with an operator
primes.intersection(odds) # equivalently with a method
OUTPUT
{3, 5, 7}
# difference: items in primes but not in odds
primes = {2, 3, 5, 7}
odds = {1, 3, 5, 7, 9}
primes - odds # with an operator
primes.difference(odds) # equivalently with a method
OUTPUT
{2}
# symmetric difference: items appearing in only one set
primes = {2, 3, 5, 7}
odds = {1, 3, 5, 7, 9}
primes ^ odds # with an operator
primes.symmetric_difference(odds) # equivalently with a method
OUTPUT
{1, 2, 9}
Set Methods
add()
method adds an element to the set. If the element already exists, the add()
method does not add the element.
# add() will add new item to the set
positions = {'forward', 'midfield', 'defender'}
positions.add('goalkeeper')
print(positions)
OUTPUT
{'midfield', 'defender', 'goalkeeper', 'forward'}
clear()
method removes all elements in a set.
# clear() removes all elements in a set
positions = {'forward', 'midfield', 'defender', 'goalkeeper'}
positions.clear()
print(positions)
OUTPUT
set()
copy()
method copies the set.
# copy() method copies the set.
ranNum = {12, 65, 11, 56, 9}
newNum = ranNum.copy()
print(newNum)
OUTPUT
{65, 56, 9, 11, 12}
remove()
method removes the specified element from the set. This method will raise an error if the specified item does not exist.
# remove() will remove specified element from set
workingDays = {'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sun'}
workingDays.remove('Sun')
print(workingDays)
OUTPUT
{'Wed', 'Mon', 'Thu', 'Tue', 'Fri'}
discard()
method removes the specified element from the set. This method will NOT raise an error, if the specified item does not exist.
# discard() will remove specified element from set
workingDays = {'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sun'}
workingDays.discard('Sun')
print(workingDays)
OUTPUT
{'Wed', 'Mon', 'Thu', 'Tue', 'Fri'}
pop()
method removes a random item from the set. This method returns the removed item.
# pop() will remove random item from the set
userDetails = {'Jasmine', 'Dsouza', 'Female', 20, True, 8.4, 'Physics'}
userDetails.pop()
print(userDetails)
OUTPUT
{True, 'Jasmine', 20, 8.4, 'Physics', 'Female'}
update()
method updates the current set, by adding items from another set (or any other iterable). If an item is present in both sets, only one appearance of this item will be present in the updated set.
# update() will update the current set, by adding items from another set
setOne = {'Python', 'C++', 'Java'}
setTwo = {'Python', 'JavaScript', 'SQL'}
setOne.update(setTwo)
print(setOne)
OUTPUT
{'C++', 'JavaScript', 'Python', 'SQL', 'Java'}
issubset()
method returns True if all items in the set exists in the specified set, otherwise it retuns False.
# issubset() returns True if all items in set exists in specified set
primes = {3, 5, 7}
odds = {3, 5, 7, 9}
primes.issubset(odds)
OUTPUT
True
issuperset()
method returns True if all items in the specified set exists in the original set, otherwise it retuns False.
# issuperset() returns True if all items in specified set exists in original set
primes = {3, 5, 7}
odds = {3, 5, 7, 9}
odds.issuperset(primes)
OUTPUT
True
frozensets
frozenset() function returns an immutable / unchangeable frozenset object (which is like a set object, only unchangeable).
Return a new set or frozenset object whose elements are taken from iterable and are unique (does not allow duplicate elements).
frozensets can be created using type constructor: frozenset()
, frozenset('foobar')
, frozenset(['a', 'b', 'foo'])
You cannot access items in a frozenset by referring to an index or a key.
You can loop through the frozenset items using a for
loop, or ask if a specified value is present in a set, by using the in
keyword.
# Creating frozenset() using iterables
frozensetOne = frozenset({'Kiwi','Figs','Papaya'}) # using Set
frozensetTwo = frozenset(['Carrot','Beet','Onion']) # using List
frozensetThree = frozenset("WORKZAM") # using String
frozensetFour = frozenset((12, 34, 67, 99, 45, 51)) # using Tuples
frozensetFive = frozenset({'BTC':1,'ETH':2,'ADA':3}) # using Dictionary
frozensetSix = frozenset(range(10)) # using Range
print(frozensetOne)
print(frozensetTwo)
print(frozensetThree)
print(frozensetFour)
print(frozensetFive)
print(frozensetSix)
OUTPUT
frozenset({'Figs', 'Kiwi', 'Papaya'}) frozenset({'Onion', 'Beet', 'Carrot'}) frozenset({'O', 'K', 'Z', 'M', 'R', 'A', 'W'}) frozenset({34, 99, 67, 12, 45, 51}) frozenset({'ETH', 'ADA', 'BTC'}) frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
# Loop through the frozenset using 'for'
colors = frozenset({"red", "green", "blue"})
for color in colors:
print(color)
OUTPUT
red blue green
# Check if an element exists 'in' the frozenset
colors = frozenset({"red", "green", "blue"})
isColorExists = 'red' in colors
print(isColorExists)
OUTPUT
True
Control Flow in Python
- [1]. Decision Making statements (
if
,elif
,else
) - [2]. Loop statements (
for...in
,while
) - [3]. Jump statements (
break
,continue
,pass
)
Decision making statements
if-else
statements, allow the programmer to execute certain pieces of code depending on some Boolean condition.- [1].
if
statement - [2].
elif
statement - [3].
else
statement
if
and else
often used in other languages; its more unique keyword is elif
, a contraction of else if. In these conditional clauses, elif
and else
blocks are optional; additionally, you can optinally include as few or as many elif
statements as you would like.Simple if
statement :
if
statement is the most simple decision-making statement.if
keyword.True
or False
:
after the if
condition and whitespace in the next-line to denote blocks of code.Example of Simple if
statement:
# Simple 'if' statement
num1 = 24
num2 = 12
if num1 > num2: # if condition is True, hence "if" block will be executed
print(f'num1({num1}) is greater than num2({num2})')
if num2 > num1: # if condition is False, hence "if" block will NOT be executed
print(f'num2({num2}) is greater than num1({num1})')
OUTPUT
num1(24) is greater than num2(12)
# IndentationError: expected an indented block
num1 = 15
num2 = 10
if num1 >= num2:
print(f'num1({num1}) is greater than num2({num2})') # Error, as no whitespace is left to denote block of code
OUTPUT
IndentationError: expected an indented block
if...else
statement :
if
statement alone tells us that if a condition is True
it will execute a block of statements and if the condition is False it won't.False
. Here comes the else
statement.else
statement with if
statement to execute a block of code when the condition is False
.
# 'if...else' statement
num1 = 36
num2 = 48
if num1 > num2: # if condition is False, hence "if" block will NOT be executed
print(f'num1({num1}) is greater than num2({num2})')
else: # else block will be executed
print(f'num1({num1}) is lesser than num2({num2})')
OUTPUT
num1(36) is lesser than num2(48)
Nested if
statement :
if
is an if
statement that is the target of another if
or else
.if
statements mean an if
statement inside an if
statement.if
statements within if
statements. i.e, we can place an if
statement inside another if
statement.
# Nested "if/else" statement
ranNum = 28
if (ranNum == 28 or ranNum <= 30): # if condition is True, hence "if" block will be executed
if ranNum < 30: # if condition is True, hence nested "if" block will be executed
print('ranNum is smaller than 30')
if ranNum < 15: # if condition is False, hence nested "if" block will NOT be executed
print('ranNum is smaller than 15')
else: # never executes else block
print('ranNum is larger than 30')
OUTPUT
ranNum is smaller than 30
if-elif-else
ladder statement :
if
statements are executed from the top down. if
is True
, the statement associated with that if
is executed, and the rest of the ladder is bypassed. True
, then the final else
statement will be executed.
# if-elif-else ladder statement
givenNum = 100
if givenNum == 25: # if condition is False, hence "if" block will NOT be executed
print('givenNum is 25')
elif givenNum == 50: # if condition is False, hence "elif" block will NOT be executed
print('givenNum is 50')
elif givenNum == 75: # if condition is False, hence "elif" block will NOT be executed
print('givenNum is 75')
elif givenNum == 100: # if condition is True, hence "elif" block will be executed
print('givenNum is 100')
else: # never executes else block
print('givenNum is INVALID')
OUTPUT
givenNum is 100
Shorthand if
statement :
if
statement.
# Shorthand "if" statement
weightOne = 225
weightTwo = 125
if weightOne > weightTwo: print("weightOne is heavier")
OUTPUT
weightOne is heavier
Shorthand if...else
statement :
if
, and one for else
, you can put it all on the same line.
# Shorthand "if...else" statement
num1 = 144
num2 = 169
print("num1 is largest") if num1 > num2 else print("=") if num1 == num2 else print("num2 is largest")
OUTPUT
num2 is largest
Loops in Python
- In python, we have two main tools to use for looping
- [1].
for
Loops - [2].
while
Loops
else in loop
as a nobreak statement
: that is, the else
block is executed only if the loop ends naturally, without encountering a break
statement.for
Loop
for
loop is used for sequential traversal i.e. it is used for iterating over an iterable like string, tuple, list, set, range(), forzenset() or dictionary.for
loop, i.e., for (i=0; i<n; i++)
. In Python, for
loops only implements the collection-based iteration.for
loops are executed once for each item in an iterable. for
loop: we specify the variable we want to use, the sequence we want to loop over, and use the in
operator to link them together in an intuitive and readable way.in
keyword, can be any Python iterator. An iterator can be thought of as a generalized sequence.for
loop does not require an indexing variable to set beforehand.else
keyword in a for
loop specifies a block of code to be executed when the loop is finished.else
block will NOT be executed if the for
loop is stopped by a break
statement.for
loop is a for
loop inside a for
loop. The "inner loop" will be executed one time for each iteration of the "outer loop".
# Using "for" loop to iterate list object
primes = [2, 3, 5, 7, 11, 13]
for prime in primes:
print(prime, end=" ") # print all on same line
else:
print("\nList finished!")
OUTPUT
2 3 5 7 11 13 List finished!
# Nested "for" loops
colors = ("red", "green")
fruits = ["apples", "grapes"]
for color in colors:
for fruit in fruits:
print(f"{fruit} are {color}.")
OUTPUT
apples are red. grapes are red. apples are green. grapes are green.
while
Loop
while
loop is used to execute a block of statements repeatedly until a given condition is satisfied.False
, the line immediately after the loop in the program is executed.while
loop falls under the category of indefinite iteration. Indefinite iteration means that the number of times the loop is executed isn't specified explicitly in advance.while
loop is executed, expression is first evaluated in a Boolean context and if it is True
, the loop body is executed. Then the expression is checked again, if it is still True
then the body is executed again and this continues until the expression becomes False
.else
statement we can run a block of code once when the condition no longer is True
else
block will NOT be executed if the while
loop is stopped by a break
statement.while
loop is a while
loop inside a while
loop.
# Using "while" loop to print numbers less than 10
i = 0
while (i < 10):
print(i, end=' ')
i+=1 # remember to increment i, or else loop will continue forever
else:
print("\n'i' is no longer less than 10")
OUTPUT
0 1 2 3 4 5 6 7 8 9 'i' is no longer less than 10
# Nested "while" loop
i=1
while i<=6:
j=1
while j<=i:
print(j,end=" ")
j+=1
print()
i+=1
OUTPUT
1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 1 2 3 4 5 6
# Using nested "while" loop to display multiplication table
i = 1
while i <= 10:
j = 1
while j <= 10:
print(f"{(i*j) : 4.0f}", end=" ")
j += 1
i += 1
print("")
OUTPUT
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100
Jump statements : break, continue, pass
break
statement breaks-out of the loop entirely.
With the break statement we can stop the
for
loop before it has looped through all the items.
With the break statement we can stop the
while
loop even if the condition is True
.
continue
statement skips the remainder of the current loop, and goes to the next iteration.
With the
continue
statement we can stop the current iteration of the for
or while
loop, and continue with the next.
pass
is a null statement. The interpreter does not ignore a pass statement, but nothing happens and the statement results into no operation.
The pass statement is useful when you don't write the implementation of a function but you want to implement it in the future.
Example of using break
statement for a less trivial task. This loop will fill a list with all Fibonacci numbers up to a certain value:
# "break" statement for printing Fibonacci numbers
a, b = 0, 1
maxNum = 100
listFibo = []
while True:
listFibo.append(a)
(a, b) = (b, a + b)
if a > maxNum:
break
print(listFibo)
OUTPUT
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Example of using continue
to print a string of odd numbers. In this case, the result could be accomplished just as well with an if...else
statement, but sometimes the continue
statement can be a more convenient way to express the idea you have in mind:
# "continue" statement for printing ODD numbers
for num in range(20):
# if the remainder of num / 2 is 0, skip the rest of the loop
if num % 2 == 0:
continue
print(num, end=' ')
OUTPUT
1 3 5 7 9 11 13 15 17 19
Example of using pass
to reserve for future use.
# "pass" statement to reserve for future use
listRange = list(range(2,10,2)) # [ 2, 4, 6, 8]
for evenNum in listRange:
if evenNum == 6:
pass # reserve for future use
print(evenNum, end=' ')
OUTPUT
2 4 6 8
Functions in Python
function
is a block of organized, reusable code that is used to perform a single, related action. Functions provide better modularity for your application and a high degree of code reusing.function
.function
will allow you to call the same block of code without having to write it multiple times. This in turn will allow you to create more complex Python scripts.Here we'll cover two ways of creating functions:
def
statement, useful for any type of function, andlambda
statement, useful for creating short anonymous functions.Function definition & invoking
def
introduces a function definition.function
name and the parenthesized list of formal parameters. function
start at the next line, and must be indented.function
body can optionally be a string literal; this string literal is the function's documentation string, or docstring.
# Using "def" for functions
# function definition or declaration
def createFullName():
'''The function createFullName() will create
fullname using fname and lname variable.'''
fname = "Guido"
lname = "van Rossum"
fullname = fname + " " + lname
print(fullname)
# function invoking / calling
createFullName()
OUTPUT
Guido van Rossum
# Accessing the docstring using __doc__ method
def createFullName():
'''The function createFullName() will create
fullname using fname and lname variable.'''
fname = "Guido"
lname = "van Rossum"
fullname = fname + " " + lname
print(fullname)
# Accessing Docstrings
print(createFullName.__doc__)
OUTPUT
The function createFullName() will create fullname using fname and lname variable.
Function Arguments & Parameters
function
name, inside the parentheses. You can add as many arguments/parameters as you want, just separate them with a comma.return
statementWhat is the difference between return
and print
?
The return
keyword allows you to actually save the result of the output of a function as a variable.
The print()
function simply displays the output to you, but doesn't save it for future use. print()
doesn't return any value, as it returns None
# function Parameters & arguments
def createFullName(fname, lname): # 2 Parameters used in function declaration
'''The function createFullName() will create
fullname using fname and lname variable.'''
fullname = fname + " " + lname
return fullname # function return a value
firstName = "Guido"
lastName = "van Rossum"
# function invoking / calling
createFullName(firstName, lastName) # 2 Arguments used in function invoking
OUTPUT
'Guido van Rossum'
Default parameter value
- [a]. giving only the mandatory argument:
ask_ok('Enter the city name : ')
- [b]. giving one of the optional arguments:
ask_ok('Enter the city name : ', 2)
- [c]. or even giving all arguments:
ask_ok('Enter the city name : ', 2, 'Just asked to enter city name!')
# Default function Parameter values
def playerClub(club = "no one"):
print(f"I play for {club}.")
playerClub("Barcelona")
playerClub() # default parameter is set
playerClub("Al-Nassr")
OUTPUT
I play for Barcelona. I play for no one. I play for Al-Nassr.
# Default function Parameter values
def ask_ok(place, retries=3, reminder='Please try again!'):
while True:
city = input(place)
if city in ('Bengaluru', 'Hyderabad', 'Chennai', 'Kolkata', 'Mumbai', 'Delhi'):
return True
if city in ('Pune', 'Mysore', 'Lucknow', 'Surat', 'Indore', 'Jaipur'):
return False
retries = retries - 1
if retries < 0:
raise ValueError('invalid user response')
print(reminder)
# function invoking using only mandatory argument
ask_ok('Enter the city name : ')
OUTPUT
Enter the city name : Delhi True
Flexible/Arbitrary Arguments : *args
& **kwargs
*args
and **kwargs
to catch all arguments that are passed.args
and kwargs
that are important, but the * characters preceding them.args
and kwargs
are just the variable names often used by convention, short for arguments and keyword arguments.key = value
".
# Arbitrary Arguments *args
def getMonth(*month):
print(f"The sixth month is {month[5]}")
getMonth('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
OUTPUT
The sixth month is Jun
# Arbitrary Keyword Arguments **kwargs
def getMonth(**month):
print(f"The month Jun has the value {month['Jun']}")
getMonth(Jan=1, Feb=2, Mar=3, Apr=4, May=5, Jun=6)
OUTPUT
The month Jun has the value 6
# Arbitrary Arguments *args and Arbitrary Kword Arguments **kwargs
def catch_all(*args, **kwargs):
print("args =", args)
print("kwargs = ", kwargs)
catch_all(11, 12, 23, 343, 45, 45, a=22, b=33, c=44, d=22, e=55)
OUTPUT
args = (11, 12, 23, 343, 45, 45) kwargs = {'a': 22, 'b': 33, 'c': 44, 'd': 22, 'e': 55}
Recursion Function
factorial()
is a function that we have defined to call itself ("recurse"). Suppose we want to find the factorial of 5, then it will goes as below:
0! = 1
1! = 1 x 0! = 1 x 1 = 1
2! = 2 x 1! = 2 x 1 = 2
3! = 3 x 2! = 3 x 2 = 6
4! = 4 x 3! = 4 x 6 = 24
5! = 5 x 4! = 5 x 24 = 120
# Function recursion example
def factorial(num):
if num == 1:
return 1
else:
result = num * factorial(num-1)
return result
randNum = 5
funcRtn = factorial(num)
print(f"The factorial of {randNum} is {funcRtn}")
OUTPUT
The factorial of 5 is 120
lambda
Expressions
lambda
keyword. lambda
function can take any number of arguments, but can only have one expression
.lambda
arguments : expression
# lambda Expressions Example
addNum = lambda num1, num2: num1 + num2
addNum(12, 13)
OUTPUT
25
# Using lambda expression to return a function.
def lambdaRtn(num):
return lambda x: x + num
incrementor = lambdaRtn(100)
incrementor(1)
OUTPUT
101
# Pass a lambda function as an argument
pairs = [('one', 1), ('two', 2), ('three', 3), ('four', 4)]
pairs.sort(key = lambda pair: pair[0]) # argument to sort() method
print(pairs)
OUTPUT
[('four', 4), ('one', 1), ('three', 3), ('two', 2)]
# Pass a lambda function as an argument
nums = [1, 2, 3, 4, 5, 6]
newListOne = list(map(lambda m: m ** 2, nums))
newListTwo = list(filter(lambda n: n % 2 == 0,nums))
print(newListOne)
print(newListTwo)
OUTPUT
[1, 4, 9, 16, 25, 36] [2, 4, 6]
Python Iterators
__iter__()
and __next__()
.iter()
function is used to return an iterator for the object. The iter()
is used to create an object that will iterate one element at a time.StopIteration
statement.iter()
method which is used to get an iterator.range()
is not a list, but is an iterator.Consider the below example of container object list
which is be looped over using a for
statement.
for
statement calls iter()
on the container object.__next__()
which accesses elements in the container one at a time. __next__()
raises a StopIteration
exception which tells the for loop to terminate. __next__()
method using the next()
built-in function; this example shows how it all works.
# Behind the scenes, the 'for' statement calls iter() on container object - list
primes = [2, 3, 5, 7]
for num in primes:
print(num)
OUTPUT
2 3 5 7
Iterating over lists
From the above example of "primes" list, the familiar "for num in primes"
syntax allows us to repeat some operation for each value in the list. The fact that the syntax of the code is so close to its English description for [each] value in [the] list
is just one of the syntactic choices that makes Python such an intuitive language to learn and use.
But the face-value behavior is not what's really happening. When you write something like "for num in primes"
, the Python interpreter checks whether it has an iterator interface, which you can check yourself with the built-in iter()
method:
# iterator object created by iter() method
primes = [2, 3, 5, 7]
iter(primes)
OUTPUT
<list_iterator at 0x25a49513c10>
It is this iterator object that provides the functionality required by the for
loop. The iter
object is a container that gives you access to the next object for as long as it's valid, which can be seen with the built-in method next()
.
What is the purpose of this level of indirection? Well, it turns out this is incredibly useful, because it allows Python to treat things as lists that are not actually lists.
# Using iter() & next() method
primes = [2, 3, 5, 7]
num = iter(primes)
print(next(num))
print(next(num))
print(next(num))
print(next(num))
OUTPUT
2 3 5 7
range() : Indirect iteration
range()
object
# range() method for Indirect iteration
N = 10 ** 12
for i in range(N):
if i >= 10: break
print(i, end=', ')
OUTPUT
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
Useful Iterators : enumerate
, zip
, map
, filter
Here we'll cover some of the more useful iterators in the Python language:
enumerate()
enumerate()
function takes a collection (e.g. list, tuple etc) and returns it as an enumerate object.enumerate()
function adds a counter as the key of the enumerate object.enumerate( iterable, start = 0 )
where, "iterable" must be a sequence, an iterator, or some other object which supports iteration.
__next__()
method of the iterator returned by enumerate()
returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over iterable.
# enumerate() on tuple
perfectNum = ( 6, 28, 496, 8128 )
for i, num in enumerate(perfectNum):
print(i, num)
OUTPUT
0 6 1 28 2 496 3 8128
# enumerate() on list with "start" argument
seasons = ['Spring', 'Summer', 'Fall', 'Winter']
for i, season in enumerate(seasons, start = 1):
print(i, season)
OUTPUT
1 Spring 2 Summer 3 Fall 4 Winter
zip()
zip()
method is used to iterate multiple iterables in parallel (simultaneously), producing tuples with an item from each one.zip()
returns an iterator of tuples, where the i-th
tuple contains the i-th
element from each of the argument iterables.zip()
is that it turns rows into columns, and columns into rows. This is similar to transposing a matrix.zip(iterator1, iterator2,...)
zip()
could have different lengths; sometimes by design, and sometimes because of a bug in the code that prepared these iterables. - [1]. By default,
zip()
stops when the shortest iterable is exhausted. It will ignore the remaining items in the longer iterables, cutting off the result to the length of the shortest iterable. - [2]. Shorter iterables can be padded with a constant value to make all the iterables have the same length. This is done by
itertools.zip_longest()
.
# zip() method on multiple lists
numbers = list(range(1, 4))
shoppingList = ['Tea', 'Milk', 'Honey']
for item in zip(numbers, shoppingList):
print(item)
OUTPUT
(1, 'Tea') (2, 'Milk') (3, 'Honey')
# zip() stops when shortest iterable (tuple) is exhausted
L = (2, 4, 6, 8, 10) # shortest will determine length of zip
C = (1, 2, 3, 4, 5, 6, 7, 8, 9)
R = (3, 6, 9, 12, 15, 18)
for lval, cval, rval in zip(L, C, R):
print((lval, cval, rval))
OUTPUT
(2, 1, 3) (4, 2, 6) (6, 3, 9) (8, 4, 12) (10, 5, 15)
# Transpose rows & columns using zip() method
matrix = [ [11, 12, 13, 14],
[15, 16, 17, 18],
[19, 20, 21, 22] ]
zipList = list(zip(*matrix))
print(zipList)
OUTPUT
[(11, 15, 19), (12, 16, 20), (13, 17, 21), (14, 18, 22)]
# Padding with a default value for shorter iterables
from itertools import zip_longest
numbers = [1, 2, 3, 4, 5]
shoppingList = ['Tea', 'Milk', 'Honey']
newList = list(zip_longest(numbers, shoppingList))
print(newList)
OUTPUT
[(1, 'Tea'), (2, 'Milk'), (3, 'Honey'), (4, None), (5, None)]
map()
map()
method return an iterator that applies function to every item of iterable, yielding the results. map( function, iterable, *iterables )
# Using map(), find square of first 10 numbers
squares = lambda x: x ** 2
for val in map(squares, range(1,11) ):
print(val, end=' ')
OUTPUT
1 4 9 16 25 36 49 64 81 100
# Passing Multiple Iterators to map() method
num1 = list(range(1,6)) # equal to [1,2,3,4,5]
num2 = [10, 20, 30, 40, 50]
incrementor = lambda x , y: x + y
result = map(incrementor, num1, num2 )
#convert the map into a list, for readability:
newList = list(result)
print(newList)
OUTPUT
[11, 22, 33, 44, 55]
# map() can listify the list of strings individually
exampleList = ['skill', 'zam', 'work']
result = list(map(list, exampleList))
print(result)
OUTPUT
[['s', 'k', 'i', 'l', 'l'], ['z', 'a', 'm'], ['w', 'o', 'r', 'k']]
filter()
filter()
method is used to construct an iterator from those elements of iterable for which function returns True
.filter( function, iterable )
None
, the identity function is assumed, that is, all elements of iterable that are False
are removed.
# Using filter(), find single digit even numbers
isEven = lambda x: x % 2 == 0
for num in filter(isEven, range(1, 10)):
print(num, end=' ')
OUTPUT
2 4 6 8
# Using filter(), find the words that do not have vowels
inputWords = ['myths', 'tea', 'milk', 'gym', 'honey', 'spy']
def containsVowels(word):
wordList = list(word)
if 'a' in wordList:
return False
elif 'e' in wordList:
return False
elif 'i' in wordList:
return False
elif 'o' in wordList:
return False
elif 'u' in wordList:
return False
else:
return True
vowelWords = filter(containsVowels, inputWords)
result = list(vowelWords)
print(result)
OUTPUT
['myths', 'gym', 'spy']
Iterators as function arguments
*args
and **kwargs
can be used to pass sequences and dictionaries to functions. It turns out that the *args
syntax works not just with sequences, but with any iterator.
# *args as the argument to print() method
print( *range(10) )
print(*map(lambda x: x ** 2, range(10)))
OUTPUT
0 1 2 3 4 5 6 7 8 9 0 1 4 9 16 25 36 49 64 81
# zip and unzip
# using the zip() method
L1 = (1, 2, 3, 4)
L2 = ('a', 'b', 'c', 'd')
z = zip(L1, L2)
print(*z)
# similar to unzip
z = zip(L1, L2)
new_L1, new_L2 = zip(*z)
print(new_L1, new_L2)
OUTPUT
(1, 'a') (2, 'b') (3, 'c') (4, 'd') (1, 2, 3, 4) ('a', 'b', 'c', 'd')
List Comprehensions
list
building for
loop into a single short, readable line.newlist = [ expression
for
item in
iterable if
condition == True
]
"expression" is the current item in the iteration, but it is also the outcome, which you can manipulate before it ends up like a list item in the new list,
"item" is a variable name,
"iterable" is any iterable Python object (like list, tuple, set, dict, str, range() etc),
"condition" is like a filter that only accepts the items that valuate to
True
''for''
expression: this is valid in Python, and is often a nice way to break-up long list comprehensions for greater readibility.Examples of list comprehension: Create a list of squares.
# Square number list using list comprehension
squares = [x**2 for x in range(10)]
print(squares)
OUTPUT
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# Even number list using list comprehension
evenNum = [item for item in range(1, 10) if (item % 2 == 0)]
print(evenNum)
OUTPUT
[2, 4, 6, 8]
Note how the order of the for
and if
statements is the same in below mentioned both of snippets.
# list comprehension using mulitple "for" Iterations
tupleList = [(x, y)
for x in [1,2,3]
for y in [1,3,4]
if x != y]
print("\nCreating list using 'list comprehension'")
print(tupleList)
# Below code will create the same new-list as above
combs = []
for x in [1,2,3]:
for y in [1,3,4]:
if x != y:
combs.append((x, y))
print("\nCreating list using 'for' loop")
print(combs)
OUTPUT
Creating list using 'list comprehension' [(1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 4)] Creating list using 'for' loop [(1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 4)]
# Using list comprehension :
# Find all the tweet-tags that starts with symbol ‘@’ in a given tweet list.
tweet_list = [
["@elonmusk : Comedy is now legal on @twitter"],
["@BarackObama : No one is born hating another person because of the color of his skin or his background or his religion"],
["@andymilonakis : Congratulations to the Astronauts that left Earth today. Good choice."]
]
tweetTags = [ word
for tweet in tweet_list
for word in ''.join(tweet).split(' ')
if '@' in word ]
print(tweetTags)
OUTPUT
['@elonmusk', '@twitter', '@BarackObama', '@andymilonakis']
# flatten a list using a list comprehension with two 'for'
nestedList = [['A','B','C'], ['D','E','F'], ['G','H','I']]
flatList = [letter
for element in nestedList
for letter in element]
print(flatList)
OUTPUT
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
# Transpose rows & columns using list comprehension
matrix = [ [11, 12, 13, 14],
[15, 16, 17, 18],
[19, 20, 21, 22] ]
transposeMatrix = [[row[i] for row in matrix] for i in range(4)]
print("Transpose rows & columns using list comprehension")
print(transposeMatrix)
# Transpose rows & columns using zip() method
zipList = list(zip(*matrix))
print("\nTranspose rows & columns using zip() method")
print(zipList)
OUTPUT
Transpose rows & columns using list comprehension [[11, 15, 19], [12, 16, 20], [13, 17, 21], [14, 18, 22]] Transpose rows & columns using zip() method [(11, 15, 19), (12, 16, 20), (13, 17, 21), (14, 18, 22)]
Once you understand the dynamics of list comprehensions, it's straightforward to move on to other types of comprehensions. The syntax is largely the same; the only difference is the type of bracket you use.
For example, with curly braces you can create a set with a set
comprehension and add a colon :
to create a dict
comprehension:
# Set & Dictionary comprehensions
# add a curly braces {} to create a set comprehension
squareSet = { n**2 for n in range(10) }
print(type(squareSet), squareSet)
# add a colon (:) to create a dict comprehension
squareDict = { n:n**2 for n in range(10) }
print(type(squareDict), squareDict)
OUTPUT
{0, 1, 64, 4, 36, 9, 16, 49, 81, 25} {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
Generators & Generator Expressions
Generator Expressions
generatorExpressions = ( expression
for
item in
iterable if
condition == True
)
"expression" is the current item in the iteration, but it is also the outcome, which you can manipulate before it ends up like an item in the new generator Expressions.
"item" is a variable name,
"iterable" is any iterable Python object (like list, tuple, set, dict, str, range() etc),
"condition" is like a filter that only accepts the items that valuate to
True
Difference between List comprehensions & Generator Expressions
( )
.Examples of Generator Expressions:
# Generator Expressions
(n ** 2 for n in range(10))
OUTPUT
<generator objectat 0x0000025A4974B9E0>
Notice that printing the generator expression does not print the contents; one way to print the contents of a generator expression is to pass it to the list
constructor:
# Generator Expressions passed to list constructor
genExp = (n ** 2 for n in range(10))
list(genExp)
OUTPUT
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# Generator Expressions is single-use
genExp = (n**2 for n in range(10))
for num in genExp:
print(num, end=' ')
if num > 20: break
print("\nDoing something in between...")
for num in genExp:
print(num, end=' ')
newList = list(genExp)
print("\n\nGenerator Expressions is empty : ", newList)
OUTPUT
0 1 4 9 16 25 Doing something in between... 36 49 64 81 Generator Expressions is empty : []
Generator Functions: Using yield
yield
keyword rather than return.yield
, the function automatically becomes a generator function.next()
method on the generator object or using the generator object in a for...in
loop.StopIteration
is called automatically on further calls.yield vs return
yield
statement is responsible for controlling the flow of the generator function. It pauses the function execution by saving all states and yielded to the caller. Later it resumes execution when a successive function is called. We can use the multiple yield statement in the generator function.return
statement returns a value and terminates the whole function and only one return statement can be used in the function.
# Generator Function using 'yield'
genExp = (n ** 2 for n in range(10))
print(*genExp)
def gen():
for n in range(10):
yield n ** 2
genFunc = gen()
print(*genFunc)
OUTPUT
0 1 4 9 16 25 36 49 64 81 0 1 4 9 16 25 36 49 64 81
# Generator Function to generate prime numbers
def gen_primes(N):
"""Generate primes up to N"""
primes = set()
for n in range(2, N):
if all(n % p > 0 for p in primes):
primes.add(n)
yield n
print(*gen_primes(30))
OUTPUT
2 3 5 7 11 13 17 19 23 29
Object Oriented Programming
object
can be defined as a data field that has unique attributes and behavior.object
. Python is an object oriented programming language. classes
and objects
. The object is related to real-word entities such as book, customer, fruit, etc. data modeling
Structure of OOP
The structure, or building blocks, of object-oriented programming include the following:
Principles of OOP
Object-oriented programming is based on the following principles:
Benefits of OOP
Difference between Procedural & Object Oriented Programming
Parameter | Procedural Programming | Object Oriented Programming |
Definition | This programming language makes use of a step by step approach for breaking down a task into a collection of routines (or subroutines) and variables by following a sequence of instructions. It carries out each step systematically in order so that a computer easily gets to understand what to do. | This programming language uses objects and classes for creating models based on the real-world environment. This model makes it very easy for a user to modify as well as maintain the existing code while new objects get created by inheriting the characteristics of the present ones. |
Security | Procedural Programming does not offer any method of hiding data. Thus, it is less secure when compared to Object Oriented Programming. | Hiding data is possible with Object Oriented Programming due to the abstraction. Thus, it is more secure than the Procedural Programming. |
Method | The main program gets divided into minute parts on the basis of the functions. It then treats them as separate programs for smaller programs individually. | It involves the concept of classes and objects. Hence, it divides the program into minute chunks known as objects. These are actually instances of classes. |
Division of Program | Procedural Programming divides the program into small programs and refers to them as functions. | Object Oriented Programming divides the program into small parts and refers to them as objects. |
Movement of Data | Available data is capable of moving freely within the system from one function to another. | The objects are capable of moving and communicating with each other through the member functions. |
Approach | The Procedural Programming follows a Top-Down approach. | The Object Oriented Programming follows a Bottom-Up approach. |
Importance | This programming model does not give importance to data. It prioritizes the functions along with the sequence of actions that needs to follow. | This programming model gives importance to the data rather than functions or procedures. It is because it works on the basis of the real world. |
Orientation | It is Structure/Procedure oriented. | It is Object Oriented. |
Basis | The main focus in Procedural Programming is on how to do the task, meaning, on the structure or procedure of the program. | The main focus in Object Oriented Programming is on data security. Hence, it only permits objects to access the class entities. |
Type of Division | It divides any large program into small units called functions. | It divides the entire program into small units called objects. |
Inheritance | It does not provide any inheritance. | It achieves inheritance in three modes- protected, private, and public. |
Virtual Classes | There is no concept of virtual classes. | The concept of virtual functions appears at the time of inheritance. |
Overloading | The case of overloading isn’t possible in the case of Procedural Programming. | Overloading is possible in the form of operator overloading and function overloading in the case of Object Oriented Programming. |
Reusability of Code | No feature of reusing codes is present in Procedural Programming. | Object Oriented Programming offers the feature to reuse any existing codes in it by utilizing a feature known as inheritance. |
Most Important Attribute | It prioritizes function over data. | It prioritizes data over function. |
Modes of Access | The Procedural Programming offers no specific accessing mode for accessing functions or attributes in a program. | The Object Oriented Programming offers three accessing modes- protected, private, and public. These, then, serve as a share to access functions of attributes. |
Size of Problems | It is not very suitable for solving any big or complex problems. | It is suitable for solving any big or complex problems. |
Addition of New Function and Data | It is not very easy to add new functions and data in the Procedural Programming. | It is very easy to add new functions and data in the Object Oriented Programming. |
Access to Data | In the Procedural Programming, most of the functions use global data for sharing. They can access freely from one function to another in any given system. | In the Object Oriented Programming, the present data cannot easily move easily from one function to another. One can keep it private or even public. Thus, a user can control the data access. |
Data Sharing | It shares the global data among the functions present in the program. | It shares data among the objects through its member functions. |
Data Hiding | No proper way is available for hiding the data. Thus, the data remains insecure. | It can hide data in three modes- protected, private, and public. It increases the overall data security. |
Basis of World | The Procedural Programming follows an unreal world. | The Object Oriented programming follows the real world. |
Friend Classes or Friend Functions | It doesn’t involve any concept of friend function. | Any class or function is capable of becoming a friend of any other class that contains the keyword
“friend.”
Note – The keyword “friend” only works for C++. |
Examples | Some common examples of Procedural Programming are C, Fortran, VB, Pascal etc | The examples of Object Oriented Programming languages are Python, JavaScript, Java, C++ etc |
Class Definition : Creating class
class
# Class Definition using 'class' keyword
class Customer:
msg = 'New Customer Created'
Creating Class Object
Object
is an instance of a Class. A class is like a blueprint while an instance is a copy of the class with actual values.An object consists of :
Declaring Objects : When an object of a class is created, the class is said to be instantiated. All the instances share the attributes and the behavior of the class. But the values of those attributes, i.e. the state are unique for each object. A single class may have any number of instances.
# Create "class" & "object"
# Class Definition
class Customer:
msg = 'New Customer Created'
# Instantiation of Customer class : Object 'custObj' created
custObj = Customer()
# Attribute references using dot (.)
custObj.msg
OUTPUT
'New Customer Created'
Constructor Function : __init__()
__init__()
which is always executed when the class is being initiated.__init__()
method is similar to constructors in C++ and Java.__init__()
method is called the constructor and is always called when an object is created.Types of constructors :
self
and the rest of the arguments are provided by the programmer.self
Parameter :
self
parameter is a reference to the current instance of the class and is used to access variables that belongs to the class.self
, you can call it whatever you like, but it has to be the first parameter of any function in the classself
this
pointer in C++ and this
reference in Java.
# default Constructor Function __init__() method
class Customer(object):
# default constructor with no arguments
def __init__(self):
self.msg = 'New Customer Created'
custObj = Customer()
custObj.msg
OUTPUT
'New Customer Created'
# Parameterized Constructor Function __init__() method
class Customer(object):
def __init__(self, name, balance=0.0):
# Return a Customer object whose fullname is *name* and starting balance is *balance*.
self.fullname = name
self.balance = balance
custObj = Customer('Rohit Shetty', 24000)
custObj.fullname
OUTPUT
'Rohit Shetty'
Destructors Function : __del__()
__del__()
method is a known as a destructor method in Python. It is called when all references to the object have been deleted i.e when an object is garbage collected.
# Destructors Function __del__() method
class Customer(object):
# Initializing
def __init__(self, name, balance=0.0):
# Return a Customer object whose fullname is *name* and starting balance is *balance*.
self.fullname = name
self.balance = balance
# Deleting (Calling destructor)
def __del__(self):
print('Destructor called, Customer deleted.')
custObj = Customer('Rohit Shetty', 24000)
print(custObj.fullname)
del custObj
OUTPUT
Rohit Shetty Destructor called, Customer deleted.
__str__()
Function
__str__()
function controls what should be returned when the class object is represented as a string.__str__()
function is not set, the string representation of the object is returned.
# string representation of an object without __str__() method
class Customer(object):
# Initializing
def __init__(self, name, balance=0.0):
# Return a Customer object whose fullname is *name* and starting balance is *balance*.
self.fullname = name
self.balance = balance
custObj = Customer('Rohit Shetty', 24000)
print(custObj)
OUTPUT
<__main__.Customer object at 0x0000020934C9E8E0>
# string representation of an object with __str__() method
class Customer(object):
# Initializing
def __init__(self, name, balance=0.0):
# Return a Customer object whose fullname is *name* and starting balance is *balance*.
self.fullname = name
self.balance = balance
# String representation of an object
def __str__(self):
return f"{self.fullname}\'s account balance is Rs.{self.balance}/-"
custObj = Customer('Rohit Shetty', 24000)
print(custObj)
OUTPUT
Rohit Shetty's account balance is Rs.24000/-
Object Methods
# Object Methods
class Customer():
# Initializing
def __init__(self, name, balance=0.0):
'''Return a Customer object whose fullname is *name* and starting balance is *balance*'''
self.fullname = name
self.balance = balance
# String representation of an object
def __str__(self):
return f"{self.fullname}\'s account balance is Rs.{self.balance}/-"
def withdraw(self, amount):
'''Return the balance remaining after withdrawing *amount*'''
if amount > self.balance:
raise RuntimeError('Amount greater than available balance.')
self.balance -= amount
return self.balance
def deposit(self, amount):
'''Return the balance remaining after depositing *amount*'''
self.balance += amount
return self.balance
# Deleting (Calling destructor)
def __del__(self):
print('Destructor called, Customer deleted.')
custObj = Customer("Rohit Shetty", 31000)
print(custObj)
print(custObj.withdraw(1000))
print(custObj.deposit(5000))
OUTPUT
Rohit Shetty's account balance is Rs.31000/- 30000 35000
Inheritance
Let's see an example by incorporating our previous work on the Midfielder class:
In this example, we have two classes: Player
and Midfielder
. The Player is the base class, the Midfielder is the derived class.
The derived class inherits the functionality of the base class.
It is shown by the play()
method.
The derived class modifies existing behavior of the base class.
shown by the whoAmI()
method.
Finally, the derived class extends the functionality of the base class, by defining a new skill()
method.
# Class Inheritance Example
class Player:
def __init__(self):
print("Player created")
def whoAmI(self):
print("Football Player")
def play(self):
print("Playing Football")
class Midfielder(Player):
def __init__(self):
Player.__init__(self)
print("Midfielder created")
def whoAmI(self):
print("Football Midfielder")
def skill(self):
print("Assisting the forward")
playerObj = Midfielder()
print("--------------------")
playerObj.whoAmI()
playerObj.play()
playerObj.skill()
OUTPUT
Player created Midfielder created -------------------- Football Midfielder Playing Football Assisting the forward
Polymorphism
Here we have a Midfielder class and a Defender class, and each has a skill()
method. When called, each object's skill()
method returns a result unique to the object.
# Class Polymorphism Example
class Player:
def __init__(self):
print("Player created")
def whoAmI(self):
print("Football Player")
def play(self):
print("Playing Football")
class Midfielder(Player):
def __init__(self):
Player.__init__(self)
print("Midfielder created")
def whoAmI(self):
print("Football Midfielder")
def skill(self):
print("Assisting the forward")
class Defender(Player):
def __init__(self):
Player.__init__(self)
print("Defender created")
def whoAmI(self):
print("Football Defender")
def skill(self):
print("Defending the goal-post")
player1 = Midfielder()
player2 = Defender()
print("------------------------")
player1.skill()
player2.skill()
OUTPUT
Player created Midfielder created Player created Defender created ------------------------ Assisting the forward Defending the goal-post
Special Methods
Listed below are some special methods:
__init__()
: All classes have a function called __init__()
, which is always executed when the class is being initiated. Use the __init__()
function to assign values to object properties, or other operations that are necessary to do when the object is being created.__str__()
: function controls what should be returned, when the class object is represented as a string. If the __str__()
function is not set, the string representation of the object is returned.__len__()
: it is basically used to implement the len()
function in Python because whenever we call the len()
function then internally __len__() magic method is called. It finally returns an integer value that is greater than or equal to zero as it represents the length of the object for which it is called.__del__()
: a destructor method which is called as soon as all references of the object are deleted i.e when an object is garbage collected.
# Special Methods
class Book:
def __init__(self, title, author, pages):
print("Book is created")
self.title = title
self.author = author
self.pages = pages
def __str__(self):
return "Title: %s, author: %s, pages: %s" %(self.title, self.author, self.pages)
def __len__(self):
return self.pages
def __del__(self):
print("Book is destroyed")
book = Book("Python Notes", "Skillzam", 248)
#Special Methods
print(book)
print(len(book))
del book
OUTPUT
Book is created Title: Python Notes, author: Skillzam, pages: 248 248 Book is destroyed
Modules & Packages
.py
appended.
Python Modules
One feature of Python that makes it useful for a wide range of tasks is the fact that it comes "batteries included" - that is, the Python standard library contains useful tools for a wide range of tasks.
On top of this, there is a broad ecosystem of third-party tools and packages that offer more specialized functionality.
If you quit from the Python interpreter and enter it again, the definitions you have made (functions and variables) are lost.
Therefore, if you want to write a somewhat longer program, you are better off using a text editor to prepare the input for the interpreter and running it with that file as input instead. This is known as creating a script.
.py
appended.__name__
dir()
method: is a built-in function to list all the function names (or variable names) in a module.For Example, create a file called skillzam.py
in the current directory with the following contents:
# Module "skillzam.py" contains basic maths operations:
def add(num1=0, num2=0):
'''Add two numbers'''
return(num1+num2)
def sub(num1=0, num2=0):
'''Substract two numbers'''
return(num1-num2)
def mul(num1=0, num2=0):
'''Multiply two numbers'''
return(num1*num2)
def div(num1=0, num2=0):
'''Divide two numbers'''
return(num1/num2)
def fib(n):
'''Generate Fibonacci series'''
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
import
statement: Loading Modules
For loading built-in and third-party modules, Python provides the import
statement.
There are a few ways to use the import
statement. Here they are :
[1]. Explicit module import
.
between them.math
module and compute the cosine of pi:
# Explicit import of built-in math module
import math
area = math.pi * 10**2
print(f"Area of circle with radius(10 units) is {area} sq.units")
OUTPUT
Area of circle with radius(10 units) is 314.1592653589793 sq.units
# Explicit import of used-defined skillzam module
import skillzam
res1 = skillzam.add(12,12)
res2 = skillzam.sub(12,12)
print(f"Addition of 12 and 12 is {res1}")
print(f"Subtraction of 12 from 12 is {res2}")
OUTPUT
Addition of 12 and 12 is 24 Subtraction of 12 from 12 is 0
[2]. Explicit module import by alias
"import ... as ..."
pattern to create a shorter alias for the namespace.np
:
# Explicit built-in module "Numpy" import by alias ('np')
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
print(arr)
OUTPUT
[1 2 3 4 5]
# Explicit used-defined module "skillzam" import by alias ('sz')
import skillzam as sz
res3 = sz.mul(12,12)
res4 = sz.div(12,12)
print(f"Multiplication of 12 and 12 is {res3}")
print(f"Division of 12 by 12 is {res4}")
OUTPUT
Multiplication of 12 and 12 is 144 Division of 12 by 12 is 1.0
[3]. Explicit import of module contents
"from ... import ..."
pattern.cos
& sin
functions and the pi
constant from the math
module:
# Explicit import of built-in module math's contents
# cos() & sin() methods and pi constant
from math import sin, cos, pi
sin(pi)**2 + cos(pi)**2
OUTPUT
1.0
# Explicit import of used-defined module skillzam's contents
# add(), sub() & fib() methods
from skillzam import add, sub, fib
res1 = add(12,12)
res2 = sub(12,12)
res5 = fib(100)
print(f"Addition of 12 and 12 is {res1}")
print(f"Subtraction of 12 from 12 is {res2}")
print(f"Fibonacci series numbers within 100 are :\n", res5)
OUTPUT
Addition of 12 and 12 is 24 Subtraction of 12 from 12 is 0 Fibonacci series numbers within 100 are : [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
[4]. Implicit import of module contents
"from ... import *"
pattern:
# Implicit import of built-in module math's contents
from math import *
squareRoot81 = sqrt(81)
piCeil = ceil(3.142)
eulerNumFloor = floor(2.7182)
print(f"squareRoot81 = {squareRoot81}")
print(f"piCeil = {piCeil}")
print(f"eulerNumFloor = {eulerNumFloor}")
OUTPUT
squareRoot81 = 9.0 piCeil = 4 eulerNumFloor = 2
# Implicit import of user-defined module "skillzam" contents
from skillzam import *
fibSeries = fib(50)
print(f"Fibonacci series numbers within 50 are :\n", fibSeries)
OUTPUT
Fibonacci series numbers within 50 are : [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Packages
A.B
designates a submodule named B
in a package named A
.__init__.py
files are required to make Python treat directories containing the file as packages.__init__.py
can just be an empty file, but it can also execute initialization code for the package or set the __all__
variable
# Using built-in package library "numpy" to import module random
# Accessing the method rand()
from numpy import random as rd
randArray = rd.rand(5,2)
randArray
OUTPUT
array([[0.87240903, 0.15051331], [0.53956761, 0.84593113], [0.02653546, 0.32163663], [0.5122181 , 0.06274799], [0.79155511, 0.87196709]])
# Using package & sub-package to import user-defined module skillzam
# Package is "myFirstPkg" and sub-package is "subPkg1"
# user-defined module is skillzam.py
from myFirstPkg.subPkg1 import skillzam as sz
result1 = sz.add(12,12)
result2 = sz.mul(12,12)
print(result1)
print(result2)
OUTPUT
24 144
Importing from Third-Party Modules
data science
, is its ecosystem of third-party modules.pip
(a recursive acronym meaning "pip installs packages"), which will automatically fetch packages released and listed on PyPI (if you use Python version 2, pip
must be installed separately).For example, if you'd like to install the Jupyter Notebook package that I wrote, all that is required is to type the following at the command line:
C:\> pip install notebook
The source code for the package will be automatically downloaded from the PyPI repository, and the package installed in the standard Python path (assuming you have permission to do so on the computer you're using).
Errors & Exceptions
No matter your skill as a programmer, you will eventually make a coding mistake. Such mistakes come in three basic flavors:
Here we're going to focus on how to deal cleanly with runtime errors. As we'll see, Python handles runtime errors via its exception handling framework.
Runtime Errors
If you've done any coding in Python, you've likely come across runtime errors. They can happen in a lot of ways.
For example, if you try to reference an undefined variable:
# RUNTIME ERROR : reference an undefined variable
print(AnnualPremium)
OUTPUT
NameError: name 'AnnualPremium' is not defined
# RUNTIME ERROR : unsupported operand
125 + 'amount'
OUTPUT
TypeError: unsupported operand type(s) for +: 'int' and 'str'
# RUNTIME ERROR: float division by zero
3.142 / 0
OUTPUT
ZeroDivisionError: float division by zero
# RUNTIME ERROR: list index out of range
numList = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
numList[200]
OUTPUT
IndexError: list index out of range
Exception Handling: try
, except
, else
, finally
try
block lets you test a block of code for errors.except
block lets you handle the error.else
block lets you execute code when there is no error.finally
block lets you execute code, regardless of the result of the try
and except
blocks. Well, the finally
clause really is executed no matter what: it used to do some sort of cleanup after an operation completes.
# Exception Handling: try, except, else, finally clause
# try block executes successfully
try:
result = 125 / 5
print(f"125 divided by 5 is {result}")
except:
print("Something is wrong.")
else:
print("Everything worked, just fine.")
finally:
print("No matter what, 'finally' will be executed!")
OUTPUT
125 divided by 5 is 25.0 Everything worked, just fine. No matter what, 'finally' will be executed!
Here we see that when the error was raised in the try
statement (in this case, a ZeroDivisionError), the error was caught, and the except
statement was executed.
# Exception Handling: try, except, else, finally clause
# try block has RUNTIME ERROR : ZeroDivisionError
try:
result = 3.142 / 0 # ZeroDivisionError
except:
print("ZeroDivisionError: float division by zero")
else:
print("Everything worked, just fine.")
finally:
print("No matter what, 'finally' will be executed!")
OUTPUT
ZeroDivisionError: float division by zero No matter what, 'finally' will be executed!
Raising Exceptions: raise
raise
keyword.raise
statement. For example:As an example of where this might be useful, let's consider fibonacci function that we defined previously:
ValueError
being raised:
# Exception Handling: raise, try, except clause
def fibonacci(N):
'''Generate Fibonacci Series'''
try:
if N < 0:
raise ValueError("N must be non-negative")
L = []
a, b = 0, 1
while len(L) < N:
L.append(a)
a, b = b, a + b
return L
except TypeError:
return "Bad value: need to do handle it!"
# NO ERROR
result1 = fibonacci(12)
print(result1)
# RUNTIME ERROR : TypeError
result2 = fibonacci("TWELVE")
print(result2)
# RUNTIME ERROR : ValueError
result3 = fibonacci(-12)
print(result3)
OUTPUT
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] Bad value: need to do handle it! ValueError: N must be non-negative
Regular Expressions
str
type give you a powerful set of tools for formatting, splitting, and manipulating string data. But even more powerful tools are available in Python's built-in regular expression (re)
module. *
character, which acts as a wildcard.For example, we can list all the py
file (i.e., files with extension .py) by using the *
wildcard to match any characters in between:
C:\Users\Skillzam> dir *.py
The Python interface to regular expressions is contained in the built-in re
module; as a simple example, let's use it to duplicate the functionality of the string split()
method:
In this case, the input is "\s+":
"\s"
is a special character that matches any whitespace (space, tab, newline, etc.), and the "+"
is a character that indicates one or more of the entity preceding it. Thus, the regular expression matches any substring consisting of one or more spaces.
# Regular Expression module "re"
import re
txt = 'regular expression is sequence of characters that forms search pattern'
regex = re.compile('\s+')
regex.split(txt)
OUTPUT
['regular', 'expression', 'is', 'sequence', 'of', 'characters', 'that', 'forms', 'search', 'pattern']
Regex Functions
re
module offers a set of functions that allows us to search a string for a match.
Method/Attribute | Purpose |
---|---|
match() | Determine if the RE matches at the beginning of the string. |
search() | Scan through a string, looking for any location where this RE matches. |
findall() | Find all substrings where the RE matches, and returns them as a list. |
finditer() | Find all substrings where the RE matches, and returns them as an iterator. |
# Regular Expression functions
# match(), search(), findall(), finditer()
import re
sentence = "regular expression, is a sequence of characters that forms a search pattern"
# Compile a regular expression pattern, returning a Pattern object
rex1 = re.compile('ar')
rex2 = re.compile('re')
# Scan through a string, looking for any location where this RE matches.
patternSearch = rex1.search(sentence)
# Determine if the RE matches at the beginning of the string.
patternMatch = rex2.match(sentence)
# Find all substrings where the RE matches, and returns them as a list.
patternFindall = rex1.findall(sentence)
# Find all substrings where the RE matches, and returns them as an iterator.
patternFinditer = rex1.finditer(sentence)
print("patternSearch:",patternSearch)
print("patternMatch:",patternMatch)
print("patternFindall:",patternFindall)
print()
print("patternFinditer:",patternFinditer)
for item in patternFinditer:
print(item)
OUTPUT
patternSearch: <re.Match object; span=(5, 7), match='ar'> patternMatch: <re.Match object; span=(0, 2), match='re'> patternFindall: ['ar', 'ar', 'ar'] patternFinditer: <callable_iterator object at 0x000002BA46EF3550> <re.Match object; span=(5, 7), match='ar'> <re.Match object; span=(39, 41), match='ar'> <re.Match object; span=(63, 65), match='ar'>
MetaCharacters
To understand the RE analogy, MetaCharacters are useful, important, and will be used in functions of module re. Below is the list of metacharacters.
MetaCharacters | Description |
---|---|
\ | Used to drop the special meaning of character following it |
[ ] | Represent a character class |
^ | Matches the beginning |
$ | Matches the end |
. | Matches any character except newline |
| | Means OR (Matches with any of the characters separated by it. |
? | Matches zero or one occurrence |
* | Any number of occurrences (including 0 occurrences) |
+ | One or more occurrences |
{ } | Indicate the number of occurrences of a preceding regex to match. |
( ) | Enclose a group of Regex |
# Regular Expression using Metacharacters
# find all the email ID's in the given text
text = "To email me, try email@example.com or the you can also try address mail_me@example.com."
email = re.compile('\w+@\w+\.[a-z]{3}')
result1 = email.findall(text)
print(result1)
# you can replace these email addresses with another string,
# perhaps to hide addresses in the output
result2 = email.sub('--@--.--', text)
print(result2)
OUTPUT
['email@example.com', 'mail_me@example.com'] To email me, try --@--.-- or the you can also try address --@--.--.
Groups in regular expressions
We can use groups for any general task that involves grouping together regular expressions (so that we can later break them down).
Example: What if we wanted to do two tasks, find phone numbers, but also be able to quickly extract their area code (the first three digits).
Method/Attribute | Purpose |
---|---|
group() | Return the string matched by the RE |
start() | Return the starting position of the match |
end() | Return the ending position of the match |
span() | Return a tuple containing the (start, end) positions of the match |
# Using group related functions in regular expressions
txt = "My phone number is 717-123-9876"
phone_pattern = re.compile(r'(\d{3})-(\d{3})-(\d{4})')
results = re.search(phone_pattern,txt)
print(results.group())
print(results.start())
print(results.end())
print(results.span())
print("----------------------")
# Can then also call by group position.
# remember groups were separated by parenthesis ()
# Something to note is that group ordering starts at 1. Passing in 0 returns everything
print(results.group(0))
print(results.group(1))
print(results.group(2))
print(results.group(3))
OUTPUT
717-123-9876 19 31 (19, 31) ---------------------- 717-123-9876 717 123 9876
Standard Modules
winreg
module is only provided on Windows systems.sys
which is built into every Python interpreter. Let us look into some popular modules:
random Module
random()
, which generates a random float uniformly in the semi-open range [0.0, 1.0). random module has a set of methods:
➤ random()
method returns a random float number between 0 and 1
# returns a random float number between 0 and 1
import random as rd
print(rd.random())
OUTPUT
0.16157881100117089
➤ randrange()
method returns a random number between the given range.
# returns random number between 10 & 99
import random as rd
print(rd.randrange(10, 99))
OUTPUT
96
➤ shuffle()
method takes a sequence like a list as an argument and reorganize the order of the items.
This shuffle()
method changes the original list, it does not return a new list.
# reorganize the order of the items in a sequence
import random as rd
teams = ["Arsenal", "Barcelona", "PSG", "Bayern", "Juventus"]
rd.shuffle(teams)
print(teams)
OUTPUT
['Barcelona', 'Bayern', 'Juventus', 'Arsenal', 'PSG']
➤ choice()
method returns a randomly selected element from the specified sequence.
The sequence can be a string, a range, a list, a tuple or any other kind of sequence.
# select element randomly from list
import random as rd
teams = ["Arsenal", "Barcelona", "PSG", "Bayern", "Juventus"]
choiceSelected = rd.choice(teams)
print(choiceSelected)
OUTPUT
Barcelona
# select element randomly from tuple
import random as rd
org = ("Skillzam","Workzam")
chSelect = rd.choice(org)
print(chSelect)
OUTPUT
Skillzam
# select element randomly from string
import random as rd
academy = "SKILLZAM"
charChoice = rd.choice(academy)
print(charChoice)
OUTPUT
Z
# select element randomly from range()
import random as rd
givenRange = range(1,100)
selectRange = rd.choice(givenRange)
print(selectRange)
OUTPUT
76
statistics Module
int
, float
, Decimal
and Fraction
.map()
to ensure a consistent result, for example: map(float, input_data)
.The statistics module was added newly in Python 3.4. Some of methods of this module are listed below:
➤ mean()
method returns the mean or the average of the given data.
# returns the mean of given data
import statistics as st
tempCelcius = [12, 33, 29, 11.5, 23, 30, 22]
meanValue = st.mean(tempCelcius)
print(meanValue)
OUTPUT
22.928571428571427
➤ median()
method returns the median or the middle value of the given data.
# returns the median of given data
import statistics as st
tempCelcius = [12, 33, 29, 11.5, 23, 30, 22]
medianValue = st.median(tempCelcius)
print(medianValue)
OUTPUT
23
➤ mode()
method returns the mode or the central tendency of the given numeric or nominal data.
# returns the mode of given data
import statistics as st
tempCelcius = [12, 33, 29, 11.5, 23, 30, 22]
modeValue = st.mode(tempCelcius)
print(modeValue)
OUTPUT
12
➤ stdev()
method returns the standard deviation from a sample of data.
# returns the standard deviation of given data
import statistics as st
tempCelcius = [12, 33, 29, 11.5, 23, 30, 22]
stdevValue = st.stdev(tempCelcius)
print(stdevValue)
OUTPUT
8.555838997572415
➤ variance()
method returns the variance from a sample of data.
# returns the variance of given data
import statistics as st
tempCelcius = [12, 33, 29, 11.5, 23, 30, 22]
varianceValue = st.variance(tempCelcius)
print(varianceValue)
OUTPUT
73.20238095238095
requests Module
Response Object
with all the response data (content, encoding, status, etc).requests.Response()
Object contains the server's response to the HTTP request.c:\> pip install requests
) before using it.Some of methods of this module are listed below:
➤ get()
method sends a GET request to the specified url.
# GET request to the specified url
import requests as rq
rqExample = rq.get('https://example.com/index.html')
print(rqExample.text) # returns content of the response
OUTPUT
<!doctype html> <html> <head> <title>Example Domain</title> <meta charset="utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style type="text/css"> body { background-color: #f0f0f2; margin: 0; padding: 0; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } div { width: 600px; margin: 5em auto; padding: 2em; background-color: #fdfdff; border-radius: 0.5em; box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02); } a:link, a:visited { color: #38488f; text-decoration: none; } @media (max-width: 700px) { div { margin: 0 auto; width: auto; } } </style> </head> <body> <div> <h1>Example Domain</h1> <p>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</p> <p><a href="https://www.iana.org/domains/example">More information...</a></p> </div> </body> </html>
# GET request to the specified url
import requests as rq
rqFitbit = rq.get('https://fitbit.com')
print(rqFitbit.url) # returns URL of the response
OUTPUT
https://www.fitbit.com/global/in/home
# GET request to the specified url
import requests as rq
rqExample = rq.get('https://example.com')
print(rqExample.status_code) # returns a number that indicates status
print(rqExample.reason) # returns a text corresponding to status code
OUTPUT
200 OK
➤ head()
method sends a HEAD request to the specified url.
HEAD requests are done when you do not need the content of the file, but only the status_code or HTTP headers.
# HEAD request to the specified url
import requests as rq
rqYahoo = rq.head('https://yahoo.com')
print(rqYahoo.headers) # returns a dictionary of response headers
OUTPUT
{'Date': 'Tue, 10 Jan 2023 14:20:17 GMT', 'Connection': 'keep-alive', 'Strict-Transport-Security': 'max-age=31536000', 'Server': 'ATS', 'Cache-Control': 'no-store, no-cache', 'Content-Type': 'text/html', 'Content-Language': 'en', 'X-Frame-Options': 'SAMEORIGIN', 'Expect-CT': 'max-age=31536000, report-uri="http://csp.yahoo.com/beacon/csp?src=yahoocom-expect-ct-report-only"', 'Referrer-Policy': 'no-referrer-when-downgrade', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Location': 'https://www.yahoo.com/', 'Content-Length': '8'}
math Module
C standard
➤ math.floor()
method rounds a number down to the nearest integer, if necessary, and returns the result.
# rounds number down to nearest integer, if necessary
import math as mt
numOne = 0.75
numTwo = 1.25
print(mt.floor(numOne))
print(mt.floor(numTwo))
OUTPUT
0 1
➤ math.factorial()
method returns the factorial of a number (positive integers).
# returns the factorial of a number
import math as mt
num = 5
print(mt.factorial(num))
OUTPUT
120
➤ math.pow()
method returns the value of x raised to power y. If x is negative and y is not an integer, it returns a ValueError. This method converts both arguments into a float.
# returns value of x raised to power y
import math as mt
x = 9
y = 2
print(mt.pow(x,y))
OUTPUT
81
➤ math.pi
constant returns the value of PI: 3.141592653589793.
➤ math.e
constant returns the Euler's number: 2.718281828459045.
# returns the value of PI & e
import math as mt
print(mt.pi)
print(mt.e)
OUTPUT
3.141592653589793 2.718281828459045
sys Module
sys
module provides access to some variables used or maintained by the interpreter and to functions that interact strongly with the interpreter
.This module has a set of attributes/methods:
➤ sys.ps1
and sys.ps2
are strings specifying the primary & secondary prompt of the interpreter. These are only defined, if the interpreter is in interactive mode. Their initial values in this case are '>>> '
and '... '
.
>>> import sys
>>> print(sys.ps1, sys.ps2)
OUTPUT
>>> ...
➤ sys.path
is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module.
When a module is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path
>>> import sys
>>> sys.path
OUTPUT
['', 'D:\\install\\python\\python311.zip', 'D:\\install\\python\\Lib', 'D:\\install\\python\\DLLs', 'D:\\install\\python', 'D:\\install\\python\\Lib\\site-packages', 'D:\\install\\python\\Lib\\site-packages\\win32', 'D:\\install\\python\\Lib\\site-packages\\win32\\lib', 'D:\\install\\python\\Lib\\site-packages\\Pythonwin']
➤ sys.stdout
a built-in file object that is analogous to the interpreter's standard output stream in Python.
stdout
is used to display output directly to the screen console.sys.stdout
and then finally on to the screen.sys.stdout.write()
serves the same purpose as the object stands for except it prints the number of letters within the text too when used in interactive mode.sys.stdout.write
doesn't switch to a new line after one text is displayed. To achieve this one can employ a new line escape character \n
.
# sys.stdout.write() usuage
import sys
# stdout assigned to a variable (output)
output = sys.stdout
mylist = ['Skillzam', 'Learn', 'without', 'limits!']
# printing everything in the same line
for word in mylist:
output.write(word)
# printing everything in a new line
for string in mylist:
output.write('\n'+string)
OUTPUT
SkillzamLearnwithoutlimits! Skillzam Learn without limits!
➤ sys.stdin
stands for standard input which is a stream from which the program reads its input data from the command line directly.
input()
method. Furthermore, it, also, automatically adds '\n'
after each sentence.sys.stdin.readline()
method is slightly different from the input() method as it also reads the escape character entered by the user.
>>> import sys
>>> fullName = sys.stdin.readline()
John Smith
>>> age = sys.stdin.readline(2)
025
>>> print(fullName)
John Smith
>>> print(age)
02
>>>
Python Interview Questions
Get the hold of actual interview questions during job hiring.
What is Python?
Python is a high-level, interpreted programming language. It emphasizes code readability and simplicity, making it a popular choice for beginners and experienced developers alike.
What is the difference between a tuple and a list in Python?
A list and a tuple are both ordered collections of elements in Python, but there are several key differences between the two. The main difference is that a list is mutable, which means that you can add, remove, or modify elements in a list, while a tuple is immutable, which means that you cannot modify its elements after it has been created. Additionally, a list is defined using square brackets, while a tuple is defined using parentheses.
What is a lambda function in Python, and when would you use one?
A lambda function is a small anonymous function that can take any number of arguments, but can only have one expression. Lambda functions are useful when you need to create a simple function for a specific purpose, and you don't want to define a named function. They can be used in place of a regular function wherever a function is expected, such as in the "key" parameter of the "sort" method.
What are decorators in Python, and how do they work?
A decorator is a special type of function that can be used to modify the behavior of another function. Decorators are implemented as functions that take another function as input and return a new function that wraps the original function. The new function can modify the behavior of the original function, such as adding functionality, logging, or error handling. Decorators are applied using the "@" symbol followed by the name of the decorator function before the function definition.
What is the difference between a module and a package in Python?
In Python, a module is a single file that contains Python code, while a package is a collection of modules in a directory. Packages allow for a hierarchical organization of modules, and they can be nested to any level.
What is a generator in Python, and how does it work?
A generator is a special type of iterable that allows you to generate a sequence of values on-the-fly. Generators are implemented as functions that use the "yield" keyword instead of "return" to return values. When a generator function is called, it returns a generator object that can be iterated over using a for loop or other iterable functions. The generator function can pause and resume execution, so it can generate an infinite sequence of values without consuming all of the memory at once.
What is PEP 8 in Python?
PEP 8 is a set of guidelines for writing Python code that are meant to promote consistency and readability. The guidelines cover topics such as code layout, naming conventions, and programming practices. Adhering to PEP 8 can make your code more readable and easier to maintain.
What is the difference between "is" and "==" in Python?
In Python, "is" is used to test if two variables refer to the same object in memory, while "==" is used to test if two variables have the same value. For example, "x is y" would return True if x and y refer to the same object in memory, while "x == y" would return True if x and y have the same value, regardless of whether they are the same object.
What is the purpose of "init" in Python?
The init() method is a special method in Python classes that is used to initialize the object's attributes when it is created. The method is called automatically when a new object of the class is created, and it can take parameters to set the initial values of the object's attributes. The init() method is commonly used to define the state of the object when it is created, such as setting default values or initializing variables.
What is a dictionary in Python?
A dictionary is an unordered collection of key-value pairs, where each key is unique.
What is a module in Python?
A module is a file containing Python code that can be reused in other Python programs.
WhWhat is the difference between a module and a package in Python?
A module is a single file that contains Python code, while a package is a directory that contains one or more modules and an optional init.py file. The init.py file can contain initialization code that is executed when the package is imported. Packages are used to organize related modules into a hierarchical namespace.
What is the difference between local and global variables in Python?
Local variables are defined within a function and are only accessible within that function, while global variables are defined outside of any function and can be accessed anywhere in the program.
How can you debug a Python program?
You can use the Python debugger (pdb) module, which allows you to step through your code line-by-line and inspect variables.
What is the use of the "pass" statement in Python?
The "pass" statement is a placeholder statement that does nothing. It is often used as a placeholder for code that will be written later.
What is the use of the "yield" keyword in Python?
The "yield" keyword is used in Python to define a generator function, which is a special kind of function that generates a sequence of values on the fly. When a generator function is called, it returns a generator object, which can be used to iterate over the sequence of values generated by the function. The "yield" keyword is used to return a value from the generator function, but instead of terminating the function like a "return" statement would, it temporarily suspends the function and saves its state, allowing it to be resumed later. The purpose of the "yield" keyword is to allow the generator function to generate a sequence of values without having to create a list or other data structure to hold all the values in memory at once.
How do you handle exceptions in Python?
You can use the "try-except" block to catch and handle exceptions in Python.
What is the purpose of the "finally" block in a "try-except" block?
The "finally" block is executed regardless of whether an exception was raised or not. It is often used to release resources or perform cleanup tasks.
What is the purpose of the "super()" function in Python?
The "super" function in Python is used to call a method in a parent class from a subclass. When a method is called using "super", Python will search for the method in the parent class and call it with the arguments passed to the subclass method. This allows the subclass to extend or modify the behavior of the parent class, without having to duplicate the entire method definition.
How do you create an empty list in Python?
You can create an empty list in Python using empty square brackets, like this: my_list = []
What is a tuple in Python?
A tuple is a data structure in Python that can hold a collection of values, which can be of different data types. Tuples are immutable, meaning their values cannot be changed once they are created.
How do you create an empty dictionary in Python?
You can create an empty dictionary in Python using empty curly braces, like this: my_dict = {}
What is the difference between a dictionary and a list in Python?
The main difference between a dictionary and a list in Python is that lists hold an ordered collection of values, while dictionaries hold key-value pairs, and the keys are used to access the corresponding values.
What is a function in Python?
A function in Python is a block of code that performs a specific task and can be reused throughout the program.
How do you define a function in Python?
You can define a function in Python using the def keyword, like this:
def my_function(parameter1, parameter2):
# Code to perform the task
return result
What is pip in Python?
Pip is a package manager for Python that is used to install, upgrade, and remove Python packages.
What is virtualenv in Python?
Virtualenv is a tool in Python that allows you to create isolated Python environments, which can have their own set of packages and dependencies.
What is object-oriented programming in Python?
Object-oriented programming (OOP) is a programming paradigm that uses objects to represent data and methods to perform actions on that data.
What is inheritance in Python?
Inheritance is a feature of object-oriented programming in Python that allows a new class to be based on an existing class, inheriting its attributes and methods.
What is polymorphism in Python?
Polymorphism is a fundamental concept in object-oriented programming that allows objects of different types to be treated as if they are of the same type. In Python, polymorphism is achieved through the use of inheritance, duck typing, and function overloading.
What is the difference between a shallow copy and a deep copy in Python?
In Python, when we copy an object, we can create either a shallow copy or a deep copy. The difference between the two is in how they handle mutable objects that are nested inside the object being copied.
A shallow copy creates a new object that points to the same memory location as the original object. In other words, the new object is a reference to the original object. This means that any changes made to the original object will also affect the shallow copy, and vice versa. Shallow copying is useful when we want to create a new object that contains references to the same objects as the original object.
On the other hand, a deep copy creates a new object with its own memory allocation. It recursively copies all the nested objects in the original object, and creates new objects for them. This means that any changes made to the original object will not affect the deep copy, and vice versa. Deep copying is useful when we want to create a completely independent copy of the original object, without any references to its nested objects.
How does Python's garbage collection work, and what are some common issues with it?
Python's garbage collection automatically frees up memory that is no longer being used by an application. It uses a reference counting system to keep track of the number of references to an object. When the reference count of an object drops to zero, it is removed from memory by the garbage collector. Additionally, Python's garbage collector also uses a cyclic garbage collector to detect and remove circular references. Common issues with Python's garbage collection include memory leaks caused by circular references or long-lived objects, and performance issues caused by frequent garbage collection cycles.
How does Python implement multithreading?
Python uses a Global Interpreter Lock (GIL) to ensure that only one thread executes Python bytecode at a time. This means that only one thread can execute Python code at any given time, even on multi-core systems. However, Python also provides a multiprocessing module, which allows multiple processes to execute Python code in parallel.
What is the difference between Python 2 and Python 3, and how would you migrate code from Python 2 to Python 3?
Python 2 and Python 3 are two different versions of the Python programming language, with significant differences in syntax and features. Python 3 introduced several changes to the language, such as the print function, integer division, and Unicode string handling. To migrate code from Python 2 to Python 3, you would need to modify the code to use Python 3 syntax and features, such as using the print function instead of the print statement, using integer division instead of floor division, and handling Unicode strings differently. You can use tools like 2to3 or Modernize to automate some of the migration process.
What is a closure in Python, and how would you use one?
A closure is a function that has access to a parent function's variables, even after the parent function has completed execution. Closures are implemented using nested functions, where the inner function can reference the variables of the outer function. Closures can be used to implement higher-order functions, such as decorators and generators, or to create private variables that are not accessible outside of the closure.
What is the Global Interpreter Lock (GIL) in Python, and how does it affect multi-threaded programming in Python?
The Global Interpreter Lock (GIL) is a mechanism used in the CPython implementation of Python that allows only one thread to execute Python bytecode at a time. This means that even if an application uses multiple threads, only one thread can execute Python code at a time, while other threads are waiting for the GIL to be released. This can limit the performance of multi-threaded applications that spend a lot of time executing Python code. To work around the GIL, you can use multiple processes instead of threads, or use a different implementation of Python, such as Jython or IronPython, that do not have a GIL.
What is the difference between a class method and a static method in Python?
A class method is a method that is bound to the class rather than an instance of the class. Class methods are defined using the "@classmethod" decorator, and they take the class itself as the first argument instead of an instance of the class. Class methods can be used to create alternative constructors for a class or to access class-level variables. A static method is a method that does not require access to the class or instance, and is defined using the "@staticmethod" decorator. Static methods can be used as utility functions that do not depend on the state of the class or instance.
What is the purpose of memoization in Python?
Memoization is a technique used to improve the performance of functions by caching the results of expensive computations and returning the cached results when the same inputs are provided again. Memoization is typically used with recursive functions or functions that involve expensive computations.
What is the difference between a generator and a list comprehension in Python?
A list comprehension is a concise way to create a new list by applying an expression to each element of an existing list or iterable. A generator, on the other hand, is a way to lazily generate a sequence of values on the fly, using a special kind of function called a generator function. The key difference between the two is that a list comprehension creates a new list in memory, while a generator generates values on the fly and does not create a new list in memory. Generators are useful when you need to generate a large sequence of values but don't want to create a new list in memory.
What is the difference between an abstract class and an interface in Python?
In Python, there is no formal concept of interfaces, but there are abstract classes, which are similar in concept. An abstract class is a class that cannot be instantiated directly, and is instead meant to be subclassed by other classes. Abstract classes can have abstract methods, which are methods that are meant to be implemented by the subclasses. The purpose of an abstract class is to provide a blueprint or template for the behavior of the subclasses. An interface, on the other hand, is a way to define a contract between different classes, specifying the methods and properties that the classes must implement. Interfaces are typically used in languages like Java and C#, but are not as common in Python.
What is the difference between a local and a global variable in Python?
A local variable is a variable that is defined inside a function or a method, and is only accessible within that function or method. Local variables have local scope, meaning that they cannot be accessed from outside the function or method in which they are defined. A global variable, on the other hand, is a variable that is defined outside any function or method, and can be accessed from anywhere in the program. Global variables have global scope, meaning that they can be accessed from any part of the program.
What is the difference between a thread and a process in Python?
A process is a separate instance of a running program, while a thread is a separate execution path within a process. This means that a process can have multiple threads, each of which can execute code independently and concurrently with the other threads. Processes have their own memory space and resources, while threads share the same memory space and resources within the process. Threads are often used for tasks that need to be run concurrently, such as downloading multiple files at the same time or performing background processing while the main program is running.
What is the purpose of the "with" statement in Python?
The "with" statement is used in Python to define a context in which a particular resource is used, such as a file, a database connection, or a network socket. The purpose of the "with" statement is to ensure that the resource is properly acquired and released, even in the face of errors or exceptions. When the "with" statement is executed, it creates a context and sets up the resource for use. When the context is exited, either normally or due to an exception, the resource is automatically released, regardless of whether an error occurred or not. This helps to ensure that resources are properly managed and that the program does not leak resources or leave them in an inconsistent state.
What is the difference between a decorator and a closure in Python?
A decorator is a special kind of function that can be used to modify the behavior of another function or method, while a closure is a function that can access and modify the variables in the enclosing scope. The key difference between the two is that a decorator is a higher-order function that takes a function as input and returns a new function, while a closure is a function that has access to variables defined in its enclosing scope. Decorators are often used for tasks like logging, timing, or caching, while closures are often used for tasks like event handling or callback functions.
What is the difference between a lambda function and a regular function in Python?
A lambda function is a small, anonymous function that can be defined in a single line of code, while a regular function is a named function that can have multiple lines of code and is defined using the "def" keyword. Lambda functions are often used for tasks that require a small function to be defined on-the-fly, such as sorting or filtering data. Regular functions are used for more complex tasks that require multiple lines of code, or for tasks that need to be called multiple times.
How does Python implement inheritance, and what are the benefits of inheritance in object-oriented programming?
In Python, inheritance is implemented by defining a subclass that inherits attributes and methods from its parent class. The subclass can then extend or modify the behavior of the parent class by adding or overriding methods. When a method is called on an instance of the subclass, Python will first look for the method in the subclass, and if it is not found, it will look in the parent class.
The benefits of inheritance in object-oriented programming are that it allows for code reuse and promotes code organization and modularity. By defining a common set of attributes and methods in a parent class, subclasses can inherit this behavior and build on it to create new functionality. Inheritance also allows for polymorphism, which means that objects of different classes can be treated as if they are the same type, as long as they have the same interface.