├── .gitignore ├── README.md ├── assets ├── arithmetic-operators.png ├── collection-module.png ├── comparison-operator.png ├── python-application.png ├── python-datatypes.png └── water-container-problem.png ├── data_files ├── data.csv ├── data.json ├── example.txt └── students.json └── tutorials ├── building_python_modules ├── building_python_module.md ├── mymath │ ├── __init__.py │ ├── calculator.py │ └── geometry.py └── run.py ├── data_structures_in_python.ipynb ├── file_operations_in_python.ipynb ├── functional_programming_in_python.ipynb ├── getting_started_with_python.ipynb ├── oop_in_python.ipynb ├── pep8_style_guide.ipynb ├── unit_testing_and_exception_handling ├── .pylintrc ├── mytest.py ├── mytest_new.py └── unit_testing_and_exception_handling_in_python.ipynb └── working_with_libraries.md /.gitignore: -------------------------------------------------------------------------------- 1 | /tutorials/building_python_modules/myvenv/ 2 | **/__pycache__/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Python-zero2hero!! 💯 💥 2 | This repository contains a comprehensive Python tutorial designed to take you from zero programming knowledge to a Python hero. Whether you're a complete beginner or someone looking to brush up on their Python skills, this tutorial will provide you with the necessary tools and knowledge. 3 | 4 | ## Table of Contents 5 | 6 | - [Getting Started with Python](tutorials/getting_started_with_python.ipynb) 7 | - Install Python and setting up the environment 8 | - Basic syntax, variables, and data types 9 | - Input and output functions 10 | 11 | - [Data Structures in Python](tutorials/data_structures_in_python.ipynb) 12 | - Understand Python’s approach to objects, names, and namespaces. 13 | - Explore lists, tuples, strings, dictionaries, and sets 14 | - Use control structures: conditional statements(if,elif, else), loops(for, while), break, continue and pass statements. 15 | - Explore collections module and comprehension techniques 16 | 17 | - [Functional Programming in Python](tutorials/functional_programming_in_python.ipynb) 18 | - Create simple function interfaces using advanced arguments types, including keyword arguments and variadic arguments. 19 | - Create functional programs, using map/filter, reduce, lambdas, iterators, and generators 20 | - Create decorators, high-level tools to transform functional behavior. 21 | 22 | - [Object Oriented Programming in Python](tutorials/oop_in_python.ipynb) 23 | - Trace the details of instantiation and attribute resolution on class objects and instance objects. 24 | - Create classes with custom methods, including initializers and decorated properties. 25 | - Analyze object-based design patterns, including polymorphism and inheritance. 26 | 27 | - [File I/O Operations in Python](tutorials/file_operations_in_python.ipynb) 28 | - Understand the principles of files and file systems, in order to open files for reading or writing. 29 | - Create programs that can read data from or write data to a plain text file. 30 | - Create programs that can read or write JSON data. 31 | - Create programs that can read or write CSV data. 32 | 33 | - [Building Python Modules](tutorials/building_python_modules) 34 | - Understand modular programming to reuse functional units of code. 35 | - Organize multiple modules as a package. 36 | - Relative and absolute imports of modules and packages. 37 | 38 | - [Working with Libraries](tutorials/working_with_libraries.md) 39 | - Working with standard python libraries 40 | - Install and use open source third party libraries to solve complex problems. 41 | - Learn how to use virtual environments to maintain clear dependency states during development. 42 | 43 | - [Unit Testing & Exception Handling](tutorials/unit_testing_and_exception_handling/unit_testing_and_exception_handling_in_python.ipynb) 44 | - Understand Unit Testing and write test cases using standard python library unittest 45 | - Use third party library-pytest for writing simple and powerful test cases. 46 | - Exception handling using try, except and finally 47 | - Writing Custom Exceptions 48 | 49 | - [Standard Coding Practice](tutorials/pep8_style_guide.ipynb) 50 | - PEP standards to write clear, compliant code. 51 | - Understand core Pythonic principles to write code that can scale. 52 | - Explore pylint library -------------------------------------------------------------------------------- /assets/arithmetic-operators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prof-sushil/Python-zero2hero/670725adb7730e19cb6656581489b80ba90bb0f4/assets/arithmetic-operators.png -------------------------------------------------------------------------------- /assets/collection-module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prof-sushil/Python-zero2hero/670725adb7730e19cb6656581489b80ba90bb0f4/assets/collection-module.png -------------------------------------------------------------------------------- /assets/comparison-operator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prof-sushil/Python-zero2hero/670725adb7730e19cb6656581489b80ba90bb0f4/assets/comparison-operator.png -------------------------------------------------------------------------------- /assets/python-application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prof-sushil/Python-zero2hero/670725adb7730e19cb6656581489b80ba90bb0f4/assets/python-application.png -------------------------------------------------------------------------------- /assets/python-datatypes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prof-sushil/Python-zero2hero/670725adb7730e19cb6656581489b80ba90bb0f4/assets/python-datatypes.png -------------------------------------------------------------------------------- /assets/water-container-problem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prof-sushil/Python-zero2hero/670725adb7730e19cb6656581489b80ba90bb0f4/assets/water-container-problem.png -------------------------------------------------------------------------------- /data_files/data.csv: -------------------------------------------------------------------------------- 1 | Name,Age,City 2 | Ram,36,Bhaktapur 3 | Sita,25,Kathmandu 4 | Laxman,35,Butwal 5 | -------------------------------------------------------------------------------- /data_files/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Ram", 3 | "age": 30, 4 | "city": "Bhaktapur" 5 | } -------------------------------------------------------------------------------- /data_files/example.txt: -------------------------------------------------------------------------------- 1 | Hello, Everyone! 2 | I am learning Python Programming.Learning Python Programming is fun. -------------------------------------------------------------------------------- /data_files/students.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Ram", 4 | "age": 21, 5 | "address": "Lalitpur", 6 | "courses": [ 7 | "Math", 8 | "Science", 9 | "Social", 10 | "Art" 11 | ], 12 | "marks": [ 13 | 88, 14 | 85, 15 | 77, 16 | 79 17 | ] 18 | }, 19 | { 20 | "name": "Mohan", 21 | "age": 21, 22 | "address": "Butwal", 23 | "courses": [ 24 | "Math", 25 | "Science", 26 | "Social", 27 | "Art" 28 | ], 29 | "marks": [ 30 | 73, 31 | 60, 32 | 92, 33 | 71 34 | ] 35 | }, 36 | { 37 | "name": "Shyam", 38 | "age": 22, 39 | "address": "Kathmandu", 40 | "courses": [ 41 | "Math", 42 | "Science", 43 | "Social", 44 | "Art" 45 | ], 46 | "marks": [ 47 | 69, 48 | 76, 49 | 70, 50 | 61 51 | ] 52 | }, 53 | { 54 | "name": "Rupa", 55 | "age": 24, 56 | "address": "Itahari", 57 | "courses": [ 58 | "Math", 59 | "Science", 60 | "Social", 61 | "Art" 62 | ], 63 | "marks": [ 64 | 93, 65 | 100, 66 | 85, 67 | 78 68 | ] 69 | }, 70 | { 71 | "name": "Kumar", 72 | "age": 19, 73 | "address": "Dhangadhi", 74 | "courses": [ 75 | "Math", 76 | "Science", 77 | "Social", 78 | "Art" 79 | ], 80 | "marks": [ 81 | 84, 82 | 80, 83 | 89, 84 | 92 85 | ] 86 | }, 87 | { 88 | "name": "Sunita", 89 | "age": 20, 90 | "address": "Janakpur", 91 | "courses": [ 92 | "Math", 93 | "Science", 94 | "Social", 95 | "Art" 96 | ], 97 | "marks": [ 98 | 67, 99 | 93, 100 | 62, 101 | 85 102 | ] 103 | }, 104 | { 105 | "name": "Manish", 106 | "age": 18, 107 | "address": "Nepalgunj", 108 | "courses": [ 109 | "Math", 110 | "Science", 111 | "Social", 112 | "Art" 113 | ], 114 | "marks": [ 115 | 77, 116 | 92, 117 | 89, 118 | 71 119 | ] 120 | }, 121 | { 122 | "name": "Mina", 123 | "age": 22, 124 | "address": "Bharatpur", 125 | "courses": [ 126 | "Math", 127 | "Science", 128 | "Social", 129 | "Art" 130 | ], 131 | "marks": [ 132 | 80, 133 | 96, 134 | 97, 135 | 76 136 | ] 137 | }, 138 | { 139 | "name": "Raj", 140 | "age": 25, 141 | "address": "Biratnagar", 142 | "courses": [ 143 | "Math", 144 | "Science", 145 | "Social", 146 | "Art" 147 | ], 148 | "marks": [ 149 | 94, 150 | 75, 151 | 68, 152 | 96 153 | ] 154 | }, 155 | { 156 | "name": "Shiva", 157 | "age": 19, 158 | "address": "Pokhara", 159 | "courses": [ 160 | "Math", 161 | "Science", 162 | "Social", 163 | "Art" 164 | ], 165 | "marks": [ 166 | 75, 167 | 68, 168 | 82, 169 | 90 170 | ] 171 | }, 172 | { 173 | "name": "Rita", 174 | "age": 20, 175 | "address": "Biratnagar", 176 | "courses": [ 177 | "Math", 178 | "Science", 179 | "Social", 180 | "Art" 181 | ], 182 | "marks": [ 183 | 98, 184 | 64, 185 | 62, 186 | 84 187 | ] 188 | }, 189 | { 190 | "name": "Sita", 191 | "age": 22, 192 | "address": "Nepalgunj", 193 | "courses": [ 194 | "Math", 195 | "Science", 196 | "Social", 197 | "Art" 198 | ], 199 | "marks": [ 200 | 69, 201 | 86, 202 | 86, 203 | 95 204 | ] 205 | }, 206 | { 207 | "name": "Gita", 208 | "age": 18, 209 | "address": "Birgunj", 210 | "courses": [ 211 | "Math", 212 | "Science", 213 | "Social", 214 | "Art" 215 | ], 216 | "marks": [ 217 | 96, 218 | 87, 219 | 79, 220 | 62 221 | ] 222 | }, 223 | { 224 | "name": "Gopal", 225 | "age": 20, 226 | "address": "Itahari", 227 | "courses": [ 228 | "Math", 229 | "Science", 230 | "Social", 231 | "Art" 232 | ], 233 | "marks": [ 234 | 63, 235 | 74, 236 | 91, 237 | 86 238 | ] 239 | }, 240 | { 241 | "name": "Sushma", 242 | "age": 24, 243 | "address": "Ghorahi", 244 | "courses": [ 245 | "Math", 246 | "Science", 247 | "Social", 248 | "Art" 249 | ], 250 | "marks": [ 251 | 89, 252 | 66, 253 | 92, 254 | 88 255 | ] 256 | }, 257 | { 258 | "name": "Bina", 259 | "age": 22, 260 | "address": "Ghorahi", 261 | "courses": [ 262 | "Math", 263 | "Science", 264 | "Social", 265 | "Art" 266 | ], 267 | "marks": [ 268 | 96, 269 | 93, 270 | 100, 271 | 84 272 | ] 273 | }, 274 | { 275 | "name": "Sarita", 276 | "age": 19, 277 | "address": "Dhangadhi", 278 | "courses": [ 279 | "Math", 280 | "Science", 281 | "Social", 282 | "Art" 283 | ], 284 | "marks": [ 285 | 82, 286 | 90, 287 | 97, 288 | 79 289 | ] 290 | }, 291 | { 292 | "name": "Mina", 293 | "age": 21, 294 | "address": "Kathmandu", 295 | "courses": [ 296 | "Math", 297 | "Science", 298 | "Social", 299 | "Art" 300 | ], 301 | "marks": [ 302 | 68, 303 | 70, 304 | 71, 305 | 60 306 | ] 307 | }, 308 | { 309 | "name": "Nita", 310 | "age": 18, 311 | "address": "Ghorahi", 312 | "courses": [ 313 | "Math", 314 | "Science", 315 | "Social", 316 | "Art" 317 | ], 318 | "marks": [ 319 | 86, 320 | 80, 321 | 75, 322 | 89 323 | ] 324 | }, 325 | { 326 | "name": "Hari", 327 | "age": 24, 328 | "address": "Ghorahi", 329 | "courses": [ 330 | "Math", 331 | "Science", 332 | "Social", 333 | "Art" 334 | ], 335 | "marks": [ 336 | 80, 337 | 61, 338 | 74, 339 | 88 340 | ] 341 | }, 342 | { 343 | "name": "Ravi", 344 | "age": 18, 345 | "address": "Biratnagar", 346 | "courses": [ 347 | "Math", 348 | "Science", 349 | "Social", 350 | "Art" 351 | ], 352 | "marks": [ 353 | 87, 354 | 89, 355 | 86, 356 | 75 357 | ] 358 | }, 359 | { 360 | "name": "Ganesh", 361 | "age": 18, 362 | "address": "Nepalgunj", 363 | "courses": [ 364 | "Math", 365 | "Science", 366 | "Social", 367 | "Art" 368 | ], 369 | "marks": [ 370 | 94, 371 | 74, 372 | 99, 373 | 96 374 | ] 375 | }, 376 | { 377 | "name": "Manish", 378 | "age": 20, 379 | "address": "Hetauda", 380 | "courses": [ 381 | "Math", 382 | "Science", 383 | "Social", 384 | "Art" 385 | ], 386 | "marks": [ 387 | 63, 388 | 62, 389 | 63, 390 | 68 391 | ] 392 | }, 393 | { 394 | "name": "Tina", 395 | "age": 18, 396 | "address": "Dharan", 397 | "courses": [ 398 | "Math", 399 | "Science", 400 | "Social", 401 | "Art" 402 | ], 403 | "marks": [ 404 | 90, 405 | 66, 406 | 97, 407 | 84 408 | ] 409 | }, 410 | { 411 | "name": "Kumar", 412 | "age": 23, 413 | "address": "Itahari", 414 | "courses": [ 415 | "Math", 416 | "Science", 417 | "Social", 418 | "Art" 419 | ], 420 | "marks": [ 421 | 78, 422 | 63, 423 | 62, 424 | 63 425 | ] 426 | }, 427 | { 428 | "name": "Krishna", 429 | "age": 25, 430 | "address": "Ghorahi", 431 | "courses": [ 432 | "Math", 433 | "Science", 434 | "Social", 435 | "Art" 436 | ], 437 | "marks": [ 438 | 97, 439 | 82, 440 | 97, 441 | 60 442 | ] 443 | }, 444 | { 445 | "name": "Shyam", 446 | "age": 19, 447 | "address": "Nepalgunj", 448 | "courses": [ 449 | "Math", 450 | "Science", 451 | "Social", 452 | "Art" 453 | ], 454 | "marks": [ 455 | 68, 456 | 73, 457 | 95, 458 | 72 459 | ] 460 | }, 461 | { 462 | "name": "Tina", 463 | "age": 23, 464 | "address": "Hetauda", 465 | "courses": [ 466 | "Math", 467 | "Science", 468 | "Social", 469 | "Art" 470 | ], 471 | "marks": [ 472 | 69, 473 | 84, 474 | 91, 475 | 75 476 | ] 477 | }, 478 | { 479 | "name": "Sunita", 480 | "age": 25, 481 | "address": "Hetauda", 482 | "courses": [ 483 | "Math", 484 | "Science", 485 | "Social", 486 | "Art" 487 | ], 488 | "marks": [ 489 | 61, 490 | 100, 491 | 87, 492 | 78 493 | ] 494 | }, 495 | { 496 | "name": "Manish", 497 | "age": 25, 498 | "address": "Janakpur", 499 | "courses": [ 500 | "Math", 501 | "Science", 502 | "Social", 503 | "Art" 504 | ], 505 | "marks": [ 506 | 78, 507 | 93, 508 | 95, 509 | 83 510 | ] 511 | } 512 | ] -------------------------------------------------------------------------------- /tutorials/building_python_modules/building_python_module.md: -------------------------------------------------------------------------------- 1 | ## Building Python Modules 2 | * Creating Python modules allows you to structure your code efficiently, promote code reuse, and make it easier to manage large codebases. 3 | * A Python module is simply a Python file with a .py extension that contains Python code. 4 | * It can define functions, classes, and variables, and it can also include runnable code. 5 | 6 | ### What is a Python Module? 7 | 8 | A Python module is a file containing Python definitions and statements. The file name is the module name with the suffix .py added. For example, the file mymodule.py is a module, and its module name is mymodule. 9 | 10 | **Using a module** 11 | 12 | * To use the module, we need to import it in another python file. 13 | 14 | **The \_\_name__ Variable** 15 | 16 | * Every Python module has a special attribute called\_\_name__. 17 | 18 | * The value of \_\_name__ is set to '\_\_main__' when the module is run directly, and it is set to the module's name when it is imported. 19 | 20 | **Packages and \_\_init__.py** 21 | 22 | * A package is a directory containing multiple modules (i.e. multiple python files) and an \_\_init__.py file (this file can be empty). 23 | 24 | * Package Structure: 25 | ├── mypackage 26 | │ ├── \_\_init__.py 27 | │ ├── module1.py 28 | │ ├── module2.py 29 | 30 | 31 | **Module Search Path** 32 | 33 | Python looks for modules in the following places: 34 | * The directory containing the input script (or the current directory if no file is specified). 35 | * The directories listed in the PYTHONPATH environment variable. 36 | * The installation-dependent default path. 37 | 38 | **Relative Imports** 39 | * We can use relative imports within a package. 40 | * For example, if module1.py wants to import function2 from module2.py, you can do it as follows: 41 | > from .module2 import function2 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /tutorials/building_python_modules/mymath/__init__.py: -------------------------------------------------------------------------------- 1 | # This __init__.py file will allow us to treat the mypackage folder as a package 2 | 3 | # In this file, we will usually write imports to other modules 4 | 5 | # from calculator import add, mul 6 | # from geometry import area, perimeter 7 | 8 | # Here I have commented the imports because I am importing from run.py for learning purpose -------------------------------------------------------------------------------- /tutorials/building_python_modules/mymath/calculator.py: -------------------------------------------------------------------------------- 1 | # This is my first python module. The module name will be calculator. 2 | 3 | ''' 4 | This is a simple calculator. 5 | This module has four simple arithmetic functions that are defined below. 6 | ''' 7 | 8 | def add(x, y): 9 | return x + y 10 | 11 | def sub(x, y): 12 | return x - y 13 | 14 | def mul(x, y): 15 | return x * y 16 | 17 | def div(x, y): 18 | return x / y 19 | 20 | # Let's print the __name__ variable 21 | print("__name__ variable of calculator module: ", __name__) 22 | # The file which we excute from terminal will have __name__ variable as __main__. 23 | # And remaining files will have __name__ variable as the name of the file 24 | 25 | if __name__ == "__main__": 26 | # This block of code will be executed only when we run this file directly 27 | print("Adding 2 and 3 using calculator: ", add(2, 3)) 28 | print("Multiplying 2 and 3 using calculator: ", mul(2, 3)) -------------------------------------------------------------------------------- /tutorials/building_python_modules/mymath/geometry.py: -------------------------------------------------------------------------------- 1 | # This is my second python module. The module name will be geometry. 2 | # For addition and multiplication, we could use '+' and '*' operator directly 3 | # But I will use add() and mul() functions from calculator module so that we will learn about 4 | # relative imports 5 | 6 | 7 | # Relatively importing calculator module because calculator and geometry are on same parent package mymath 8 | from .calculator import add, mul # Here . represents the package at the same level 9 | 10 | ''' 11 | This is a simple geometry module. 12 | This module has four simple geometry functions that are defined below. 13 | ''' 14 | 15 | def area(length, breadth): 16 | return mul(length, breadth) 17 | 18 | def perimeter(length, breadth): 19 | return 2 * add(length, breadth) 20 | 21 | # Let's print the __name__ variable 22 | print("__name__ variable of geometry module: ", __name__) 23 | # The file which we excute from terminal will have __name__ variable as __main__. 24 | # And remaining files will have __name__ variable as the name of the file 25 | 26 | if __name__ == "__main__": 27 | # This block of code will be executed only when we run this file directly 28 | print("Area of rectangle with l=5 and b=2: ", area(5, 2)) 29 | print("Perimeter of rectangle with l=5 and b=2: ", perimeter(5, 2)) -------------------------------------------------------------------------------- /tutorials/building_python_modules/run.py: -------------------------------------------------------------------------------- 1 | # From this file I will use my custom package called mymath 2 | 3 | # Importing mymath module 4 | from mymath.calculator import * # This will import all the functions from the calculator module(* means import all) 5 | 6 | # Similarly we can import geometry module as well 7 | # But I will show you slightly different way to do it for learning purpose 8 | from mymath import geometry # This will import only geometry module 9 | 10 | 11 | # Let's print the __name__ variable 12 | print("__name__ variable of run.py: ", __name__) 13 | # The file which we excute from terminal will have __name__ variable as __main__. 14 | # And remaining files will have __name__ variable as the name of the file 15 | 16 | if __name__ == "__main__": 17 | print("Adding 2 and 3 using calculator: ", add(2, 3)) 18 | print("Multiplying 2 and 3 using calculator: ", mul(2, 3)) 19 | # We have imported only geometry module not its functions. So we need to use geometry. to access its functions 20 | print("Area of rectangle with l=5 and b=2: ", geometry.area(5, 2)) 21 | print("Perimeter of rectangle with l=5 and b=2: ", geometry.perimeter(5, 2)) -------------------------------------------------------------------------------- /tutorials/file_operations_in_python.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Lesson 5: File I/O operations\n", 8 | "\n", 9 | "* Objectives:\n", 10 | "\n", 11 | " 1. Understand the principles of files and file systems, in order to open files for reading or writing.\n", 12 | " \n", 13 | " 2. Create programs that can read data from or write data to a plain text file.\n", 14 | " \n", 15 | " 3. Create programs that can read or write JSON data.\n", 16 | "\n", 17 | " 4. Create programs that can read or write CSV data." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "### Understanding Files and File Systems\n", 25 | "\n", 26 | "* A file is a collection of data stored on a disk. \n", 27 | "\n", 28 | "* Files can be of various types, such as text files, binary files, JSON files, CSV files, etc. \n", 29 | "\n", 30 | "* Each file is identified by its filename and usually has a specific extension (e.g., .txt, .json, .csv)." 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "Opening Files\n", 38 | "\n", 39 | "* In Python, you can open files using the open() function, which returns a file object. \n", 40 | "\n", 41 | "* The open() function requires at least one argument: the name of the file. You can also specify the mode in which the file should be opened:\n", 42 | "\n", 43 | " * 'r' for reading (default)\n", 44 | "\n", 45 | " * 'w' for writing (creates a new file or truncates an existing file)\n", 46 | "\n", 47 | " * 'a' for appending (adds data to the end of the file)\n", 48 | "\n", 49 | " * 'b' for binary mode\n", 50 | " \n", 51 | " * 't' for text mode (default)\n", 52 | " \n", 53 | " * '+' for updating (reading and writing)\n" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "### I/O Operations on Plain Text File" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "Reading from a Plain Text File\n", 68 | "\n", 69 | "* We can read a text file using methods like read(), readline(), or readlines()." 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 11, 75 | "metadata": {}, 76 | "outputs": [ 77 | { 78 | "name": "stdout", 79 | "output_type": "stream", 80 | "text": [ 81 | "\n", 82 | "content with read: Hello World!\n", 83 | "Welcome to Python Programming Session\n" 84 | ] 85 | } 86 | ], 87 | "source": [ 88 | "# Opening a file for reading\n", 89 | "file = open('../data_files/example.txt', 'r')\n", 90 | "\n", 91 | "# Reading the contents\n", 92 | "content_with_read = file.read()\n", 93 | "# content_with_readline = file.readline()\n", 94 | "# content_with_readlines = file.readlines()\n", 95 | "\n", 96 | "print(\"\\ncontent with read: \", content_with_read)\n", 97 | "# print(\"\\ncontent with readline: \", content_with_readline)\n", 98 | "# print(\"\\ncontent with readlines: \", content_with_readlines)\n", 99 | "\n", 100 | "# Closing the file\n", 101 | "file.close()" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "Using context manager to open a file" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 5, 114 | "metadata": {}, 115 | "outputs": [ 116 | { 117 | "name": "stdout", 118 | "output_type": "stream", 119 | "text": [ 120 | "Hello World!\n", 121 | "Welcome to Python Programming Session\n" 122 | ] 123 | } 124 | ], 125 | "source": [ 126 | "# When we open a file with context manager, we don't need to close it explicitly\n", 127 | "with open('../data_files/example.txt', 'r') as file:\n", 128 | " content = file.read()\n", 129 | " print(content)" 130 | ] 131 | }, 132 | { 133 | "cell_type": "markdown", 134 | "metadata": {}, 135 | "source": [ 136 | "Writing to a Plain Text File\n", 137 | "\n", 138 | "* We can write to a text file using the write() method." 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 15, 144 | "metadata": {}, 145 | "outputs": [], 146 | "source": [ 147 | "# Using a context manager to open the file in write mode\n", 148 | "# This will override the contents of the file if the file already exits\n", 149 | "# Otherwise, it will create a new file\n", 150 | "with open('../data_files/example.txt', 'w') as file:\n", 151 | " file.write(\"Hello, Everyone!\\n\")\n", 152 | " file.write(\"I am learning Python Programming.\")" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": 16, 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [ 161 | "# Writing file in append mode\n", 162 | "with open('../data_files/example.txt', 'a') as file:\n", 163 | " file.write(\"Learning Python Programming is fun.\")" 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "### I/O Operations on JSON File\n", 171 | "\n", 172 | "* JSON (JavaScript Object Notation) is a lightweight **data interchange format**. \n", 173 | "\n", 174 | "* Python provides the json module to work with JSON data.\n", 175 | "\n", 176 | "* It is similar to python dictionary but not same.\n", 177 | "\n", 178 | "* JSON uses double quotes for strings and keys whereas in python dictionary we can use single or double quote." 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": {}, 184 | "source": [ 185 | "Writing to a JSON File\n" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": 20, 191 | "metadata": {}, 192 | "outputs": [], 193 | "source": [ 194 | "# We need json module to read and write JSON files\n", 195 | "import json\n", 196 | "\n", 197 | "# Sample data\n", 198 | "data = {\n", 199 | " \"name\": \"Ram\",\n", 200 | " \"age\": 30,\n", 201 | " \"city\": \"Bhaktapur\"\n", 202 | "}\n", 203 | "\n", 204 | "# Writing JSON Object to a file\n", 205 | "with open('../data_files/data.json', 'w') as file:\n", 206 | " json.dump(data, file, indent=4)\n" 207 | ] 208 | }, 209 | { 210 | "cell_type": "markdown", 211 | "metadata": {}, 212 | "source": [ 213 | "Reading from JSON File" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 22, 219 | "metadata": {}, 220 | "outputs": [ 221 | { 222 | "name": "stdout", 223 | "output_type": "stream", 224 | "text": [ 225 | "{'name': 'Ram', 'age': 30, 'city': 'Bhaktapur'}\n" 226 | ] 227 | } 228 | ], 229 | "source": [ 230 | "import json\n", 231 | "\n", 232 | "# Reading JSON from a file\n", 233 | "with open('../data_files/data.json', 'r') as file:\n", 234 | " data = json.load(file)\n", 235 | " print(data)" 236 | ] 237 | }, 238 | { 239 | "cell_type": "markdown", 240 | "metadata": {}, 241 | "source": [ 242 | "Accessing Elements of JSON Object or Parsing JSON Object" 243 | ] 244 | }, 245 | { 246 | "cell_type": "code", 247 | "execution_count": 26, 248 | "metadata": {}, 249 | "outputs": [ 250 | { 251 | "name": "stdout", 252 | "output_type": "stream", 253 | "text": [ 254 | "\n", 255 | "Ram\n", 256 | "Bhaktapur\n", 257 | "30\n" 258 | ] 259 | } 260 | ], 261 | "source": [ 262 | "print(type(data))\n", 263 | "print(data[\"name\"])\n", 264 | "print(data[\"city\"])\n", 265 | "print(data[\"age\"])" 266 | ] 267 | }, 268 | { 269 | "cell_type": "markdown", 270 | "metadata": {}, 271 | "source": [ 272 | "### I/O Operations on CSV File\n", 273 | "\n", 274 | "* CSV (Comma-Separated Values) files are commonly used for storing tabular data. \n", 275 | "\n", 276 | "* Python provides the csv module to work with CSV files." 277 | ] 278 | }, 279 | { 280 | "cell_type": "markdown", 281 | "metadata": {}, 282 | "source": [ 283 | "Writing CSV Data to CSV File" 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": 31, 289 | "metadata": {}, 290 | "outputs": [], 291 | "source": [ 292 | "# We need to use csv module to read and write CSV files\n", 293 | "import csv\n", 294 | "\n", 295 | "# Sample data\n", 296 | "csv_data = [\n", 297 | " ['Name', 'Age', 'City'],\n", 298 | " ['Ram', '36', 'Bhaktapur'],\n", 299 | " ['Sita', '25', 'Kathmandu'],\n", 300 | " ['Laxman', '35', 'Butwal']\n", 301 | "]\n", 302 | "\n", 303 | "# Writing to a CSV file\n", 304 | "with open('../data_files/data.csv', 'w') as file:\n", 305 | " writer = csv.writer(file)\n", 306 | " writer.writerows(csv_data)" 307 | ] 308 | }, 309 | { 310 | "cell_type": "markdown", 311 | "metadata": {}, 312 | "source": [ 313 | "Readint CSV File" 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "execution_count": 33, 319 | "metadata": {}, 320 | "outputs": [ 321 | { 322 | "name": "stdout", 323 | "output_type": "stream", 324 | "text": [ 325 | "['Name', 'Age', 'City']\n", 326 | "['Ram', '36', 'Bhaktapur']\n", 327 | "['Sita', '25', 'Kathmandu']\n", 328 | "['Laxman', '35', 'Butwal']\n" 329 | ] 330 | } 331 | ], 332 | "source": [ 333 | "import csv\n", 334 | "\n", 335 | "# Reading a CSV file\n", 336 | "with open('../data_files/data.csv', 'r') as file:\n", 337 | " reader = csv.reader(file)\n", 338 | " for row in reader:\n", 339 | " print(row)" 340 | ] 341 | }, 342 | { 343 | "cell_type": "markdown", 344 | "metadata": {}, 345 | "source": [ 346 | "### Assignment 5.1\n", 347 | "\n", 348 | "1. I have provided the students.json inside data_files folder that contains students records. Using that json, compute following things:\n", 349 | "\n", 350 | "* Calculate the percentage for each students assuming 100 is the full marks for each subjects. Also create a new json file with additional field \"percentage\" in json whose value will be the percentage you have computed.\n", 351 | "\n", 352 | "* Then load the new json file and generate the statistics of:\n", 353 | " * How many students failed? (i.e. percentage < 40)\n", 354 | " * How many students achieve third division (i.e. percentage between 40 and 50)\n", 355 | " * How many students achieve second division (i.e. percentage between 50 and 65)\n", 356 | " * How many students achieve first division (i.e. percentage between 65 and 80)\n", 357 | " * How many students achieve distinction division (i.e. percentage 80 and above )\n", 358 | "\n" 359 | ] 360 | }, 361 | { 362 | "cell_type": "code", 363 | "execution_count": null, 364 | "metadata": {}, 365 | "outputs": [], 366 | "source": [] 367 | } 368 | ], 369 | "metadata": { 370 | "kernelspec": { 371 | "display_name": "Python 3", 372 | "language": "python", 373 | "name": "python3" 374 | }, 375 | "language_info": { 376 | "codemirror_mode": { 377 | "name": "ipython", 378 | "version": 3 379 | }, 380 | "file_extension": ".py", 381 | "mimetype": "text/x-python", 382 | "name": "python", 383 | "nbconvert_exporter": "python", 384 | "pygments_lexer": "ipython3", 385 | "version": "3.8.10" 386 | } 387 | }, 388 | "nbformat": 4, 389 | "nbformat_minor": 2 390 | } 391 | -------------------------------------------------------------------------------- /tutorials/functional_programming_in_python.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Lesson 3: Functional Programming in Python\n", 8 | "\n", 9 | "* Objectives:\n", 10 | "\n", 11 | " 1. Create simple function interfaces using advanced arguments types, including keyword arguments and variadic arguments.\n", 12 | "\n", 13 | " 2. Create functional programs, using map/filter, reduce, lambdas, iterators, and generators.\n", 14 | " \n", 15 | " 3. Create decorators, high-level tools to transform functional behavior." 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "### Functions in Python\n", 23 | "\n", 24 | "* Functions in Python are reusable blocks of code designed to perform a specific task.\n", 25 | "\n", 26 | "* They help in organizing code, reducing redundancy, and improving readability.\n", 27 | "\n", 28 | "* Return:\n", 29 | "\n", 30 | " * Functions can return a value using the return statement.\n", 31 | " \n", 32 | " * A function without a return statement returns None by default." 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 28, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "# Syntax\n", 42 | "\n", 43 | "# Function definition\n", 44 | "def function_name(parameters):\n", 45 | " \"\"\"Docstring\"\"\"\n", 46 | " # body of the function\n", 47 | " \n", 48 | " # return value\n", 49 | " \n", 50 | "# Function call\n", 51 | "# function_name(parameters)" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 5, 57 | "metadata": {}, 58 | "outputs": [ 59 | { 60 | "name": "stdout", 61 | "output_type": "stream", 62 | "text": [ 63 | "30\n" 64 | ] 65 | } 66 | ], 67 | "source": [ 68 | "# Example function to add two numbers\n", 69 | "\n", 70 | "# Function definition\n", 71 | "def add_two_numbers(x, y):\n", 72 | " \"\"\"This function adds two numbers.\n", 73 | " \n", 74 | " Arguments:\n", 75 | " x: The first number.\n", 76 | " y: The second number.\n", 77 | " \n", 78 | " Returns:\n", 79 | " The sum of the two numbers.\n", 80 | " \n", 81 | " \"\"\"\n", 82 | " return x + y\n", 83 | "\n", 84 | "# Function call\n", 85 | "sum = add_two_numbers(10, 20)\n", 86 | "print(sum)" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "Positional Arguments\n", 94 | "* Arguments passed to the function in the correct positional order." 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 10, 100 | "metadata": {}, 101 | "outputs": [ 102 | { 103 | "name": "stdout", 104 | "output_type": "stream", 105 | "text": [ 106 | "30\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "# Function definition\n", 112 | "def add_two_numbers(x, y):\n", 113 | " return x + y\n", 114 | "\n", 115 | "# Function call with positional arguments\n", 116 | "sum = add_two_numbers(10, 20) # first argument is 10 i.e. x and second argument is 20 i.e. y\n", 117 | "print(sum)" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "Keyword Arguments\n", 125 | "* Arguments passed to the function with their parameter names." 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": 11, 131 | "metadata": {}, 132 | "outputs": [ 133 | { 134 | "name": "stdout", 135 | "output_type": "stream", 136 | "text": [ 137 | "30\n" 138 | ] 139 | } 140 | ], 141 | "source": [ 142 | "# Function definition\n", 143 | "def add_two_numbers(x, y):\n", 144 | " return x + y\n", 145 | "\n", 146 | "# Function call with keyword arguments\n", 147 | "sum = add_two_numbers(x=10, y=20)\n", 148 | "print(sum)" 149 | ] 150 | }, 151 | { 152 | "cell_type": "markdown", 153 | "metadata": {}, 154 | "source": [ 155 | "Default Arguments\n", 156 | "* Parameters with default values if no argument is provided." 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 13, 162 | "metadata": {}, 163 | "outputs": [ 164 | { 165 | "name": "stdout", 166 | "output_type": "stream", 167 | "text": [ 168 | "30\n" 169 | ] 170 | } 171 | ], 172 | "source": [ 173 | "# Function definition\n", 174 | "\n", 175 | "# IMP: Parameters with default values should be at the end\n", 176 | "def add_two_numbers(x, y=10):\n", 177 | " return x + y\n", 178 | "\n", 179 | "# Function call with keyword arguments\n", 180 | "sum = add_two_numbers(20)\n", 181 | "print(sum)" 182 | ] 183 | }, 184 | { 185 | "cell_type": "markdown", 186 | "metadata": {}, 187 | "source": [ 188 | "### Arbitary Arguments\n", 189 | "\n", 190 | "* Using *args and **kwargs to accept a variable number of arguments.\n", 191 | "\n", 192 | "* Before learning about *args and *kwargs, we must have good understanding of Unpacking conceps in python.\n" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "Unpacking in Python\n", 200 | "\n", 201 | "* Unpacking in Python is a powerful feature that allows you to assign values from a collection (such as a list, tuple, dictionary, etc.) to multiple variables in a single statement. \n", 202 | "\n", 203 | "* This feature can simplify your code and make it more readable." 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": 14, 209 | "metadata": {}, 210 | "outputs": [ 211 | { 212 | "name": "stdout", 213 | "output_type": "stream", 214 | "text": [ 215 | "3\n", 216 | "4\n" 217 | ] 218 | } 219 | ], 220 | "source": [ 221 | "# Unpacking a tuple\n", 222 | "point = (3, 4)\n", 223 | "x, y = point\n", 224 | "print(x) \n", 225 | "print(y) " 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 15, 231 | "metadata": {}, 232 | "outputs": [ 233 | { 234 | "name": "stdout", 235 | "output_type": "stream", 236 | "text": [ 237 | "red\n", 238 | "green\n", 239 | "blue\n" 240 | ] 241 | } 242 | ], 243 | "source": [ 244 | "# Unpacking a list\n", 245 | "colors = [\"red\", \"green\", \"blue\"]\n", 246 | "r, g, b = colors\n", 247 | "print(r) # Output: red\n", 248 | "print(g) # Output: green\n", 249 | "print(b) # Output: blue" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "Using the * Operator for Extended Unpacking\n", 257 | "\n", 258 | "* The * operator allows you to capture multiple items during unpacking." 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": 18, 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "name": "stdout", 268 | "output_type": "stream", 269 | "text": [ 270 | "1\n", 271 | "2\n", 272 | "[3, 4, 5]\n" 273 | ] 274 | } 275 | ], 276 | "source": [ 277 | "# Extended unpacking\n", 278 | "numbers = [1, 2, 3, 4, 5]\n", 279 | "first, second, *rest = numbers\n", 280 | "print(first) \n", 281 | "print(second) \n", 282 | "print(rest) " 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 19, 288 | "metadata": {}, 289 | "outputs": [ 290 | { 291 | "name": "stdout", 292 | "output_type": "stream", 293 | "text": [ 294 | "1\n", 295 | "[2, 3, 4]\n", 296 | "5\n" 297 | ] 298 | } 299 | ], 300 | "source": [ 301 | "# Using * in the middle\n", 302 | "numbers = [1, 2, 3, 4, 5]\n", 303 | "first, *middle, last = numbers\n", 304 | "print(first) \n", 305 | "print(middle) \n", 306 | "print(last) " 307 | ] 308 | }, 309 | { 310 | "cell_type": "markdown", 311 | "metadata": {}, 312 | "source": [ 313 | "'*args' and '**kwargs' in Python\n", 314 | "\n", 315 | "* args and **kwargs are used to pass a variable number of arguments to a function. So often called as variadic arguments and variadic functions.\n", 316 | "\n", 317 | "* This allows for greater flexibility and enables functions to handle a varying number of input arguments.\n", 318 | "\n", 319 | "* Usage: When you are unsure of how many arguments might be passed to a function.\n", 320 | "\n", 321 | "* *args allows a function to accept any number of positional arguments.\n", 322 | "\n", 323 | "* **kwargs allows a function to accept any number of keyword arguments.\n", 324 | "\n", 325 | "* When defining a function that uses *args and **kwargs, the order of parameters should be:\n", 326 | "\n", 327 | " 1. Regular positional arguments\n", 328 | " 2. *args\n", 329 | " 3. **kwargs" 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": 12, 335 | "metadata": {}, 336 | "outputs": [ 337 | { 338 | "name": "stdout", 339 | "output_type": "stream", 340 | "text": [ 341 | "args: (10, 20, 30, 40, 50)\n", 342 | "We can notice that args is a list\n", 343 | "sum, 150\n", 344 | "args: (10, 20)\n", 345 | "We can notice that args is a list\n", 346 | "sum, 30\n", 347 | "args: ()\n", 348 | "We can notice that args is a list\n", 349 | "sum, 0\n" 350 | ] 351 | } 352 | ], 353 | "source": [ 354 | "# *args in python\n", 355 | "\n", 356 | "# Function definition \n", 357 | "def add_numbers(*args):\n", 358 | " sum = 0\n", 359 | " print(\"args:\", args)\n", 360 | " print(\"We can notice that args is a tuple\")\n", 361 | " \n", 362 | " for num in args:\n", 363 | " sum = sum + num\n", 364 | " return sum\n", 365 | "\n", 366 | "# Function call\n", 367 | "# Here we can pass any number of positional arguments\n", 368 | "sum = add_numbers(10, 20, 30, 40, 50)\n", 369 | "print(\"sum: \", sum) \n", 370 | "sum = add_numbers(10, 20)\n", 371 | "print(\"sum: \", sum) \n", 372 | "sum = add_numbers()\n", 373 | "print(\"sum: \", sum) \n", 374 | " " 375 | ] 376 | }, 377 | { 378 | "cell_type": "code", 379 | "execution_count": 19, 380 | "metadata": {}, 381 | "outputs": [ 382 | { 383 | "name": "stdout", 384 | "output_type": "stream", 385 | "text": [ 386 | "kwargs: {'math': 70, 'english': 80, 'science': 90}\n", 387 | "We can notice that kwargs is a dictionary\n", 388 | "3\n", 389 | "Percentage: 80.0\n", 390 | "kwargs: {'math': 70, 'english': 80}\n", 391 | "We can notice that kwargs is a dictionary\n", 392 | "2\n", 393 | "Percentage: 75.0\n" 394 | ] 395 | } 396 | ], 397 | "source": [ 398 | "# **kwargs in python\n", 399 | "\n", 400 | "def calculate_percentage(**kwargs):\n", 401 | " sum = 0\n", 402 | " print(\"kwargs:\", kwargs)\n", 403 | " print(\"We can notice that kwargs is a dictionary\")\n", 404 | " print(len(kwargs))\n", 405 | " for key, value in kwargs.items():\n", 406 | " sum = sum + value\n", 407 | " return sum / len(kwargs) \n", 408 | "\n", 409 | "# Here we can pass any number of keyword arguments\n", 410 | "percentage = calculate_percentage(math=70, english=80, science=90)\n", 411 | "print(\"Percentage: \", percentage)\n", 412 | "\n", 413 | "percentage = calculate_percentage(math=70, english=80)\n", 414 | "print(\"Percentage: \", percentage)" 415 | ] 416 | }, 417 | { 418 | "cell_type": "code", 419 | "execution_count": 26, 420 | "metadata": {}, 421 | "outputs": [ 422 | { 423 | "name": "stdout", 424 | "output_type": "stream", 425 | "text": [ 426 | "Attributes:\n", 427 | "- Tall\n", 428 | "- Blue eyes\n", 429 | "\n", 430 | "Details:\n", 431 | "name: Rob\n", 432 | "age: 30\n", 433 | "job: Engineer\n" 434 | ] 435 | } 436 | ], 437 | "source": [ 438 | "# Combining both *args and **kwargs\n", 439 | "\n", 440 | "# Function definition with *args and **kwargs\n", 441 | "def describe_person(*args, **kwargs):\n", 442 | " print(\"Attributes:\")\n", 443 | " for arg in args:\n", 444 | " print(f\"- {arg}\")\n", 445 | " print(\"\\nDetails:\")\n", 446 | " for key, value in kwargs.items():\n", 447 | " print(f\"{key}: {value}\")\n", 448 | "\n", 449 | "# Function call with *args and **kwargs\n", 450 | "describe_person(\"Tall\", \"Blue eyes\", name=\"Rob\", age=30, job=\"Engineer\")" 451 | ] 452 | }, 453 | { 454 | "cell_type": "code", 455 | "execution_count": 27, 456 | "metadata": {}, 457 | "outputs": [ 458 | { 459 | "name": "stdout", 460 | "output_type": "stream", 461 | "text": [ 462 | "Name: Rob\n", 463 | "Age: 30\n", 464 | "Attributes:\n", 465 | "- Tall\n", 466 | "- Blue eyes\n", 467 | "\n", 468 | "Details:\n", 469 | "job: Engineer\n" 470 | ] 471 | } 472 | ], 473 | "source": [ 474 | "# Combining positional arguments, *args, and keyword arguments, **kwargs\n", 475 | "\n", 476 | "# Function definition with positional arguments, *args and **kwargs\n", 477 | "def describe_person(name, age, *args, **kwargs):\n", 478 | " print(\"Name:\", name)\n", 479 | " print(\"Age:\", age)\n", 480 | " print(\"Attributes:\")\n", 481 | " for arg in args:\n", 482 | " print(f\"- {arg}\")\n", 483 | " print(\"\\nDetails:\")\n", 484 | " for key, value in kwargs.items():\n", 485 | " print(f\"{key}: {value}\")\n", 486 | " \n", 487 | "# Function call with positional arguments, *args, and keyword arguments, **kwargs\n", 488 | "describe_person(\"Rob\", 30, \"Tall\", \"Blue eyes\", job=\"Engineer\")" 489 | ] 490 | }, 491 | { 492 | "cell_type": "markdown", 493 | "metadata": {}, 494 | "source": [ 495 | "### Assignment 3.1\n", 496 | "\n", 497 | "1. You are given a large integer represented as an integer list of digits, where each digits[i] is the ith digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading 0's. Increment the large integer by one and return the resulting ;list of digits. Implement the logic by creating a function.\n", 498 | "\n", 499 | " Example 1:\n", 500 | " Input: digits = [1,2,3]\n", 501 | " Output: [1,2,4]\n", 502 | " Explanation: The array represents the integer 123.\n", 503 | " Incrementing by one gives 123 + 1 = 124.\n", 504 | " Thus, the result should be [1,2,4].\n", 505 | "\n", 506 | " Example 2:\n", 507 | " Input: digits = [4,3,2,1]\n", 508 | " Output: [4,3,2,2]\n", 509 | " Explanation: The array represents the integer 4321.\n", 510 | " Incrementing by one gives 4321 + 1 = 4322.\n", 511 | " Thus, the result should be [4,3,2,2].\n", 512 | "\n", 513 | " Example 3:\n", 514 | " Input: digits = [9]\n", 515 | " Output: [1,0]\n", 516 | " Explanation: The array represents the integer 9.\n", 517 | " Incrementing by one gives 9 + 1 = 10.\n", 518 | " Thus, the result should be [1,0]." 519 | ] 520 | }, 521 | { 522 | "cell_type": "markdown", 523 | "metadata": {}, 524 | "source": [ 525 | "### Iterable and Iterators in Python\n", 526 | "\n", 527 | "* Understanding iterators and iterables is fundamental to mastering Python's capabilities for looping and data manipulation.\n", 528 | "\n", 529 | "* These concepts are central to Python's for-loops and other collection-processing mechanisms." 530 | ] 531 | }, 532 | { 533 | "cell_type": "markdown", 534 | "metadata": {}, 535 | "source": [ 536 | "### Iterable\n", 537 | "\n", 538 | "* An iterable is any Python object capable of returning its members one at a time, allowing it to be iterated over in a loop.\n", 539 | "\n", 540 | "* Examples: Lists, tuples, strings, dictionaries, and sets \n", 541 | "\n", 542 | "* An object is considered an iterable if it implements the __iter__() method, which returns an iterator." 543 | ] 544 | }, 545 | { 546 | "cell_type": "code", 547 | "execution_count": 48, 548 | "metadata": {}, 549 | "outputs": [], 550 | "source": [ 551 | "# List is an iterable\n", 552 | "my_list = [1, 2, 3, 4, 5]\n", 553 | "\n", 554 | "# String is an iterable\n", 555 | "my_string = \"hello\"\n" 556 | ] 557 | }, 558 | { 559 | "cell_type": "markdown", 560 | "metadata": {}, 561 | "source": [ 562 | "### Iterator\n", 563 | "\n", 564 | "* An iterator is an object representing a stream of data. \n", 565 | "\n", 566 | "* It returns one element at a time when you call the next() function on it.\n", 567 | "\n", 568 | "* Examples: Objects that implement both the __iter__() and __next__() methods are iterators.\n", 569 | "\n", 570 | "* An iterator keeps state and remembers where it is during iteration. When __next__() is called, the iterator returns the next item in the sequence.\n", 571 | "\n", 572 | "* If there are no further elements, then the method __next__() will raise an exception to StopIteration.\n", 573 | "\n", 574 | "* Every iterator is basically iterable but reverse may not be true." 575 | ] 576 | }, 577 | { 578 | "cell_type": "code", 579 | "execution_count": 6, 580 | "metadata": {}, 581 | "outputs": [ 582 | { 583 | "name": "stdout", 584 | "output_type": "stream", 585 | "text": [ 586 | "1\n", 587 | "2\n", 588 | "3\n", 589 | "4\n", 590 | "5\n" 591 | ] 592 | }, 593 | { 594 | "ename": "StopIteration", 595 | "evalue": "", 596 | "output_type": "error", 597 | "traceback": [ 598 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 599 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 600 | "Cell \u001b[0;32mIn[6], line 11\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mnext\u001b[39m(iterator)) \n\u001b[1;32m 10\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mnext\u001b[39m(iterator)) \n\u001b[0;32m---> 11\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28;43mnext\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43miterator\u001b[49m\u001b[43m)\u001b[49m) \u001b[38;5;66;03m# This will raise StopIteration error\u001b[39;00m\n", 601 | "\u001b[0;31mStopIteration\u001b[0m: " 602 | ] 603 | } 604 | ], 605 | "source": [ 606 | "# Creating an iterator from an iterable\n", 607 | "my_list = [1, 2, 3, 4, 5]\n", 608 | "iterator = iter(my_list) # iter() method is used to create an iterator from an iterable\n", 609 | "\n", 610 | "# Using next() to get items\n", 611 | "print(next(iterator)) \n", 612 | "print(next(iterator)) \n", 613 | "print(next(iterator)) \n", 614 | "print(next(iterator)) \n", 615 | "print(next(iterator)) \n", 616 | "print(next(iterator)) # This will raise StopIteration error" 617 | ] 618 | }, 619 | { 620 | "cell_type": "code", 621 | "execution_count": 7, 622 | "metadata": {}, 623 | "outputs": [ 624 | { 625 | "name": "stdout", 626 | "output_type": "stream", 627 | "text": [ 628 | "1\n", 629 | "2\n", 630 | "3\n", 631 | "4\n", 632 | "5\n" 633 | ] 634 | } 635 | ], 636 | "source": [ 637 | "my_list = [1, 2, 3, 4, 5]\n", 638 | "iterator = iter(my_list) # iter() method is used to create an iterator from an iterable\n", 639 | "\n", 640 | "# Using loops to get items\n", 641 | "# We can loop over iterators to get items\n", 642 | "for item in iterator:\n", 643 | " print(item)" 644 | ] 645 | }, 646 | { 647 | "cell_type": "markdown", 648 | "metadata": {}, 649 | "source": [ 650 | "### lambda Function in Python\n", 651 | "\n", 652 | "* Also known as anonymous function because it is unnamed function.\n", 653 | "\n", 654 | "* The are small, unnamed functions defined using the lambda keyword. \n", 655 | "\n", 656 | "* They are often used for short, simple operations and can be especially useful when passing functions as arguments to higher-order functions like map, filter, and reduce.\n", 657 | "\n", 658 | "* Syntax: \n", 659 | "\n", 660 | " lambda arguments: expression\n", 661 | "\n", 662 | "* Syntax with conditional expression\n", 663 | "\n", 664 | " lambda arguments: value_if_true if condition else value_if_false\n" 665 | ] 666 | }, 667 | { 668 | "cell_type": "code", 669 | "execution_count": 40, 670 | "metadata": {}, 671 | "outputs": [ 672 | { 673 | "name": "stdout", 674 | "output_type": "stream", 675 | "text": [ 676 | "8\n" 677 | ] 678 | } 679 | ], 680 | "source": [ 681 | "# Regula function\n", 682 | "def add(x, y):\n", 683 | " return x + y\n", 684 | "\n", 685 | "print(add(3, 5)) " 686 | ] 687 | }, 688 | { 689 | "cell_type": "code", 690 | "execution_count": 42, 691 | "metadata": {}, 692 | "outputs": [ 693 | { 694 | "name": "stdout", 695 | "output_type": "stream", 696 | "text": [ 697 | "8\n" 698 | ] 699 | } 700 | ], 701 | "source": [ 702 | "# lambda function\n", 703 | "add = lambda x, y: x + y\n", 704 | "print(add(3, 5))" 705 | ] 706 | }, 707 | { 708 | "cell_type": "code", 709 | "execution_count": 47, 710 | "metadata": {}, 711 | "outputs": [ 712 | { 713 | "name": "stdout", 714 | "output_type": "stream", 715 | "text": [ 716 | "Even\n", 717 | "Odd\n" 718 | ] 719 | } 720 | ], 721 | "source": [ 722 | "# lambda function with if-else\n", 723 | "check_even_odd = lambda x: \"Even\" if x % 2 == 0 else \"Odd\"\n", 724 | "\n", 725 | "print(check_even_odd(10)) \n", 726 | "print(check_even_odd(7)) \n" 727 | ] 728 | }, 729 | { 730 | "cell_type": "markdown", 731 | "metadata": {}, 732 | "source": [ 733 | "### map, filter, and reduce in Python\n", 734 | "\n", 735 | "* map, filter, and reduce are functional programming tools in Python that allow for efficient and concise data processing.\n", 736 | "\n", 737 | "* They enable you to apply functions to collections of data, filter out unwanted elements, and perform cumulative operations.\n", 738 | "\n", 739 | "* They are higher order functions because they take function as an argument." 740 | ] 741 | }, 742 | { 743 | "cell_type": "markdown", 744 | "metadata": {}, 745 | "source": [ 746 | "### map Function\n", 747 | "\n", 748 | "* The map function applies a given function to all items in an input list (or any iterable) and returns an iterator with the results.\n", 749 | "\n", 750 | "* Syntax: map(function, *iterable)\n", 751 | "\n", 752 | "* Usage: Useful for applying a transformation to each item in a collection." 753 | ] 754 | }, 755 | { 756 | "cell_type": "code", 757 | "execution_count": 34, 758 | "metadata": {}, 759 | "outputs": [ 760 | { 761 | "name": "stdout", 762 | "output_type": "stream", 763 | "text": [ 764 | "[1, 4, 9, 16, 25]\n" 765 | ] 766 | } 767 | ], 768 | "source": [ 769 | "def square(x):\n", 770 | " return x * x\n", 771 | "\n", 772 | "numbers = [1, 2, 3, 4, 5]\n", 773 | "squared_numbers = map(square, numbers) # output is a map object which is an iterator so we need to convert it into a iterable\n", 774 | "squared_numbers = list(squared_numbers)\n", 775 | "\n", 776 | "print(squared_numbers)\n" 777 | ] 778 | }, 779 | { 780 | "cell_type": "code", 781 | "execution_count": 43, 782 | "metadata": {}, 783 | "outputs": [ 784 | { 785 | "name": "stdout", 786 | "output_type": "stream", 787 | "text": [ 788 | "[1, 4, 9, 16, 25]\n" 789 | ] 790 | } 791 | ], 792 | "source": [ 793 | "# map function with lambda function\n", 794 | "\n", 795 | "numbers = [1, 2, 3, 4, 5]\n", 796 | "squared_numbers = map(lambda x: x * x, numbers)\n", 797 | "squared_numbers = list(squared_numbers)\n", 798 | "\n", 799 | "print(squared_numbers)" 800 | ] 801 | }, 802 | { 803 | "cell_type": "markdown", 804 | "metadata": {}, 805 | "source": [ 806 | "### filter Function\n", 807 | "\n", 808 | "* The filter function constructs an iterator from elements of an iterable for which a function returns true.\n", 809 | "\n", 810 | "* Syntax: filter(function, iterable)\n", 811 | "\n", 812 | "* Usage: Useful for filtering elements of a collection based on a condition." 813 | ] 814 | }, 815 | { 816 | "cell_type": "code", 817 | "execution_count": 36, 818 | "metadata": {}, 819 | "outputs": [ 820 | { 821 | "name": "stdout", 822 | "output_type": "stream", 823 | "text": [ 824 | "[2, 4, 6]\n" 825 | ] 826 | } 827 | ], 828 | "source": [ 829 | "def is_even(x):\n", 830 | " return x % 2 == 0\n", 831 | "\n", 832 | "numbers = [1, 2, 3, 4, 5, 6]\n", 833 | "\n", 834 | "even_numbers = filter(is_even, numbers) # is_even is the function that must return True or False\n", 835 | "\n", 836 | "print(list(even_numbers))" 837 | ] 838 | }, 839 | { 840 | "cell_type": "code", 841 | "execution_count": 44, 842 | "metadata": {}, 843 | "outputs": [ 844 | { 845 | "name": "stdout", 846 | "output_type": "stream", 847 | "text": [ 848 | "[2, 4, 6]\n" 849 | ] 850 | } 851 | ], 852 | "source": [ 853 | "# filter function with lambda function\n", 854 | "\n", 855 | "numbers = [1, 2, 3, 4, 5, 6]\n", 856 | "even_numbers = filter(lambda x: x % 2 == 0, numbers)\n", 857 | "even_numbers = list(even_numbers)\n", 858 | "\n", 859 | "print(even_numbers)" 860 | ] 861 | }, 862 | { 863 | "cell_type": "markdown", 864 | "metadata": {}, 865 | "source": [ 866 | "### reduce Function\n", 867 | "\n", 868 | "* The reduce function applies a binary function to the items of an iterable, cumulatively, from left to right, to reduce the iterable to a single value.\n", 869 | "\n", 870 | "* Syntax: reduce(function, iterable[, initial])\n", 871 | "\n", 872 | "* Usage: Useful for performing cumulative operations on a collection of data.\n" 873 | ] 874 | }, 875 | { 876 | "cell_type": "code", 877 | "execution_count": 39, 878 | "metadata": {}, 879 | "outputs": [ 880 | { 881 | "name": "stdout", 882 | "output_type": "stream", 883 | "text": [ 884 | "15\n" 885 | ] 886 | } 887 | ], 888 | "source": [ 889 | "from functools import reduce\n", 890 | "\n", 891 | "def add(x, y):\n", 892 | " return x + y\n", 893 | "\n", 894 | "numbers = [1, 2, 3, 4, 5]\n", 895 | "\n", 896 | "sum_of_numbers = reduce(add, numbers)\n", 897 | "\n", 898 | "print(sum_of_numbers) \n" 899 | ] 900 | }, 901 | { 902 | "cell_type": "code", 903 | "execution_count": 45, 904 | "metadata": {}, 905 | "outputs": [ 906 | { 907 | "name": "stdout", 908 | "output_type": "stream", 909 | "text": [ 910 | "15\n" 911 | ] 912 | } 913 | ], 914 | "source": [ 915 | "# reduce function with lambda function\n", 916 | "from functools import reduce\n", 917 | "\n", 918 | "numbers = [1, 2, 3, 4, 5]\n", 919 | "sum_of_numbers = reduce(lambda x, y: x + y, numbers)\n", 920 | "\n", 921 | "print(sum_of_numbers)" 922 | ] 923 | }, 924 | { 925 | "cell_type": "markdown", 926 | "metadata": {}, 927 | "source": [ 928 | "### Generators in Python\n", 929 | "\n", 930 | "* Generator is a function that returns an iterator that produces a sequence of values when iterated over.\n", 931 | "\n", 932 | "* Generators are useful when we want to produce a large sequence of values, but we don't want to store all of them in memory at once.\n", 933 | "\n", 934 | "* Generators generate values on the fly and can be iterated over only once.\n", 935 | "\n", 936 | "* Benefits: \n", 937 | "\n", 938 | " * Memory Efficiency: Generators are memory-efficient because they yield items one at a time and do not store the entire sequence in memory.\n", 939 | "\n", 940 | " * Lazy Evaluation: Generators generate items only when requested, which can improve performance when dealing with large datasets.\n", 941 | "\n", 942 | "\n" 943 | ] 944 | }, 945 | { 946 | "cell_type": "markdown", 947 | "metadata": {}, 948 | "source": [ 949 | "Creating Generator using Generator Function\n", 950 | "* A generator function is defined like a normal function but uses the yield statement to return data instead of return statement. \n", 951 | "\n", 952 | "* When yield is called, the function's state is saved, and the value is returned to the caller. The function can be resumed later from where it left off." 953 | ] 954 | }, 955 | { 956 | "cell_type": "code", 957 | "execution_count": 15, 958 | "metadata": {}, 959 | "outputs": [ 960 | { 961 | "name": "stdout", 962 | "output_type": "stream", 963 | "text": [ 964 | "\n", 965 | "0\n", 966 | "1\n", 967 | "2\n", 968 | "3\n", 969 | "4\n" 970 | ] 971 | } 972 | ], 973 | "source": [ 974 | "# Generator function definition\n", 975 | "def my_generator(n):\n", 976 | " for i in range(n):\n", 977 | " yield i\n", 978 | "\n", 979 | "# When we call the generator function, it returns an iterator object\n", 980 | "my_iterator = my_generator(5)\n", 981 | "print(my_iterator)\n", 982 | "\n", 983 | "# Similar to any other iterator, we can use access the items in two different ways\n", 984 | " # 1. Using a for loop\n", 985 | " # 2. Using next() function\n", 986 | " \n", 987 | "# Using a for loop\n", 988 | "for item in my_iterator:\n", 989 | " print(item)\n", 990 | "\n", 991 | "# IMP: Generator will generate items one by one and only once\n", 992 | "# So if we try to loop over the generator again, it will no longer generate items\n", 993 | "for item in my_iterator:\n", 994 | " print(\"Again\",item)" 995 | ] 996 | }, 997 | { 998 | "cell_type": "code", 999 | "execution_count": 16, 1000 | "metadata": {}, 1001 | "outputs": [ 1002 | { 1003 | "name": "stdout", 1004 | "output_type": "stream", 1005 | "text": [ 1006 | "0\n", 1007 | "1\n", 1008 | "2\n", 1009 | "3\n", 1010 | "4\n" 1011 | ] 1012 | }, 1013 | { 1014 | "ename": "StopIteration", 1015 | "evalue": "", 1016 | "output_type": "error", 1017 | "traceback": [ 1018 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 1019 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 1020 | "Cell \u001b[0;32mIn[16], line 8\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mnext\u001b[39m(my_iterator)) \u001b[38;5;66;03m# This will return 3\u001b[39;00m\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mnext\u001b[39m(my_iterator)) \u001b[38;5;66;03m# This will return 4\u001b[39;00m\n\u001b[0;32m----> 8\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28;43mnext\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mmy_iterator\u001b[49m\u001b[43m)\u001b[49m) \u001b[38;5;66;03m# This will raise StopIteration error\u001b[39;00m\n", 1021 | "\u001b[0;31mStopIteration\u001b[0m: " 1022 | ] 1023 | } 1024 | ], 1025 | "source": [ 1026 | "# Using next() function\n", 1027 | "my_iterator = my_generator(5)\n", 1028 | "print(next(my_iterator)) # This will return 0\n", 1029 | "print(next(my_iterator)) # This will return 1\n", 1030 | "print(next(my_iterator)) # This will return 2\n", 1031 | "print(next(my_iterator)) # This will return 3\n", 1032 | "print(next(my_iterator)) # This will return 4\n", 1033 | "print(next(my_iterator)) # This will raise StopIteration error" 1034 | ] 1035 | }, 1036 | { 1037 | "cell_type": "markdown", 1038 | "metadata": {}, 1039 | "source": [ 1040 | "Creating Generators Using Generator Expression\n", 1041 | "\n", 1042 | "* Generator expression is a concise way to create a generator object.\n", 1043 | "\n", 1044 | "* It is similar to a list comprehension, but instead of creating a list, it creates a generator object that can be iterated over to produce the values in the generator.\n", 1045 | "\n", 1046 | "* It uses parenthesis () instead of square bracket.\n", 1047 | "* Syntax: \n", 1048 | "\n", 1049 | " (expression for item in iterable)" 1050 | ] 1051 | }, 1052 | { 1053 | "cell_type": "code", 1054 | "execution_count": 17, 1055 | "metadata": {}, 1056 | "outputs": [ 1057 | { 1058 | "name": "stdout", 1059 | "output_type": "stream", 1060 | "text": [ 1061 | "0\n", 1062 | "1\n", 1063 | "2\n", 1064 | "3\n", 1065 | "4\n" 1066 | ] 1067 | } 1068 | ], 1069 | "source": [ 1070 | "my_iterator_from_gen_expr = (x for x in range(5))\n", 1071 | "\n", 1072 | "# Using the generator expression\n", 1073 | "for value in my_iterator_from_gen_expr:\n", 1074 | " print(value)\n" 1075 | ] 1076 | }, 1077 | { 1078 | "cell_type": "markdown", 1079 | "metadata": {}, 1080 | "source": [ 1081 | "### Passing Function as Arguments\n", 1082 | "\n", 1083 | "* In python, we can pass function as arguments similar to integers, floats, strings etc. because function is also an object." 1084 | ] 1085 | }, 1086 | { 1087 | "cell_type": "code", 1088 | "execution_count": 19, 1089 | "metadata": {}, 1090 | "outputs": [ 1091 | { 1092 | "name": "stdout", 1093 | "output_type": "stream", 1094 | "text": [ 1095 | "Hello from function2\n", 1096 | "Hello from function1\n" 1097 | ] 1098 | } 1099 | ], 1100 | "source": [ 1101 | "def function1():\n", 1102 | " print(\"Hello from function1\")\n", 1103 | " \n", 1104 | "def function2(func):\n", 1105 | " print(\"Hello from function2\")\n", 1106 | " func()\n", 1107 | " \n", 1108 | "# Calling function2 with function1 as an argument\n", 1109 | "function2(function1) # We pass only reference to function1 object" 1110 | ] 1111 | }, 1112 | { 1113 | "cell_type": "markdown", 1114 | "metadata": {}, 1115 | "source": [ 1116 | "### Returning Function\n" 1117 | ] 1118 | }, 1119 | { 1120 | "cell_type": "code", 1121 | "execution_count": 20, 1122 | "metadata": {}, 1123 | "outputs": [ 1124 | { 1125 | "name": "stdout", 1126 | "output_type": "stream", 1127 | "text": [ 1128 | "Hello from outer_func\n", 1129 | "Hello from inner_func\n" 1130 | ] 1131 | } 1132 | ], 1133 | "source": [ 1134 | "def outer_func():\n", 1135 | " print(\"Hello from outer_func\")\n", 1136 | " \n", 1137 | " # Defining function within function\n", 1138 | " def inner_func():\n", 1139 | " print(\"Hello from inner_func\")\n", 1140 | " \n", 1141 | " return inner_func # Returning only reference to inner_func without calling\n", 1142 | "\n", 1143 | "\n", 1144 | "my_func = outer_func()\n", 1145 | "my_func()" 1146 | ] 1147 | }, 1148 | { 1149 | "cell_type": "markdown", 1150 | "metadata": {}, 1151 | "source": [ 1152 | "### Decorators in Python\n", 1153 | "* A decorator is a function that takes another function and extends or alters its behavior. \n", 1154 | "\n", 1155 | "* We use decorators to add additional functionality to existing functions.\n", 1156 | "\n", 1157 | "* A basic decorator takes a function as an argument and returns a new function that adds some behavior before or after the original function.\n", 1158 | "\n", 1159 | "* Decorators are commonly used for logging, access control, instrumentation, caching, and more.\n", 1160 | "\n", 1161 | "* While creating decorator we need to follow three major steps:\n", 1162 | " 1. We pass our original function to our decorator function.\n", 1163 | "\n", 1164 | " 2. Inside decorator function, we have to define a wrapper function which will add additional logic and then call the original function and then return the result.\n", 1165 | " \n", 1166 | " 3. At last we have to return the reference of wrapper function from our decorator function." 1167 | ] 1168 | }, 1169 | { 1170 | "cell_type": "code", 1171 | "execution_count": 30, 1172 | "metadata": {}, 1173 | "outputs": [ 1174 | { 1175 | "name": "stdout", 1176 | "output_type": "stream", 1177 | "text": [ 1178 | "Squrare root of 4: 2.0\n" 1179 | ] 1180 | }, 1181 | { 1182 | "ename": "ValueError", 1183 | "evalue": "Only positive numbers are allowed. Error msg displayed from decorator.", 1184 | "output_type": "error", 1185 | "traceback": [ 1186 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 1187 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 1188 | "Cell \u001b[0;32mIn[30], line 23\u001b[0m\n\u001b[1;32m 21\u001b[0m func \u001b[38;5;241m=\u001b[39m positive_number_only_decorator(calculate_square_root)\n\u001b[1;32m 22\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mSqurare root of 4: \u001b[39m\u001b[38;5;124m\"\u001b[39m, func(\u001b[38;5;241m4\u001b[39m))\n\u001b[0;32m---> 23\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mSquare root of -4:\u001b[39m\u001b[38;5;124m\"\u001b[39m,\u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m4\u001b[39;49m\u001b[43m)\u001b[49m) \u001b[38;5;66;03m# This will raise error\u001b[39;00m\n", 1189 | "Cell \u001b[0;32mIn[30], line 14\u001b[0m, in \u001b[0;36mpositive_number_only_decorator..wrapper\u001b[0;34m(num)\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mwrapper\u001b[39m(num): \u001b[38;5;66;03m# The wrapper function will take argument num from the original function\u001b[39;00m\n\u001b[1;32m 13\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m num \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[0;32m---> 14\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mOnly positive numbers are allowed. Error msg displayed from decorator.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 15\u001b[0m square_root \u001b[38;5;241m=\u001b[39m func(num)\n\u001b[1;32m 16\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m square_root\n", 1190 | "\u001b[0;31mValueError\u001b[0m: Only positive numbers are allowed. Error msg displayed from decorator." 1191 | ] 1192 | } 1193 | ], 1194 | "source": [ 1195 | "import math\n", 1196 | "\n", 1197 | "# This is our original function\n", 1198 | "def calculate_square_root(number):\n", 1199 | " \"\"\"Calculate the square root of a positive number.\"\"\"\n", 1200 | " return math.sqrt(number)\n", 1201 | "\n", 1202 | "\n", 1203 | "# This is our decorator which checks if the number is positive (additional logic)\n", 1204 | "def positive_number_only_decorator(func):\n", 1205 | "\n", 1206 | " def wrapper(num): # The wrapper function will take argument num from the original function\n", 1207 | " if num < 0:\n", 1208 | " raise ValueError(\"Only positive numbers are allowed. Error msg displayed from decorator.\")\n", 1209 | " square_root = func(num)\n", 1210 | " return square_root\n", 1211 | " \n", 1212 | " return wrapper\n", 1213 | "\n", 1214 | "# Decorating our original function\n", 1215 | "func = positive_number_only_decorator(calculate_square_root)\n", 1216 | "print(\"Squrare root of 4: \", func(4))\n", 1217 | "print(\"Square root of -4:\",func(-4)) # This will raise error" 1218 | ] 1219 | }, 1220 | { 1221 | "cell_type": "markdown", 1222 | "metadata": {}, 1223 | "source": [ 1224 | "Shorthand way to use decorator\n", 1225 | "* We can decorate our original function by using @ syntax.\n", 1226 | "\n", 1227 | "* We specify the decorator name to be used before the definition of original function as shown below." 1228 | ] 1229 | }, 1230 | { 1231 | "cell_type": "code", 1232 | "execution_count": 29, 1233 | "metadata": {}, 1234 | "outputs": [ 1235 | { 1236 | "name": "stdout", 1237 | "output_type": "stream", 1238 | "text": [ 1239 | "Squrare root of 4: 2.0\n" 1240 | ] 1241 | }, 1242 | { 1243 | "ename": "ValueError", 1244 | "evalue": "Only positive numbers are allowed. Error msg displayed from decorator.", 1245 | "output_type": "error", 1246 | "traceback": [ 1247 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 1248 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 1249 | "Cell \u001b[0;32mIn[29], line 21\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m math\u001b[38;5;241m.\u001b[39msqrt(number)\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mSqurare root of 4: \u001b[39m\u001b[38;5;124m\"\u001b[39m, func(\u001b[38;5;241m4\u001b[39m))\n\u001b[0;32m---> 21\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mSquare root of -4:\u001b[39m\u001b[38;5;124m\"\u001b[39m,\u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m4\u001b[39;49m\u001b[43m)\u001b[49m) \u001b[38;5;66;03m# This will raise error\u001b[39;00m\n", 1250 | "Cell \u001b[0;32mIn[28], line 14\u001b[0m, in \u001b[0;36mpositive_number_only_decorator..wrapper\u001b[0;34m(num)\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mwrapper\u001b[39m(num): \u001b[38;5;66;03m# The wrapper function will take argument num from the original function\u001b[39;00m\n\u001b[1;32m 13\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m num \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[0;32m---> 14\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mOnly positive numbers are allowed. Error msg displayed from decorator.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 15\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m func(num)\n", 1251 | "\u001b[0;31mValueError\u001b[0m: Only positive numbers are allowed. Error msg displayed from decorator." 1252 | ] 1253 | } 1254 | ], 1255 | "source": [ 1256 | "import math\n", 1257 | "\n", 1258 | "# This is our decorator which checks if the number is positive (additional logic)\n", 1259 | "def positive_number_only_decorator(func):\n", 1260 | "\n", 1261 | " def wrapper(num): # The wrapper function will take argument num from the original function\n", 1262 | " if num < 0:\n", 1263 | " raise ValueError(\"Only positive numbers are allowed. Error msg displayed from decorator.\")\n", 1264 | " square_root = func(num)\n", 1265 | " return square_root\n", 1266 | " \n", 1267 | " return wrapper\n", 1268 | "\n", 1269 | "# Decorating our original function\n", 1270 | "@positive_number_only_decorator\n", 1271 | "def calculate_square_root(number):\n", 1272 | " \"\"\"Calculate the square root of a positive number.\"\"\"\n", 1273 | " return math.sqrt(number)\n", 1274 | "\n", 1275 | "print(\"Squrare root of 4: \", func(4))\n", 1276 | "print(\"Square root of -4:\",func(-4)) # This will raise error" 1277 | ] 1278 | }, 1279 | { 1280 | "cell_type": "markdown", 1281 | "metadata": {}, 1282 | "source": [ 1283 | "### Assignment 3.2\n", 1284 | "1. Use a custom defined timeit decorator to measure the execution time of any function. Use time module to compute time.\n", 1285 | " \n", 1286 | " Hint:\n", 1287 | " import time\n", 1288 | " current_time = time.time()" 1289 | ] 1290 | }, 1291 | { 1292 | "cell_type": "code", 1293 | "execution_count": null, 1294 | "metadata": {}, 1295 | "outputs": [], 1296 | "source": [ 1297 | " " 1298 | ] 1299 | } 1300 | ], 1301 | "metadata": { 1302 | "kernelspec": { 1303 | "display_name": "Python 3", 1304 | "language": "python", 1305 | "name": "python3" 1306 | }, 1307 | "language_info": { 1308 | "codemirror_mode": { 1309 | "name": "ipython", 1310 | "version": 3 1311 | }, 1312 | "file_extension": ".py", 1313 | "mimetype": "text/x-python", 1314 | "name": "python", 1315 | "nbconvert_exporter": "python", 1316 | "pygments_lexer": "ipython3", 1317 | "version": "3.8.10" 1318 | } 1319 | }, 1320 | "nbformat": 4, 1321 | "nbformat_minor": 2 1322 | } 1323 | -------------------------------------------------------------------------------- /tutorials/getting_started_with_python.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Intermediate Python Session\n", 8 | "Python is a high-level, interpreted programming language known for its simplicity and readability.\n", 9 | "\n", 10 | "Key features:\n", 11 | "* Simple and Readable Syntax\n", 12 | "* Interpreted Language\n", 13 | "* Dynamically Typed\n", 14 | "* Versatile and Portable\n", 15 | "* Extensive Standard Library and Ecosystem\n", 16 | "* Community and Support\n", 17 | "\n", 18 | "Applications:\n", 19 | "* Web Development\n", 20 | "* Data Science and Machine Learning\n", 21 | "* Automation and Scripting\n", 22 | "* Scientific Computing\n", 23 | "* Game Development\n", 24 | "* Embedded Systems\n", 25 | "\n", 26 | "
\n", 27 | "\n", 28 | "
" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "## Lesson 1: Getting Started with Python\n", 36 | "\n", 37 | "* Objectives:\n", 38 | "\n", 39 | " 1. Install the python from [python.org](https://www.python.org/downloads/)\n", 40 | "\n", 41 | " 2. Install vs-code from [here](https://code.visualstudio.com/download)\n", 42 | "\n", 43 | " 3. Basic syntax, variables, and data types\n", 44 | " \n", 45 | " 4. Input and output functions" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 1, 51 | "metadata": {}, 52 | "outputs": [ 53 | { 54 | "name": "stdout", 55 | "output_type": "stream", 56 | "text": [ 57 | "Python 3.10.10\n" 58 | ] 59 | } 60 | ], 61 | "source": [ 62 | "# Check if python is installed\n", 63 | "!python --version" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 2, 69 | "metadata": {}, 70 | "outputs": [ 71 | { 72 | "name": "stdout", 73 | "output_type": "stream", 74 | "text": [ 75 | "Hello, World! from Python\n" 76 | ] 77 | } 78 | ], 79 | "source": [ 80 | "# Hello world from Python\n", 81 | "print(\"Hello, World! from Python\")" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "### Comments in Python\n", 89 | "* Comments are non-executable part of python program which are used to explain the program.\n", 90 | "\n", 91 | "* Hash i.e. # is used for single line comment.\n", 92 | "\n", 93 | "* Triple quotes either (\"\"\" \"\"\") or (''' ''') are used for multi-line comments." 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 3, 99 | "metadata": {}, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "Hello, World!\n" 106 | ] 107 | } 108 | ], 109 | "source": [ 110 | "# This is single line comment\n", 111 | "\n", 112 | "# This will not be executed\n", 113 | "\n", 114 | "print(\"Hello, World!\")" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": 4, 120 | "metadata": {}, 121 | "outputs": [ 122 | { 123 | "name": "stdout", 124 | "output_type": "stream", 125 | "text": [ 126 | "Hello, World!\n" 127 | ] 128 | } 129 | ], 130 | "source": [ 131 | "\"\"\" \n", 132 | "This is multiline comment.\n", 133 | "This will be used to explain the code section.\n", 134 | "\"\"\"\n", 135 | "print(\"Hello, World!\")" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 5, 141 | "metadata": {}, 142 | "outputs": [ 143 | { 144 | "name": "stdout", 145 | "output_type": "stream", 146 | "text": [ 147 | "Hello, World!\n" 148 | ] 149 | } 150 | ], 151 | "source": [ 152 | "'''\n", 153 | "This is also multiline comment.\n", 154 | "This will be used to explain the code section.\n", 155 | "I am printing Hello World.\n", 156 | "'''\n", 157 | "print(\"Hello, World!\")" 158 | ] 159 | }, 160 | { 161 | "cell_type": "markdown", 162 | "metadata": {}, 163 | "source": [ 164 | "### Variables" 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "metadata": {}, 170 | "source": [ 171 | "* Variables: Variables in Python are used to store data. Python is dynamically typed, so you don't need to declare the type of a variable.\n", 172 | "\n", 173 | "* Variable Naming: Variable names can contain letters, numbers, and underscores, but cannot start with a number.\n", 174 | "\n", 175 | "* Case Sensitivity: Variable names are case-sensitive." 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": 6, 181 | "metadata": {}, 182 | "outputs": [ 183 | { 184 | "name": "stdout", 185 | "output_type": "stream", 186 | "text": [ 187 | "10\n", 188 | "\n" 189 | ] 190 | } 191 | ], 192 | "source": [ 193 | "# Variable declaration and dynamic typing\n", 194 | "x = 10\n", 195 | "print(x)\n", 196 | "\n", 197 | "# type method is used to get the type of the variable\n", 198 | "print(type(x))" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": 7, 204 | "metadata": {}, 205 | "outputs": [ 206 | { 207 | "name": "stdout", 208 | "output_type": "stream", 209 | "text": [ 210 | "Hello, World!\n", 211 | "\n" 212 | ] 213 | } 214 | ], 215 | "source": [ 216 | "# Dynamic typing\n", 217 | "y = \"Hello, World!\"\n", 218 | "print(y)\n", 219 | "print(type(y))" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": 8, 225 | "metadata": {}, 226 | "outputs": [ 227 | { 228 | "name": "stdout", 229 | "output_type": "stream", 230 | "text": [ 231 | "10\n", 232 | "20\n" 233 | ] 234 | } 235 | ], 236 | "source": [ 237 | "# Case sensitive\n", 238 | "myVar = 10\n", 239 | "MyVar =20\n", 240 | "print(myVar)\n", 241 | "print(MyVar)" 242 | ] 243 | }, 244 | { 245 | "cell_type": "markdown", 246 | "metadata": {}, 247 | "source": [ 248 | "### Python Datatypes\n", 249 | "\n", 250 | "
\n", 251 | "\n", 252 | "
\n", 253 | "\n", 254 | "* We will learn numeric and boolean data types in this lesson and remaining data types will be covered in following lesson." 255 | ] 256 | }, 257 | { 258 | "cell_type": "markdown", 259 | "metadata": {}, 260 | "source": [ 261 | "### Numeric Data Types and Operations\n", 262 | "* Int – It stores the integers values that can be positive or negative and do not contain any decimal point. \n", 263 | "\n", 264 | " Example: num1=10, num2 = 15\n", 265 | "\n", 266 | "* Float – These are floating-point real numbers that stores the decimal values. It consists of integer and fraction parts. \n", 267 | "\n", 268 | " Example: fnum = 25.4, fnum1=67.8\n", 269 | "\n", 270 | "* Complex – These are complex numbers specified as a real part and an imaginary part. They are stored in the form of a + bj where a is the real part and j represents the imaginary part. \n", 271 | "\n", 272 | " Example: num1= 2 + 3j, num2 = 5 – 7j\n", 273 | "\n", 274 | "* Arithmetic Operators\n", 275 | "\n", 276 | "![Arithmetic_Operators](../assets/arithmetic-operators.png)" 277 | ] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "execution_count": 9, 282 | "metadata": {}, 283 | "outputs": [ 284 | { 285 | "name": "stdout", 286 | "output_type": "stream", 287 | "text": [ 288 | "30\n", 289 | "\n" 290 | ] 291 | } 292 | ], 293 | "source": [ 294 | "# Addition operation\n", 295 | "x = 10\n", 296 | "y = 20\n", 297 | "z = x + y\n", 298 | "print(z)\n", 299 | "print(type(z))" 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": 10, 305 | "metadata": {}, 306 | "outputs": [ 307 | { 308 | "name": "stdout", 309 | "output_type": "stream", 310 | "text": [ 311 | "0.5\n", 312 | "\n" 313 | ] 314 | } 315 | ], 316 | "source": [ 317 | "# Modulo operation\n", 318 | "a = 10.5\n", 319 | "b = 2\n", 320 | "c = a % b\n", 321 | "print(c)\n", 322 | "print(type(c))" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": 11, 328 | "metadata": {}, 329 | "outputs": [ 330 | { 331 | "name": "stdout", 332 | "output_type": "stream", 333 | "text": [ 334 | "100.0\n", 335 | "\n" 336 | ] 337 | } 338 | ], 339 | "source": [ 340 | "# Exponent operation\n", 341 | "x = 10.0\n", 342 | "y = 2\n", 343 | "z = x ** y\n", 344 | "print(z)\n", 345 | "print(type(z))" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "execution_count": 12, 351 | "metadata": {}, 352 | "outputs": [ 353 | { 354 | "name": "stdout", 355 | "output_type": "stream", 356 | "text": [ 357 | "3\n", 358 | "\n" 359 | ] 360 | } 361 | ], 362 | "source": [ 363 | "# Floor Division operation\n", 364 | "a, b = 10, 3 # a = 10, b = 3\n", 365 | "c = a // b\n", 366 | "print(c)\n", 367 | "print(type(c))\n", 368 | "\n", 369 | "# Similarly you could try other arithmetic operations" 370 | ] 371 | }, 372 | { 373 | "cell_type": "code", 374 | "execution_count": 13, 375 | "metadata": {}, 376 | "outputs": [ 377 | { 378 | "name": "stdout", 379 | "output_type": "stream", 380 | "text": [ 381 | "(10+20j)\n", 382 | "\n" 383 | ] 384 | } 385 | ], 386 | "source": [ 387 | "# Complex number\n", 388 | "x = 10\n", 389 | "y = 20\n", 390 | "z = complex(x, y)\n", 391 | "print(z)\n", 392 | "print(type(z))" 393 | ] 394 | }, 395 | { 396 | "cell_type": "code", 397 | "execution_count": 14, 398 | "metadata": {}, 399 | "outputs": [ 400 | { 401 | "name": "stdout", 402 | "output_type": "stream", 403 | "text": [ 404 | "(30+50j)\n" 405 | ] 406 | } 407 | ], 408 | "source": [ 409 | "# Addition, subtraction, multiplication, division and exponent can be performed on complex numbers\n", 410 | "a = complex(20, 30)\n", 411 | "b = complex(10, 20)\n", 412 | "print(a+b)" 413 | ] 414 | }, 415 | { 416 | "cell_type": "markdown", 417 | "metadata": {}, 418 | "source": [ 419 | "### Boolean Data Type\n", 420 | "* The boolean data type in Python represents logical values of True and False." 421 | ] 422 | }, 423 | { 424 | "cell_type": "code", 425 | "execution_count": 15, 426 | "metadata": {}, 427 | "outputs": [ 428 | { 429 | "name": "stdout", 430 | "output_type": "stream", 431 | "text": [ 432 | "False\n", 433 | "True\n", 434 | "False\n", 435 | "True\n" 436 | ] 437 | } 438 | ], 439 | "source": [ 440 | "# Logical Operations on Boolean variables\n", 441 | "a = True\n", 442 | "b = False\n", 443 | "result_and = a and b\n", 444 | "result_or = a or b\n", 445 | "result_not = not a\n", 446 | "result_xor = a ^ b\n", 447 | "print(result_and)\n", 448 | "print(result_or)\n", 449 | "print(result_not)\n", 450 | "print(result_xor)" 451 | ] 452 | }, 453 | { 454 | "cell_type": "markdown", 455 | "metadata": {}, 456 | "source": [ 457 | "### Type Casting in Python\n", 458 | "* There may be times when you want to specify a type on to a variable. This can be done with casting.\n", 459 | "\n", 460 | "* Casting is done using following functions:\n", 461 | "\n", 462 | " * int()\n", 463 | " * float()\n", 464 | " * str()" 465 | ] 466 | }, 467 | { 468 | "cell_type": "code", 469 | "execution_count": 16, 470 | "metadata": {}, 471 | "outputs": [ 472 | { 473 | "name": "stdout", 474 | "output_type": "stream", 475 | "text": [ 476 | "1\n", 477 | "\n", 478 | "2\n", 479 | "\n", 480 | "3\n", 481 | "\n" 482 | ] 483 | } 484 | ], 485 | "source": [ 486 | "# Casting to Integers\n", 487 | "x = int(1) # x will be 1\n", 488 | "y = int(2.8) # y will be 2\n", 489 | "z = int(\"3\") # z will be 3\n", 490 | "\n", 491 | "print(x)\n", 492 | "print(type(x))\n", 493 | "\n", 494 | "print(y)\n", 495 | "print(type(y))\n", 496 | "\n", 497 | "print(z)\n", 498 | "print((type(z)))" 499 | ] 500 | }, 501 | { 502 | "cell_type": "code", 503 | "execution_count": 17, 504 | "metadata": {}, 505 | "outputs": [ 506 | { 507 | "name": "stdout", 508 | "output_type": "stream", 509 | "text": [ 510 | "1.0\n", 511 | "\n", 512 | "2.8\n", 513 | "\n", 514 | "3.0\n", 515 | "\n", 516 | "4.2\n", 517 | "\n" 518 | ] 519 | } 520 | ], 521 | "source": [ 522 | "# Casting to Float\n", 523 | "x = float(1) # x will be 1.0\n", 524 | "y = float(2.8) # y will be 2.8\n", 525 | "z = float(\"3\") # z will be 3.0\n", 526 | "w = float(\"4.2\") # w will be 4.2\n", 527 | "\n", 528 | "print(x)\n", 529 | "print(type(x))\n", 530 | "\n", 531 | "print(y)\n", 532 | "print(type(y))\n", 533 | "\n", 534 | "print(z)\n", 535 | "print((type(z)))\n", 536 | "\n", 537 | "print(w)\n", 538 | "print(type(w))" 539 | ] 540 | }, 541 | { 542 | "cell_type": "code", 543 | "execution_count": 18, 544 | "metadata": {}, 545 | "outputs": [ 546 | { 547 | "name": "stdout", 548 | "output_type": "stream", 549 | "text": [ 550 | "s1\n", 551 | "\n", 552 | "2\n", 553 | "\n", 554 | "3.0\n", 555 | "\n" 556 | ] 557 | } 558 | ], 559 | "source": [ 560 | "# Casting to string\n", 561 | "\n", 562 | "x = str(\"s1\") # x will be 's1'\n", 563 | "y = str(2) # y will be '2'\n", 564 | "z = str(3.0) # z will be '3.0'\n", 565 | "\n", 566 | "print(x)\n", 567 | "print(type(x))\n", 568 | "\n", 569 | "print(y)\n", 570 | "print(type(y))\n", 571 | "\n", 572 | "print(z)\n", 573 | "print((type(z)))" 574 | ] 575 | }, 576 | { 577 | "cell_type": "markdown", 578 | "metadata": {}, 579 | "source": [ 580 | "### Input and Output Functions\n", 581 | "* input(): \n", 582 | " * input() function is used to take input from the user. \n", 583 | " * It always returns the input as a string." 584 | ] 585 | }, 586 | { 587 | "cell_type": "code", 588 | "execution_count": 19, 589 | "metadata": {}, 590 | "outputs": [ 591 | { 592 | "name": "stdout", 593 | "output_type": "stream", 594 | "text": [ 595 | "Sushil\n", 596 | "\n" 597 | ] 598 | } 599 | ], 600 | "source": [ 601 | "name = input(\"Enter your name: \")\n", 602 | "print(name)\n", 603 | "print(type(name))" 604 | ] 605 | }, 606 | { 607 | "cell_type": "code", 608 | "execution_count": 20, 609 | "metadata": {}, 610 | "outputs": [ 611 | { 612 | "name": "stdout", 613 | "output_type": "stream", 614 | "text": [ 615 | "25\n", 616 | "\n" 617 | ] 618 | } 619 | ], 620 | "source": [ 621 | "age = input(\"Enter your age: \")\n", 622 | "print(age)\n", 623 | "print(type(age))" 624 | ] 625 | }, 626 | { 627 | "cell_type": "markdown", 628 | "metadata": {}, 629 | "source": [ 630 | "* print():\n", 631 | " * print() function is the most common way to produce output in Python. \n", 632 | " * It outputs data to the console." 633 | ] 634 | }, 635 | { 636 | "cell_type": "markdown", 637 | "metadata": {}, 638 | "source": [ 639 | "Basic output" 640 | ] 641 | }, 642 | { 643 | "cell_type": "code", 644 | "execution_count": 21, 645 | "metadata": {}, 646 | "outputs": [ 647 | { 648 | "name": "stdout", 649 | "output_type": "stream", 650 | "text": [ 651 | "Name: Ram, Age: 20\n" 652 | ] 653 | } 654 | ], 655 | "source": [ 656 | "print(\"Name: Ram, Age: 20\")" 657 | ] 658 | }, 659 | { 660 | "cell_type": "markdown", 661 | "metadata": {}, 662 | "source": [ 663 | "Output Multiple Items" 664 | ] 665 | }, 666 | { 667 | "cell_type": "code", 668 | "execution_count": 22, 669 | "metadata": {}, 670 | "outputs": [ 671 | { 672 | "name": "stdout", 673 | "output_type": "stream", 674 | "text": [ 675 | "Name: Ram Age: 20\n" 676 | ] 677 | } 678 | ], 679 | "source": [ 680 | "name = \"Ram\"\n", 681 | "age = 20\n", 682 | "print(\"Name:\", name, \"Age:\", age)" 683 | ] 684 | }, 685 | { 686 | "cell_type": "markdown", 687 | "metadata": {}, 688 | "source": [ 689 | "Formatted Strings (f-strings)" 690 | ] 691 | }, 692 | { 693 | "cell_type": "code", 694 | "execution_count": 23, 695 | "metadata": {}, 696 | "outputs": [ 697 | { 698 | "name": "stdout", 699 | "output_type": "stream", 700 | "text": [ 701 | "Name: Ram, Age: 20\n" 702 | ] 703 | } 704 | ], 705 | "source": [ 706 | "name = \"Ram\"\n", 707 | "age = 20\n", 708 | "print(f\"Name: {name}, Age: {age}\")" 709 | ] 710 | }, 711 | { 712 | "cell_type": "markdown", 713 | "metadata": {}, 714 | "source": [ 715 | "String Formatting with format()" 716 | ] 717 | }, 718 | { 719 | "cell_type": "code", 720 | "execution_count": 24, 721 | "metadata": {}, 722 | "outputs": [ 723 | { 724 | "name": "stdout", 725 | "output_type": "stream", 726 | "text": [ 727 | "Name: Ram, Age: 20\n" 728 | ] 729 | } 730 | ], 731 | "source": [ 732 | "name = \"Ram\"\n", 733 | "age = 20\n", 734 | "print(\"Name: {}, Age: {}\".format(name, age))" 735 | ] 736 | }, 737 | { 738 | "cell_type": "markdown", 739 | "metadata": {}, 740 | "source": [ 741 | "Old-Style String Formatting" 742 | ] 743 | }, 744 | { 745 | "cell_type": "code", 746 | "execution_count": 25, 747 | "metadata": {}, 748 | "outputs": [ 749 | { 750 | "name": "stdout", 751 | "output_type": "stream", 752 | "text": [ 753 | "Name: Ram, Age: 20\n" 754 | ] 755 | } 756 | ], 757 | "source": [ 758 | "name = \"Ram\"\n", 759 | "age = 20\n", 760 | "print(\"Name: %s, Age: %d\" % (name, age))" 761 | ] 762 | } 763 | ], 764 | "metadata": { 765 | "kernelspec": { 766 | "display_name": "Python 3", 767 | "language": "python", 768 | "name": "python3" 769 | }, 770 | "language_info": { 771 | "codemirror_mode": { 772 | "name": "ipython", 773 | "version": 3 774 | }, 775 | "file_extension": ".py", 776 | "mimetype": "text/x-python", 777 | "name": "python", 778 | "nbconvert_exporter": "python", 779 | "pygments_lexer": "ipython3", 780 | "version": "3.8.10" 781 | } 782 | }, 783 | "nbformat": 4, 784 | "nbformat_minor": 2 785 | } 786 | -------------------------------------------------------------------------------- /tutorials/oop_in_python.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Lesson 4: Object Oriented Programming in Python\n", 8 | "\n", 9 | "* Objectives:\n", 10 | "\n", 11 | " 1. Trace the details of instantiation and attribute resolution on class objects and instance objects.\n", 12 | "\n", 13 | " 2. Create classes with custom methods, including initializers and decorated properties.\n", 14 | " \n", 15 | " 3. Analyze object-based design patterns, including polymorphism (through magic methods) and inheritance." 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "### Key Concepts\n", 23 | "\n", 24 | "* Class: A blueprint for creating objects (a particular data structure).\n", 25 | "\n", 26 | "* Object: An instance of a class.\n", 27 | "\n", 28 | "* Attributes: Variables that belong to an object or class. It represent **STATE/CONTEXT OF OBJECT**.\n", 29 | "\n", 30 | "* Methods: Functions that belong to an object or class.\n", 31 | "\n", 32 | "* Inheritance: Mechanism to create a new class using the properties and methods of an existing class.\n", 33 | "\n", 34 | "* Encapsulation: Bundling data and methods within a class.\n", 35 | "\n", 36 | "* Polymorphism: Ability to present the same interface for different data types.\n", 37 | "\n", 38 | "* Abstraction: Mechanism to hide the complex implementation details and showing only the essential features of the object.\n", 39 | "\n", 40 | "* Constructor__init__(): It is the special method which is called automatically when a new object is created. It is used for initializing the object's atribute. \n", 41 | "\n", 42 | "* Destructor__del__(): It is the special method which is called automatically when an object is about to be destroyed and can be used to clean up resources.\n", 43 | "\n", 44 | "* Garbage Collection: Python uses automatic garbage collection to manage memory. Objects are destroyed when they are no longer needed, and their destructor__del__() is called.\n", 45 | "\n" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "### Creating our First Class\n", 53 | "\n", 54 | "* Syntax:\n", 55 | "\n", 56 | " class ClassName:\n", 57 | " \n", 58 | " # class attributes section\n", 59 | "\n", 60 | " # class methods section" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 2, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "# Let's create our first class\n", 70 | "class Book:\n", 71 | " # Object attributes are initialized inside the constructor __init__ method\n", 72 | " def __init__(self, title, author, pages, price, discount):\n", 73 | " self.title = title\n", 74 | " self.author = author\n", 75 | " self.pages = pages\n", 76 | " self.price = price\n", 77 | " self.discount = discount\n", 78 | " self.selling_price = None\n", 79 | " print(\"I am constructor and I have initialized all the attributes of the object\")\n", 80 | " \n", 81 | " # Class methods\n", 82 | " def calculate_selling_price(self):\n", 83 | " \n", 84 | " sp = self.price * (1 - self.discount / 100) # Here sp is local variable\n", 85 | " \n", 86 | " self.selling_price = sp # Here selling_price is an object attribute" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "### Instantiating the Class or Creating our First Object" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 3, 99 | "metadata": {}, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "I am constructor and I have initialized all the attributes of the object\n" 106 | ] 107 | } 108 | ], 109 | "source": [ 110 | "# Let's create an object\n", 111 | "book1 = Book('Python', 'Guido van Rossum', 500, 100, 10) # This will automatically call the __init__ method" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "Accessing Object Attributes and Methods\n", 119 | "\n", 120 | "* We use dot (.) operator to access object attributes and class methods." 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 4, 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "name": "stdout", 130 | "output_type": "stream", 131 | "text": [ 132 | "Python\n", 133 | "Guido van Rossum\n", 134 | "500\n", 135 | "100\n", 136 | "10\n", 137 | "None\n" 138 | ] 139 | } 140 | ], 141 | "source": [ 142 | "# Accessing object attributes/properties\n", 143 | "print(book1.title)\n", 144 | "print(book1.author)\n", 145 | "print(book1.pages)\n", 146 | "print(book1.price)\n", 147 | "print(book1.discount)\n", 148 | "print(book1.selling_price)" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": 5, 154 | "metadata": {}, 155 | "outputs": [ 156 | { 157 | "name": "stdout", 158 | "output_type": "stream", 159 | "text": [ 160 | "90.0\n" 161 | ] 162 | } 163 | ], 164 | "source": [ 165 | "# Accessing class methods\n", 166 | "book1.calculate_selling_price()\n", 167 | "print(book1.selling_price)" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": {}, 173 | "source": [ 174 | "### What is self ??\n", 175 | "\n", 176 | "* It is a reference to the instance of the class.\n", 177 | "\n", 178 | "* It ensures that whenever we call the method, the method is operating on particular object attributes and methods." 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": 6, 184 | "metadata": {}, 185 | "outputs": [ 186 | { 187 | "name": "stdout", 188 | "output_type": "stream", 189 | "text": [ 190 | "Object created: <__main__.Book object at 0x7f44fe481850>\n", 191 | "Object created: <__main__.Book object at 0x7f44fe481fd0>\n" 192 | ] 193 | } 194 | ], 195 | "source": [ 196 | "class Book:\n", 197 | " # Object attributes are initialized inside the constructor __init__ method\n", 198 | " def __init__(self, title, author, pages, price, discount):\n", 199 | " self.title = title\n", 200 | " self.author = author\n", 201 | " self.pages = pages\n", 202 | " self.price = price\n", 203 | " self.discount = discount\n", 204 | " self.selling_price = None\n", 205 | " print('Object created: ', self)\n", 206 | " \n", 207 | " # Class methods\n", 208 | " def calculate_selling_price(self):\n", 209 | " \n", 210 | " sp = self.price * (1 - self.discount / 100)\n", 211 | " \n", 212 | " self.selling_price = sp\n", 213 | " \n", 214 | " \n", 215 | "# Instance creation\n", 216 | "book1 = Book('Python', 'Guido van Rossum', 500, 100, 10)\n", 217 | "book2 = Book('Java', 'James Gosling', 800, 150, 15)" 218 | ] 219 | }, 220 | { 221 | "cell_type": "markdown", 222 | "metadata": {}, 223 | "source": [ 224 | "### Assignment 4.1\n", 225 | "\n", 226 | "1. Create a class Rectangle. Define the required object attributes/state yourself. Define class methods: area() and perimeter() and use them by creating an instance of rectangle.\n", 227 | "\n", 228 | "2. You are given an integer list height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).Find two lines that together with the x-axis form a container, such that the container contains the most water.Return the maximum amount of water a container can store. Notice that you may not slant the container.\n", 229 | "\n", 230 | "Example1:\n", 231 | "\n", 232 | "
\n", 233 | "\n", 234 | "
\n", 235 | "\n", 236 | " Input: height = [1,8,6,2,5,4,8,3,7]\n", 237 | "\n", 238 | " Output: 49\n", 239 | "\n", 240 | "Explanation: The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.\n", 241 | "\n", 242 | "\n", 243 | "Example2:\n", 244 | "\n", 245 | " Input: height = [1,1]\n", 246 | "\n", 247 | " Output: 1\n", 248 | "\n", 249 | "\n" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "### Commonly Used Decorators" 257 | ] 258 | }, 259 | { 260 | "cell_type": "markdown", 261 | "metadata": {}, 262 | "source": [ 263 | "@classmethod\n", 264 | "* The @classmethod decorator is used to define a method that is bound to the class and not the instance of the class. \n", 265 | "\n", 266 | "* The first parameter of a class method is cls, which refers to the class itself.\n", 267 | "\n", 268 | "* The class method can only access the class attributes but not the instance attributes.\n", 269 | "\n", 270 | "* The class method can be called using ClassName.MethodName() and also using object.\n", 271 | "\n", 272 | "* It can return an object of the class." 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": 7, 278 | "metadata": {}, 279 | "outputs": [], 280 | "source": [ 281 | "class Book:\n", 282 | " \n", 283 | " # These are class attributes\n", 284 | " book_title = \"Python Programming\"\n", 285 | " \n", 286 | " # Constructor\n", 287 | " def __init__(self, title, author, pages, price, discount):\n", 288 | " # These are instance attributes\n", 289 | " self.title = title\n", 290 | " self.author = author\n", 291 | " self.pages = pages\n", 292 | " self.price = price\n", 293 | " self.discount = discount\n", 294 | " self.selling_price = None\n", 295 | " \n", 296 | " # Class method to create an object\n", 297 | " @classmethod\n", 298 | " def create_object_from_string(cls, book_str):\n", 299 | " print(\"Default book title: \", cls.book_title)\n", 300 | " book_title, author, pages, price, discount = book_str.split(' ')\n", 301 | " \n", 302 | " # Creating an object and returning it\n", 303 | " return cls(book_title, author, int(pages), int(price), int(discount))\n", 304 | " \n", 305 | " # Class methods\n", 306 | " def calculate_selling_price(self):\n", 307 | " sp = self.price * (1 - self.discount / 100)\n", 308 | " self.selling_price = sp" 309 | ] 310 | }, 311 | { 312 | "cell_type": "code", 313 | "execution_count": 8, 314 | "metadata": {}, 315 | "outputs": [ 316 | { 317 | "name": "stdout", 318 | "output_type": "stream", 319 | "text": [ 320 | "Default book title: Python Programming\n", 321 | "None\n", 322 | "Python\n", 323 | "Python Programming\n" 324 | ] 325 | } 326 | ], 327 | "source": [ 328 | "book1 = Book.create_object_from_string('Python Programming 500 100 10')\n", 329 | "print(book1.selling_price)\n", 330 | "print(book1.title)\n", 331 | "print(book1.book_title)" 332 | ] 333 | }, 334 | { 335 | "cell_type": "markdown", 336 | "metadata": {}, 337 | "source": [ 338 | "@staticmethod\n", 339 | "\n", 340 | "* The @staticmethod decorator is used to define a method that doesn't depend on class or instance variables. \n", 341 | "\n", 342 | "* Static methods are similar to regular functions but belong to the class's namespace." 343 | ] 344 | }, 345 | { 346 | "cell_type": "code", 347 | "execution_count": 9, 348 | "metadata": {}, 349 | "outputs": [], 350 | "source": [ 351 | "class Book:\n", 352 | " \n", 353 | " # These are class attributes\n", 354 | " book_title = \"Python Programming\"\n", 355 | " \n", 356 | " # Constructor\n", 357 | " def __init__(self, title, author, pages, price, discount):\n", 358 | " # These are instance attributes\n", 359 | " self.title = title\n", 360 | " self.author = author\n", 361 | " self.pages = pages\n", 362 | " self.price = price\n", 363 | " self.discount = discount\n", 364 | " self.selling_price = None\n", 365 | " \n", 366 | " # Class method to create an object\n", 367 | " @classmethod\n", 368 | " def create_from_string(cls, book_str):\n", 369 | " print(\"Default book title: \", cls.book_title)\n", 370 | " book_title, author, pages, price, discount = book_str.split(' ')\n", 371 | " \n", 372 | " # Creating an object and returning it\n", 373 | " return cls(book_title, author, int(pages), int(price), int(discount))\n", 374 | " \n", 375 | " # Static method\n", 376 | " @staticmethod\n", 377 | " def get_default_title():\n", 378 | " print(\"I am static method and I can access class attributes\")\n", 379 | " return Book.book_title\n", 380 | " \n", 381 | " # Class methods\n", 382 | " def calculate_selling_price(self):\n", 383 | " sp = self.price * (1 - self.discount / 100)\n", 384 | " self.selling_price = sp" 385 | ] 386 | }, 387 | { 388 | "cell_type": "code", 389 | "execution_count": 10, 390 | "metadata": {}, 391 | "outputs": [ 392 | { 393 | "name": "stdout", 394 | "output_type": "stream", 395 | "text": [ 396 | "I am static method and I can access class attributes\n", 397 | "Python Programming\n" 398 | ] 399 | } 400 | ], 401 | "source": [ 402 | "book_default_title = Book.get_default_title()\n", 403 | "print(book_default_title)" 404 | ] 405 | }, 406 | { 407 | "cell_type": "markdown", 408 | "metadata": {}, 409 | "source": [ 410 | "@property\n", 411 | "\n", 412 | "* The @property decorator is used to define a method as a property. \n", 413 | "\n", 414 | "* This allows you to define methods that can be accessed like attributes. \n", 415 | "\n", 416 | "* It is commonly used for getter methods.\n", 417 | "\n", 418 | "* By default all the variables in python are public. But python developers use variable naming convention to define the visibility of variable.\n", 419 | "\n", 420 | " * Public: Public variables are accessible from anywhere, both inside and outside of the class. By default, all variables in a class are public. Eg: var1, func1()\n", 421 | "\n", 422 | " * Protected: Protected variables are intended to be accessible only within the class and its subclasses. They are not strictly enforced by Python but are indicated by a single underscore prefix _. Eg: _var1, _func1()\n", 423 | "\n", 424 | " * Private: Private variables are intended to be accessible only within the class they are defined. They are indicated by a double underscore prefix __. Eg: __var1, __func1()" 425 | ] 426 | }, 427 | { 428 | "cell_type": "code", 429 | "execution_count": 11, 430 | "metadata": {}, 431 | "outputs": [], 432 | "source": [ 433 | "class Person:\n", 434 | " \n", 435 | " def __init__(self, name, age):\n", 436 | " self._name = name\n", 437 | " self._age = age\n", 438 | " \n", 439 | " # Getter\n", 440 | " def get_name(self):\n", 441 | " return self._name\n", 442 | " \n", 443 | " # Getter\n", 444 | " def get_age(self):\n", 445 | " return self._age\n", 446 | " \n", 447 | " # Setter\n", 448 | " def set_name(self, name):\n", 449 | " self._name = name\n", 450 | " \n", 451 | " # Setter\n", 452 | " def set_age(self, age):\n", 453 | " self._age = age" 454 | ] 455 | }, 456 | { 457 | "cell_type": "code", 458 | "execution_count": 13, 459 | "metadata": {}, 460 | "outputs": [ 461 | { 462 | "name": "stdout", 463 | "output_type": "stream", 464 | "text": [ 465 | "Ram\n", 466 | "20\n", 467 | "Shyam\n", 468 | "21\n" 469 | ] 470 | } 471 | ], 472 | "source": [ 473 | "person1 = Person('Ram', 20)\n", 474 | "\n", 475 | "# Since name and age are protected attributes, we cannot access them directly by convention\n", 476 | "# So we have to use getter to get values\n", 477 | "print(person1.get_name())\n", 478 | "print(person1.get_age())\n", 479 | "\n", 480 | "# If we have to set new values, we have to use setter\n", 481 | "person1.set_name('Shyam')\n", 482 | "person1.set_age(21)\n", 483 | "\n", 484 | "print(person1.get_name())\n", 485 | "print(person1.get_age())" 486 | ] 487 | }, 488 | { 489 | "cell_type": "markdown", 490 | "metadata": {}, 491 | "source": [ 492 | "We can use @property decorator for using getter and setter" 493 | ] 494 | }, 495 | { 496 | "cell_type": "code", 497 | "execution_count": 16, 498 | "metadata": {}, 499 | "outputs": [], 500 | "source": [ 501 | "class Person:\n", 502 | " \n", 503 | " def __init__(self, name, age):\n", 504 | " self._name = name\n", 505 | " self._age = age\n", 506 | " \n", 507 | " @property\n", 508 | " def name(self):\n", 509 | " print(\"Getter for name is called\")\n", 510 | " return self._name\n", 511 | " \n", 512 | " @property\n", 513 | " def age(self):\n", 514 | " print(\"Getter for age is called\")\n", 515 | " return self._age\n", 516 | " \n", 517 | " @name.setter\n", 518 | " def name(self, name):\n", 519 | " print(\"Setter for name is called\")\n", 520 | " self._name = name\n", 521 | " \n", 522 | " @age.setter\n", 523 | " def age(self, age):\n", 524 | " print(\"Setter for age is called\")\n", 525 | " self._age = age" 526 | ] 527 | }, 528 | { 529 | "cell_type": "code", 530 | "execution_count": 17, 531 | "metadata": {}, 532 | "outputs": [ 533 | { 534 | "name": "stdout", 535 | "output_type": "stream", 536 | "text": [ 537 | "Getter for name is called\n", 538 | "Ram\n", 539 | "Getter for age is called\n", 540 | "20\n", 541 | "Setter for name is called\n", 542 | "Setter for age is called\n", 543 | "Getter for name is called\n", 544 | "Shyam\n", 545 | "Getter for age is called\n", 546 | "21\n" 547 | ] 548 | } 549 | ], 550 | "source": [ 551 | "person1 = Person('Ram', 20)\n", 552 | "\n", 553 | "print(person1.name)\n", 554 | "print(person1.age)\n", 555 | "\n", 556 | "person1.name = 'Shyam'\n", 557 | "person1.age = 21\n", 558 | "\n", 559 | "print(person1.name)\n", 560 | "print(person1.age)" 561 | ] 562 | }, 563 | { 564 | "cell_type": "markdown", 565 | "metadata": {}, 566 | "source": [ 567 | "### Inheritance in Python\n", 568 | "\n", 569 | "* Using inheritance, we will create new class from the existing class by inheriting properties of existing class.\n", 570 | "\n", 571 | "* The existing class is called parent class or super class whereas the new inherited class is called child class or sub class.\n", 572 | "\n", 573 | "* This promotes code reusability and a hierarchical class structure.\n", 574 | "\n", 575 | "* This extends the functionality of existing classes.\n", 576 | "\n", 577 | "* super() function allows you to call methods from the superclass in your subclass." 578 | ] 579 | }, 580 | { 581 | "cell_type": "code", 582 | "execution_count": 18, 583 | "metadata": {}, 584 | "outputs": [], 585 | "source": [ 586 | "# Syntax\n", 587 | "class ParentClass:\n", 588 | " pass\n", 589 | "\n", 590 | "class ChildClass(ParentClass):\n", 591 | " pass" 592 | ] 593 | }, 594 | { 595 | "cell_type": "markdown", 596 | "metadata": {}, 597 | "source": [ 598 | "### Types of Inheritance\n", 599 | "\n", 600 | "* Single Inheritance\n", 601 | " * A subclass inherits from one superclass.\n", 602 | "\n", 603 | "* Multiple Inheritance: \n", 604 | "\n", 605 | " * A subclass inherits from more than one superclass.\n", 606 | "\n", 607 | "* Multilevel Inheritance: \n", 608 | "\n", 609 | " * A class is derived from a class which is also derived from another class.\n", 610 | "\n", 611 | "* Hierarchical Inheritance: \n", 612 | "\n", 613 | " * Multiple subclasses inherit from a single superclass." 614 | ] 615 | }, 616 | { 617 | "cell_type": "code", 618 | "execution_count": 21, 619 | "metadata": {}, 620 | "outputs": [ 621 | { 622 | "name": "stdout", 623 | "output_type": "stream", 624 | "text": [ 625 | "Vehicle is used for transportation\n", 626 | "BMW is used for transportation\n", 627 | "200\n" 628 | ] 629 | } 630 | ], 631 | "source": [ 632 | "# Single Inheritance\n", 633 | "class Vehicle:\n", 634 | " def __init__(self, name, color):\n", 635 | " self.name = name\n", 636 | " self.color = color\n", 637 | " \n", 638 | " def usage(self):\n", 639 | " print(f\"Vehicle is used for transportation\")\n", 640 | " \n", 641 | "class Car(Vehicle):\n", 642 | " \n", 643 | " def __init__(self, name, color, top_speed):\n", 644 | " # Calling parent class constructor\n", 645 | " super().__init__(name, color)\n", 646 | " self.top_speed = top_speed\n", 647 | " \n", 648 | " # Method overriding\n", 649 | " # This subclass method usage() will override the parent class method usage()\n", 650 | " # So if we have to call parent class method, we have to use super()\n", 651 | " def usage(self):\n", 652 | " # Calling parent class method\n", 653 | " super().usage() \n", 654 | " print(f\"{self.name} is used for transportation\")\n", 655 | " \n", 656 | "\n", 657 | "car1 = Car('BMW', 'Black', 200)\n", 658 | "car1.usage()\n", 659 | "print(car1.top_speed)\n" 660 | ] 661 | }, 662 | { 663 | "cell_type": "markdown", 664 | "metadata": {}, 665 | "source": [ 666 | "### Polymorphism in Python\n", 667 | "\n", 668 | "* Polymorphisms refer to the occurrence of something in multiple forms. \n", 669 | "\n", 670 | "* Examples: \n", 671 | "\n", 672 | " * Operator overloading\n", 673 | "\n", 674 | " * Method Overriding\n", 675 | "\n", 676 | "* Method overriding is not allowed in python.\n" 677 | ] 678 | }, 679 | { 680 | "cell_type": "code", 681 | "execution_count": 22, 682 | "metadata": {}, 683 | "outputs": [], 684 | "source": [ 685 | "# Example of polymorphism\n", 686 | "\n", 687 | "# Addition (+) operation has multiple uses and it is called operator overloading\n", 688 | "\n", 689 | "sum = 10 + 20 # + is used to add numbers\n", 690 | "str_cat = \"Hello\" + \" \" + \"World\" # + is used to concatenate strings\n", 691 | "list_cat = [1, 2, 3] + [4, 5, 6] # + is used to concatenate lists" 692 | ] 693 | }, 694 | { 695 | "cell_type": "markdown", 696 | "metadata": {}, 697 | "source": [ 698 | "Polymorphism: Method Overriding\n", 699 | "\n", 700 | "* In inheritance, we can redefine certain methods and attributes specifically to fit the child class, which is known as Method Overriding." 701 | ] 702 | }, 703 | { 704 | "cell_type": "code", 705 | "execution_count": 28, 706 | "metadata": {}, 707 | "outputs": [], 708 | "source": [ 709 | "import math\n", 710 | "\n", 711 | "class Shape:\n", 712 | " def __init__(self, name):\n", 713 | " self.name = name\n", 714 | "\n", 715 | " def area(self):\n", 716 | " pass\n", 717 | "\n", 718 | " def fact(self):\n", 719 | " return \"I am a two-dimensional shape. I have length and breadth.\"\n", 720 | "\n", 721 | "class Square(Shape):\n", 722 | " def __init__(self, length):\n", 723 | " super().__init__(\"Square\")\n", 724 | " self.length = length\n", 725 | "\n", 726 | " def area(self):\n", 727 | " return self.length**2\n", 728 | "\n", 729 | "class Circle(Shape):\n", 730 | " def __init__(self, radius):\n", 731 | " super().__init__(\"Circle\")\n", 732 | " self.radius = radius\n", 733 | "\n", 734 | " def area(self):\n", 735 | " return math.pi*self.radius**2\n", 736 | " \n", 737 | " def fact(self):\n", 738 | " return \"I am circle. I have radius.\"" 739 | ] 740 | }, 741 | { 742 | "cell_type": "code", 743 | "execution_count": 30, 744 | "metadata": {}, 745 | "outputs": [ 746 | { 747 | "name": "stdout", 748 | "output_type": "stream", 749 | "text": [ 750 | "I am a two-dimensional shape. I have length and breadth.\n", 751 | "25\n" 752 | ] 753 | } 754 | ], 755 | "source": [ 756 | "sqr = Square(5)\n", 757 | "print(sqr.fact())\n", 758 | "print(sqr.area())" 759 | ] 760 | }, 761 | { 762 | "cell_type": "code", 763 | "execution_count": 31, 764 | "metadata": {}, 765 | "outputs": [ 766 | { 767 | "name": "stdout", 768 | "output_type": "stream", 769 | "text": [ 770 | "I am circle. I have radius.\n", 771 | "78.53981633974483\n" 772 | ] 773 | } 774 | ], 775 | "source": [ 776 | "circle = Circle(5)\n", 777 | "print(circle.fact())\n", 778 | "print(circle.area())" 779 | ] 780 | } 781 | ], 782 | "metadata": { 783 | "kernelspec": { 784 | "display_name": "Python 3", 785 | "language": "python", 786 | "name": "python3" 787 | }, 788 | "language_info": { 789 | "codemirror_mode": { 790 | "name": "ipython", 791 | "version": 3 792 | }, 793 | "file_extension": ".py", 794 | "mimetype": "text/x-python", 795 | "name": "python", 796 | "nbconvert_exporter": "python", 797 | "pygments_lexer": "ipython3", 798 | "version": "3.8.10" 799 | } 800 | }, 801 | "nbformat": 4, 802 | "nbformat_minor": 2 803 | } 804 | -------------------------------------------------------------------------------- /tutorials/pep8_style_guide.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Lesson 9: Standard Coding Practices\n", 8 | "* Objectives:\n", 9 | "\n", 10 | " * PEP standards to write clear, compliant code.\n", 11 | "\n", 12 | " * Understand core Pythonic principles to write code that can scale.\n", 13 | " \n", 14 | " * Explore pylint library" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "### PEP8 Style Guide\n", 22 | "\n", 23 | "* PEP (Python Enhancement Proposals) are design documents that provide guidelines and best practices for writing Python code. \n", 24 | "\n", 25 | "* Purpose of PEP Standards:\n", 26 | " * Consistency: Ensures uniformity in code style across different projects and teams.\n", 27 | "\n", 28 | " * Readability: Makes code easier to read and understand by following common conventions.\n", 29 | "\n", 30 | " * Maintainability: Facilitates maintaining and updating code by adhering to standardized practices.\n", 31 | " \n", 32 | " * Collaboration: Promotes better collaboration among developers by using a common coding style." 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "Some Key Guidelines from PEP 8\n", 40 | "\n", 41 | "* Refer to the official documentation [here](https://peps.python.org/pep-0008/) for complete guidelines." 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "metadata": {}, 47 | "source": [ 48 | "Naming Conventions" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 2, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "# Variables and Functions: Use snake_case for variable and function names\n", 58 | "\n", 59 | "my_variable = 10\n", 60 | "def my_function():\n", 61 | " pass" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 3, 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "# Classes: Use CamelCase for class names\n", 71 | "class MyClass:\n", 72 | " pass" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 4, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "# Constants: Use UPPER_CASE for constants.\n", 82 | "MAX_VALUE = 100" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "Blank Lines\n", 90 | "* Use blank lines to separate top-level functions and class definitions.\n", 91 | "* Use two blank lines before and after class definitions.\n", 92 | "* Use one blank line to separate methods within a class.\n", 93 | "python\n" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 5, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "class MyClass:\n", 103 | " \n", 104 | " def method_one(self):\n", 105 | " pass\n", 106 | " \n", 107 | " def method_two(self):\n", 108 | " pass\n", 109 | "\n" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "Imports\n", 117 | "* Imports should be on separate lines.\n", 118 | "* Group imports in the following order: \n", 119 | " 1. standard library imports, \n", 120 | " 2. related third-party imports, \n", 121 | " 3. local application/library-specific imports.\n", 122 | "* Use absolute imports whenever possible.\n" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "# Standard libraries\n", 132 | "import os\n", 133 | "import sys\n", 134 | "\n", 135 | "# Third-party libraries\n", 136 | "import numpy as np\n", 137 | "import pandas as pd\n", 138 | "\n", 139 | "# Local libraries\n", 140 | "from mymodule import myfunction\n" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "Comments\n", 148 | "* Use comments to explain why something is done, not what is done.\n", 149 | "* Block comments should start with # and a single space.\n", 150 | "* Inline comments should be separated by at least two spaces from the statement." 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 7, 156 | "metadata": {}, 157 | "outputs": [], 158 | "source": [ 159 | "# This is a block comment\n", 160 | "x = 10\n", 161 | "x = x + 1 # Increment x by 1\n" 162 | ] 163 | }, 164 | { 165 | "cell_type": "markdown", 166 | "metadata": {}, 167 | "source": [ 168 | "Docstrings\n", 169 | "* Use triple quotes for docstrings.\n", 170 | "* The docstring should describe the method's effect and arguments" 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": 8, 176 | "metadata": {}, 177 | "outputs": [], 178 | "source": [ 179 | "def my_function(param1, param2):\n", 180 | " \"\"\"\n", 181 | " This is a docstring.\n", 182 | " \n", 183 | " Args:\n", 184 | " param1 (int): The first parameter.\n", 185 | " param2 (str): The second parameter.\n", 186 | " \n", 187 | " Returns:\n", 188 | " bool: The return value. True for success, False otherwise.\n", 189 | " \"\"\"\n", 190 | " pass\n" 191 | ] 192 | }, 193 | { 194 | "cell_type": "markdown", 195 | "metadata": {}, 196 | "source": [ 197 | "**Zen of Python**\n", 198 | "1. Beautiful is better than ugly.\n", 199 | "2. Explicit is better than implicit.\n", 200 | "3. Simple is better than complex.\n", 201 | "4. Complex is better than complicated.\n", 202 | "5. Flat is better than nested.\n", 203 | "6. Sparse is better than dense.\n", 204 | "7. Readability counts.\n", 205 | "8. Special cases aren't special enough to break the rules.\n", 206 | "9. Although practicality beats purity.\n", 207 | "10. Errors should never pass silently.\n", 208 | "11. Unless explicitly silenced.\n", 209 | "12. In the face of ambiguity, refuse the temptation to guess.\n", 210 | "13. There should be one-- and preferably only one --obvious way to do it.\n", 211 | "14. Although that way may not be obvious at first unless you're Dutch.\n", 212 | "15. Now is better than never.\n", 213 | "16. Although never is often better than right now.\n", 214 | "17. If the implementation is hard to explain, it's a bad idea.\n", 215 | "18. If the implementation is easy to explain, it may be a good idea.\n", 216 | "19. Namespaces are one honking great idea -- let's do more of those!" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "metadata": {}, 222 | "source": [ 223 | "**Annotation in Python**\n", 224 | "* Annotations in Python provide a way to attach metadata to function arguments and return values. \n", 225 | "\n", 226 | "* They are primarily used for type hints, which can help with code readability, maintainability, and tooling support, such as static analysis and IDE autocompletion. \n", 227 | "\n", 228 | "* Annotations do not affect the runtime behavior of the code but serve as useful documentation." 229 | ] 230 | }, 231 | { 232 | "cell_type": "markdown", 233 | "metadata": {}, 234 | "source": [ 235 | "Example" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": 9, 241 | "metadata": {}, 242 | "outputs": [], 243 | "source": [ 244 | "def add(a: int, b: int) -> int:\n", 245 | " return a + b" 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "metadata": {}, 251 | "source": [ 252 | "Use the typing module for more complex type hints, such as optional and union types." 253 | ] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "metadata": {}, 258 | "source": [ 259 | "Example in function level" 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": null, 265 | "metadata": {}, 266 | "outputs": [], 267 | "source": [ 268 | "from typing import List\n", 269 | "\n", 270 | "def add(x: List[int]) -> int:\n", 271 | " \"\"\"\n", 272 | " Function to add elements of a list\n", 273 | "\n", 274 | " Args:\n", 275 | " x (List[int]): Input list of integers\n", 276 | "\n", 277 | " Returns:\n", 278 | " int: sum of all the elements of a list\n", 279 | " \"\"\"\n", 280 | " return sum(x)\n" 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "metadata": {}, 286 | "source": [ 287 | "Example in class level" 288 | ] 289 | }, 290 | { 291 | "cell_type": "code", 292 | "execution_count": null, 293 | "metadata": {}, 294 | "outputs": [], 295 | "source": [ 296 | "class Person:\n", 297 | " \"\"\"\n", 298 | " This is person class to store name and age\n", 299 | " \"\"\"\n", 300 | " def __init__(self, name: str, age: int) -> None:\n", 301 | " \"\"\"\n", 302 | " Initialize name and age\n", 303 | "\n", 304 | " Args:\n", 305 | " name (str): name of person\n", 306 | " age (int): age of person\n", 307 | " \"\"\"\n", 308 | " self.name = name\n", 309 | " self.age = age\n", 310 | " \n", 311 | " def get_name(self) -> str:\n", 312 | " \"\"\"\n", 313 | " This is getter for name\n", 314 | "\n", 315 | " Returns:\n", 316 | " str: Returns name\n", 317 | " \"\"\"\n", 318 | " return self.name\n", 319 | " \n", 320 | " def get_age(self) -> int:\n", 321 | " \"\"\"\n", 322 | " This is getter for age\n", 323 | "\n", 324 | " Returns:\n", 325 | " int: Returns age\n", 326 | " \"\"\"\n", 327 | " return self.age\n", 328 | " " 329 | ] 330 | }, 331 | { 332 | "cell_type": "markdown", 333 | "metadata": {}, 334 | "source": [ 335 | "**Pylint: A code quality tool for Python**\n", 336 | "\n", 337 | "* Pylint is a widely-used static code analysis tool in Python. \n", 338 | "\n", 339 | "* It helps ensure code quality by checking for errors, enforcing a coding standard, and suggesting improvements. \n", 340 | "\n", 341 | "* By integrating Pylint into your development workflow, you can maintain high-quality, readable, and maintainable code." 342 | ] 343 | }, 344 | { 345 | "cell_type": "markdown", 346 | "metadata": {}, 347 | "source": [ 348 | "Installing pylint\n", 349 | "\n", 350 | "> pip install pylint\n" 351 | ] 352 | }, 353 | { 354 | "cell_type": "markdown", 355 | "metadata": {}, 356 | "source": [ 357 | "Running pylint\n", 358 | "\n", 359 | "> pylint your_script.py" 360 | ] 361 | }, 362 | { 363 | "cell_type": "markdown", 364 | "metadata": {}, 365 | "source": [ 366 | "Understanding Pylint Messages\n", 367 | "* Pylint categorizes its messages into different types, each with a unique code. \n", 368 | "\n", 369 | "* Here are some common categories:\n", 370 | "\n", 371 | " * Convention (C): Issues related to coding style.\n", 372 | " * Refactor (R): Suggestions for code refactoring.\n", 373 | " * Warning (W): Potential issues in the code.\n", 374 | " * Error (E): Likely errors in the code.\n", 375 | " * Fatal (F): Errors that prevent Pylint from analyzing the code." 376 | ] 377 | }, 378 | { 379 | "cell_type": "markdown", 380 | "metadata": {}, 381 | "source": [ 382 | "Customizing pylint\n", 383 | "\n", 384 | "* Pylint can be customized to better fit your project's needs. \n", 385 | "\n", 386 | "* This includes modifying its configuration to ignore certain warnings or adjusting the coding standards it enforces.\n", 387 | "\n", 388 | "* You can create a .pylintrc file to customize Pylint's behavior. This file can be generated using:\n", 389 | "\n", 390 | "> pylint --generate-rcfile > .pylintrc\n" 391 | ] 392 | }, 393 | { 394 | "cell_type": "markdown", 395 | "metadata": {}, 396 | "source": [ 397 | "Common Customization\n", 398 | "\n", 399 | "* Disable Specific Messages: You can disable specific messages by adding their codes to the disable option in the .pylintrc file." 400 | ] 401 | }, 402 | { 403 | "cell_type": "code", 404 | "execution_count": null, 405 | "metadata": {}, 406 | "outputs": [], 407 | "source": [ 408 | "# Inside [MESSAGES CONTROL] block in .pylintrc file\n", 409 | "# disable=C0114,C0115,C0116 # Disable missing module/function/class docstring warnings\n" 410 | ] 411 | } 412 | ], 413 | "metadata": { 414 | "kernelspec": { 415 | "display_name": "Python 3", 416 | "language": "python", 417 | "name": "python3" 418 | }, 419 | "language_info": { 420 | "codemirror_mode": { 421 | "name": "ipython", 422 | "version": 3 423 | }, 424 | "file_extension": ".py", 425 | "mimetype": "text/x-python", 426 | "name": "python", 427 | "nbconvert_exporter": "python", 428 | "pygments_lexer": "ipython3", 429 | "version": "3.8.10" 430 | } 431 | }, 432 | "nbformat": 4, 433 | "nbformat_minor": 2 434 | } 435 | -------------------------------------------------------------------------------- /tutorials/unit_testing_and_exception_handling/.pylintrc: -------------------------------------------------------------------------------- 1 | [MAIN] 2 | 3 | 4 | # Analyse import fallback blocks. This can be used to support both Python 2 and 5 | # 3 compatible code, which means that the block might have code that exists 6 | # only in one or another interpreter, leading to false positives when analysed. 7 | analyse-fallback-blocks=no 8 | 9 | # Clear in-memory caches upon conclusion of linting. Useful if running pylint 10 | # in a server-like mode. 11 | clear-cache-post-run=no 12 | 13 | # Load and enable all available extensions. Use --list-extensions to see a list 14 | # all available extensions. 15 | #enable-all-extensions= 16 | 17 | # In error mode, messages with a category besides ERROR or FATAL are 18 | # suppressed, and no reports are done by default. Error mode is compatible with 19 | # disabling specific errors. 20 | #errors-only= 21 | 22 | # Always return a 0 (non-error) status code, even if lint errors are found. 23 | # This is primarily useful in continuous integration scripts. 24 | #exit-zero= 25 | 26 | # A comma-separated list of package or module names from where C extensions may 27 | # be loaded. Extensions are loading into the active Python interpreter and may 28 | # run arbitrary code. 29 | extension-pkg-allow-list= 30 | 31 | # A comma-separated list of package or module names from where C extensions may 32 | # be loaded. Extensions are loading into the active Python interpreter and may 33 | # run arbitrary code. (This is an alternative name to extension-pkg-allow-list 34 | # for backward compatibility.) 35 | extension-pkg-whitelist= 36 | 37 | # Return non-zero exit code if any of these messages/categories are detected, 38 | # even if score is above --fail-under value. Syntax same as enable. Messages 39 | # specified are enabled, while categories only check already-enabled messages. 40 | fail-on= 41 | 42 | # Specify a score threshold under which the program will exit with error. 43 | fail-under=10 44 | 45 | # Interpret the stdin as a python script, whose filename needs to be passed as 46 | # the module_or_package argument. 47 | #from-stdin= 48 | 49 | # Files or directories to be skipped. They should be base names, not paths. 50 | ignore=CVS 51 | 52 | # Add files or directories matching the regular expressions patterns to the 53 | # ignore-list. The regex matches against paths and can be in Posix or Windows 54 | # format. Because '\\' represents the directory delimiter on Windows systems, 55 | # it can't be used as an escape character. 56 | ignore-paths= 57 | 58 | # Files or directories matching the regular expression patterns are skipped. 59 | # The regex matches against base names, not paths. The default value ignores 60 | # Emacs file locks 61 | ignore-patterns=^\.# 62 | 63 | # List of module names for which member attributes should not be checked and 64 | # will not be imported (useful for modules/projects where namespaces are 65 | # manipulated during runtime and thus existing member attributes cannot be 66 | # deduced by static analysis). It supports qualified module names, as well as 67 | # Unix pattern matching. 68 | ignored-modules= 69 | 70 | # Python code to execute, usually for sys.path manipulation such as 71 | # pygtk.require(). 72 | #init-hook= 73 | 74 | # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the 75 | # number of processors available to use, and will cap the count on Windows to 76 | # avoid hangs. 77 | jobs=1 78 | 79 | # Control the amount of potential inferred values when inferring a single 80 | # object. This can help the performance when dealing with large functions or 81 | # complex, nested conditions. 82 | limit-inference-results=100 83 | 84 | # List of plugins (as comma separated values of python module names) to load, 85 | # usually to register additional checkers. 86 | load-plugins= 87 | 88 | # Pickle collected data for later comparisons. 89 | persistent=yes 90 | 91 | # Resolve imports to .pyi stubs if available. May reduce no-member messages and 92 | # increase not-an-iterable messages. 93 | prefer-stubs=no 94 | 95 | # Minimum Python version to use for version dependent checks. Will default to 96 | # the version used to run pylint. 97 | py-version=3.10 98 | 99 | # Discover python modules and packages in the file system subtree. 100 | recursive=no 101 | 102 | # Add paths to the list of the source roots. Supports globbing patterns. The 103 | # source root is an absolute path or a path relative to the current working 104 | # directory used to determine a package namespace for modules located under the 105 | # source root. 106 | source-roots= 107 | 108 | # When enabled, pylint would attempt to guess common misconfiguration and emit 109 | # user-friendly hints instead of false-positive error messages. 110 | suggestion-mode=yes 111 | 112 | # Allow loading of arbitrary C extensions. Extensions are imported into the 113 | # active Python interpreter and may run arbitrary code. 114 | unsafe-load-any-extension=no 115 | 116 | # In verbose mode, extra non-checker-related info will be displayed. 117 | #verbose= 118 | 119 | 120 | [BASIC] 121 | 122 | # Naming style matching correct argument names. 123 | argument-naming-style=snake_case 124 | 125 | # Regular expression matching correct argument names. Overrides argument- 126 | # naming-style. If left empty, argument names will be checked with the set 127 | # naming style. 128 | #argument-rgx= 129 | 130 | # Naming style matching correct attribute names. 131 | attr-naming-style=snake_case 132 | 133 | # Regular expression matching correct attribute names. Overrides attr-naming- 134 | # style. If left empty, attribute names will be checked with the set naming 135 | # style. 136 | #attr-rgx= 137 | 138 | # Bad variable names which should always be refused, separated by a comma. 139 | bad-names=foo, 140 | bar, 141 | baz, 142 | toto, 143 | tutu, 144 | tata 145 | 146 | # Bad variable names regexes, separated by a comma. If names match any regex, 147 | # they will always be refused 148 | bad-names-rgxs= 149 | 150 | # Naming style matching correct class attribute names. 151 | class-attribute-naming-style=any 152 | 153 | # Regular expression matching correct class attribute names. Overrides class- 154 | # attribute-naming-style. If left empty, class attribute names will be checked 155 | # with the set naming style. 156 | #class-attribute-rgx= 157 | 158 | # Naming style matching correct class constant names. 159 | class-const-naming-style=UPPER_CASE 160 | 161 | # Regular expression matching correct class constant names. Overrides class- 162 | # const-naming-style. If left empty, class constant names will be checked with 163 | # the set naming style. 164 | #class-const-rgx= 165 | 166 | # Naming style matching correct class names. 167 | class-naming-style=PascalCase 168 | 169 | # Regular expression matching correct class names. Overrides class-naming- 170 | # style. If left empty, class names will be checked with the set naming style. 171 | #class-rgx= 172 | 173 | # Naming style matching correct constant names. 174 | const-naming-style=UPPER_CASE 175 | 176 | # Regular expression matching correct constant names. Overrides const-naming- 177 | # style. If left empty, constant names will be checked with the set naming 178 | # style. 179 | #const-rgx= 180 | 181 | # Minimum line length for functions/classes that require docstrings, shorter 182 | # ones are exempt. 183 | docstring-min-length=-1 184 | 185 | # Naming style matching correct function names. 186 | function-naming-style=snake_case 187 | 188 | # Regular expression matching correct function names. Overrides function- 189 | # naming-style. If left empty, function names will be checked with the set 190 | # naming style. 191 | #function-rgx= 192 | 193 | # Good variable names which should always be accepted, separated by a comma. 194 | good-names=i, 195 | j, 196 | k, 197 | ex, 198 | Run, 199 | _ 200 | 201 | # Good variable names regexes, separated by a comma. If names match any regex, 202 | # they will always be accepted 203 | good-names-rgxs= 204 | 205 | # Include a hint for the correct naming format with invalid-name. 206 | include-naming-hint=no 207 | 208 | # Naming style matching correct inline iteration names. 209 | inlinevar-naming-style=any 210 | 211 | # Regular expression matching correct inline iteration names. Overrides 212 | # inlinevar-naming-style. If left empty, inline iteration names will be checked 213 | # with the set naming style. 214 | #inlinevar-rgx= 215 | 216 | # Naming style matching correct method names. 217 | method-naming-style=snake_case 218 | 219 | # Regular expression matching correct method names. Overrides method-naming- 220 | # style. If left empty, method names will be checked with the set naming style. 221 | #method-rgx= 222 | 223 | # Naming style matching correct module names. 224 | module-naming-style=snake_case 225 | 226 | # Regular expression matching correct module names. Overrides module-naming- 227 | # style. If left empty, module names will be checked with the set naming style. 228 | #module-rgx= 229 | 230 | # Colon-delimited sets of names that determine each other's naming style when 231 | # the name regexes allow several styles. 232 | name-group= 233 | 234 | # Regular expression which should only match function or class names that do 235 | # not require a docstring. 236 | no-docstring-rgx=^_ 237 | 238 | # List of decorators that produce properties, such as abc.abstractproperty. Add 239 | # to this list to register other decorators that produce valid properties. 240 | # These decorators are taken in consideration only for invalid-name. 241 | property-classes=abc.abstractproperty 242 | 243 | # Regular expression matching correct type alias names. If left empty, type 244 | # alias names will be checked with the set naming style. 245 | #typealias-rgx= 246 | 247 | # Regular expression matching correct type variable names. If left empty, type 248 | # variable names will be checked with the set naming style. 249 | #typevar-rgx= 250 | 251 | # Naming style matching correct variable names. 252 | variable-naming-style=snake_case 253 | 254 | # Regular expression matching correct variable names. Overrides variable- 255 | # naming-style. If left empty, variable names will be checked with the set 256 | # naming style. 257 | #variable-rgx= 258 | 259 | 260 | [CLASSES] 261 | 262 | # Warn about protected attribute access inside special methods 263 | check-protected-access-in-special-methods=no 264 | 265 | # List of method names used to declare (i.e. assign) instance attributes. 266 | defining-attr-methods=__init__, 267 | __new__, 268 | setUp, 269 | asyncSetUp, 270 | __post_init__ 271 | 272 | # List of member names, which should be excluded from the protected access 273 | # warning. 274 | exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit 275 | 276 | # List of valid names for the first argument in a class method. 277 | valid-classmethod-first-arg=cls 278 | 279 | # List of valid names for the first argument in a metaclass class method. 280 | valid-metaclass-classmethod-first-arg=mcs 281 | 282 | 283 | [DESIGN] 284 | 285 | # List of regular expressions of class ancestor names to ignore when counting 286 | # public methods (see R0903) 287 | exclude-too-few-public-methods= 288 | 289 | # List of qualified class names to ignore when counting class parents (see 290 | # R0901) 291 | ignored-parents= 292 | 293 | # Maximum number of arguments for function / method. 294 | max-args=5 295 | 296 | # Maximum number of attributes for a class (see R0902). 297 | max-attributes=7 298 | 299 | # Maximum number of boolean expressions in an if statement (see R0916). 300 | max-bool-expr=5 301 | 302 | # Maximum number of branch for function / method body. 303 | max-branches=12 304 | 305 | # Maximum number of locals for function / method body. 306 | max-locals=15 307 | 308 | # Maximum number of parents for a class (see R0901). 309 | max-parents=7 310 | 311 | # Maximum number of public methods for a class (see R0904). 312 | max-public-methods=20 313 | 314 | # Maximum number of return / yield for function / method body. 315 | max-returns=6 316 | 317 | # Maximum number of statements in function / method body. 318 | max-statements=50 319 | 320 | # Minimum number of public methods for a class (see R0903). 321 | min-public-methods=2 322 | 323 | 324 | [EXCEPTIONS] 325 | 326 | # Exceptions that will emit a warning when caught. 327 | overgeneral-exceptions=builtins.BaseException,builtins.Exception 328 | 329 | 330 | [FORMAT] 331 | 332 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 333 | expected-line-ending-format= 334 | 335 | # Regexp for a line that is allowed to be longer than the limit. 336 | ignore-long-lines=^\s*(# )??$ 337 | 338 | # Number of spaces of indent required inside a hanging or continued line. 339 | indent-after-paren=4 340 | 341 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 342 | # tab). 343 | indent-string=' ' 344 | 345 | # Maximum number of characters on a single line. 346 | max-line-length=100 347 | 348 | # Maximum number of lines in a module. 349 | max-module-lines=1000 350 | 351 | # Allow the body of a class to be on the same line as the declaration if body 352 | # contains single statement. 353 | single-line-class-stmt=no 354 | 355 | # Allow the body of an if to be on the same line as the test if there is no 356 | # else. 357 | single-line-if-stmt=no 358 | 359 | 360 | [IMPORTS] 361 | 362 | # List of modules that can be imported at any level, not just the top level 363 | # one. 364 | allow-any-import-level= 365 | 366 | # Allow explicit reexports by alias from a package __init__. 367 | allow-reexport-from-package=no 368 | 369 | # Allow wildcard imports from modules that define __all__. 370 | allow-wildcard-with-all=no 371 | 372 | # Deprecated modules which should not be used, separated by a comma. 373 | deprecated-modules= 374 | 375 | # Output a graph (.gv or any supported image format) of external dependencies 376 | # to the given file (report RP0402 must not be disabled). 377 | ext-import-graph= 378 | 379 | # Output a graph (.gv or any supported image format) of all (i.e. internal and 380 | # external) dependencies to the given file (report RP0402 must not be 381 | # disabled). 382 | import-graph= 383 | 384 | # Output a graph (.gv or any supported image format) of internal dependencies 385 | # to the given file (report RP0402 must not be disabled). 386 | int-import-graph= 387 | 388 | # Force import order to recognize a module as part of the standard 389 | # compatibility libraries. 390 | known-standard-library= 391 | 392 | # Force import order to recognize a module as part of a third party library. 393 | known-third-party=enchant 394 | 395 | # Couples of modules and preferred modules, separated by a comma. 396 | preferred-modules= 397 | 398 | 399 | [LOGGING] 400 | 401 | # The type of string formatting that logging methods do. `old` means using % 402 | # formatting, `new` is for `{}` formatting. 403 | logging-format-style=old 404 | 405 | # Logging modules to check that the string format arguments are in logging 406 | # function parameter format. 407 | logging-modules=logging 408 | 409 | 410 | [MESSAGES CONTROL] 411 | 412 | # Only show warnings with the listed confidence levels. Leave empty to show 413 | # all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, 414 | # UNDEFINED. 415 | confidence=HIGH, 416 | CONTROL_FLOW, 417 | INFERENCE, 418 | INFERENCE_FAILURE, 419 | UNDEFINED 420 | 421 | # Disable the message, report, category or checker with the given id(s). You 422 | # can either give multiple identifiers separated by comma (,) or put this 423 | # option multiple times (only on the command line, not in the configuration 424 | # file where it should appear only once). You can also use "--disable=all" to 425 | # disable everything first and then re-enable specific checks. For example, if 426 | # you want to run only the similarities checker, you can use "--disable=all 427 | # --enable=similarities". If you want to run only the classes checker, but have 428 | # no Warning level messages displayed, use "--disable=all --enable=classes 429 | # --disable=W". 430 | disable=raw-checker-failed, 431 | bad-inline-option, 432 | locally-disabled, 433 | file-ignored, 434 | suppressed-message, 435 | useless-suppression, 436 | deprecated-pragma, 437 | use-implicit-booleaness-not-comparison-to-string, 438 | use-implicit-booleaness-not-comparison-to-zero, 439 | use-symbolic-message-instead, 440 | C0303, C0304 441 | 442 | 443 | # Enable the message, report, category or checker with the given id(s). You can 444 | # either give multiple identifier separated by comma (,) or put this option 445 | # multiple time (only on the command line, not in the configuration file where 446 | # it should appear only once). See also the "--disable" option for examples. 447 | enable= 448 | 449 | 450 | [METHOD_ARGS] 451 | 452 | # List of qualified names (i.e., library.method) which require a timeout 453 | # parameter e.g. 'requests.api.get,requests.api.post' 454 | timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request 455 | 456 | 457 | [MISCELLANEOUS] 458 | 459 | # List of note tags to take in consideration, separated by a comma. 460 | notes=FIXME, 461 | XXX, 462 | TODO 463 | 464 | # Regular expression of note tags to take in consideration. 465 | notes-rgx= 466 | 467 | 468 | [REFACTORING] 469 | 470 | # Maximum number of nested blocks for function / method body 471 | max-nested-blocks=5 472 | 473 | # Complete name of functions that never returns. When checking for 474 | # inconsistent-return-statements if a never returning function is called then 475 | # it will be considered as an explicit return statement and no message will be 476 | # printed. 477 | never-returning-functions=sys.exit,argparse.parse_error 478 | 479 | # Let 'consider-using-join' be raised when the separator to join on would be 480 | # non-empty (resulting in expected fixes of the type: ``"- " + " - 481 | # ".join(items)``) 482 | suggest-join-with-non-empty-separator=yes 483 | 484 | 485 | [REPORTS] 486 | 487 | # Python expression which should return a score less than or equal to 10. You 488 | # have access to the variables 'fatal', 'error', 'warning', 'refactor', 489 | # 'convention', and 'info' which contain the number of messages in each 490 | # category, as well as 'statement' which is the total number of statements 491 | # analyzed. This score is used by the global evaluation report (RP0004). 492 | evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) 493 | 494 | # Template used to display messages. This is a python new-style format string 495 | # used to format the message information. See doc for all details. 496 | msg-template= 497 | 498 | # Set the output format. Available formats are: text, parseable, colorized, 499 | # json2 (improved json format), json (old json format) and msvs (visual 500 | # studio). You can also give a reporter class, e.g. 501 | # mypackage.mymodule.MyReporterClass. 502 | #output-format= 503 | 504 | # Tells whether to display a full report or only the messages. 505 | reports=no 506 | 507 | # Activate the evaluation score. 508 | score=yes 509 | 510 | 511 | [SIMILARITIES] 512 | 513 | # Comments are removed from the similarity computation 514 | ignore-comments=yes 515 | 516 | # Docstrings are removed from the similarity computation 517 | ignore-docstrings=yes 518 | 519 | # Imports are removed from the similarity computation 520 | ignore-imports=yes 521 | 522 | # Signatures are removed from the similarity computation 523 | ignore-signatures=yes 524 | 525 | # Minimum lines number of a similarity. 526 | min-similarity-lines=4 527 | 528 | 529 | [SPELLING] 530 | 531 | # Limits count of emitted suggestions for spelling mistakes. 532 | max-spelling-suggestions=4 533 | 534 | # Spelling dictionary name. No available dictionaries : You need to install 535 | # both the python package and the system dependency for enchant to work. 536 | spelling-dict= 537 | 538 | # List of comma separated words that should be considered directives if they 539 | # appear at the beginning of a comment and should not be checked. 540 | spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: 541 | 542 | # List of comma separated words that should not be checked. 543 | spelling-ignore-words= 544 | 545 | # A path to a file that contains the private dictionary; one word per line. 546 | spelling-private-dict-file= 547 | 548 | # Tells whether to store unknown words to the private dictionary (see the 549 | # --spelling-private-dict-file option) instead of raising a message. 550 | spelling-store-unknown-words=no 551 | 552 | 553 | [STRING] 554 | 555 | # This flag controls whether inconsistent-quotes generates a warning when the 556 | # character used as a quote delimiter is used inconsistently within a module. 557 | check-quote-consistency=no 558 | 559 | # This flag controls whether the implicit-str-concat should generate a warning 560 | # on implicit string concatenation in sequences defined over several lines. 561 | check-str-concat-over-line-jumps=no 562 | 563 | 564 | [TYPECHECK] 565 | 566 | # List of decorators that produce context managers, such as 567 | # contextlib.contextmanager. Add to this list to register other decorators that 568 | # produce valid context managers. 569 | contextmanager-decorators=contextlib.contextmanager 570 | 571 | # List of members which are set dynamically and missed by pylint inference 572 | # system, and so shouldn't trigger E1101 when accessed. Python regular 573 | # expressions are accepted. 574 | generated-members= 575 | 576 | # Tells whether to warn about missing members when the owner of the attribute 577 | # is inferred to be None. 578 | ignore-none=yes 579 | 580 | # This flag controls whether pylint should warn about no-member and similar 581 | # checks whenever an opaque object is returned when inferring. The inference 582 | # can return multiple potential results while evaluating a Python object, but 583 | # some branches might not be evaluated, which results in partial inference. In 584 | # that case, it might be useful to still emit no-member and other checks for 585 | # the rest of the inferred objects. 586 | ignore-on-opaque-inference=yes 587 | 588 | # List of symbolic message names to ignore for Mixin members. 589 | ignored-checks-for-mixins=no-member, 590 | not-async-context-manager, 591 | not-context-manager, 592 | attribute-defined-outside-init 593 | 594 | # List of class names for which member attributes should not be checked (useful 595 | # for classes with dynamically set attributes). This supports the use of 596 | # qualified names. 597 | ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace 598 | 599 | # Show a hint with possible names when a member name was not found. The aspect 600 | # of finding the hint is based on edit distance. 601 | missing-member-hint=yes 602 | 603 | # The minimum edit distance a name should have in order to be considered a 604 | # similar match for a missing member name. 605 | missing-member-hint-distance=1 606 | 607 | # The total number of similar names that should be taken in consideration when 608 | # showing a hint for a missing member. 609 | missing-member-max-choices=1 610 | 611 | # Regex pattern to define which classes are considered mixins. 612 | mixin-class-rgx=.*[Mm]ixin 613 | 614 | # List of decorators that change the signature of a decorated function. 615 | signature-mutators= 616 | 617 | 618 | [VARIABLES] 619 | 620 | # List of additional names supposed to be defined in builtins. Remember that 621 | # you should avoid defining new builtins when possible. 622 | additional-builtins= 623 | 624 | # Tells whether unused global variables should be treated as a violation. 625 | allow-global-unused-variables=yes 626 | 627 | # List of names allowed to shadow builtins 628 | allowed-redefined-builtins= 629 | 630 | # List of strings which can identify a callback function by name. A callback 631 | # name must start or end with one of those strings. 632 | callbacks=cb_, 633 | _cb 634 | 635 | # A regular expression matching the name of dummy variables (i.e. expected to 636 | # not be used). 637 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ 638 | 639 | # Argument names that match this expression will be ignored. 640 | ignored-argument-names=_.*|^ignored_|^unused_ 641 | 642 | # Tells whether we should check for unused import in __init__ files. 643 | init-import=no 644 | 645 | # List of qualified module names which can have objects that can redefine 646 | # builtins. 647 | redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io 648 | -------------------------------------------------------------------------------- /tutorials/unit_testing_and_exception_handling/mytest.py: -------------------------------------------------------------------------------- 1 | # First we should import the unittest module 2 | import unittest 3 | 4 | # This is the function we want to test 5 | def div(x, y): 6 | return x / y 7 | 8 | # Create a class that inherits from unittest.TestCase 9 | class TestDiv(unittest.TestCase): 10 | # We will write tests here which will test the vulnerable function 11 | def test_div_by_zero(self): 12 | self.assertRaises(ZeroDivisionError, div, 1, 0) 13 | 14 | def test_div_pass(self): 15 | self.assertEqual(div(1, 1), 1) 16 | self.assertGreaterEqual(div(1, 2), 0.5) 17 | 18 | def test_div_fail(self): 19 | self.assertEqual(div(1, 1), 2) 20 | 21 | if __name__ == '__main__': 22 | unittest.main() -------------------------------------------------------------------------------- /tutorials/unit_testing_and_exception_handling/mytest_new.py: -------------------------------------------------------------------------------- 1 | def add(x, y): 2 | return x + y 3 | 4 | # All test cases should have test_ prefix 5 | def test_add_pass(): 6 | assert add(1, 1) == 2 7 | assert add(10, 10.5) == 20.5 8 | 9 | def test_add_fail(): 10 | assert add(1, 1) == 3 -------------------------------------------------------------------------------- /tutorials/unit_testing_and_exception_handling/unit_testing_and_exception_handling_in_python.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Lesson 8: Unit Testing and Exception Handling \n", 8 | "* Objectives: \n", 9 | "\n", 10 | " 1. Importance of unit testing \n", 11 | "\n", 12 | " 2. Writing test cases \n", 13 | "\n", 14 | " 3. Try, except, and finally\n", 15 | "\n", 16 | " 4. Custom exceptions \n", 17 | " \n", 18 | " 5. Debugging techniques " 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "### Unit Testing\n", 26 | "\n", 27 | "* Unit testing is a method of testing individual units of source code to determine if they are fit for use. \n", 28 | "\n", 29 | "* In Python, the unittest module, which is part of the standard library, provides a framework for creating and running unit tests." 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "### assert Statement\n", 37 | "\n", 38 | "* Assertions are statements that assert or state a fact confidently in your program.\n", 39 | "\n", 40 | "* It is also a debugging tool as it halts the program as soon as an error occurs and displays it.\n", 41 | "\n", 42 | "* Syntax: \n", 43 | " * assert \\\n", 44 | " * assert \\, \\" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 3, 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "ename": "AssertionError", 54 | "evalue": "Divide by zero error", 55 | "output_type": "error", 56 | "traceback": [ 57 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 58 | "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", 59 | "Cell \u001b[0;32mIn[3], line 6\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m y \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m0\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDivide by zero error\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m x \u001b[38;5;241m/\u001b[39m y\n\u001b[0;32m----> 6\u001b[0m \u001b[43mdiv\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\n", 60 | "Cell \u001b[0;32mIn[3], line 2\u001b[0m, in \u001b[0;36mdiv\u001b[0;34m(x, y)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mdiv\u001b[39m(x, y):\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m y \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m0\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDivide by zero error\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m x \u001b[38;5;241m/\u001b[39m y\n", 61 | "\u001b[0;31mAssertionError\u001b[0m: Divide by zero error" 62 | ] 63 | } 64 | ], 65 | "source": [ 66 | "def div(x, y):\n", 67 | " assert y != 0, \"Divide by zero error\"\n", 68 | " return x / y\n", 69 | "\n", 70 | "\n", 71 | "div(1, 0)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "### Creating Unit tests with unittest module\n", 79 | "\n", 80 | "* A test case is a single unit of testing. \n", 81 | "\n", 82 | "* To create a test case, we define a class that inherits from unittest.TestCase and add test methods. \n", 83 | "\n", 84 | "* Each test method should start with the word test.\n", 85 | "\n", 86 | "* For more on unittest, please refer to official documentation [here](https://docs.python.org/3/library/unittest.html)." 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "Create a file mytest.py" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 4, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "# Inside mytest.py\n", 103 | "# First we should import the unittest module\n", 104 | "import unittest\n", 105 | "\n", 106 | "# This is the function we want to test\n", 107 | "def div(x, y):\n", 108 | " return x / y\n", 109 | "\n", 110 | "class TestDiv(unittest.TestCase):\n", 111 | " # We will write tests here which will test the vulnerable function\n", 112 | " def test_div_by_zero(self):\n", 113 | " self.assertRaises(ZeroDivisionError, div, 1, 0)\n", 114 | " \n", 115 | " def test_div_pass(self):\n", 116 | " self.assertEqual(div(1, 1), 1)\n", 117 | " self.assertGreaterEqual(div(1, 2), 0.5)\n", 118 | " \n", 119 | " def test_div_fail(self):\n", 120 | " self.assertEqual(div(1, 1), 2)\n", 121 | "\n", 122 | "if __name__ == '__main__':\n", 123 | " unittest.main()" 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "Run the test file mytest.py\n", 131 | ">python mytest.py" 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "### Creating TestCases with pytest\n", 139 | "\n", 140 | "* pytest is a popular third-party testing framework that offers a simpler and more powerful testing experience compared to unittest.\n", 141 | "\n", 142 | "* Installing pytest:\n", 143 | "\n", 144 | " > pip install pytest" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": {}, 150 | "source": [ 151 | "Create a test file mytest_new.py" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": null, 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "def add(x, y):\n", 161 | " return x + y\n", 162 | "\n", 163 | "# All test cases should have test_ prefix\n", 164 | "def test_add_pass(self):\n", 165 | " assert add(1, 1) == 2\n", 166 | " assert add(10, 10.5) == 20.5\n", 167 | " \n", 168 | "def test_add_fail(self):\n", 169 | " assert add(1, 1) == 3\n", 170 | " assert add(10, 10.5) == 22" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "Run the test file using pytest.\n", 178 | "> pytest mytest_new.py" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": {}, 184 | "source": [ 185 | "### Exception Handling in Python\n", 186 | "\n", 187 | "* Error and exception handling is a crucial part of programming that allows our code to handle unexpected situations gracefully, preventing crashes and providing meaningful error messages to users." 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "metadata": {}, 193 | "source": [ 194 | "**Using try, except, else, and finally**\n", 195 | "\n", 196 | "* The try block lets you test a block of code for errors\n", 197 | "\n", 198 | "* The except block lets you handle the error. \n", 199 | "\n", 200 | "* The else block lets you execute code if no error occurs.\n", 201 | "\n", 202 | "* The finally block lets you execute code, regardless of the result of the try and except blocks." 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 1, 208 | "metadata": {}, 209 | "outputs": [], 210 | "source": [ 211 | "try:\n", 212 | " # Code that may raise an exception\n", 213 | " pass\n", 214 | "except ExceptionType:\n", 215 | " # Code that runs if the exception occurs\n", 216 | " pass\n", 217 | "else:\n", 218 | " # Code that runs if no exception occurs\n", 219 | " pass\n", 220 | "finally:\n", 221 | " # Code that runs no matter what\n", 222 | " pass" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "Example" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": 3, 235 | "metadata": {}, 236 | "outputs": [ 237 | { 238 | "name": "stdout", 239 | "output_type": "stream", 240 | "text": [ 241 | "Cannot divide by zero!\n", 242 | "This is finally block, it will run no matter what.\n" 243 | ] 244 | } 245 | ], 246 | "source": [ 247 | "try:\n", 248 | " result = 10 / 0\n", 249 | "except ZeroDivisionError:\n", 250 | " print(\"Cannot divide by zero!\")\n", 251 | "else:\n", 252 | " print(\"Division successful!\")\n", 253 | "finally:\n", 254 | " print(\"This is finally block, it will run no matter what.\")" 255 | ] 256 | }, 257 | { 258 | "cell_type": "markdown", 259 | "metadata": {}, 260 | "source": [ 261 | "Multiple Exceptions" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 13, 267 | "metadata": {}, 268 | "outputs": [ 269 | { 270 | "name": "stdout", 271 | "output_type": "stream", 272 | "text": [ 273 | "Cannot divide by zero.\n", 274 | "Execution completed.\n" 275 | ] 276 | } 277 | ], 278 | "source": [ 279 | "numerator = 10\n", 280 | "denominator = 0\n", 281 | "\n", 282 | "try:\n", 283 | " result = numerator / denominator\n", 284 | "except ValueError:\n", 285 | " print(\"Invalid input. Please enter a valid number.\")\n", 286 | "except ZeroDivisionError:\n", 287 | " print(\"Cannot divide by zero.\")\n", 288 | "else:\n", 289 | " print(f\"Result: {result}\")\n", 290 | "finally:\n", 291 | " print(\"Execution completed.\")\n" 292 | ] 293 | }, 294 | { 295 | "cell_type": "markdown", 296 | "metadata": {}, 297 | "source": [ 298 | "**Built-In Exceptions**\n", 299 | "\n", 300 | "* Python has many built-in exceptions that are raised when the program encounters an error.\n", 301 | "\n", 302 | " * ZeroDivisionError: Raised when division by zero is attempted.\n", 303 | "\n", 304 | " * IndexError: Raised when an index is not found in a sequence.\n", 305 | "\n", 306 | " * KeyError: Raised when a key is not found in a dictionary.\n", 307 | "\n", 308 | " * TypeError: Raised when an operation or function is applied to an object of inappropriate type.\n", 309 | " \n", 310 | " * ValueError: Raised when a function receives an argument of the correct type but inappropriate value." 311 | ] 312 | }, 313 | { 314 | "cell_type": "markdown", 315 | "metadata": {}, 316 | "source": [ 317 | "Example" 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "execution_count": 6, 323 | "metadata": {}, 324 | "outputs": [ 325 | { 326 | "name": "stdout", 327 | "output_type": "stream", 328 | "text": [ 329 | "list index out of range\n", 330 | "My custom message: Index out of range!\n" 331 | ] 332 | } 333 | ], 334 | "source": [ 335 | "try:\n", 336 | " my_list = [1, 2, 3]\n", 337 | " print(my_list[5])\n", 338 | "except IndexError as e:\n", 339 | " print(e)\n", 340 | " print(\"My custom message: Index out of range!\")" 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "metadata": {}, 346 | "source": [ 347 | "**Raising Exceptions**\n", 348 | "* We can raise exceptions using the raise keyword" 349 | ] 350 | }, 351 | { 352 | "cell_type": "code", 353 | "execution_count": 8, 354 | "metadata": {}, 355 | "outputs": [ 356 | { 357 | "name": "stdout", 358 | "output_type": "stream", 359 | "text": [ 360 | "Cannot take square root of negative number\n" 361 | ] 362 | } 363 | ], 364 | "source": [ 365 | "def square_root(x):\n", 366 | " if x < 0:\n", 367 | " raise ValueError(\"Cannot take square root of negative number\")\n", 368 | " return x**0.5\n", 369 | "\n", 370 | "# Since the square_root function may raise exception during runtime, we need to handle it\n", 371 | "try:\n", 372 | " square_root(-1)\n", 373 | "except ValueError as e:\n", 374 | " print(e)" 375 | ] 376 | }, 377 | { 378 | "cell_type": "markdown", 379 | "metadata": {}, 380 | "source": [ 381 | "**Creating Custom Exceptions**\n", 382 | "* Custom exceptions can be created by inheriting from the Exception class.\n", 383 | "\n", 384 | "* Custom exceptions allow you to define your own error types." 385 | ] 386 | }, 387 | { 388 | "cell_type": "code", 389 | "execution_count": 15, 390 | "metadata": {}, 391 | "outputs": [ 392 | { 393 | "name": "stdout", 394 | "output_type": "stream", 395 | "text": [ 396 | "Exception occurred: Invalid Age\n" 397 | ] 398 | } 399 | ], 400 | "source": [ 401 | "# Custom exception\n", 402 | "class InvalidAgeException(Exception):\n", 403 | " \"Raised when the input value is less than 18\"\n", 404 | " pass" 405 | ] 406 | }, 407 | { 408 | "cell_type": "code", 409 | "execution_count": 16, 410 | "metadata": {}, 411 | "outputs": [ 412 | { 413 | "name": "stdout", 414 | "output_type": "stream", 415 | "text": [ 416 | "Exception occurred: Invalid Age\n" 417 | ] 418 | } 419 | ], 420 | "source": [ 421 | "age = 17\n", 422 | "\n", 423 | "try:\n", 424 | " if age < 18:\n", 425 | " raise InvalidAgeException\n", 426 | " else:\n", 427 | " print(\"Eligible to Vote\")\n", 428 | " \n", 429 | "except InvalidAgeException:\n", 430 | " print(\"Exception occurred: Invalid Age\")" 431 | ] 432 | }, 433 | { 434 | "cell_type": "markdown", 435 | "metadata": {}, 436 | "source": [ 437 | "**Customizing Exception Classes**" 438 | ] 439 | }, 440 | { 441 | "cell_type": "code", 442 | "execution_count": 25, 443 | "metadata": {}, 444 | "outputs": [], 445 | "source": [ 446 | "class InvalidAgeException(Exception):\n", 447 | " \"Raised when the input value is less than 18\"\n", 448 | " def __init__(self, age, message=\"Age should be greater than 18 to vote\"):\n", 449 | " self.age = age\n", 450 | " self.message = f\"{age} < 18: {message}\"\n", 451 | " super().__init__(self.message)\n", 452 | " " 453 | ] 454 | }, 455 | { 456 | "cell_type": "code", 457 | "execution_count": 24, 458 | "metadata": {}, 459 | "outputs": [ 460 | { 461 | "name": "stdout", 462 | "output_type": "stream", 463 | "text": [ 464 | "Eligible to Vote\n" 465 | ] 466 | } 467 | ], 468 | "source": [ 469 | "age = 18\n", 470 | "\n", 471 | "try:\n", 472 | " if age < 18:\n", 473 | " raise InvalidAgeException(age)\n", 474 | " else:\n", 475 | " print(\"Eligible to Vote\")\n", 476 | " \n", 477 | "except InvalidAgeException as e:\n", 478 | " print(e)" 479 | ] 480 | }, 481 | { 482 | "cell_type": "code", 483 | "execution_count": null, 484 | "metadata": {}, 485 | "outputs": [], 486 | "source": [] 487 | } 488 | ], 489 | "metadata": { 490 | "kernelspec": { 491 | "display_name": "Python 3", 492 | "language": "python", 493 | "name": "python3" 494 | }, 495 | "language_info": { 496 | "codemirror_mode": { 497 | "name": "ipython", 498 | "version": 3 499 | }, 500 | "file_extension": ".py", 501 | "mimetype": "text/x-python", 502 | "name": "python", 503 | "nbconvert_exporter": "python", 504 | "pygments_lexer": "ipython3", 505 | "version": "3.8.10" 506 | } 507 | }, 508 | "nbformat": 4, 509 | "nbformat_minor": 2 510 | } 511 | -------------------------------------------------------------------------------- /tutorials/working_with_libraries.md: -------------------------------------------------------------------------------- 1 | ## Working with Libraries in Python 2 | Libraries in Python are collections of modules and packages that provide pre-written code to help you perform common tasks, saving time and effort. Python has a rich ecosystem of standard libraries, as well as third-party libraries, which we can use to extend the functionality of your programs. 3 | 4 | ### Standard Libraries 5 | 6 | Python's standard library is a collection of modules and packages that come with Python, providing a wide range of functionalities. We do not need to install standard libraries separately. 7 | 8 | **Commonly Used Standard Libraries** 9 | 10 | * os: Provides functions to interact with the operating system. 11 | * sys: Provides access to some variables used or maintained by the interpreter. 12 | * datetime: Supplies classes for manipulating dates and times. 13 | * random: Implements pseudo-random number generators. 14 | * json: Provides methods for working with JSON data. 15 | 16 | **Importing and Using Standard Libraries** 17 | ``` 18 | import math 19 | 20 | print(math.sqrt(16)) 21 | print(math.pi) 22 | ``` 23 | We can also import specific functions or classes from a module: 24 | 25 | ``` 26 | from datetime import datetime 27 | 28 | now = datetime.now() 29 | print(now) # Output: current date and time 30 | ``` 31 | 32 | ### Third-Party Libraries 33 | Third-party libraries are packages that are not included in the standard library but can be installed using the Python package manager, pip. 34 | 35 | Command to install third party libraries 36 | ``` 37 | pip install pakage_name 38 | ``` 39 | Example: 40 | NumPy is a library for numerical operations and working with arrays. 41 | Let's install numpy. 42 | ``` 43 | pip install numpy 44 | ``` 45 | Once installed, we can import and use the library just like any other module: 46 | 47 | ``` 48 | import numpy as np 49 | 50 | arr = np.array([1, 2, 3, 4, 5]) 51 | print(arr.mean()) 52 | ``` 53 | 54 | ### Virtual Environment 55 | 56 | A virtual environment is a Python environment such that the Python interpreter, libraries and scripts installed into it are isolated from those installed in other virtual environments, and (by default) any libraries installed in a “system” Python, i.e., one which is installed as part of your operating system 57 | 58 | ``` 59 | pip install virtualenv 60 | ``` 61 | If virutalenv could not be installed then try installing with apt. 62 | ``` 63 | sudo apt install python-venv 64 | ``` 65 | 66 | Create a virtual environment 67 | ``` 68 | python -m venv 69 | ``` 70 | 71 | Example: 72 | ``` 73 | python3.8 -m venv myvenv 74 | ``` 75 | 76 | Once the virtual env has been created then, we can install libraries inside that virtual environment. 77 | 78 | ``` 79 | source path_to_virtual_env/bin/activate 80 | ``` 81 | 82 | To check the packages installed inside our virtual environment: 83 | ``` 84 | pip list 85 | ``` 86 | 87 | To deactivate the virtual environment use following command 88 | ``` 89 | deactivate 90 | ``` 91 | --------------------------------------------------------------------------------