{
  "Python Introduction": [
    {
      "title": "Introduction to Python",
      "description": "Python is a high-level, general-purpose, dynamically typed, compiled and interpreted, garbage-collected, and purely object-oriented language that supports procedural, object-oriented, and functional programming.It was created by Van Guido van Rossum in 1991.",
      "sub_description": "It is among the top programming languages widely used around the world and is utilized extensively in numerous AI, Machine Learning, Data Sciences, and web development applications.",
      "additional_info": "The Python script is pretty simple to understand and grasp because of easy-to-understand and a straightforward syntax. For freshers in the IT business, the best reason one would pick this up could be it gets going into coding quickly.",
      "content": [
        {
          "type": "textarea",
          "text": "print('Welcome to Webcooks!')"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Use cases of python:"
        },
        {
          "type": "list",
          "items": [
            "This language may create web applications by being implemented in a server.",
            "One is able to connect this up to the database system with Python. Also, modify data files as per wish.",
            "The application handles great big data, mathematical handling.",
            "Python can be extensively used in AI, Automation, Machine Learning."
          ]
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Who uses Python today?"
        },
        {
          "type": "list",
          "items": [
            "Production firms like Industrial Light & Magic, Pixar among many other firms, apply Python to productions of cartoon movies.",
            "To predict applications in the financial market uses of Python exist among the financial firms that include; JPMorgan Chase ,UBS, Getco and Citadel.",
            "Other uses exist for this Python programming language in its applied aspects. NASA,Los Alamos, Fermilab, JPL etc apply it for scientific programmimg.",
            "iRobot applies python as an application for their industrial commercial robotic devices, or simply put, develops those robotic devices using it.",
            "ESRI company which has its popular GIS Mapping uses it as an End user customization tool."
          ]
        },
        {
          "type": "heading",
          "level": 2,
          "text": "What can Python be used for?"
        },
        {
          "type": "list",
          "items": [
            "System Programming",
            "GUI’s",
            "Internet Scripting",
            "Component Integration",
            "Database Programming",
            "Numeric and Scientific Programming",
            "Gaming, Images, Robots"
          ]
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Technical Strength of Python"
        },
        {
          "type": "list",
          "items": [
            "Purely Object-Oriented",
            "Easily Portable",
            "Easy to learn and use",
            "High level",
            "Compiled and Interpreter",
            "Free to use / Open-source",
            "Large Standard Library"
          ]
        }
      ]
    },
    {
      "title": "Python syntax",
      "description": "In python print() function is used to get output in console or terminal. This helps to display text, variables, etc., in human readable. ",
      "sub_description": "Unlike Semicolon available in other programming languages; Python uses Newline character to end a statement. ",
      "additional_info": "That is, it is a case sensitive language; as Upper Case and Lower Case Letters has different meaning within the language. ",
      "content": [
        {
          "type": "textarea",
          "text": "value1 = 'Welcome to WebCooks'\nvalue2 = 'welcome to webcooks'\n\nprint(value1)\nprint(value2)\n\nif value1 != value2:\n    print('The variables are treated as different due to case sensitivity.')"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Python Indentation"
        },
        {
          "type": "paragraph",
          "text": "Python is an easy language, almost as simple as the English language. In python, no curly braces or semicolons are used. It defines a block of code with indentation. If indentation is misused, it will lead to an 'Indentation Error' in the python code."
        },
        {
          "type": "textarea",
          "text": "if True:\n    print('This is properly indented')  # This line is indented correctly\n\nprint('This line is not indented')  # This line is at the outer block"
        },
        {
          "type": "paragraph",
          "text": "Indentation is used only for readability of code in other languages, but in Python it plays a very crucial role. If indentation skips then an error will occur. "
        }
      ]
    },
    {
      "title": "Comments in python",
      "description": "Comments in Python are notes in the code for readability and for explaining what the code is doing. The comments get ignored during execution because, naturally, they are for the developer to read. ",
      "sub_description": "Comments are created using a pound sign # at the start of the line.",
      "additional_info": "There are two types of comments in python:",
      "content": [
        {
          "type": "heading",
          "level": 2,
          "text": "Single-line comment"
        },
        {
          "type": "paragraph",
          "text": "Created by placing a # at the beginning of a line, marking everything after it as a comment until the end of that line."
        },
        {
          "type": "textarea",
          "text": "# This is a single-line comment in Python\n# Welcome to Webcooks!"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Multi-line comment"
        },
        {
          "type": "paragraph",
          "text": "While Python does not have a dedicated multi-line comment syntax, multiple lines can be commented out by placing # at the beginning of each line. Alternatively, triple quotes (\"\"\" ... \"\"\" or ''' ... ''') can be used to write multi-line comments, even though they are technically multi-line strings."
        },
        {
          "type": "textarea",
          "text": "\"\"\"\\nThis is a multi-line comment in Python.\\nWelcome to Webcooks!\\n\"\"\""
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Features of Comments"
        },
        {
          "type": "list",
          "items": [
            "Comments are meant for later use because comments make our code readable.",
            "For debugging.",
            "Sharing and commenting on the codes among the peer developers, in the coding collaboration."
          ]
        }
      ]
    }
  ],
  "Python Fundamentals": [
    {
      "title": "Python variables and literals",
      "description": "Variables are containers that hold the values of data. A variable is the label assigned to a memory address.The identifier is also known as a value-holding Python variable.",
      "sub_description": "There is no command to declare a variable.When a variable first assign with a value, that is considered as the variable creation point. It need not be declared as any special type,and even can be changed in type after they have been defined.",
      "additional_info": "Variable name can be of any length but it must begin with a letter or an underscore, but they can be a group of both letters and digits.",
      "content": [
        {
          "type": "textarea",
          "text": "# Defining variables in Python\nwebcooks_variable = 'Welcome to Webcooks'\nprint(webcooks_variable)"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Literals in Python"
        },
        {
          "type": "paragraph",
          "text": "Data assigned to a variable or constant can be described as literals. Literals are program representations of fixed values. They can either be numeric values, characters, or a string, etc."
        },
        {
          "type": "textarea",
          "text": "# Python Literals Example\n\n# String literal\nstring_literal = 'Welcome to Webcooks'\n\n# Integer literal\ninteger_literal = 100\n\n# Float literal\nfloat_literal = 3.14\n\n# Boolean literal\nboolean_literal = True\n\n# List literal\nlist_literal = [1, 2, 3, 'Webcooks']\n\n# Dictionary literal\ndict_literal = {'course': 'Python', 'duration': '6 months'}\n\nprint(string_literal)\nprint(integer_literal)\nprint(float_literal)\nprint(boolean_literal)\nprint(list_literal)\nprint(dict_literal)"
        },
        {
          "type": "heading",
          "level": 4,
          "text": "Python Numeric Literals"
        },
        {
          "type": "paragraph",
          "text": "Numeric Literals are immutable i.e this is unchangeable.The three types of numeric literals could be integer, float, or even complex."
        },
        {
          "type": "heading",
          "level": 5,
          "text": "Integer Literals"
        },
        {
          "type": "paragraph",
          "text": "Integer are numbers that do not have decimal parts.Integer literals are numbers without decimal part. It also includes the negative numbers. For instance, 5, -11, 0, 12, etc."
        },
        {
          "type": "textarea",
          "text": "# Positive Integer Literal\npositive_integer = 42\n\n# Negative Integer Literal\nnegative_integer = -7\n\n# Example of using integer literals in arithmetic operation:\nresult = positive_integer + negative_integer # result will be 35"
        },
        {
          "type": "heading",
          "level": 5,
          "text": "Floating-Point Literals"
        },
        {
          "type": "paragraph",
          "text": "Floating point are numbers that have decimal parts. Like integers, there are also positive and negative floating point. For example, 2.5, 6.76, 0.0, -9.45, etc."
        },
        {
          "type": "textarea",
          "text": "# Positive floating-point literal\npositive_float = 3.14\n\n# Negative floating-point literal\nnegative_float = -2.71\n\n# Using floating-point literals in a calculation\nresult = positive_float * 2  # result will be 6.28\n\n# Scientific notation for floating-point literals\nscientific_float = 1.23e4  # equivalent to 12300.0\n\n# Negative scientific notation\nnegative_scientific_float = -5.67e-3  # equivalent to -0.00567"
        },
        {
          "type": "heading",
          "level": 5,
          "text": "Complex Literals"
        },
        {
          "type": "paragraph",
          "text": "Complex literals are numbers which define complex numbers.Here, numerals can be written in the format a + bj, such that a is real while b is imaginary. So, some examples of 6+9j and 2+3j."
        },
        {
          "type": "textarea",
          "text": "# Imaginary part is denoted by 'j'.\n\n# Examples:\n\n# Positive complex number\ncomplex_num1 = 3 + 4j  # real part: 3, imaginary part: 4j\n\n# Negative complex number\ncomplex_num2 = -2.5 - 3.5j  # real part: -2.5, imaginary part: -3.5j\n\n# Adding complex literals\nresult = complex_num1 + complex_num2  # result will be (0.5 + 0.5j)\n\n# Accessing real and imaginary parts\nreal_part = complex_num1.real  # 3.0\nimaginary_part = complex_num1.imag  # 4.0"
        },
        {
          "type": "heading",
          "level": 4,
          "text": "String Literals"
        },
        {
          "type": "paragraph",
          "text": "In Python, texts wrapped inside quotation marks are called string literals.They can use both the single and double quotes together to write a string."
        },
        {
          "type": "textarea",
          "text": "message1 = 'Hello, Webcooks!'\nmessage2 = \"Learning Python is fun!\"\n\n# Printing the string literals\nprint(message1)  # Output: Hello, Webcooks!\nprint(message2)  # Output: Learning Python is fun!"
        }
      ]
    },
    {
      "title": "Datatypes",
      "description": "In Python, everything has a datatype.Variables can hold values, which are nothing but pieces of data.",
      "sub_description": " We can easily get the data type of any object by using the type() function.",
      "additional_info": "",
      "content": [
        {
          "type": "textarea",
          "text": "# Basic Data Types in Python\n\n# 1. Integer\nnum = 10  # Integer type\n\n# 2. Float\npi = 3.14  # Float type\n\n# 3. Complex\ncomplex_num = 3 + 4j  # Complex type\n\n# 4. String\ntext = 'Welcome to Webcooks'  # String type\n\n# 5. List\nfruits = ['apple', 'banana', 'cherry']  # List type\n\n# 6. Tuple\ncoordinates = (10, 20)  # Tuple type\n\n# 7. Dictionary\ndata = {'name': 'Webcooks', 'course': 'Python'}  # Dictionary type\n\n# 8. Boolean \n is_active = True"
        },
        {
          "type": "heading",
          "level": 1,
          "text": "Numbers"
        },
        {
          "type": "paragraph",
          "text": "Numbers in Python support the normal mathematical operations.Python provides three different numeric datatypes."
        },
        {
          "type": "list",
          "items": [
            "<b>int</b> - stores signed integers of arbitrary size",
            "<b>float</b> - stores floating point decimal values and is good up to 15 decimal places.",
            "<b>complex</b> - store complex number."
          ]
        },
        {
          "type": "textarea",
          "text": "# Examples of Numbers in Python\n\n# Integer\nint_num = 42  # Signed integer of non-limited length\n\n# Float\nfloat_num = 3.141592653589793  # Float with up to 15 decimal places\n\n# Complex\ncomplex_num = 5 + 2j  # Complex number with real and imaginary parts\n\n# Demonstrating operations\nsum_result = int_num + float_num  # Adding an integer and a float\ncomplex_operation = complex_num + 3j  # Adding two complex numbers"
        },
        {
          "type": "heading",
          "level": 4,
          "text": "Type Conversion"
        },
        {
          "type": "paragraph",
          "text": "Type conversion is the process of converting one data type to another with the int(), float(), complex() methods."
        },
        {
          "type": "textarea",
          "text": "# Type Conversion in Python\n\n# Integer to Float\nint_num = 10\nfloat_num = float(int_num)  # Converts integer to float, result: 10.0\n\n# Float to Integer\nfloat_val = 15.8\nint_val = int(float_val)  # Converts float to integer, result: 15\n\n# Integer to Complex\nint_num = 7\ncomplex_num = complex(int_num)  # Converts integer to complex, result: (7+0j)\n\n# Displaying the conversions\nprint('Integer to Float:', float_num)\nprint('Float to Integer:', int_val)\nprint('Integer to Complex:', complex_num)"
        },
        {
          "type": "heading",
          "level": 4,
          "text": "Random Number"
        },
        {
          "type": "paragraph",
          "text": "Random Number Python has an in-built module named random by which it can generate the random number or can pick the random item from an iterator. "
        },
        {
          "type": "textarea",
          "text": "# Generating Random Numbers in Python\nimport random\n\n# Generate a random integer between 1 and 10\nrand_int = random.randint(1, 10)\nprint('Random Integer:', rand_int)\n\n# Generate a random float between 0 and 1\nrand_float = random.random()\nprint('Random Float:', rand_float)\n\n# Pick a random item from a list\nitems = ['apple', 'banana', 'cherry']\nrand_item = random.choice(items)\nprint('Random Item:', rand_item)"
        },
        {
          "type": "heading",
          "level": 4,
          "text": "Python Mathematics"
        },
        {
          "type": "paragraph",
          "text": "The math module of the python implements several mathematical operations such as trigonometry, logarithms, probability and statistics."
        },
        {
          "type": "textarea",
          "text": "# Python Mathematics Examples\nimport math\n\n# 1. Square root\nnum = 16\nsqrt = math.sqrt(num)\nprint('Square root of', num, 'is', sqrt)\n\n# 2. Power\nbase = 3\nexponent = 4\npower = math.pow(base, exponent)\nprint(base, 'raised to the power of', exponent, 'is', power)\n\n# 3. Rounding\nvalue = 5.7\nrounded_value = round(value)\nprint('Rounded value of', value, 'is', rounded_value)\n\n# 4. Trigonometry\nangle = math.radians(90)  # Convert 90 degrees to radians\nsin_value = math.sin(angle)\nprint('Sine of 90 degrees is', sin_value)"
        },
        {
          "type": "heading",
          "level": 1,
          "text": "Strings"
        },
        {
          "type": "paragraph",
          "text": "String is a sequence of characters which can be represented in several ways. They are enclosed either within single quote marks or double quote marks."
        },
        {
          "type": "textarea",
          "text": "# Working with Strings in Python\n\n# 1. Creating a String\nwelcome_msg = \"Welcome to Webcooks\"\n\n# 2. Creating another String\njoin_msg = 'Join python course at Webcooks'\n"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Multiline Strings"
        },
        {
          "type": "paragraph",
          "text": "Using triple quotes assign a string containing multiple lines to a variable."
        },
        {
          "type": "textarea",
          "text": "# Multiline Strings in Python\n\n# Using triple quotes to create a multiline string\ncourse_description = \"\"\"\\nWebcooks offers a variety of Python courses,\\nfrom beginner to advanced levels,\\nthat help students develop their coding skills.\\n\"\"\""
        }
      ]
    },
    {
      "title": "Basic Input Output",
      "description": "",
      "sub_description": "",
      "additional_info": "",
      "content": [
        {
          "type": "heading",
          "level": 1,
          "text": "Python Output"
        },
        {
          "type": "paragraph",
          "text": "We can directly use the print() function to print out of Python. print() is utilized to print or output the string enclosed between quotes."
        },
        {
          "type": "heading",
          "level": 4,
          "text": "Syntax of print()"
        },
        {
          "type": "paragraph",
          "text": "The print() is accepting single parameter. However the precise syntax of the print accepts 5 parameters as follows:<br>print(object= separator= end= file= flush=)<br>Here,"
        },
        {
          "type": "list",
          "items": [
            "<b>object</b> -  is a value(s) for being printed",
            "<b>sep (optional)</b> - lets us separate multiple objects inside print().",
            "<b>end (optional)</b> - lets us add specific values like new line \\n, tab \\t.",
            "<b>file (optional)</b> - where the values are printed. It's default value is sys.stdout (screen).",
            "<b>flush (optional)</b> - boolean indicating whether output is flushed or buffered. Defaults to False."
          ]
        },
        {
          "type": "textarea",
          "text": "# Python Output Examples\n\n# 1. Simple Print Statement\nprint(\"Welcome to Webcooks\")  # Outputs: Welcome to Webcooks\n\n# 2. Printing Variables\nname = \"Webcooks\"\nprint(\"Hello,\", name)  # Outputs: Hello, Webcooks\n\n# 3. Formatted String Output\ncourse = \"Python\"\nduration = 6\nprint(f\"Join the {course} course at Webcooks for {duration} weeks\")  # Outputs: Join the Python course at Webcooks for 6 weeks"
        },
        {
          "type": "heading",
          "level": 4,
          "text": "Output Formatting"
        },
        {
          "type": "paragraph",
          "text": "In python str.format() method is used for the formatting output to make look more attractive."
        },
        {
          "type": "textarea",
          "text": "# Output Formatting in Python\n\n# Using str.format() Method\nname = \"Webcooks\"\ncourse = \"Python\"\nduration = 6\n\n# Example of output formatting\nformatted_message = \"Welcome to {}. Join the {} course for {} weeks.\".format(name, course, duration)\nprint(formatted_message)  # Outputs: Welcome to Webcooks. Join the Python course for 6 weeks."
        },
        {
          "type": "heading",
          "level": 1,
          "text": "Python Input"
        },
        {
          "type": "paragraph",
          "text": "In python, input() function is use to take input from user."
        },
        {
          "type": "heading",
          "level": 4,
          "text": "Syntax of input()"
        },
        {
          "type": "paragraph",
          "text": "The syntax of the input() function accepts one optional parameter as follows:"
        },
        {
          "type": "paragraph",
          "text": "input(prompt)<br>Here,"
        },
        {
          "type": "textarea",
          "text": "# Python Input\n\n# Using input() Function\nuser_name = input(\"Enter your name: \")\nprint(\"Hello, {}! Welcome to Webcooks.\".format(user_name))  # Prompts the user to enter their name and greets them."
        },
        {
          "type": "paragraph",
          "text": "prompt (optional) – A string that is written to standard output (usually the console) as a message before the user enters input. If the prompt is not provided, the function will not display any message."
        },
        {
          "type": "textarea",
          "text": "# Python Input with Prompt\n\n# Using input() Function with a Prompt\nuser_age = input(\"Enter your age: \")  # Prompts the user to enter their age\nprint(\"You are {} years old! Welcome to Webcooks!\".format(user_age))"
        }
      ]
    },
    {
      "title": "Operators",
      "description": "Operator is a special symbol that carries out an operation on the two operands.",
      "sub_description": " In Python, there are multiple types of operators like Arithmetic, comparison, logical, bitwise, assignment operators etc.",
      "additional_info": "Here's a little description about all the operators:",
      "content": [
        {
          "type": "textarea",
          "text": "a = 7\nb = 3\nis_greater = a > b\n# Output will be True since 7 is greater than 3"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Arithmetic Operators"
        },
        {
          "type": "paragraph",
          "text": "Some arithmetic operators are required to perform some primitive operations: addition, subtraction, multiplication, etc."
        },
        {
          "type": "textarea",
          "text": "a = 15\nb = 4\naddition = a + b  # Output will be 19\nsubtraction = a - b  # Output will be 11\nmultiplication = a * b  # Output will be 60\ndivision = a / b  # Output will be 3.75\nmodulus = a % b  # Output will be 3\nfloor_division = a // b  # Output will be 3\nexponentiation = a ** b  # Output will be 50625"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Assignment Operators"
        },
        {
          "type": "paragraph",
          "text": "Assignment operators assign values to variables and can also carry out operations like adding or subtracting before assignment."
        },
        {
          "type": "textarea",
          "text": "x = 10  # Assigns 10 to x\nx += 5  # Adds 5 to x (x becomes 15)\nx -= 3  # Subtracts 3 from x (x becomes 12)\nx *= 2  # Multiplies x by 2 (x becomes 24)\nx /= 4  # Divides x by 4 (x becomes 6.0)\nx %= 5  # Modulus of x by 5 (x becomes 1.0)"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Comparison Operators"
        },
        {
          "type": "paragraph",
          "text": "Comparison operators compare two values, returning a Boolean result (True or False) based on the relationship between them."
        },
        {
          "type": "textarea",
          "text": "x = 10\ny = 5\n\nx == y  # Checks if x is equal to y, returns False\nx != y  # Checks if x is not equal to y, returns True\nx > y   # Checks if x is greater than y, returns True\nx < y   # Checks if x is less than y, returns False\nx >= y  # Checks if x is greater than or equal to y, returns True\nx <= y  # Checks if x is less than or equal to y, returns False"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Logical Operators"
        },
        {
          "type": "paragraph",
          "text": "Logical operators check the truth value of expressions and are often used in conditional statements to make decisions."
        },
        {
          "type": "textarea",
          "text": "# Example:\nx = 10\ny = 20\n\n# and operator: returns True if both statements are true\nresult = (x > 5 and y < 25)  # True\n\n# or operator: returns True if at least one statement is true\nresult_or = (x > 15 or y < 25)  # True\n\n# not operator: reverses the result, returns False if the result is true\nresult_not = not(x > 5)  # False"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Bitwise Operators"
        },
        {
          "type": "paragraph",
          "text": "Bitwise operators work on operands as if they were a string of binary digits and operate on each bit, and that is why they are known as Bitwise operators."
        },
        {
          "type": "textarea",
          "text": "# Example:\na = 5  # Binary: 0101\nb = 3  # Binary: 0011\n\n# AND operator (&): Sets each bit to 1 if both bits are 1\nresult_and = a & b  # 1 (Binary: 0001)\n\n# OR operator (|): Sets each bit to 1 if at least one bit is 1\nresult_or = a | b  # 7 (Binary: 0111)\n\n# XOR operator (^): Sets each bit to 1 if only one of the bits is 1\nresult_xor = a ^ b  # 6 (Binary: 0110)\n\n# NOT operator (~): Inverts all the bits\nresult_not = ~a  # -6 (Binary for 5 is 0101, ~ inverts to 1010)"
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Special Operators"
        },
        {
          "type": "heading",
          "level": 5,
          "text": "Python Membership Operator"
        },
        {
          "type": "paragraph",
          "text": "Python's is and is not operators check that the two variables refer to the same location in memory."
        },
        {
          "type": "textarea",
          "text": "# Example:\nfruits = ['apple', 'banana', 'cherry']\n\n# 'in' operator: Checks if an item is present in a list\nis_apple_in_list = 'apple' in fruits  # True\n\n# 'not in' operator: Checks if an item is not present in a list\nis_orange_in_list = 'orange' not in fruits  # True"
        },
        {
          "type": "heading",
          "level": 5,
          "text": "Python Identity Operator"
        },
        {
          "type": "paragraph",
          "text": "In Python, is and is not are commands that determine whether two values occupy the same memory place."
        },
        {
          "type": "textarea",
          "text": "# Creating two variables with the same list reference\nx = [1, 2, 3]\ny = x  # y points to the same object as x\n\n# Using 'is' to check if x and y refer to the same object\nprint(x is y)  # Output: True\n\n# Creating a different list with the same values\nz = [1, 2, 3]\n\n# Using 'is not' to check if x and z refer to different objects\nprint(x is not z)  # Output: True\n\n# 'is' checks identity, not value, so even with same values, z is a different object."
        },
        {
          "type": "heading",
          "level": 2,
          "text": "Operator Precedence"
        },
        {
          "type": "paragraph",
          "text": "Operator precedence is a term used to denote the order in which operations have to be performed.It is also important because it tells which operator needs to be carried first. But whenever operators have a higher precedence to the same operator, the expression would evaluate from the left-hand side to the right side in case operators have a priority to be the same."
        },
        {
          "type": "textarea",
          "text": "# Expression with multiple operators\nresult = 10 + 2 * 3 ** 2  # Exponentiation, multiplication, then addition\n\n# Output the result\nprint(result)  # Output: 28\n\n# Explanation:\n# 1. ** (Exponentiation) is evaluated first: 3 ** 2 = 9\n# 2. * (Multiplication) is evaluated next: 2 * 9 = 18\n# 3. + (Addition) is evaluated last: 10 + 18 = 28"
        }
      ]
    }
  ],
  "Python Control Structure": [
    {
      "title": "Control Structure",
      "description": "Control structures refer to those constructs in Python which control the flow of execution within a program.",
      "sub_description": "These determine decision-making, looping, and branching within the code.",
      "additional_info": "Here are the core control structures in Python:",
      "content": [
        {
          "type": "image",
          "src": "/assets/images/Untitled-1-03.jpg",
          "alt": "JavaScript Logo"
        }
      ]
    },
    {
      "title": "If else",
      "description": "",
      "sub_description": "",
      "additional_info": "",
      "content": [
        {
          "type": "heading",
          "level": 2,
          "text": "If-statement"
        },
        {
          "type": "paragraph",
          "text": "If statements are the statements that use for evaluation of a condition. And if the given condition becomes true, it runs any block of particular code defined as an \"if-block\". It is preceded with the keyword \"if, then the condition\"."
        },
        {
          "type": "paragraph",
          "text": "if expression:<br>&nbsp;&nbsp;&nbsp;&nbsp;statement"
        },
        {
          "type": "textarea",
          "text": "number = 10\n\n# Check if the number is positive\nif number > 0:\n    print('The number is positive.')  # This line will execute because the condition is True"
        },
        {
          "type": "image",
          "src": "/assets/images/Untitled-1-12.jpg",
          "alt": "JavaScript Logo"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Python Indentation"
        },
        {
          "type": "paragraph",
          "text": "It is a Python way of defining the structure of the block of code.Statements are said to belong to a block if it shares a common level of indentation with other statements."
        },
        {
          "type": "textarea",
          "text": "# Example of indentation in Python\n\nnumber = 5\nif number > 0:\n    print('Number is positive')  # This line is indented and part of the if statement\nprint('This line is outside the if block')  # No indentation, outside of the if block"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "If-else Statement"
        },
        {
          "type": "paragraph",
          "text": "If it does not holds true or becomes false then it is going to execute the piece of code lying in its else block."
        },
        {
          "type": "textarea",
          "text": "# Example of if-else statement in Python\n\nage = 18\nif age >= 18:\n    print('Eligible to vote')  # Executes if age is 18 or older\nelse:\n    print('Not eligible to vote')  # Executes if age is less than 18"
        },
        {
          "type": "image",
          "src": "assets/images/Untitled-1-13.jpg",
          "alt": "JavaScript Logo"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "elif Statement"
        },
        {
          "type": "paragraph",
          "text": "When we need to handle more than one condition then we have to use the elif statement.It allows you to define alternate paths beyond the initial if and final else. "
        },
        {
          "type": "textarea",
          "text": "# Example of if-else statement in Python\n\nage = 18\nif age >= 18:\n    print('Eligible to vote')  # Executes if age is 18 or older\nelse:\n    print('Not eligible to vote')  # Executes if age is less than 18"
        },
        {
          "type": "image",
          "src": "assets/images/Untitled-1-14.jpg",
          "alt": "JavaScript Logo"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Ternary Operator in if-else"
        },
        {
          "type": "paragraph",
          "text": "While Python lacks a traditional ternary operator, it offers a shorthand if-else format for conditional expressions, often called the \"ternary conditional operator.\" "
        },
        {
          "type": "textarea",
          "text": "# Example of Ternary Operator in Python\n\n# Using a ternary operator to assign a value based on a condition\nage = 18\nstatus = 'Adult' if age >= 18 else 'Minor'\n\nprint(f'Status: {status}')"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Nested if"
        },
        {
          "type": "paragraph",
          "text": "In case when the if statement is placed inside the other if statement, then it becomes the nested if statement.This setup allows you to check multiple conditions in layers, where the inner condition is only checked if the outer condition is True."
        },
        {
          "type": "textarea",
          "text": "# Example of Nested If Statements in Python\n\n# Check if a number is positive, negative, or zero\nnumber = 10\n\nif number > 0:\n    print('The number is positive.')\n    if number > 100:\n        print('The number is greater than 100.')\n    else:\n        print('The number is 100 or less.')\nelif number < 0:\n    print('The number is negative.')\nelse:\n    print('The number is zero.')"
        },
        {
          "type": "image",
          "src": "assets/images/Untitled-1-09.jpg",
          "alt": "JavaScript Logo"
        }
      ]
    },
    {
      "title": "Loops in python",
      "description": "Loops are essential control structures that allow code to repeat a specific number of times, making repetitive tasks more efficient and less prone to error.",
      "sub_description": "Python has two primitive loop commands:",
      "additional_info": "",
      "content": [
        {
          "type": "list",
          "items": [
            "While loop",
            "For loop"
          ]
        },
        {
          "type": "heading",
          "level": "1",
          "text": "For loop"
        },
        {
          "type": "paragraph",
          "text": "In Python, a for loop iterates over items in a sequence (like lists, strings, dictionaries, or sets). For each item, the loop’s code block runs, ending once the sequence is fully traversed."
        },
        {
          "type": "paragraph",
          "text": "The loop stops once all the items have been processed. This is different from how for loops work in some other programming languages, as it's more like using an iterator method in object-oriented programming languages."
        },
        {
          "type": "textarea",
          "text": "# Example of For Loop in Python\n\n# Loop through a list of fruits\nfruits = ['apple', 'banana', 'cherry']\n\nfor fruit in fruits:\n    print('I like', fruit)"
        },
        {
          "type": "image",
          "src": "assets/images/Untitled-1-02.jpg",
          "alt": "JavaScript Logo"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Indentation in for-loop"
        },
        {
          "type": "paragraph",
          "text": "In python, indentation is used to define a block of code, such as the body of a loop."
        },
        {
          "type": "textarea",
          "text": "# Indentation in For Loop\n\n# Loop through a list of numbers\nnumbers = [1, 2, 3, 4, 5]\n\nfor number in numbers:\n    print('Number:', number)  # This line is indented to indicate it is part of the loop\n\nprint('Loop finished!')  # This line is not indented and is outside the loop"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "for-loop with pyton range()"
        },
        {
          "type": "paragraph",
          "text": "The range() function in Python creates a sequence of numbers, beginning at 0 by default, increasing by 1 with each iteration, and stopping just before a defined endpoint. It’s commonly used within for loops to manage the number of iterations."
        },
        {
          "type": "textarea",
          "text": "# For Loop with Python range()\n\n# Using range to iterate through numbers from 0 to 4\nfor i in range(5):\n    print('Current number:', i)  # This line prints the current number in the loop\n\nprint('Loop has completed!')  # This line executes after the loop ends"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "else in for-loop"
        },
        {
          "type": "paragraph",
          "text": "The else keyword in a for loop specifies a block of code to be executed when the loop is finished."
        },
        {
          "type": "textarea",
          "text": "# For Loop with Else\n\n# Using else in a for loop to execute a block after the loop finishes\nfor i in range(5):\n    print('Current number:', i)  # This line prints the current number in the loop\nelse:\n    print('Loop has completed without break!')  # This line executes after the loop ends"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Nested loops"
        },
        {
          "type": "paragraph",
          "text": "A nested loop is a loop contained within another loop, enabling more intricate patterns of iteration, such as iterating over multiple levels of data.In this structure, the inner loop runs through all its iterations for each iteration of outer loop."
        },
        {
          "type": "textarea",
          "text": "# Nested Loops\n\n# Using nested for loops to print a multiplication table\nfor i in range(1, 4):  # Outer loop\n    for j in range(1, 4):  # Inner loop\n        print(f'{i} x {j} = {i * j}')  # Prints the product of i and j\n    print('---')  # Separator after each outer loop iteration"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "loop through a string"
        },
        {
          "type": "textarea",
          "text": "# Looping Through a String\n\n# Example string\nmy_string = 'Webcooks'\n\n# Loop through each character in the string\nfor char in my_string:\n    print(char)  # Print each character"
        },
        {
          "type": "heading",
          "level": "1",
          "text": "Python while loop"
        },
        {
          "type": "paragraph",
          "text": "The while loop in Python keeps executing a block of code as long as a specified condition remains True, making it useful for situations where the number of iterations isn’t predetermined.Once the condition turns false, the program continues with the statements after the loop."
        },
        {
          "type": "textarea",
          "text": "# Python While Loop\n\n# Initialize a counter\ncounter = 0\n\n# While loop that runs until counter is less than 5\nwhile counter < 5:\n    print('Counter:', counter)  # Print the current counter value\n    counter += 1  # Increment the counter"
        },
        {
          "type": "image",
          "src": "assets/images/Untitled-1-01.jpg",
          "alt": "JavaScript Logo"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "infinite while loop"
        },
        {
          "type": "paragraph",
          "text": "If the condition in a while loop never becomes False, the loop continues endlessly, resulting in an infinite loop."
        },
        {
          "type": "textarea",
          "text": "# Infinite While Loop Example\n\n# This loop will run indefinitely\nwhile True:\n    print('This is an infinite loop. Press Ctrl+C to stop it.')"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Python while loop with an else clause"
        },
        {
          "type": "paragraph",
          "text": "An else clause in a while loop runs when the loop’s condition becomes False, providing a way to execute code after the loop completes naturally."
        },
        {
          "type": "textarea",
          "text": "count = 0\nwhile count < 5:\n    print('Count:', count)\n    count += 1\nelse:\n    print('Count reached 5, exiting loop.')"
        }
      ]
    },
    {
      "title": "Loop Control Statement",
      "description": "Loops in Python are used for repeatedly executing code, but control statements allow you to adjust the loop’s behavior based on specific conditions. This flexibility helps manage the loop’s flow as needed.",
      "sub_description": "Python includes the following control statements:",
      "additional_info": "",
      "content": [
        {
          "type": "list",
          "items": [
            "Continue Statement",
            "Break Statement",
            "Pass Statement"
          ]
        },
        {
          "type": "image",
          "src": "/assets/images/Untitled-1-11.jpg",
          "alt": "JavaScript Logo"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Break Statement"
        },
        {
          "type": "paragraph",
          "text": "The break statement immediately stops the loop and shifts execution to the code following the loop."
        },
        {
          "type": "textarea",
          "text": "count = 0\nwhile True:\n    print('Count:', count)\n    count += 1\n    if count >= 5:\n        break\nprint('Loop exited, count reached 5.')"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Continue Statement"
        },
        {
          "type": "paragraph",
          "text": "The continue statement bypasses the remaining code in the current loop cycle and jumps directly to the start of the next iteration."
        },
        {
          "type": "textarea",
          "text": "count = 0\nwhile count < 5:\n    count += 1\n    if count == 3:\n        continue\n    print('Count:', count)\nprint('Loop completed.')"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Pass Statement"
        },
        {
          "type": "paragraph",
          "text": "The pass statement acts as a placeholder where a code block is required by syntax but no action is needed; it allows the code to run without executing any operations in that spot."
        },
        {
          "type": "textarea",
          "text": "count = 0\nwhile count < 5:\n    count += 1\n    if count == 3:\n        pass  # Placeholder for future code\n    print('Count:', count)\nprint('Loop completed.')"
        }
      ]
    }
  ],
  "Python Data types": [
    {
      "title": "Python List",
      "description": "In Python, lists are a fundamental data structure designed to hold multiple items within a single variable. They’re versatile, allowing items to be added, removed, and updated with ease.",
      "sub_description": "Lists are created using square brackets [] and are one of four main collection types in Python, along with tuples, sets, and dictionaries, each with distinct features.",
      "additional_info": "Lists are useful, for example, in creating a music playlist.",
      "content": [
        {
          "type": "heading",
          "level": "2",
          "text": "Create a Python List:"
        },
        {
          "type": "paragraph",
          "text": "Creating a list in Python is straightforward. Here’s how to do it."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using Square Brackets:"
        },
        {
          "type": "paragraph",
          "text": "A list is formed by placing items inside square brackets [], separated by commas."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date']\nprint('List of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using the list() Constructor:"
        },
        {
          "type": "paragraph",
          "text": "The list() function can convert other iterable types (like strings, tuples, or sets) into a list."
        },
        {
          "type": "textarea",
          "text": "fruits = list(('apple', 'banana', 'cherry', 'date'))\nprint('List of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Creating an Empty List:"
        },
        {
          "type": "paragraph",
          "text": "An empty list is created with empty square brackets []."
        },
        {
          "type": "textarea",
          "text": "empty_list = []\nprint('Empty list:', empty_list)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Including Different Data Types:"
        },
        {
          "type": "paragraph",
          "text": "Storing Different Data Types Lists support a variety of data types, including numbers, strings, and even nested lists, providing versatile options for data organization."
        },
        {
          "type": "textarea",
          "text": "mixed_list = [42, 'apple', 3.14, True]\nprint('List with different data types:', mixed_list)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "List Characteristics:"
        },
        {
          "type": "paragraph",
          "text": " Lists are "
        },
        {
          "type": "list",
          "items": [
            "<b>Ordered -</b>Lists keep elements in the order they were added.",
            "<b>Mutable - </b> Items in a list are modifiable after the list has been created.",
            "<b>Allow Duplicates - </b>Lists can contain duplicate values."
          ]
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Accessing List Elements"
        },
        {
          "type": "paragraph",
          "text": "Each element in a list is assigned an index, starting with [0] for the first element, [1] for the second, and so on. "
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date']\nprint('First fruit:', fruits[0])  # Accessing the first element\nprint('Last fruit:', fruits[-1])   # Accessing the last element"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Slicing a List in Python"
        },
        {
          "type": "paragraph",
          "text": "Slicing lets you access specific parts of a list by defining a range of indices with the : operator. "
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Basic Syntax"
        },
        {
          "type": "paragraph",
          "text": "The syntax list[start:end] allows you to slice a list from the starting index (inclusive) to the ending index (exclusive). "
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']\nsliced_fruits = fruits[1:4]  # Slicing from index 1 to 3 (4 is excluded)\nprint('Sliced list:', sliced_fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Negative Indexing in Python"
        },
        {
          "type": "paragraph",
          "text": "Python supports negative indexing, where the last element is -1, the second-to-last is -2, etc."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']\nprint('Last fruit:', fruits[-1])       # Accessing the last element\nprint('Second last fruit:', fruits[-2]) # Accessing the second last element"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Omitting Indices:"
        },
        {
          "type": "paragraph",
          "text": "Omitting the starting index in slicing causes the slice to begin from the start of the list.Leaving the end index empty allows the slice to continue until the list’s end."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']\nprint('From start to index 3:', fruits[:3])      # Slicing from the beginning to index 3 (excluding 3)\nprint('From index 2 to end:', fruits[2:])         # Slicing from index 2 to the end\nprint('Entire list:', fruits[:])                  # Slicing the entire list"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Step Value:"
        },
        {
          "type": "paragraph",
          "text": "The syntax list[start:end:step] allows you to specify a step to control the intervals between indices."
        },
        {
          "type": "textarea",
          "text": "numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\nprint('Every second element:', numbers[::2])     # Slicing with a step of 2\nprint('Elements in reverse order:', numbers[::-1]) # Slicing with a step of -1 for reverse order"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Add Elements to a Python List:"
        },
        {
          "type": "paragraph",
          "text": "Python lists are dynamic and can grow as new items are added, whether at the end, at a specific index, or by merging with other lists."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using append():"
        },
        {
          "type": "paragraph",
          "text": "The append() method places a new item at the end of a list, making it useful for sequentially adding elements."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana']\nfruits.append('cherry')  # Adding 'cherry' to the end of the list\nfruits.append('date')    # Adding 'date' to the end of the list\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using insert():"
        },
        {
          "type": "paragraph",
          "text": "The insert() method places an element at a specified index without replacing any existing items, shifting elements to accommodate the new one. "
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana']\nfruits.insert(1, 'cherry')  # Inserting 'cherry' at index 1\nfruits.insert(0, 'date')    # Inserting 'date' at index 0\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using extend():"
        },
        {
          "type": "paragraph",
          "text": "The extend() method adds each item from another iterable (like a list or tuple) individually to the end of the list, unlike append(), which would add the iterable as a single element. "
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana']\nfruits.extend(['cherry', 'date', 'elderberry'])  # Adding multiple fruits to the list\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Change List Items:"
        },
        {
          "type": "paragraph",
          "text": "Since lists are mutable, individual items or groups of items can be updated. Here are some common methods to update elements in a list:"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Modifying a Single Element:"
        },
        {
          "type": "paragraph",
          "text": "To update an item, reference its index and assign it a new value."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry']\nfruits[1] = 'date'  # Changing the element at index 1 to 'date'\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Changing Multiple Elements:"
        },
        {
          "type": "paragraph",
          "text": "Use slicing to modify multiple items simultaneously. "
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date']\nfruits[1:3] = ['kiwi', 'mango']  # Changing elements at index 1 and 2\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using Loops to Update Elements:"
        },
        {
          "type": "paragraph",
          "text": "A loop can update items based on conditions or calculations. "
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry']\nfor i in range(len(fruits)):\n    fruits[i] = fruits[i].upper()  # Converting each fruit name to uppercase\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Remove an Item From a List"
        },
        {
          "type": "paragraph",
          "text": "Python offers several ways to remove items, whether targeting specific values, indices, or removing multiple items at once. Below are the most commonly used techniques for removing elements from a list:"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using remove():"
        },
        {
          "type": "paragraph",
          "text": "This method removes the first occurrence of a specified item; an error will occur if the item doesn’t exist."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date']\nfruits.remove('banana')  # Removing 'banana' from the list\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using pop():"
        },
        {
          "type": "paragraph",
          "text": "The pop() method removes and returns the item at a specified index; when no index is given, it removes the last item by default. "
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date']\nremoved_fruit = fruits.pop(1)  # Removing the fruit at index 1\nprint('Removed fruit:', removed_fruit)\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using del Statement:"
        },
        {
          "type": "paragraph",
          "text": "The del keyword removes an item or multiple items by index."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date']\ndel fruits[2]  # Deleting the fruit at index 2\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using clear():"
        },
        {
          "type": "paragraph",
          "text": "The clear() method empties the list entirely."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date']\nfruits.clear()  # Removing all elements from the list\nprint('Updated list of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Finding the Length of a List in Python:"
        },
        {
          "type": "paragraph",
          "text": "The len() function calculates the total count of elements in a list, making it easy to assess the list's size."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date']\nlength_of_fruits = len(fruits)  # Finding the length of the list\nprint('Number of fruits in the list:', length_of_fruits)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Listing Iteration:"
        },
        {
          "type": "paragraph",
          "text": "Iterating through a list in Python allows for the processing of each element one by one. This can be efficiently accomplished using a for loop, which is a common method for accessing and manipulating list items."
        },
        {
          "type": "textarea",
          "text": "fruits = ['apple', 'banana', 'cherry', 'date']\nprint('List of fruits:')\nfor fruit in fruits:\n    print(fruit)  # Printing each fruit in the list"
        }
      ]
    },
    {
      "title": "Python Tuple",
      "description": "A collection of items stored in a variable is known as tuple. Python has four different types of collections: lists, sets, dictionaries and tuples, each with a characteristic. A collection or tuple is ordered and its elements are immutable since after defining the elements in the tuple cannot be changed.",
      "sub_description": "Tuples are defined using round brackets.",
      "additional_info": " Unlike lists, once a tuple is created, it cannot be modified. For instance, when you wanted to store date you may have used- it's like (year, month, day).",
      "content": [
        {
          "type": "heading",
          "level": "2",
          "text": "How to Create Tuples:"
        },
        {
          "type": "paragraph",
          "text": "The process to create a tuple in Python is very easy and is achieved with the use of parentheses.The following are some common methods to create a tuple:"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using Parentheses:"
        },
        {
          "type": "paragraph",
          "text": "The most general way to create a tuple is by putting elements between round brackets, separated with commas."
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')  # Creating a tuple using parentheses\nprint('Tuple of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using the tuple() Function:"
        },
        {
          "type": "paragraph",
          "text": "You can define a tuple using the function tuple(), which takes any iterable type, including lists, and converts it to a tuple."
        },
        {
          "type": "textarea",
          "text": "fruits = tuple(['apple', 'banana', 'cherry'])  # Creating a tuple using the tuple() function\nprint('Tuple of fruits:', fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Creating an Empty Tuple:"
        },
        {
          "type": "paragraph",
          "text": "To create an empty tuple, use empty parentheses ()."
        },
        {
          "type": "textarea",
          "text": "empty_tuple = ()  # Creating an empty tuple\nprint('Empty tuple:', empty_tuple)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Single Element Tuple:"
        },
        {
          "type": "paragraph",
          "text": "To create a tuple with a single element, a comma must be included after the element to differentiate it from a regular parenthesis."
        },
        {
          "type": "textarea",
          "text": "single_element_tuple = ('apple',)  # Creating a single-element tuple with a comma\nprint('Single-element tuple:', single_element_tuple)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Tuple with Mixed Data Types:"
        },
        {
          "type": "paragraph",
          "text": "Tuples can have elements of any data types, including integers, strings, and floats."
        },
        {
          "type": "textarea",
          "text": "mixed_tuple = (42, 'banana', 3.14, True)  # Creating a tuple with mixed data types\nprint('Tuple with mixed data types:', mixed_tuple)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Tuple Characteristics:"
        },
        {
          "type": "paragraph",
          "text": "Tuples are:"
        },
        {
          "type": "list",
          "items": [
            "<b>Ordered - </b>The order of elements is preserved.",
            "<b>Immutable - </b> Elements cannot be modified after the tuple is created.",
            "<b>Allow duplicates - </b> The same value can occur more than once in a tuple."
          ]
        },
        {
          "type": "heading",
          "level": "4",
          "text": "How to Access Tuple Elements:"
        },
        {
          "type": "paragraph",
          "text": "The elements of a tuple are accessed through indexing which starts at 0; for example, the element at index 0 corresponds to the first element; the element at index 1 corresponds to the second, and so on."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Access Items Using Index: "
        },
        {
          "type": "paragraph",
          "text": "Index numbers are used to access items in a tuple."
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')\nfirst_fruit = fruits[0]  # Accessing the first element\nlast_fruit = fruits[-1]  # Accessing the last element\nprint('First fruit:', first_fruit)\nprint('Last fruit:', last_fruit)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Tuple Cannot Be Modified: "
        },
        {
          "type": "paragraph",
          "text": "Tuples are immutable, so their elements cannot be altered after creation. If there is an attempt to modify a tuple, an error will occur. "
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')\ntry:\n    fruits[1] = 'date'  # Attempting to change the second element\nexcept TypeError as e:\n    print('Error:', e)  # Catching the TypeError and printing it"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "How to Get Tuple Length"
        },
        {
          "type": "paragraph",
          "text": "The length of a tuple is accessed by using the len() function. It returns to you the number of items that a tuple contains."
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')\ntuple_length = len(fruits)  # Getting the length of the tuple\nprint('Length of the tuple:', tuple_length)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Iterating Over a Tuple"
        },
        {
          "type": "paragraph",
          "text": "To loop through the elements of a tuple, the for loop is commonly used. This allows each item in the tuple to be accessed one by one without the need for indexing."
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')\nprint('List of fruits:')\nfor fruit in fruits:\n    print(fruit)  # Printing each fruit in the tuple"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Iterating with Index: "
        },
        {
          "type": "paragraph",
          "text": "If access to both the item and its index is needed, the enumerate() function can be used.This prints both index and value of each element in the tuple."
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')\nprint('List of fruits with their indices:')\nfor index, fruit in enumerate(fruits):\n    print(f'Index {index}: {fruit}')  # Printing each fruit with its index"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Finding Elements in a Tuple"
        },
        {
          "type": "paragraph",
          "text": "To test for membership of a particular item in a tuple, one uses the in keyword. "
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')\n\n# Checking if an element exists in the tuple\nif 'banana' in fruits:\n    print('Banana is in the tuple.')\nelse:\n    print('Banana is not in the tuple.')\n\n# Finding the index of an element\nindex_of_cherry = fruits.index('cherry')  # Getting the index of 'cherry'\nprint('Index of cherry:', index_of_cherry)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "How to change Tuple Items"
        },
        {
          "type": "paragraph",
          "text": "Python tuples are immutable, meaning they cannot be changed. Items cannot be added, modified, or deleted from a tuple. This immutability is a fundamental characteristic of tuples and ensures that their contents remain constant throughout their lifetime. As a result, it is not possible to change an individual element of a tuple directly."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Convert to a List:"
        },
        {
          "type": "paragraph",
          "text": "The most common way of accomplishing this is converting the tuple to a list make any necessary changes, then re-convert it to a tuple."
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')\n\n# Converting the tuple to a list\nfruits_list = list(fruits)\n\n# Changing an element in the list\nfruits_list[1] = 'date'  # Changing 'banana' to 'date'\n\n# Converting the list back to a tuple\nupdated_fruits = tuple(fruits_list)\nprint('Updated tuple of fruits:', updated_fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Creating a New Tuple:"
        },
        {
          "type": "paragraph",
          "text": "We can create another tuple that contains the modification we want."
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')\n\n# Creating a new tuple with modified elements\nnew_fruits = ('apple', 'date', 'cherry')  # Directly defining a new tuple\nprint('New tuple of fruits:', new_fruits)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using Slicing:"
        },
        {
          "type": "paragraph",
          "text": "Slicing can also be used to create a new tuple by including elements before and after the target element that needs to be changed."
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry', 'date')\n\n# Creating a new tuple using slicing\nnew_fruits = fruits[1:3]  # Slicing from index 1 to index 3 (exclusive)\nprint('New tuple created by slicing:', new_fruits)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Deleting Tuples in Python: "
        },
        {
          "type": "paragraph",
          "text": "In Python, we cannot delete the elements within a tuple. Tuples are immutable objects. However, we can remove the entire tuple with the del keyword.This will remove the tuple from memory, and any attempt to access it afterward will result in an error."
        },
        {
          "type": "textarea",
          "text": "fruits = ('apple', 'banana', 'cherry')\n\n# Deleting the tuple\ntry:\n    del fruits  # Attempting to delete the tuple\n    print('Tuple deleted successfully.')\n    print(fruits)  # This line will raise an error because 'fruits' no longer exists\nexcept NameError as e:\n    print('Error:', e)  # Catching the NameError if trying to access the deleted tuple"
        }
      ]
    },
    {
      "title": "Python Sets",
      "description": "A set is a collection that only contains unique elements, meaning values cannot be repeated. Thus, this property makes it very suitable for storing any data in which uniqueness may be needed, such as student IDs.",
      "sub_description": "Sets are one of Python's four built-in data types used for storing collections of data, alongside Lists, Tuples, and Dictionaries.",
      "additional_info": "A set is an unordered, unchangeable* and unindexed collection.",
      "content": [
        {
          "type": "heading",
          "level": "4",
          "text": "How to create a set in python"
        },
        {
          "type": "paragraph",
          "text": "In Python, sets are created by enclosing the elements within curly braces {}, with each element separated by a comma.It may contain many elements and is of any type: int, float, tuple, string, and so forth. However, it cannot include mutable elements like lists, sets, or dictionaries as its items."
        },
        {
          "type": "textarea",
          "text": "# Creating a set using curly braces\nfruits_set = {'apple', 'banana', 'cherry'}\nprint('Set of fruits:', fruits_set)\n\n# Creating a set using the set() function\nnumbers_set = set([1, 2, 3, 4, 5])\nprint('Set of numbers:', numbers_set)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Initializing an Empty Set in Python"
        },
        {
          "type": "paragraph",
          "text": "An empty set in Python is initialized using set(). Since lists and dictionaries can be initialized by using empty curly braces {}, using {} actually forms an empty dictionary, not an empty set. Therefore, to ensure the creation of a set, the set() function is the preferred method."
        },
        {
          "type": "textarea",
          "text": "# Initializing an empty set\nempty_set = set()\nprint('Empty set:', empty_set)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "How Sets Manage Duplicate Elements"
        },
        {
          "type": "paragraph",
          "text": "When working with sets in Python, it's important to note that they automatically handle duplicate items. If duplicate elements are added to a set, Python will only keep one instance of each unique element."
        },
        {
          "type": "textarea",
          "text": "# Creating a set with duplicate elements\nfruits_set = {'apple', 'banana', 'cherry', 'apple'}  # 'apple' is duplicated\nprint('Set of fruits:', fruits_set)  # Duplicates will be removed"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Adding and Updating Set Items in Python"
        },
        {
          "type": "paragraph",
          "text": "Sets in Python are mutable, which means the contents of a set may be modified.However, because sets are unordered collections, indexing is not applicable. This means that elements within a set cannot be accessed or modified using indexing or slicing."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Adding Items to a Set:"
        },
        {
          "type": "paragraph",
          "text": "To append an item to a set, use the add() method. Here's an example:"
        },
        {
          "type": "textarea",
          "text": "# Creating an initial set\nfruits_set = {'apple', 'banana'}\n\n# Adding an item to the set\nfruits_set.add('cherry')\nprint('Set after adding cherry:', fruits_set)\n\n# Adding another item to the set\nfruits_set.add('banana')  # Adding a duplicate item\nprint('Set after trying to add banana again:', fruits_set)  # Duplicates are not added"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Updating a Set:"
        },
        {
          "type": "paragraph",
          "text": "The update() method is utilized to add multiple items from other iterable types, such as lists, tuples, or even other sets."
        },
        {
          "type": "textarea",
          "text": "Creating an initial set\nfruits_set = {'apple', 'banana'}\n\n# Updating the set with multiple items\nfruits_set.update(['cherry', 'date', 'banana'])  # Adding new items and trying to add a duplicate\nprint('Set after updating:', fruits_set)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Removing elements from a Set"
        },
        {
          "type": "paragraph",
          "text": "In Python, you have multiple ways to remove an element from a set. Depending on the situation you face, you should call the following methods: "
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using the remove() Method"
        },
        {
          "type": "paragraph",
          "text": "The remove() method removes any specified item from the set.It throws a KeyError if the item does not exist in the set."
        },
        {
          "type": "textarea",
          "text": "# Creating an initial set\nfruits_set = {'apple', 'banana', 'cherry'}\n\n# Removing an item from the set\nfruits_set.remove('banana')\nprint('Set after removing banana:', fruits_set)\n\n# Attempting to remove an item that does not exist\ntry:\n    fruits_set.remove('date')  # This will raise a KeyError\nexcept KeyError as e:\n    print('Error:', e)  # Catching the KeyError"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using the discard() Method"
        },
        {
          "type": "paragraph",
          "text": "The discard() method also removes an arbitrary item from the given set. However, instead of raising an error in case the item is not located, it does nothing because it has no effect since there is no such specified item."
        },
        {
          "type": "textarea",
          "text": "# Creating an initial set\nfruits_set = {'apple', 'banana', 'cherry'}\n\n# Removing an item from the set using discard()\nfruits_set.discard('banana')\nprint('Set after discarding banana:', fruits_set)\n\n# Attempting to discard an item that does not exist\nfruits_set.discard('date')  # No error will be raised\nprint('Set after attempting to discard date:', fruits_set)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": " Using the pop() Method"
        },
        {
          "type": "paragraph",
          "text": "This method removes and returns some arbitrary element from the set. Since sets are unordered, the specific item that is removed is not guaranteed to be the same each time."
        },
        {
          "type": "textarea",
          "text": "# Creating an initial set\nfruits_set = {'apple', 'banana', 'cherry'}\n\n# Removing an arbitrary item from the set using pop()\nremoved_item = fruits_set.pop()\nprint('Removed item:', removed_item)\nprint('Set after popping an item:', fruits_set)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using the clear() Method"
        },
        {
          "type": "paragraph",
          "text": "All elements contained in a set can be removed using the clear() method.This method empties the set without deleting it."
        },
        {
          "type": "textarea",
          "text": "# Creating an initial set\nfruits_set = {'apple', 'banana', 'cherry'}\n\n# Clearing all items from the set\nfruits_set.clear()\nprint('Set after clearing all items:', fruits_set)  # This will show an empty set"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Looping Through a Set in Python"
        },
        {
          "type": "paragraph",
          "text": "Iterating over a set in Python can be accomplished using a for loop.Elements in a set do not necessarily need to be returned in an order that is identical to the order in which they were inserted. The above does not prevent direct access to any element in the set."
        },
        {
          "type": "textarea",
          "text": "# Creating a set\nfruits_set = {'apple', 'banana', 'cherry'}\n\n# Looping through the set\nprint('Fruits in the set:')\nfor fruit in fruits_set:\n    print(fruit)  # Printing each fruit in the set"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Evaluating the Number of Items in a Set"
        },
        {
          "type": "paragraph",
          "text": "In Python, finding the count of elements in a set is simple and can be done using the built-in len() function.This function returns the count of total unique elements present in the set."
        },
        {
          "type": "textarea",
          "text": "# Creating a set\nfruits_set = {'apple', 'banana', 'cherry'}\n\n# Evaluating the number of items in the set\nnumber_of_items = len(fruits_set)\nprint('Number of items in the set:', number_of_items)"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Set Operations in python"
        },
        {
          "type": "paragraph",
          "text": "Sets in Python provide several built-in operations that allow for effective manipulation and comparison of data collections.These come very handy when you would want to find common things, differences, or unison of sets. A few of the most frequent set operations are:"
        },
        {
          "type": "heading",
          "level": "5",
          "text": " Union Operation:"
        },
        {
          "type": "paragraph",
          "text": "The union operation is that which combines all the unique elements from two or more sets.Using the union() method, or the | operator in python you can do this. "
        },
        {
          "type": "textarea",
          "text": "# Creating two sets\nset_a = {1, 2, 3}\nset_b = {3, 4, 5}\n\n# Performing union using the union() method\nunion_set_method = set_a.union(set_b)\nprint('Union using union() method:', union_set_method)\n\n# Performing union using the | operator\nunion_set_operator = set_a | set_b\nprint('Union using | operator:', union_set_operator)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Intersection Operation:"
        },
        {
          "type": "paragraph",
          "text": "It returns a new set that contains elements common to the two sets. This could be done by the help of the intersection() method or the & operator."
        },
        {
          "type": "textarea",
          "text": "# Creating two sets\nset_a = {1, 2, 3}\nset_b = {3, 4, 5}\n\n# Performing intersection using the intersection() method\nintersection_set_method = set_a.intersection(set_b)\nprint('Intersection using intersection() method:', intersection_set_method)\n\n# Performing intersection using the & operator\nintersection_set_operator = set_a & set_b\nprint('Intersection using & operator:', intersection_set_operator)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Set Difference Operation:"
        },
        {
          "type": "paragraph",
          "text": "The difference returns a new set consisting of all elements of the first set, not in the second.It can be carried out either by the method() difference or by using - operator.Symmetric Difference Function:"
        },
        {
          "type": "textarea",
          "text": "# Creating two sets\nset_a = {1, 2, 3, 4}\nset_b = {3, 4, 5}\n\n# Performing set difference using the difference() method\ndifference_set_method = set_a.difference(set_b)\nprint('Difference using difference() method (set_a - set_b):', difference_set_method)\n\n# Performing set difference using the - operator\ndifference_set_operator = set_a - set_b\nprint('Difference using - operator (set_a - set_b):', difference_set_operator)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Symmetric Difference Operation:"
        },
        {
          "type": "paragraph",
          "text": "It returns elements in one of the sets and may not be in the two. This also can be done by using symmetric difference() method or ^ operator."
        },
        {
          "type": "textarea",
          "text": "# Creating two sets\nset_a = {1, 2, 3, 4}\nset_b = {3, 4, 5, 6}\n\n# Performing symmetric difference using the symmetric_difference() method\nsymmetric_difference_method = set_a.symmetric_difference(set_b)\nprint('Symmetric difference using symmetric_difference() method:', symmetric_difference_method)\n\n# Performing symmetric difference using the ^ operator\nsymmetric_difference_operator = set_a ^ set_b\nprint('Symmetric difference using ^ operator:', symmetric_difference_operator)"
        }
      ]
    },
    {
      "title": "Python Dictionary",
      "description": "A set of objects in Python through which data is stored, with every key linked up with a certain value in the dictionary.Unlike lists and tuples, which access values with an index, dictionaries use keys for accessing values. ",
      "sub_description": "Dictionaries are mutable because items can be modified after their creation.They also do not allow duplicate keys, ensuring each key is unique. Since 3.7, the dictionaries retain the order with which the items are inserted. In earlier versions, the order of items is not guaranteed.",
      "additional_info": "Dictionaries are defined by the use of curly braces {}; keys and their corresponding values are separated by a colon (:). ",
      "content": [
        {
          "type": "heading",
          "level": "2",
          "text": "Creating a dictionary"
        },
        {
          "type": "paragraph",
          "text": "A dictionary in Python is a set of key-value pairs in which each key is related to a particular value. One defines a dictionary with curly braces {} and separating each key from its values by a colon :. Separations between each key-value pairs are done using commas."
        },
        {
          "type": "textarea",
          "text": "# Creating a dictionary using curly braces\ndictionary_a = {'name': 'Alice', 'age': 25, 'city': 'New York'}\nprint('Dictionary created using curly braces:', dictionary_a)\n\n# Creating a dictionary using the dict() function\ndictionary_b = dict(name='Bob', age=30, city='Los Angeles')\nprint('Dictionary created using dict() function:', dictionary_b)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Empty Dictionary in python"
        },
        {
          "type": "paragraph",
          "text": "An empty dictionary can be created by using the empty curly braces."
        },
        {
          "type": "textarea",
          "text": "# Creating an empty dictionary\nempty_dictionary = {}\nprint('Empty dictionary:', empty_dictionary)\n\n# Creating another empty dictionary using the dict() function\nanother_empty_dictionary = dict()\nprint('Another empty dictionary:', another_empty_dictionary)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Valid and Invalid Dictionaries in Python"
        },
        {
          "type": "paragraph",
          "text": "In Python, dictionary keys must be of immutable data types, meaning the keys cannot be modified once created.  List type which is mutable can't use as dictionary keys."
        },
        {
          "type": "textarea",
          "text": "# Valid dictionaries\nvalid_dict_1 = {'name': 'Alice', 'age': 25}\nvalid_dict_2 = {1: 'one', 2: 'two'}\nvalid_dict_3 = {'key': [1, 2, 3], 'value': (4, 5)}  # Values can be of any data type\n\nprint('Valid dictionary 1:', valid_dict_1)\nprint('Valid dictionary 2:', valid_dict_2)\nprint('Valid dictionary 3:', valid_dict_3)\n\n# Invalid dictionaries\n# invalid_dict_1 = {1: 'one', 1: 'two'}  # Duplicate keys (invalid)\n# invalid_dict_2 = {'name': 'Alice', 'age': 25, [1, 2]: 'list key'}  # List as a key (invalid)\n\n# Uncommenting the lines below will raise errors:\n# print('Invalid dictionary 1:', invalid_dict_1)\n# print('Invalid dictionary 2:', invalid_dict_2)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Accessing Dictionary Items in Python"
        },
        {
          "type": "paragraph",
          "text": "In Python, dictionary items are accessed by referring to their keys. The key-value pair structure allows easy retrieval of values using the corresponding key."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Accessing Items Using the Key"
        },
        {
          "type": "paragraph",
          "text": "To access an item in a dictionary, use the key inside square brackets []:"
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York'}\n\n# Accessing items using keys\nname = dictionary['name']\nage = dictionary['age']\ncity = dictionary['city']\n\nprint('Name:', name)\nprint('Age:', age)\nprint('City:', city)\n\n# Accessing a key that does not exist (will raise a KeyError)\n# Uncomment the line below to see the error:\n# country = dictionary['country']  # This will raise KeyError"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using the get() Method"
        },
        {
          "type": "paragraph",
          "text": "Another way to access dictionary items is by using the get() method.The advantage of using this method is that does not throw an error on failing to find a particular key. It instead it returns None or any preset default value. "
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York'}\n\n# Accessing items using the get() method\nname = dictionary.get('name')\nage = dictionary.get('age')\ncity = dictionary.get('city')\n\nprint('Name:', name)\nprint('Age:', age)\nprint('City:', city)\n\n# Accessing a key that does not exist using get()\ncountry = dictionary.get('country', 'Not Found')  # Providing a default value\nprint('Country:', country)  # This will print 'Not Found'"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Adding Items to a Dictionary in Python"
        },
        {
          "type": "paragraph",
          "text": "It's actually pretty simple to insert a new entry into a dictionary in Python"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Adding a New Item:"
        },
        {
          "type": "paragraph",
          "text": "An element can be added in a dictionary using the assignment operator with a key that hasn't been previously assigned inside the dictionary.To add an entry just use the assignment operator = with your new key and value."
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25}\n\n# Adding a new item to the dictionary\n# Adding a new key-value pair for 'city'\ndictionary['city'] = 'New York'\n\nprint('Updated dictionary:', dictionary)  # This will show the updated dictionary\n\n# Adding another new item for 'country'\ndictionary['country'] = 'USA'\nprint('Dictionary after adding country:', dictionary)  # This will show the dictionary with the new item"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Updating an Existing Item"
        },
        {
          "type": "paragraph",
          "text": "If the key is already in the dictionary, it will update the current value for that key if we assign a new value. "
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Using the update() Method:"
        },
        {
          "type": "paragraph",
          "text": "The update() method is another way of adding or updating multiple items within a dictionary at one go.These can be from another dictionary or any iterable containing key-value pairs. "
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York'}\n\n# Updating an existing item using the update() method\n# Updating the 'age' and adding a new key-value pair for 'country'\ndictionary.update({'age': 26, 'country': 'USA'})\n\nprint('Updated dictionary:', dictionary)  # This will show the dictionary with the updated age and new country"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Removing Dictionary Items in Python"
        },
        {
          "type": "paragraph",
          "text": " Depending on the situation, specific methods can be used to delete a single item, multiple items, or even clear the entire dictionary."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Removing a Specific Item Using pop()"
        },
        {
          "type": "paragraph",
          "text": "The pop() function removes a specific item from the dictionary using its key.It also returns the value of the removed item."
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York', 'country': 'USA'}\n\n# Removing a specific item using the pop() method\nremoved_item = dictionary.pop('city')\n\nprint('Removed item:', removed_item)  # This will show the value of the removed item\nprint('Updated dictionary:', dictionary)  # This will show the dictionary after the removal"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Removing an Item Using del"
        },
        {
          "type": "paragraph",
          "text": "The del statement is used to delete a specific item from the dictionary using its key."
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York', 'country': 'USA'}\n\n# Removing an item using the del statement\ndel dictionary['age']\n\nprint('Updated dictionary after removing age:', dictionary)  # This will show the dictionary after the removal"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Clearing the Entire Dictionary Using clear()"
        },
        {
          "type": "paragraph",
          "text": "The clear() function removes all items from the dictionary and leaves it empty."
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York', 'country': 'USA'}\n\n# Clearing the entire dictionary\ndictionary.clear()\n\nprint('Dictionary after clearing:', dictionary)  # This will show the dictionary as empty"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Deleting the Entire Dictionary Using del"
        },
        {
          "type": "paragraph",
          "text": "The del statement can also be used to delete the whole dictionary itself."
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York', 'country': 'USA'}\n\n# Deleting the entire dictionary\ndel dictionary\n\n# Attempting to print the dictionary after deletion will raise an error\n# Uncomment the line below to see the error:\n# print('Dictionary after deletion:', dictionary)  # This will raise a NameError"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Looping Over a Dictionary"
        },
        {
          "type": "paragraph",
          "text": "You can iterate through each key-value pair to perform operations on them.To loop over a dictionary, the for loop can be used to access keys, values, or both together:"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Looping Through Keys:"
        },
        {
          "type": "paragraph",
          "text": "By default, a for loop on a dictionary iterates over its keys."
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York', 'country': 'USA'}\n\n# Looping through the keys of the dictionary\nprint('Keys in the dictionary:')\nfor key in dictionary:\n    print(key)\n\n# Alternatively, using the keys() method\nprint('\\nUsing keys() method:')\nfor key in dictionary.keys():\n    print(key)"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Looping Through Values:"
        },
        {
          "type": "paragraph",
          "text": "Use the values() method to iterate through the dictionary values"
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York', 'country': 'USA'}\n\n# Looping through the values of the dictionary\nprint('Values in the dictionary:')\nfor value in dictionary.values():\n    print(value)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Evaluating Dictionary Length"
        },
        {
          "type": "paragraph",
          "text": "To determine the number of key-value pairs in a dictionary, the built-in len() function can be used. This function returns the total count of items (pairs) in the dictionary."
        },
        {
          "type": "textarea",
          "text": "# Creating a sample dictionary\ndictionary = {'name': 'Alice', 'age': 25, 'city': 'New York', 'country': 'USA'}\n\n# Evaluating the length of the dictionary\nlength = len(dictionary)\nprint('Length of the dictionary:', length)  # This will show the number of key-value pairs in the dictionary"
        }
      ]
    },
    {
      "title": "Python Strings",
      "description": "In Python, a string is a sequence of characters, like 'hello', made up of individual characters such as 'h', 'e', 'l', 'l', and 'o'. Strings can be created using either single quotes (' ') or double quotes (\" \"), and both work in the same way.",
      "sub_description": "For example, 'hello' and \"hello\" represent the same string. ",
      "additional_info": "You can use the print() function to output a string.",
      "content": [
        {
          "type": "textarea",
          "text": "webcooks_string = 'Welcome to WebCooks, where you can learn web development and digital marketing!'\n\n# Printing the string\nprint(webcooks_string)"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Ways to Access String Elements in Python"
        },
        {
          "type": "paragraph",
          "text": "In Python, characters in a string can be accessed in several ways:"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Indexing:"
        },
        {
          "type": "paragraph",
          "text": "Strings can be treated like lists, where each character has an index."
        },
        {
          "type": "textarea",
          "text": "# Accessing String Elements Using Indexing\n# Defining a sample string\nsample_string = 'WebCooks'\n\n# Accessing characters using indexing\nfirst_character = sample_string[0]         # Accessing the first character\nsecond_character = sample_string[1]        # Accessing the second character\nthird_character = sample_string[2]         # Accessing the third character\n\n# Printing the accessed characters\nprint('First character:', first_character)       # Output: W\nprint('Second character:', second_character)     # Output: e\nprint('Third character:', third_character)       # Output: b"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Negative Indexing:"
        },
        {
          "type": "paragraph",
          "text": "It is possible to use Python to do negative indexing-that is, start from the end of the string. "
        },
        {
          "type": "textarea",
          "text": "# Accessing String Elements Using Negative Indexing\n\n# Defining a sample string\nsample_string = 'WebCooks'\n\n# Accessing characters using negative indexing\nlast_character = sample_string[-1]         # Accessing the last character\nsecond_last_character = sample_string[-2]   # Accessing the second last character\nthird_last_character = sample_string[-3]     # Accessing the third last character\n\n# Printing the accessed characters\nprint('Last character:', last_character)               # Output: s\nprint('Second last character:', second_last_character)  # Output: o\nprint('Third last character:', third_last_character)    # Output: o"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Slicing:"
        },
        {
          "type": "paragraph",
          "text": "A range of characters can be accessed using the slicing operator (:)."
        },
        {
          "type": "textarea",
          "text": "# Accessing String Elements Using Slicing\n\n# Defining a sample string\nsample_string = 'WebCooks'\n\n# Slicing the string to get different parts\nsubstring1 = sample_string[0:4]      # Slicing from index 0 to 3 (exclusive of 4)\nsubstring2 = sample_string[4:]         # Slicing from index 4 to the end\nsubstring3 = sample_string[:3]          # Slicing from the start to index 2 (exclusive of 3)\nsubstring4 = sample_string[-4:]        # Slicing the last 4 characters\n\n# Printing the sliced substrings\nprint('Substring 1 (0 to 3):', substring1)  # Output: WebC\nprint('Substring 2 (4 to end):', substring2) # Output: Cooks\nprint('Substring 3 (start to 2):', substring3)  # Output: Web\nprint('Substring 4 (last 4):', substring4)   # Output: Cooks"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Why Strings in Python Cannot Be Changed"
        },
        {
          "type": "paragraph",
          "text": "String characters in Python can't be changed once they are created."
        },
        {
          "type": "textarea",
          "text": "# Example of String Immutability:\noriginal_string = 'WebCooks'\n# Attempting to change the first character will result in an error:\n# original_string[0] = 'w'  # This will raise a TypeError\n\n# Instead, to modify a string, you create a new one:\nmodified_string = 'w' + original_string[1:]  # This creates a new string\nprint('Original String:', original_string)  # Output: WebCooks\nprint('Modified String:', modified_string)  # Output: webCooks"
        },
        {
          "type": "paragraph",
          "text": "However, it is possible to assign a new string to the same variable."
        },
        {
          "type": "textarea",
          "text": "# Example:\noriginal_string = 'WebCooks'\nprint('Original String:', original_string)  # Output: WebCooks\n\n# Assigning a new string to the same variable\noriginal_string = 'WebCooks Academy'\nprint('Reassigned String:', original_string)  # Output: WebCooks Academy\n\n# Explanation:\n# 1. The original string 'WebCooks' remains unchanged in memory.\n# 2. The variable original_string now points to a new string object 'WebCooks Academy'.\n# 3. The previous string can still be accessed if stored in another variable.\n\n# Storing the original string in another variable:\nprevious_string = 'WebCooks'\nprint('Previous String:', previous_string)  # Output: WebCooks"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Python Multiline Strings: "
        },
        {
          "type": "paragraph",
          "text": "In Python, multiline strings can be created using triple quotes, either triple single quotes (''') or triple double quotes (``` ```). This feature allows for the inclusion of string literals that span multiple lines, making it convenient for writing long texts or documentation within the code."
        },
        {
          "type": "textarea",
          "text": "# Example of a multiline string:\nmultiline_string = '''\nThis is a multiline string.\nIt can span multiple lines.\nYou can include new lines and special characters.\n'''\n\nprint('Multiline String:')\nprint(multiline_string)\n\n# Another example using double quotes:\nanother_multiline_string = \"\"\"\\nThis is another example\\nof a multiline string.\\nIt uses double quotes.\\n\"\"\"\n\nprint('Another Multiline String:')\nprint(another_multiline_string)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Benefits of Multiline Strings:"
        },
        {
          "type": "list",
          "items": [
            "<b>Readability:</b>They make the code more readable, especially for cases where there are very long strings or blocks of text.",
            "<b>Documentation:</b> Multiline strings are often used for docstrings, which describe the purpose and usage of functions, classes, or modules.",
            "<b>Preservation of Format:</b> When using multiline strings, the formatting (including line breaks and spaces) is preserved, making it ideal for structured text."
          ]
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Common String Methods in Python"
        },
        {
          "type": "paragraph",
          "text": "String manipulation in Python refers to a variety of methods and techniques used to modify, format, or analyze string data. Python provides built-in methods that make string manipulation efficient and straightforward."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "String Concatenation"
        },
        {
          "type": "paragraph",
          "text": "Concatenation refers to the process where two or more strings are connected together using the + operator.This operation combines the strings end-to-end. Python does not add any spaces automatically, so you must manually insert them if needed. For example, combining ``Hello`` and ``World`` would give ``Hello World``."
        },
        {
          "type": "textarea",
          "text": "# Example using `+` operator:\nstring1 = 'Hello'\nstring2 = 'WebCooks'\nconcatenated_string = string1 + ' ' + string2\nprint('Concatenated String using +:', concatenated_string)  # Output: Hello WebCooks"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "String Comparison"
        },
        {
          "type": "paragraph",
          "text": "To check whether two strings are equal, the == operator is used. A comparison between two strings. It returns True if and only if both strings consist of the same sequence of characters; otherwise, it will return False."
        },
        {
          "type": "textarea",
          "text": "# Example of equality comparison:\nstring1 = 'WebCooks'\nstring2 = 'WebCooks'\nequal_check = string1 == string2\nprint('Are the strings equal?', equal_check)  # Output: True"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Looping Over Characters in a String"
        },
        {
          "type": "paragraph",
          "text": "In Python, you can loop over each character in a string using a for loop. This allows you to access each character one at a time. Since strings are sequences of characters, the for loop iterates through the string in order from the first character to the last."
        },
        {
          "type": "textarea",
          "text": "string = 'WebCooks'\n\n# Looping through each character\nfor char in string:\n    print(char)"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Calculating the Length of a String in Python"
        },
        {
          "type": "paragraph",
          "text": "You will often want to know how long a string is in a program. Python has an actual function called len(). This function returns the total number of characters in the string, including spaces, punctuation, and special characters."
        },
        {
          "type": "textarea",
          "text": "string = 'WebCooks'\n\n# Calculating the length\nlength = len(string)\nprint('Length of the string:', length)  # Output: 8"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Determining String Membership"
        },
        {
          "type": "paragraph",
          "text": "In Python, the in keyword is used to check if a specific substring exists within a string. This operation returns True if the substring is found and False if it is not. It's a quick and intuitive way to perform membership tests without needing to write loops or complex conditions."
        },
        {
          "type": "textarea",
          "text": "string = 'Welcome to WebCooks Academy'\n\n# Check if 'WebCooks' is in the string\nmembership_check = 'WebCooks' in string\nprint('Is \"WebCooks\" in the string?', membership_check)  # Output: True"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Escape Sequences in python"
        },
        {
          "type": "paragraph",
          "text": "Escape sequences are special characters used to include certain characters within a string that might otherwise cause errors. For instance, if we want to include both double quotes and single quotes in a string, we might encounter issues."
        },
        {
          "type": "textarea",
          "text": "# Escape Sequences in Python\n\n# Escape sequences allow special characters to be used within strings.\n# Common escape sequences:\n\nnewline = \"Hello, WebCooks!\\nWelcome to Python programming.\"  # Newline escape sequence\nprint('Newline Example:')\nprint(newline)\n\nquote = \"She said, \\\"Hello!\\\"\"  # Double quote escape sequence\nprint('\\nQuote Example:')\nprint(quote)\n\nbackslash = \"This is a backslash: \\\\\"  # Backslash escape sequence\nprint('\\nBackslash Example:')\nprint(backslash)\n\n# Explanation:\n# 1. `\\n` inserts a new line in the string.\n# 2. `\\\"` allows double quotes to be used within a string.\n# 3. `\\\\` adds a backslash in the string."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Introduction to String Formatting (f-Strings) in Python"
        },
        {
          "type": "paragraph",
          "text": "Python f-Strings, introduced in Python 3.6, provide a concise and efficient way to format strings. This formatting syntax allows for easy insertion of values and variables directly within string literals, making code more readable and maintainable."
        },
        {
          "type": "paragraph",
          "text": "An f-string is created by adding an f or F letter to the left side of a string. Inside the { } bracket, you place valid Python expressions, variables, arithmetic operations, function calls, and much more."
        },
        {
          "type": "textarea",
          "text": "name = 'WebCooks'\ncourse = 'Python Programming'\n\n# Using f-string to format the string\nformatted_string = f\"Welcome to {name}! Enjoy learning {course}.\"\nprint('Formatted String:', formatted_string)  # Output: Welcome to WebCooks! Enjoy learning Python Programming."
        }
      ]
    }
  ],
  "Python Functions": [
    {
      "title": "Functions",
      "description": "A function is a block of statements, which once it is called gets executed.It can be used to perform specific tasks, such that we do not need to rewrite the same code again to get same task done.",
      "sub_description": "",
      "additional_info": "",
      "content": [
        {
          "type": "heading",
          "level": "4",
          "text": "Calling a function"
        },
        {
          "type": "paragraph",
          "text": "To invoke a procedure, we must write the procedure name followed by both an opening and closing parenthesis. Once written then it redirects the compiler or interpreter to run the function. Note that it is important for function name to have parenthesis next to it to make a function call."
        },
        {
          "type": "textarea",
          "text": "# Define a function\ndef greet(name):\n    return f\"Hello, {name}! Welcome to WebCooks.\"\n\n# Call the function\ngreeting_message = greet('Tanishq')\nprint(greeting_message)  # Output: Hello, Tanishq! Welcome to WebCooks."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Function Arguments"
        },
        {
          "type": "paragraph",
          "text": "Inputs can be passed to a function, by writing the function name and in the parenthesis typing the inputs to pass followed by a “,”(comma) as a separator, when calling the function, and while defining a function.Functions can accept any number of arguments to customize their behavior. Note that when defining a function, the inputs put in parenthesis are called parameters and when calling the function the inputs provided are known as arguments."
        },
        {
          "type": "textarea",
          "text": "def add_numbers(a, b):\n    return a + b\n\n# Calling the function with arguments\nresult = add_numbers(5, 10)\nprint('Sum:', result)  # Output: Sum: 15"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "return statement"
        },
        {
          "type": "paragraph",
          "text": "To return any value during a program execution we use return statement."
        },
        {
          "type": "textarea",
          "text": "def square(number):\n    return number * number  # Returns the square of the number\n\n# Calling the function and storing the result\nresult = square(4)\nprint('Square of 4:', result)  # Output: Square of 4: 16"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Pass Statement"
        },
        {
          "type": "paragraph",
          "text": "The pass statement serves as a placeholder that is kept for future code and to avoid errors during execution."
        },
        {
          "type": "textarea",
          "text": "def placeholder_function():\n    pass  # This function does nothing for now\n\n# Example of using the function\nplaceholder_function()\nprint('The placeholder function has been called.')  # Output: The placeholder function has been called."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Python library functions:"
        },
        {
          "type": "paragraph",
          "text": "These are built-in functions in python which can be used to perform a specific task, for example, print() can be used to print a string and pow() can be used to get power of a function."
        },
        {
          "type": "textarea",
          "text": "# Example 1: Using `print()` to display text\nprint('Welcome to WebCooks')  # Output: Welcome to WebCooks\n\n# Example 2: Using `pow()` to calculate powers\nresult = pow(2, 3)  # Calculates 2 raised to the power of 3\nprint('2 to the power of 3 is:', result)  # Output: 2 to the power of 3 is: 8\n\n# Explanation:\n# 1. `print()` is a built-in function to output text or other values.\n# 2. `pow()` calculates the power of a number (in this case, 2^3), a common mathematical operation."
        }
      ]
    },
    {
      "title": "Python function arguments",
      "description": "Function arguments with default value: You can give default value to parameters of a function in python by specifying value of parameters of a function.",
      "sub_description": "Here the output clearly shows that when a function with default value to its parameters is called without any arguments, it uses default value provided in its execution and if arguments are provided then it uses the arguments provided for a calculation.",
      "additional_info": "",
      "content": [
        {
          "type": "textarea",
          "text": "def introduce(name, age=18, *hobbies, **details):\n    print(f\"Name: {name}\")\n    print(f\"Age: {age}\")\n    print(f\"Hobbies: {', '.join(hobbies)}\")\n    for key, value in details.items():\n        print(f\"{key}: {value}\")\n\n# Calling the function with various argument types\nintroduce('Tanisha', 21, 'painting', 'coding', city='Mumbai', profession='Developer')"
        },
        {
          "type": "heading",
          "level": "3",
          "text": "Function arguments with name:"
        },
        {
          "type": "paragraph",
          "text": "There’s another way to provide arguments to a function in python in which we assign value to the arguments based on its name."
        },
        {
          "type": "textarea",
          "text": "def greet(name):\n    return f\"Hello, {name}! Welcome to WebCooks.\"\n\n# Calling the function with a name argument\nmessage = greet(name='Tanisha')\nprint(message)  # Output: Hello, Tanisha! Welcome to WebCooks."
        },
        {
          "type": "heading",
          "level": "3",
          "text": "Python function with unknown arguments:"
        },
        {
          "type": "paragraph",
          "text": "When the number of arguments for a function is unknown then we can assign all the arguments under 1 variable name by typing a “*” and then the parameter name in the function definition. This is make the parameter contain all the arguments provided during function call."
        },
        {
          "type": "textarea",
          "text": "def display_info(name, *args, **kwargs):\n    print(f\"Name: {name}\")\n    print(\"Additional Arguments:\")\n    for arg in args:\n        print(f\"- {arg}\")\n    print(\"Additional Keyword Arguments:\")\n    for key, value in kwargs.items():\n        print(f\"{key}: {value}\")\n\n# Calling the function with various arguments\n\ndisplay_info('Tanisha', 'Python Enthusiast', 'Web Developer', city='Mumbai', profession='Developer')"
        }
      ]
    },
    {
      "title": "python variable scope",
      "description": "Python variable scope is the region of code through which it is accessible.",
      "sub_description": "There are 3 variable scope in python:",
      "additional_info": "",
      "content": [
        {
          "type": "list",
          "items": [
            "Local Variables",
            "Global Variables",
            "Non-Local Variables"
          ]
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Local Variables: "
        },
        {
          "type": "paragraph",
          "text": "For example, when we declare a variable within a python function, we can only access it inside the function and not anywhere outside the function."
        },
        {
          "type": "textarea",
          "text": "def greet():\n    message = \"Hello from WebCooks!\"  # Local variable\n    print(message)\n\n# Calling the function\n\ngreet()  # Output: Hello from WebCooks!\n\n# Trying to access `message` outside the function will raise an error\n# print(message)  # This will raise a NameError because `message` is local to `greet`"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Global Variables: "
        },
        {
          "type": "paragraph",
          "text": "When we define a variable outside any function or class and in global scope then it is known as a global variable. This variable can be accessed from anywhere, including for example it can be accessed from within and outside any function."
        },
        {
          "type": "textarea",
          "text": "greeting = \"Welcome to WebCooks!\"  # Global variable\n\ndef greet():\n    print(greeting)  # Accessing the global variable within a function\n\n# Calling the function\n\ngreet()  # Output: Welcome to WebCooks!"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Non-local variables"
        },
        {
          "type": "paragraph",
          "text": "While using nested functions when declaring a variable in non-local scope it makes it accessible outside the inner function and inside the inner function but not outside the outer function, hence it’s different from a global variable."
        },
        {
          "type": "textarea",
          "text": "def outer_function():\n    message = \"Hello from Outer\"\n\n    def inner_function():\n        nonlocal message  # Declaring `message` as non-local\n        message = \"Hello from Inner\"\n\n    inner_function()\n    print(message)  # Output: Hello from Inner\n\n# Calling the outer function\nouter_function()"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Python Global keyword: "
        },
        {
          "type": "paragraph",
          "text": "When a variable is defined in global scope it can be accessed by any function but it cannot be modified within the function.To resolve this and be able to change the global variable inside the function, we make use of the keyword global."
        },
        {
          "type": "textarea",
          "text": "count = 0  # Global variable\n\ndef increment():\n    global count  # Declaring `count` as global\n    count += 1\n    print(f\"Inside function: count = {count}\")\n\n# Calling the function\nincrement()  # Output: Inside function: count = 1\n\n# Accessing the updated global variable outside the function\nprint(f\"Outside function: count = {count}\")  # Output: Outside function: count = 1"
        },
        {
          "type": "paragraph",
          "text": "Note also how using the keyword global outside the function is of no effect.It is only used inside the function to read or write a global variable."
        }
      ]
    },
    {
      "title": "Recursion function",
      "description": "A function can be used to call other functions, it can also be used to call itself.",
      "sub_description": "A function that is called by itself is defined as a recursive function.",
      "additional_info": "",
      "content": [
        {
          "type": "textarea",
          "text": "def factorial(n):\n    if n == 0:\n        return 1\n    else:\n        return n * factorial(n - 1)  # Recursive call\n\n# Using the function in a WebCooks context\nnumber = 5\nresult = factorial(number)\nprint(f\"Welcome to WebCooks! The factorial of {number} is: {result}\")  # Output: Welcome to WebCooks! The factorial of 5 is: 120"
        },
        {
          "type": "image",
          "src": "/assets/images/Untitled-1-10.jpg",
          "alt": "JavaScript Logo"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Advantages of recursion: "
        },
        {
          "type": "list",
          "items": [
            "Reduces length of code.",
            "With recursion code written is clean.",
            "A difficult task can be divided into simpler parts using recursion.",
            "Sequence generation and tree traversals get easier with recursion."
          ]
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Disadvantages of recursion: "
        },
        {
          "type": "list",
          "items": [
            "Recursive functions are somewhat slower.",
            "Recursive functions take up quite a lot of memory as compared to the non-recursive ones and take up much time.",
            "Recursive functions can be hard to comprehend and debug."
          ]
        }
      ]
    },
    {
      "title": "Modules in python",
      "description": "A module is a code written in another python program which can be imported in another program to use its functions, variables etc.",
      "sub_description": "This makes coding easier and neat as there is less lines of code in a program.",
      "additional_info": "To import any python module we write: ",
      "content": [
        {
          "type": "paragraph",
          "text": "import module_name"
        },
        {
          "type": "textarea",
          "text": "import math\n\n# Using functions from the math module\nnumber = 16\nsquare_root = math.sqrt(number)\nprint(f\"The square root of {number} is: {square_root}\")  # Output: The square root of 16 is: 4.0"
        },
        {
          "type": "paragraph",
          "text": "Here import is the keyword used to import and module_name is the name of module to be imported."
        },
        {
          "type": "paragraph",
          "text": "To import a single variable or function from any module we can also write:"
        },
        {
          "type": "paragraph",
          "text": "from module_name import variable_name"
        },
        {
          "type": "textarea",
          "text": "from math import sqrt\nnumber = 25\nsquare_root = sqrt(number)\nprint(f\"The square root of {number} is: {square_root}\")  # Output: The square root of 25 is: 5.0"
        },
        {
          "type": "paragraph",
          "text": "this fetches a variable called variable_name from a module, module_name. This way we don’t import an entire module but a particular name from it."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "as keyword:"
        },
        {
          "type": "paragraph",
          "text": "this can be used to import any module as another name. for example:"
        },
        {
          "type": "paragraph",
          "text": "import math as m"
        },
        {
          "type": "textarea",
          "text": "import math as m\n# Using the alias to call a function\nnumber = 49\nsquare_root = m.sqrt(number)\nprint(f\"The square root of {number} is: {square_root}\")  # Output: The square root of 49 is: 7.0"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "import all :"
        },
        {
          "type": "paragraph",
          "text": "To import all names from any module we can use:"
        },
        {
          "type": "paragraph",
          "text": "from module_name import*"
        },
        {
          "type": "textarea",
          "text": "from math import *\n\n# Using functions from the math module directly\nnumber = 16\nsquare_root = sqrt(number)  # No need to prefix with `math.`\nprint(f\"The square root of {number} is: {square_root}\")  # Output: The square root of 16 is: 4.0"
        }
      ]
    },
    {
      "title": "Python packages",
      "description": "When we write a lot of different code in the same python file, it can become messy.",
      "sub_description": " Python packages allow us to write specific code in separate files and import them later which makes code neat and clean.",
      "additional_info": "Import package_name.Module_Name.Function_name",
      "content": [
        {
          "type": "textarea",
          "text": "# my_package/\n# ├── __init__.py\n# ├── module1.py\n# └── module2.py\n\n# Inside `module1.py`, you might have:\n# def function1():\n#     return \"This is function 1 from module 1\"\n\n# Inside `module2.py`, you might have:\n# def function2():\n#     return \"This is function 2 from module 2\"\n\n# Importing functions from a package:\n# To use the functions from the package, you would write:\nfrom my_package.module1 import function1\nfrom my_package.module2 import function2\n\n# Using the imported functions:\nresult1 = function1()\nresult2 = function2()\nprint(result1)  # Output: This is function 1 from module 1\nprint(result2)  # Output: This is function 2 from module 2"
        },
        {
          "type": "paragraph",
          "text": "Here package_name is the parent package that contains the module. Not that “.” Is used to access the contents of the file. And “Module_Name.Function_name” means that we want to access a specific function, “Function_name” in the module, therefore we are importing particular function_name from the package."
        },
        {
          "type": "paragraph",
          "text": "There are more ways to access functions or variables from packages just like that from modules.for example:"
        },
        {
          "type": "paragraph",
          "text": "from Package_name.Module_name import Function_name"
        },
        {
          "type": "textarea",
          "text": "# my_package/\n# ├── __init__.py\n# ├── module1.py\n# └── module2.py\n\n# Inside `module1.py`, we define a function:\n# def greet():\n#     return \"Hello from module 1!\"\n\n# Inside `module2.py`, we define another function:\n# def farewell():\n#     return \"Goodbye from module 2!\"\n\n# To access the `greet` function from `module1`, you can use:\nfrom my_package.module1 import greet\n\n# To access the `farewell` function from `module2`, you can use:\nfrom my_package.module2 import farewell\n\n# Using the imported functions:\nprint(greet())     # Output: Hello from module 1!\nprint(farewell())  # Output: Goodbye from module 2!"
        },
        {
          "type": "paragraph",
          "text": "Here we use “from” keyword to specify that we are trying to access function name from “Package_name.Module_name” and we import “Function_name” from it."
        }
      ]
    }
  ],
  "Python File and Directory Handling": [
    {
      "title": "Python File and Directory Handling",
      "description": "A directory is essentially a storage space that holds various files and potentially other directories, which are referred to as subdirectories. This hierarchical structure helps organize files systematically.",
      "sub_description": "In Python, the os module is an essential tool for interacting with the operating system, and it offers a variety of methods for managing both files and directories.",
      "additional_info": "This module allows users to perform operations such as creating, deleting, and navigating through directories, as well as manipulating files.",
      "content": [
        {
          "type": "heading",
          "level": "2",
          "text": "How to Fetch the Current Directory in Python:"
        },
        {
          "type": "paragraph",
          "text": "In Python, you can easily retrieve the current working directory using the getcwd() method from the os module. The current working directory is the location where the Python script runs. "
        },
        {
          "type": "textarea",
          "text": "import os\n# Fetch the current working directory\ncurrent_directory = os.getcwd()\n\n# Print the current directory\nprint(f\"Current Directory: {current_directory}\")"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Why Use getcwd()?"
        },
        {
          "type": "list",
          "items": [
            "It is essential when you are dealing with file paths.",
            "Helps ensure the program behaves correctly when reading or writing files.",
            "It is useful when navigating directories in a larger project."
          ]
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Creating a Directory: "
        },
        {
          "type": "paragraph",
          "text": "To create a new directory in Python, the mkdir() method from the os module can be used. By passing a directory name as a string to mkdir(), a new directory is created in the current working directory unless a full path is specified."
        },
        {
          "type": "textarea",
          "text": "import os\n\n# Specify the name of the directory you want to create\nnew_directory = 'my_new_directory'\n\n# Create the directory\ntry:\n    os.mkdir(new_directory)\n    print(f\"Directory '{new_directory}' created successfully.\")\nexcept FileExistsError:\n    print(f\"Directory '{new_directory}' already exists.\")\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Changing the Current Working Directory:"
        },
        {
          "type": "paragraph",
          "text": "In Python, the current working directory can be changed using the chdir() method from the os module.The chdir() method from the os module allows changing the current working directory."
        },
        {
          "type": "paragraph",
          "text": "Paths for the chdir() method can be specified using forward slashes (/) or backward slashes (\\), depending on the operating system."
        },
        {
          "type": "textarea",
          "text": "import os\n\n# Specify the path to the new directory\nnew_directory = 'path/to/your/directory'\n\n# Change the current working directory\ntry:\n    os.chdir(new_directory)\n    print(f\"Current working directory changed to: {os.getcwd()}\")\nexcept FileNotFoundError:\n    print(f\"The directory '{new_directory}' does not exist.\")\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "How to Rename a Directory or a File"
        },
        {
          "type": "paragraph",
          "text": "To rename a directory or file, use the rename() method from the os module. It requires two arguments:"
        },
        {
          "type": "list",
          "items": [
            "<b>old_name:</b> The current name or path of the directory or file.",
            "<b>new_name:</b> The new name or path to assign to the directory or file."
          ]
        },
        {
          "type": "textarea",
          "text": "import os\n\n# Specify the current file name and the new file name\ncurrent_file_name = 'old_file.txt'\nnew_file_name = 'new_file.txt'\n\n# Rename the file\ntry:\n    os.rename(current_file_name, new_file_name)\n    print(f\"File renamed from '{current_file_name}' to '{new_file_name}'.\")\nexcept FileNotFoundError:\n    print(f\"The file '{current_file_name}' does not exist.\")\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "How to Delete Files and Directories in Python:"
        },
        {
          "type": "paragraph",
          "text": "In Python, you can remove files and directories using various methods from the os and shutil modules. These methods allow you to manage your filesystem effectively, but it's important to use them with caution, as the deletions are permanent."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Removing a File with remove()"
        },
        {
          "type": "paragraph",
          "text": "The remove() method in the os module is used to delete files by specifying the file name, including the path if it’s outside the current directory."
        },
        {
          "type": "textarea",
          "text": "import os\n\n# Specify the file name to be removed\nfile_to_remove = 'file_to_delete.txt'\n\n# Remove the file\ntry:\n    os.remove(file_to_remove)\n    print(f\"File '{file_to_remove}' has been deleted successfully.\")\nexcept FileNotFoundError:\n    print(f\"The file '{file_to_remove}' does not exist.\")\nexcept PermissionError:\n    print(f\"Permission denied: cannot delete '{file_to_remove}'.\")\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Removing an Empty Directory with rmdir()"
        },
        {
          "type": "paragraph",
          "text": " The rmdir() method in os removes empty directories. This method can only delete directories that contain no files or subdirectories."
        },
        {
          "type": "textarea",
          "text": "import os\n\n# Specify the directory name to be removed\nempty_directory = 'empty_directory'\n\n# Remove the empty directory\ntry:\n    os.rmdir(empty_directory)\n    print(f\"Directory '{empty_directory}' has been removed successfully.\")\nexcept FileNotFoundError:\n    print(f\"The directory '{empty_directory}' does not exist.\")\nexcept OSError:\n    print(f\"The directory '{empty_directory}' is not empty or cannot be removed.\")\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "How to List Directories and Files in Python"
        },
        {
          "type": "paragraph",
          "text": "To retrieve all files and subdirectories in a directory, the listdir() method from the os module can be utilized.This method requires a directory path as an argument and yields a list of all files and subdirectories present in the specified directory."
        },
        {
          "type": "paragraph",
          "text": "If a path is not specified, listdir() defaults to the current working directory and returns its contents."
        },
        {
          "type": "textarea",
          "text": "import os\n\n# Specify the directory path (use '.' for the current directory)\ndirectory_path = '.'\n\n# List all files and directories in the specified path\ntry:\n    items = os.listdir(directory_path)\n    print(f\"Contents of '{directory_path}':\")\n    for item in items:\n        print(item)\nexcept FileNotFoundError:\n    print(f\"The directory '{directory_path}' does not exist.\")\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")"
        }
      ]
    },
    {
      "title": "Handling CSV Files in Python: Reading and Writing",
      "description": "Reading and Writing CSV, or Comma Separated Values, is a format commonly used for storing tabular data as plain text.In a CSV file, data is structured in rows and columns where every single row represents a record and columns are divided by commas.",
      "sub_description": "These files usually have a .csv extension.",
      "additional_info": "To illustrate how to work with CSV files in Python, let’s consider a sample CSV file named std_data.csv that contains the following data:",
      "content": [
        {
          "type": "textarea",
          "text": "import csv\n\n# Specify the CSV file name\ncsv_file = 'std_data.csv'\n\n# Reading the CSV file\ntry:\n    with open(csv_file, mode='r') as file:\n        csv_reader = csv.reader(file)\n        header = next(csv_reader)  # Read the header row\n        print(f\"Header: {header}\")\n        \n        for row in csv_reader:\n            print(f\"Row: {row}\")\nexcept FileNotFoundError:\n    print(f\"The file '{csv_file}' does not exist.\")\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Handling CSV Files in Python"
        },
        {
          "type": "paragraph",
          "text": "Python offers a specialized csv module that simplifies working with CSV files. This module is equipped with a range of functions that allow you to read from and write to CSV files effortlessly, making it easier to handle tabular data."
        },
        {
          "type": "paragraph",
          "text": "To work with CSV files in Python, the csv module is used, which can be imported directly into the Python script."
        },
        {
          "type": "textarea",
          "text": "import csv"
        },
        {
          "type": "paragraph",
          "text": "Once imported, you can utilize the various methods available in the module for different operations.Here’s an outline of key tasks for working with CSV files using the csv module: "
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Reading CSV Files"
        },
        {
          "type": "paragraph",
          "text": "To read data from a CSV file, the csv.reader() function is available. This function takes a file object as input and provides an iterable that allows looping through each row in the CSV."
        },
        {
          "type": "textarea",
          "text": "# Example of Reading a CSV File in Python\n\nimport csv\n\n# Sample CSV file named 'std_data.csv'\n# The content of the file is:\n# ID,Name,Age,Grade\n# 1,John Doe,20,A\n# 2,Jane Smith,21,B\n# 3,Bob Johnson,19,C\n\n# Specify the name of the CSV file\ncsv_file = 'std_data.csv'\n\ntry:\n    # Open the CSV file in read mode\n    with open(csv_file, mode='r') as file:\n        csv_reader = csv.reader(file)\n        \n        # Read the header row\n        header = next(csv_reader)\n        print(f\"Header: {header}\")\n        \n        # Iterate over the rows in the CSV file\n        for row in csv_reader:\n            print(f\"Row: {row}\")\nexcept FileNotFoundError:\n    print(f\"The file '{csv_file}' does not exist.\")\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Writing to CSV Files"
        },
        {
          "type": "paragraph",
          "text": "To save data into a CSV file, the csv.writer() function is used. This function generates a writer object, which can then be used to add rows of data to a specified CSV file."
        },
        {
          "type": "textarea",
          "text": "# Writing to CSV Files in Python\n\nimport csv\n\n# Sample data to be written to the CSV file\nheader = ['ID', 'Name', 'Age', 'Grade']\nrows = [\n    [1, 'John Doe', 20, 'A'],\n    [2, 'Jane Smith', 21, 'B'],\n    [3, 'Bob Johnson', 19, 'C']\n]\n\n# Specify the name of the CSV file to write to\ncsv_file = 'std_data.csv'\n\ntry:\n    # Open the CSV file in write mode\n    with open(csv_file, mode='w', newline='') as file:\n        csv_writer = csv.writer(file)\n        \n        # Write the header to the CSV file\n        csv_writer.writerow(header)\n        \n        # Write multiple rows to the CSV file\n        csv_writer.writerows(rows)\n        \n    print(f'Successfully written to {csv_file}.')\nexcept Exception as e:\n    print(f'An error occurred: {e}')"
        }
      ]
    }
  ],
  "Python Exception Handling": [
    {
      "title": "Errors",
      "description": "Errors can arise for several reasons, including incorrect syntax, invalid operations, or unexpected conditions during runtime. Python offers tools like try-except blocks to manage exceptions and maintain program stability. ",
      "sub_description": "An error in Python refers to a problem in the code that disrupts the normal flow of execution.",
      "additional_info": "Errors are issues in program that stop program execution. It is also known as parsing errors.",
      "content": [
        {
          "type": "image",
          "src": "/assets/images/Untitled-1-07.jpg",
          "alt": "JavaScript Logo"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Type of Errors: "
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Syntax error: "
        },
        {
          "type": "paragraph",
          "text": "It’s a type of error that is triggered when the interpreter finds incorrect code written according to syntax rules. This error includes, spelling mistakes, erroneous enclosing of string, missing parenthesis or bracket etc."
        },
        {
          "type": "textarea",
          "text": "# Example of a Syntax Error: Missing Colon\n\nif x > 10   # SyntaxError: expected ':'\n    print(\"x is greater than 10\")\n\n# Correction:\nif x > 10:\n    print(\"x is greater than 10\")  # Add a colon at the end of the if statement"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Index error: "
        },
        {
          "type": "paragraph",
          "text": "This error is triggered when an incorrect list or tuple index is accessed. For example, accessing 3rd element from a list made of 2 elements."
        },
        {
          "type": "textarea",
          "text": "# Example of an IndexError\n\nmy_list = [1, 2, 3]\n\n# Trying to access an index that is out of range\nprint(my_list[5])  # IndexError: list index out of range\n\n# Correction:\nprint(my_list[2])  # This will correctly print '3' as it is the last element of the list."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Indentation error"
        },
        {
          "type": "paragraph",
          "text": "An indentation error appears when there is an inconsistency in the code's indentation or spacing.For example, incorrect nesting of elements or incorrect spacing of code."
        },
        {
          "type": "textarea",
          "text": "# Example of an IndentationError\n\ndef my_function():\nprint(\"Hello\")  # IndentationError: expected an indented block\n\n# Correction:\n    print(\"Hello\")  # Indent the print statement to fix the error."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Zero division error"
        },
        {
          "type": "paragraph",
          "text": "A zero division error is triggered when dividing a number by zero."
        },
        {
          "type": "textarea",
          "text": "# Example of a ZeroDivisionError\n\n# Attempting to divide by zero\nresult = 10 / 0  # ZeroDivisionError: division by zero\n\n# Correction:\n# Check if the denominator is not zero before division\n denominator = 0\n if denominator != 0:\n     result = 10 / denominator\n else:\n     result = 'Cannot divide by zero'\n print(result)  # This will safely handle the division."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Logical errors"
        },
        {
          "type": "paragraph",
          "text": "These errors occur when the syntax and structure of program is correct and program executes successfully but gives incorrect output or unintended results. This error is harder to detect than the likes of syntax errors etc. and can arise due to incorrect logic, assumption etc."
        },
        {
          "type": "textarea",
          "text": "# Example of a Logical Error\n\n# Incorrect calculation of the average\nnumbers = [10, 20, 30]\n\n# Logical error: using len(numbers) instead of the total sum\naverage = sum(numbers) / len(numbers) * 2  # This will give an incorrect average\n\n# Correction:\n# To get the correct average, remove the multiplication by 2\naverage = sum(numbers) / len(numbers)\nprint(average)  # This will correctly print '20.0'"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Built-in exception:"
        },
        {
          "type": "textarea",
          "text": "# Example of Built-in Exceptions in Python\n\n# 1. ValueError: Raised when a function receives an argument of the right type but inappropriate value.\n\ntry:\n    number = int(\"abc\")  # This will raise a ValueError\nexcept ValueError as e:\n    print(f\"ValueError: {e}\")\n\n# 2. TypeError: Raised when an operation or function is applied to an object of inappropriate type.\n\ntry:\n    result = '2' + 2  # This will raise a TypeError\nexcept TypeError as e:\n    print(f\"TypeError: {e}\")\n\n# 3. FileNotFoundError: Raised when a file or directory is requested but cannot be found.\n\ntry:\n    with open('non_existent_file.txt', 'r') as file:\n        content = file.read()\nexcept FileNotFoundError as e:\n    print(f\"FileNotFoundError: {e}\")"
        }
      ]
    },
    {
      "title": "Exceptions",
      "description": "Python classifies errors into two primary types: syntax errors and exceptions.  Syntax errors arise when the code is written incorrectly according to Python's language rules, preventing program execution.On the other hand, Exceptions, are raised when an error occurs which can stop program execution.",
      "sub_description": " These can disrupt the program's flow and cause it to stop unless they are handled.",
      "additional_info": "To manage exceptions, Python uses `try` and `except` blocks, which allow the program to catch and handle the error gracefully without terminating unexpectedly.",
      "content": [
        {
          "type": "image",
          "src": "/assets/images/Untitled-1-08.jpg",
          "alt": "JavaScript Logo"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Try block"
        },
        {
          "type": "paragraph",
          "text": "Try Block contains statements that might raise an exception during execution.  Python attempts to execute the code within this block. If no exceptions are encountered, the code executes as intended.If no exceptions occur, the code runs as expected."
        },
        {
          "type": "textarea",
          "text": "# Example of a Try Block in Python\n\n# The try block allows you to test a block of code for errors.\ntry:\n    # Code that may raise an exception\n    result = 10 / 0  # This will raise a ZeroDivisionError\n    print(result)\nexcept ZeroDivisionError as e:\n    # This block will execute if a ZeroDivisionError occurs\n    print(f\"Error: {e}\")  # Output: Error: division by zero\n\n# Additional code can run after the try-except blocks\nprint(\"This will still run even after the error.\")"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Except block"
        },
        {
          "type": "paragraph",
          "text": "An except block is utilized to catch and manage exceptions that arise within the try block. If an error is encountered in the try block, Python searches for a corresponding except block to address the issue."
        },
        {
          "type": "textarea",
          "text": "# Example of an Except Block in Python\n\n# The except block allows you to handle exceptions that may occur in a try block.\ntry:\n    # Code that may raise an exception\n    number = int(\"abc\")  # This will raise a ValueError\nexcept ValueError as e:\n    # This block will execute if a ValueError occurs\n    print(f\"Caught a ValueError: {e}\")  # Output: Caught a ValueError: invalid literal for int() with base 10: 'abc'\n\n# After the except block, the program continues to run\nprint(\"Program continues after handling the exception.\")"
        },
        {
          "type": "paragraph",
          "text": "There can be multiple except blocks in python for a try block to catch multiple exceptions separately."
        },
        {
          "type": "textarea",
          "text": "# Example of Multiple Except Blocks in Python\n\n# You can have multiple except blocks to handle different exceptions separately.\ntry:\n    # Code that may raise exceptions\n    num1 = int(input(\"Enter a number: \"))  # Could raise ValueError\n    result = 10 / num1  # Could raise ZeroDivisionError\nexcept ValueError as e:\n    # Handle ValueError when input is not an integer\n    print(f\"ValueError: {e}. Please enter a valid integer.\")\nexcept ZeroDivisionError as e:\n    # Handle ZeroDivisionError when input is zero\n    print(f\"ZeroDivisionError: {e}. Division by zero is not allowed.\")\nelse:\n    # This block executes if no exceptions were raised\n    print(f\"The result is: {result}\")\nfinally:\n    # This block always executes, regardless of whether an exception occurred\n    print(\"Execution completed.\")"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "else block"
        },
        {
          "type": "paragraph",
          "text": "The else clause defines a code section that only executes if no exceptions were triggered in the try block. In Python's exception handling framework, the else clause is an optional component of the try-except construct.The else clause will be executed after the try block finishes successfully, but it will be skipped if an exception is raised."
        },
        {
          "type": "textarea",
          "text": "# Example of an Else Block in Python\n\n# The else block can be used after the except blocks in a try statement.\ntry:\n    # Code that may raise an exception\n    num1 = int(input(\"Enter a number: \"))  # User input\n    result = 10 / num1  # This may raise ZeroDivisionError\nexcept ValueError as e:\n    # Handle ValueError when input is not an integer\n    print(f\"ValueError: {e}. Please enter a valid integer.\")\nexcept ZeroDivisionError as e:\n    # Handle ZeroDivisionError when input is zero\n    print(f\"ZeroDivisionError: {e}. Division by zero is not allowed.\")\nelse:\n    # This block executes if no exceptions were raised\n    print(f\"The result is: {result}\")\nfinally:\n    # This block always executes\n    print(\"Execution completed.\")"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "finally block"
        },
        {
          "type": "paragraph",
          "text": "The finally block ensures that a specific code segment will execute regardless of whether an exception was encountered in the try block.This block executes at the end of try.  The finally block is typically used for cleanup actions, such as closing files, releasing resources, or any other tasks that need to be performed after the execution of the try block."
        },
        {
          "type": "textarea",
          "text": "# Example of a Finally Block in Python\n\n# The finally block is used to execute code regardless of whether an exception was raised or not.\ntry:\n    # Code that may raise an exception\n    num1 = int(input(\"Enter a number: \"))  # User input\n    result = 10 / num1  # This may raise ZeroDivisionError\nexcept ValueError as e:\n    # Handle ValueError when input is not an integer\n    print(f\"ValueError: {e}. Please enter a valid integer.\")\nexcept ZeroDivisionError as e:\n    # Handle ZeroDivisionError when input is zero\n    print(f\"ZeroDivisionError: {e}. Division by zero is not allowed.\")\nelse:\n    # This block executes if no exceptions were raised\n    print(f\"The result is: {result}\")\nfinally:\n    # This block always executes\n    print(\"Execution completed, whether or not an error occurred.\")"
        }
      ]
    }
  ],
  "Python Object & Class": [
    {
      "title": "Python OOPS",
      "description": "Python, like other general-purpose programming languages, has always been object-oriented.In Python, classes allow the creation and use of objects to structure applications, supporting the development of reusable code. ",
      "sub_description": "In an object-oriented approach, programs are designed using these classes and objects, which are like real-world things such as a book, house, or pencil. By creating objects, you can solve problems in a more organized way.",
      "additional_info": "Here are some main principles of object-oriented programming (OOP):",
      "content": [
        {
          "type": "list",
          "items": [
            "Class",
            "Object",
            "Method",
            "Inheritance",
            "Polymorphism",
            "Data Abstraction",
            "Encapsulation"
          ]
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Class"
        },
        {
          "type": "paragraph",
          "text": "In Python, a class is established using the class keyword and serves as a template to define objects.  It combines data and functions to represent the attributes and actions of these objects.A class is a framework for grouping data and functions together. When a new class is created, it establishes a new object type, making it possible to create multiple instances of that type. Each instance can have attributes to maintain its state, as well as methods for modifying it."
        },
        {
          "type": "textarea",
          "text": "class Car:\n    model = \"\"   # attribute for the car model\n    year = 0       # attribute for the car's manufacturing year\n\n# Create an instance of the Car class\ncar1 = Car()\n\n# Assign values to the instance attributes\ncar1.model = 'Sedan'\ncar1.year = 2022\n\n# Access and print the values of the instance attributes\nprint('Car Model:', car1.model)  # Output: Car Model: Sedan\nprint('Manufacturing Year:', car1.year)  # Output: Manufacturing Year: 2022"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Objects"
        },
        {
          "type": "paragraph",
          "text": "An object in Python is a specific instance of a class, symbolizing a real-world element with defined attributes (state) and methods (behavior).Examples of objects include physical items like a mouse, keyboard, chair, or pen. Since Python considers everything as an object, most items come with built-in attributes and methods.For example, functions have a built-in __doc__ attribute, which returns the docstring specified in the function’s source code."
        },
        {
          "type": "paragraph",
          "text": "When a class is defined, objects are created from that class to allocate memory for storing their state and behavior."
        },
        {
          "type": "textarea",
          "text": "# Create a Class in Python\n\nclass Laptop:\n    brand = \"\"  # attribute for the laptop brand\n    ram = 0      # attribute for the amount of RAM (in GB)\n\n# Create objects of the Laptop class\nlaptop1 = Laptop()\nlaptop2 = Laptop()\n\n# Assign values to the instance attributes for each object\nlaptop1.brand = 'Dell'\nlaptop1.ram = 16\n\nlaptop2.brand = 'HP'\nlaptop2.ram = 8\n\n# Access and print the values of the instance attributes for each object\nprint('Laptop 1 Brand:', laptop1.brand)  # Output: Laptop 1 Brand: Dell\nprint('Laptop 1 RAM:', laptop1.ram)      # Output: Laptop 1 RAM: 16\n\nprint('Laptop 2 Brand:', laptop2.brand)  # Output: Laptop 2 Brand: HP\nprint('Laptop 2 RAM:', laptop2.ram)      # Output: Laptop 2 RAM: 8"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Access Class Attributes using Objects: "
        },
        {
          "type": "paragraph",
          "text": "In Python, class attributes are variables defined within a class, but outside of any instance methods. Class attributes belong to the class itself, meaning they are shared across all instances (objects) of the class.To access class attributes, you can use dot notation (.), either through the class name or via an object (an instance of the class)."
        },
        {
          "type": "textarea",
          "text": "# Access and Modify Class Attributes Using Objects\n\nclass Laptop:\n    brand = \"\"  # attribute for the laptop brand\n    ram = 0      # attribute for the amount of RAM (in GB)\n\n# Create an object of the Laptop class\nlaptop1 = Laptop()\n\n# Modify the 'brand' attribute\nlaptop1.brand = 'Apple MacBook'\n\n# Access the 'ram' attribute\nlaptop1.ram = 16\n\n# Print the modified attributes\nprint('Laptop Brand:', laptop1.brand)  # Output: Laptop Brand: Apple MacBook\nprint('Laptop RAM:', laptop1.ram)      # Output: Laptop RAM: 16"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Create Multiple Objects of python Class: "
        },
        {
          "type": "textarea",
          "text": "# Define a Class\n\nclass Smartphone:\n    brand = \"\"\n    storage = 0  # storage in GB\n\n# Create objects of the Smartphone class\nphone1 = Smartphone()\nphone2 = Smartphone()\n\n# Access attributes and assign new values for each object\nphone1.brand = 'Samsung'\nphone1.storage = 128\n\nphone2.brand = 'Apple'\nphone2.storage = 256\n\n# Print the details of each object\nprint(f\"Phone 1 - Brand: {phone1.brand}, Storage: {phone1.storage} GB\")  # Output: Phone 1 - Brand: Samsung, Storage: 128 GB\nprint(f\"Phone 2 - Brand: {phone2.brand}, Storage: {phone2.storage} GB\")  # Output: Phone 2 - Brand: Apple, Storage: 256 GB"
        }
      ]
    },
    {
      "title": "Constructor",
      "description": "A constructor is a unique function that sets up an object’s attributes upon its creation. In C++ or Java, it shares the name of the class, but in python, it’s called __init__.",
      "sub_description": "There are two types of constructors: ",
      "additional_info": "one with arguments (parameterized)  and one without (non-parameterized).",
      "content": [
        {
          "type": "heading",
          "level": "4",
          "text": "The Self-Parameter: "
        },
        {
          "type": "paragraph",
          "text": "The self parameter identifies the specific instance of a class, making it possible to access that instance's variables and methods. Although any name can technically replace self, it must always be the first parameter in any class function."
        },
        {
          "type": "textarea",
          "text": "# Example of Self Parameter in Python\n\nclass Student:\n    def __init__(self, name, grade):\n        self.name = name  # 'self' allows access to instance attributes\n        self.grade = grade\n\n    def introduce(self):\n        print(f\"Hello, my name is {self.name} and I am in grade {self.grade}.\")\n\n# Create an object of the Student class\nstudent1 = Student('John', 10)\n\n# Call the introduce method\nstudent1.introduce()  # Output: Hello, my name is John and I am in grade 10."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "_ _init_ _ method: "
        },
        {
          "type": "paragraph",
          "text": "The __init__ method is a special function that initializes a new instance of a class. This function, often called a constructor, helps set up the object's attributes when it's created. It requires the self parameter, which points to the specific instance being created.You can also add other arguments to the `__init__` method to set the initial values of the object's attributes."
        },
        {
          "type": "textarea",
          "text": "# Example of __init__ Method in Python\n\nclass Book:\n    def __init__(self, title, author):\n        self.title = title  # Initialize title attribute\n        self.author = author  # Initialize author attribute\n\n    def details(self):\n        print(f\"Book: '{self.title}', Author: {self.author}\")\n\n# Create an object of the Book class\nbook1 = Book('The Great Gatsby', 'F. Scott Fitzgerald')\n\n# Call the details method\nbook1.details()  # Output: Book: 'The Great Gatsby', Author: F. Scott Fitzgerald"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Python Parameterized Constructor: "
        },
        {
          "type": "paragraph",
          "text": "A parameterized constructor includes multiple parameters in addition to self, allowing for more specific initializations when creating an object."
        },
        {
          "type": "textarea",
          "text": "# Example of Parameterized Constructor in Python\n\nclass Car:\n    def __init__(self, make, model, year):\n        self.make = make      # Initialize make attribute\n        self.model = model    # Initialize model attribute\n        self.year = year      # Initialize year attribute\n\n    def display_info(self):\n        print(f\"Car Make: {self.make}, Model: {self.model}, Year: {self.year}\")\n\n# Create an object of the Car class with parameters\ncar1 = Car('Toyota', 'Corolla', 2020)\n\n# Call the display_info method\ncar1.display_info()  # Output: Car Make: Toyota, Model: Corolla, Year: 2020"
        },
        {
          "type": "heading",
          "level": "3",
          "text": "Methods"
        },
        {
          "type": "paragraph",
          "text": "A method is a function linked to an object that defines its behavior or actions.In Python, methods are not limited to class instances—many object types can have associated methods."
        },
        {
          "type": "textarea",
          "text": "# Example of Methods in a Python Class\n\nclass Rectangle:\n    def __init__(self, width, height):\n        self.width = width  # Initialize width attribute\n        self.height = height  # Initialize height attribute\n\n    def area(self):\n        return self.width * self.height  # Method to calculate area\n\n    def perimeter(self):\n        return 2 * (self.width + self.height)  # Method to calculate perimeter\n\n# Create an object of the Rectangle class\nrect = Rectangle(5, 10)\n\n# Call the area and perimeter methods\nprint(f\"Area: {rect.area()}\")        # Output: Area: 50\nprint(f\"Perimeter: {rect.perimeter()}\")  # Output: Perimeter: 30"
        }
      ]
    },
    {
      "title": "Inheritance",
      "description": "Python, as an object-oriented language, supports inheritance, enabling the creation of a new class from an existing one.",
      "sub_description": "Inheritance in Python enables a class to acquire all the properties and methods from another class.",
      "additional_info": "The class being inherited from is termed the parent or base class, whereas the class that derives from it is called the subclass or derived class.",
      "content": [
        {
          "type": "list",
          "items": [
            "Single Inheritance",
            "Multiple Inheritance",
            "Multilevel Inheritance",
            "Hierarchical Inheritance",
            "Hybrid Inheritance"
          ]
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Python Single Inheritance: "
        },
        {
          "type": "paragraph",
          "text": "This type of inheritance involves a child class inheriting from only one parent class. The child class gains all the attributes and methods of the parent class, allowing it to use and extend those features while adding its own."
        },
        {
          "type": "textarea",
          "text": "# Example of Single Inheritance in Python\n\nclass Animal:\n    def speak(self):\n        return \"Animal speaks\"\n\n# Child class that inherits from Animal\nclass Dog(Animal):\n    def bark(self):\n        return \"Dog barks\"\n\n# Create an object of the Dog class\ndog = Dog()\n\n# Call methods from both the Dog and Animal classes\nprint(dog.speak())  # Output: Animal speaks\nprint(dog.bark())   # Output: Dog barks"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Python Multi-Level Inheritance: "
        },
        {
          "type": "paragraph",
          "text": "In python, like other object-oriented languages, multi-level inheritance is possible.In multi-level inheritance, one class may inherit from a parent, which itself inherited from some other parent class. A child class inherits from its parent class, which is inheriting from its parent class.  Python allows an unlimited number of inheritance levels. "
        },
        {
          "type": "textarea",
          "text": "# Example of Multi-Level Inheritance in Python\n\nclass Animal:\n    def speak(self):\n        return \"Animal speaks\"\n\nclass Dog(Animal):\n    def bark(self):\n        return \"Dog barks\"\n\nclass Puppy(Dog):\n    def weep(self):\n        return \"Puppy weeps\"\n\n# Create an object of the Puppy class\npuppy = Puppy()\n\n# Call methods from the Puppy, Dog, and Animal classes\nprint(puppy.speak())  # Output: Animal speaks\nprint(puppy.bark())   # Output: Dog barks\nprint(puppy.weep())   # Output: Puppy weeps"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Python Multiple Inheritance: "
        },
        {
          "type": "paragraph",
          "text": "Python allows a child class to inherit from more than one parent class, giving it the flexibility to combine features from multiple base classes."
        },
        {
          "type": "textarea",
          "text": "# Example of Multiple Inheritance in Python\n\nclass Flyer:\n    def fly(self):\n        return \"Flying in the sky\"\n\nclass Swimmer:\n    def swim(self):\n        return \"Swimming in the water\"\n\nclass Duck(Flyer, Swimmer):\n    def quack(self):\n        return \"Quack!\"\n\n# Create an object of the Duck class\nduck = Duck()\n\n# Call methods from both Flyer and Swimmer classes\nprint(duck.fly())    # Output: Flying in the sky\nprint(duck.swim())   # Output: Swimming in the water\nprint(duck.quack())  # Output: Quack!"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Python Hierarchical Inheritance: "
        },
        {
          "type": "paragraph",
          "text": "This type of inheritance combines different inheritance styles, such as single, multiple, and hierarchical inheritance, within a single program.This form of inheritance supports multiple inheritance relationships, where various subclasses are derived from a single base class, creating complex class relationships."
        },
        {
          "type": "textarea",
          "text": "# Example of Hierarchical Inheritance in Python\n\nclass Vehicle:\n    def start_engine(self):\n        return \"Engine started\"\n\nclass Car(Vehicle):\n    def drive(self):\n        return \"Car is driving\"\n\nclass Bike(Vehicle):\n    def ride(self):\n        return \"Bike is riding\"\n\n# Create objects of Car and Bike classes\ncar = Car()\nbike = Bike()\n\n# Call methods from the Vehicle, Car, and Bike classes\nprint(car.start_engine())  # Output: Engine started\nprint(car.drive())         # Output: Car is driving\n\nprint(bike.start_engine()) # Output: Engine started\nprint(bike.ride())        # Output: Bike is riding"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Python Hybrid Inheritance: "
        },
        {
          "type": "paragraph",
          "text": "Hybrid inheritance combines different forms of inheritance—like single, multiple, and hierarchical—in one program, allowing for flexible and complex class relationships."
        },
        {
          "type": "textarea",
          "text": "# Example of Hybrid Inheritance in Python\n\nclass Person:\n    def __init__(self, name):\n        self.name = name\n\n    def introduce(self):\n        return f\"Hi, I'm {self.name}\"\n\nclass Employee(Person):\n    def __init__(self, name, employee_id):\n        super().__init__(name)\n        self.employee_id = employee_id\n\n    def work(self):\n        return f\"Employee {self.employee_id} is working\"\n\nclass Student(Person):\n    def __init__(self, name, student_id):\n        super().__init__(name)\n        self.student_id = student_id\n\n    def study(self):\n        return f\"Student {self.student_id} is studying\"\n\nclass Intern(Employee, Student):\n    def __init__(self, name, employee_id, student_id):\n        Employee.__init__(self, name, employee_id)\n        Student.__init__(self, name, student_id)\n\n    def intern(self):\n        return f\"Intern {self.name} is doing an internship\"\n\n# Create an object of the Intern class\nintern = Intern(\"Charlie\", \"E123\", \"S456\")\n\n# Call methods from the Person, Employee, and Student classes\nprint(intern.introduce())  # Output: Hi, I'm Charlie\nprint(intern.work())        # Output: Employee E123 is working\nprint(intern.study())       # Output: Student S456 is studying\nprint(intern.intern())      # Output: Intern Charlie is doing an internship"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Use of Inheritance: "
        },
        {
          "type": "list",
          "items": [
            "<b>Code Reusability:</b>  Inheritance reduces code redundancy by reusing code from existing classes, making it easier to maintain.",
            "<b>Hierarchical Organization:</b> Inheritance structures classes in a hierarchy, providing clear relationships between base and derived classes.",
            "<b>Extension of Functionality:</b>  Subclasses can extend or override the functionality of their parent classes, allowing for more specific or enhanced behaviour.",
            "<b>Improved Maintainability:</b>    Changes made to the base class automatically propagate to derived classes, simplifying updates and maintenance."
          ]
        }
      ]
    },
    {
      "title": "Polymorphism",
      "description": "In OOP, polymorphism means that the same interface has been presented but by totally different underlying data types. The word \"polymorphism\" is originated from Greek, which simply translates to \"many shapes.\"",
      "sub_description": " In programming, methods have the same name and hence perform different functions on basis of the object invoking the call.",
      "additional_info": "",
      "content": [
        {
          "type": "heading",
          "level": "4",
          "text": "Key Principles of Polymorphism:"
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Same Method, Different Behavior:"
        },
        {
          "type": "paragraph",
          "text": "In Python, methods with identical names in different classes can function differently, influenced by the object that invokes them."
        },
        {
          "type": "heading",
          "level": "5",
          "text": "Enhanced Flexibility: "
        },
        {
          "type": "paragraph",
          "text": " Polymorphism allows dynamic method calls, improving code flexibility and maintainability without needing to know the object's type upfront."
        },
        {
          "type": "heading",
          "level": "1",
          "text": "Types of Polymorphism in Python: "
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Compile-time Polymorphism&nbsp;(Method Overloading): "
        },
        {
          "type": "paragraph",
          "text": "This concept allows for multiple methods to share the same name but require different parameters.However, Python, unlike many other programming languages like Java or C++, does not support method overloading directly."
        },
        {
          "type": "paragraph",
          "text": " If more than one methods share the same name, Python will overwrite all of the previous ones with the last defined method. Using default parameters or variable-length arguments, method overloading can be simulated. "
        },
        {
          "type": "textarea",
          "text": "# Example of Compile-time Polymorphism (Method Overloading) in Python\n\nclass MathOperations:\n    def add(self, a, b):\n        return a + b\n\n    def add_multiple(self, *args):\n        return sum(args)\n\n# Create an object of the MathOperations class\nmath_ops = MathOperations()\n\n# Call the add method with two arguments\nresult1 = math_ops.add(5, 10)  # Output: 15\n\n# Call the add_multiple method with multiple arguments\nresult2 = math_ops.add_multiple(1, 2, 3, 4, 5)  # Output: 15\n\nprint('Result of add(5, 10):', result1)  # Output: Result of add(5, 10): 15\nprint('Result of add_multiple(1, 2, 3, 4, 5):', result2)  # Output: Result of add_multiple(1, 2, 3, 4, 5): 15"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Run-time Polymorphism&nbsp;(Method Overriding): "
        },
        {
          "type": "paragraph",
          "text": "This occurs when a subclass provides an implementation of some method already defined in the superclass. The method implemented within the subclass overrules the superclass method in that different behaviors are achieved according to the types of the objects at runtime.This type of polymorphism occurs when a method in a subclass overrides a method with the same name in its superclass."
        },
        {
          "type": "paragraph",
          "text": "It’s more commonly used in Python to achieve polymorphism. Run-time polymorphism allows the use of methods that are overridden in derived classes, enabling dynamic and flexible code execution."
        },
        {
          "type": "textarea",
          "text": "# Example of Run-time Polymorphism (Method Overriding) in Python\n\nclass Animal:\n    def sound(self):\n        return \"Some sound\"\n\nclass Dog(Animal):\n    def sound(self):\n        return \"Bark\"\n\nclass Cat(Animal):\n    def sound(self):\n        return \"Meow\"\n\n# Create a list of Animal objects\nanimals = [Dog(), Cat()]\n\n# Iterate over the list and call the sound method\nfor animal in animals:\n    print(animal.sound())  # Output: Bark\n                       # Output: Meow"
        },
        {
          "type": "heading",
          "level": "1",
          "text": "Function Polymorphism:"
        },
        {
          "type": "paragraph",
          "text": "In Python, there are certain functions which are designed to work with various data types."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Example : Polymorphic len() function"
        },
        {
          "type": "textarea",
          "text": "print(len(`Programiz`)) <br>print(len([`Python`, `Java`, `C`]))<br>print(len({`Name`: `John`, `Address`: `Nepal`}))"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Class Polymorphism in Python:"
        },
        {
          "type": "paragraph",
          "text": "Python supports polymorphism in class methods, allowing different classes to define methods with the same name. This flexibility enables us to generalize method calls without needing to know which object is being used."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Example : Polymorphism in class Methods"
        },
        {
          "type": "textarea",
          "text": "print(len(`Programiz`)) <br>print(len([`Python`, `Java`, `C`]))<br>print(len({`Name`: `John`, `Address`: `Nepal`}))"
        }
      ]
    },
    {
      "title": "Operator Overloading",
      "description": "Operator overloading in Python enables you to specify unique behaviors for standard operators (such as +, -, *) when they are used with objects from a user-defined class. ",
      "sub_description": " In Python, operators such as + or - are essentially shorthand for calling special methods within objects, like __add__() for addition or __sub__() for subtraction.By overriding these special methods, you can control how operators behave with instances of your classes.",
      "additional_info": "As we know, the + operator can add two numbers, merge lists, or concatenate strings.By customizing the behavior, the + operator can also be applied to user-defined objects. This feature, where the same operator behaves differently based on the context, is known as operator overloading in Python.",
      "content": [
        {
          "type": "heading",
          "level": "4",
          "text": "Python Special Functions: "
        },
        {
          "type": "paragraph",
          "text": "In Python, methods that have double underscores (__) before and after their names serve special purposes, such as __add__(), __len__(), etc. These special methods can be used to define specific behaviors for user-defined objects."
        },
        {
          "type": "textarea",
          "text": "# Python Special Functions (Magic Methods)\n\n# In Python, special methods have double underscores (__) before and after their names. These methods allow you to define specific behaviors for your custom objects.\n\nclass CustomNumber:\n    def __init__(self, value):\n        self.value = value\n\n    # Special method for addition\n    def __add__(self, other):\n        return CustomNumber(self.value + other.value)\n\n    # Special method for string representation\n    def __str__(self):\n        return f\"CustomNumber({self.value})\"\n\n    # Special method for getting the length (for demonstration)\n    def __len__(self):\n        return len(str(self.value))  # Length of the string representation\n\n# Create two CustomNumber objects\nnum1 = CustomNumber(10)\nnum2 = CustomNumber(20)\n\n# Using the overloaded + operator\nresult = num1 + num2  # This calls num1.__add__(num2)\n\n# Print the result using the __str__ method\nprint(result)  # Output: CustomNumber(30)\n\n# Using the __len__ method\nprint(len(num1))  # Output: 2 (length of '10')\nprint(len(num2))  # Output: 2 (length of '20')"
        },
        {
          "type": "paragraph",
          "text": "For instance, we can use the __add__() method to add two numbers without directly using the + operator."
        },
        {
          "type": "heading",
          "level": "4",
          "text": "How to Use Operator Overloading"
        },
        {
          "type": "paragraph",
          "text": "If you want to use the + operator to add two user-defined objects, you can implement the __add__() method in your class."
        },
        {
          "type": "textarea",
          "text": "# Example of Adding Two Coordinates (Without Operator Overloading)\n\nclass Coordinate:\n    def __init__(self, x, y):\n        self.x = x\n        self.y = y\n\n    def add(self, other):\n        # Add the coordinates of the current object and another Coordinate object\n        new_x = self.x + other.x\n        new_y = self.y + other.y\n        return Coordinate(new_x, new_y)\n\n    def __str__(self):\n        return f\"Coordinate({self.x}, {self.y})\"\n\n# Create two Coordinate objects\ncoord1 = Coordinate(3, 4)\ncoord2 = Coordinate(1, 2)\n\n# Add the two coordinates using the add method\nresult = coord1.add(coord2)\n\n# Print the result\nprint(result)  # Output: Coordinate(4, 6)"
        },
        {
          "type": "textarea",
          "text": "# Example of Adding Two Coordinates (With Operator Overloading)\n\nclass Coordinate:\n    def __init__(self, x, y):\n        self.x = x\n        self.y = y\n\n    # Overloading the + operator\n    def __add__(self, other):\n        new_x = self.x + other.x\n        new_y = self.y + other.y\n        return Coordinate(new_x, new_y)\n\n    def __str__(self):\n        return f\"Coordinate({self.x}, {self.y})\"\n\n# Create two Coordinate objects\ncoord1 = Coordinate(3, 4)\ncoord2 = Coordinate(1, 2)\n\n# Add the two coordinates using the overloaded + operator\nresult = coord1 + coord2\n\n# Print the result\nprint(result)  # Output: Coordinate(4, 6)"
        },
        {
          "type": "heading",
          "level": "3",
          "text": "Advantages of Operator Overloading:"
        },
        {
          "type": "list",
          "items": [
            "<b>Enhanced code readability:</b>You can use familiar operators with custom objects.",
            "<b>Consistency:</b>Objects can behave similarly to built-in types.",
            "<b>Code simplification:</b>Especially useful for complex data types.",
            "<b>Code reusability:</b>Once you implement one operator method, you can extend it to other operators."
          ]
        }
      ]
    },
    {
      "title": "Data Abstraction",
      "description": "Abstraction is a core concept in object-oriented programming (OOP) that helps simplify complex systems in Python.It allows users to interact with the essential features of a function while concealing the intricate details of its implementation.",
      "sub_description": "In simple terms, abstraction allows us to interact with objects at a higher level without needing to understand the underlying mechanics.",
      "additional_info": "For instance, when we use a smartphone to make a call, we don’t need to know how the phone converts sound into radio waves or how it connects to the network. Similarly, Python allows us to abstract certain details in our programs, which makes them easier to manage and maintain.",
      "content": [
        {
          "type": "textarea",
          "text": "from abc import ABC, abstractmethod\n\n# Abstract class\nclass Shape(ABC):\n    @abstractmethod\n    def area(self):\n        pass  # Abstract method to calculate area\n\n    @abstractmethod\n    def perimeter(self):\n        pass  # Abstract method to calculate perimeter\n\n# Concrete class implementing the abstract methods\nclass Rectangle(Shape):\n    def __init__(self, width, height):\n        self.width = width\n        self.height = height\n\n    def area(self):\n        return self.width * self.height\n\n    def perimeter(self):\n        return 2 * (self.width + self.height)\n\nclass Circle(Shape):\n    def __init__(self, radius):\n        self.radius = radius\n\n    def area(self):\n        return 3.14 * (self.radius ** 2)\n\n    def perimeter(self):\n        return 2 * 3.14 * self.radius\n\n# Create objects of Rectangle and Circle\nrect = Rectangle(5, 3)\nprint(f\"Rectangle Area: {rect.area()}\")  # Output: Rectangle Area: 15\nprint(f\"Rectangle Perimeter: {rect.perimeter()}\")  # Output: Rectangle Perimeter: 16\n\ncirc = Circle(4)\nprint(f\"Circle Area: {circ.area()}\")  # Output: Circle Area: 50.24\nprint(f\"Circle Perimeter: {circ.perimeter()}\")  # Output: Circle Perimeter: 25.12"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Why abstraction is Important?"
        },
        {
          "type": "paragraph",
          "text": "In Python, abstraction simplifies complexity by hiding unnecessary details and enhancing security. It also enhances efficiency and promotes easier code maintenance."
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Abstract Classes"
        },
        {
          "type": "paragraph",
          "text": " An abstract class acts as a framework for other classes, specifying methods that any subclass inheriting from it must implement. "
        },
        {
          "type": "textarea",
          "text": "from abc import ABC, abstractmethod\n\n# Define an abstract class\nclass Animal(ABC):\n    @abstractmethod\n    def sound(self):\n        pass  # Abstract method to be implemented by subclasses\n\n    def info(self):\n        return \"This is an animal.\"\n\n# Concrete class inheriting from the abstract class\nclass Dog(Animal):\n    def sound(self):\n        return \"Woof!\"\n\nclass Cat(Animal):\n    def sound(self):\n        return \"Meow!\"\n\n# Create instances of the concrete classes\ndog = Dog()\ncat = Cat()\n\n# Call the implemented methods\nprint(dog.info())  # Output: This is an animal.\nprint(dog.sound())  # Output: Woof!\n\nprint(cat.info())  # Output: This is an animal.\nprint(cat.sound())  # Output: Meow!"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "How abstract class works?"
        },
        {
          "type": "paragraph",
          "text": " An abstract class in Python serves as a template for other classes. "
        },
        {
          "type": "textarea",
          "text": "from abc import ABC, abstractmethod\n\n# Define an abstract class\nclass Vehicle(ABC):\n    @abstractmethod\n    def start_engine(self):\n        pass  # Abstract method to be implemented by subclasses\n\n    @abstractmethod\n    def stop_engine(self):\n        pass  # Abstract method to be implemented by subclasses\n\n# Concrete class inheriting from the abstract class\nclass Car(Vehicle):\n    def start_engine(self):\n        return \"Car engine started.\"\n\n    def stop_engine(self):\n        return \"Car engine stopped.\"\n\nclass Motorcycle(Vehicle):\n    def start_engine(self):\n        return \"Motorcycle engine started.\"\n\n    def stop_engine(self):\n        return \"Motorcycle engine stopped.\"\n\n# Create instances of the concrete classes\ncar = Car()\nmotorcycle = Motorcycle()\n\n# Call the implemented methods\nprint(car.start_engine())     # Output: Car engine started.\nprint(car.stop_engine())      # Output: Car engine stopped.\n\nprint(motorcycle.start_engine())  # Output: Motorcycle engine started.\nprint(motorcycle.stop_engine())   # Output: Motorcycle engine stopped."
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Key Aspects of How Abstract Classes Work:"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Defining an Abstract Class:"
        },
        {
          "type": "list",
          "items": [
            "Abstract classes can be declared by using the ABC module of the abc library.",
            "You can define an abstract class by inheriting from ABC. "
          ]
        },
        {
          "type": "textarea",
          "text": "from abc import ABC, abstractmethod\n\n# Define an abstract class\nclass Animal(ABC):\n    @abstractmethod\n    def make_sound(self):\n        pass  # Abstract method to be implemented by subclasses\n\n# Concrete class inheriting from the abstract class\nclass Dog(Animal):\n    def make_sound(self):\n        return \"Woof!\"\n\n# Create an instance of the Dog class\ndog = Dog()\n\n# Call the implemented method\nprint(dog.make_sound())  # Output: Woof!"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Abstract Methods:"
        },
        {
          "type": "list",
          "items": [
            "Abstract methods are included in the abstract class but lack implementations.",
            "They are identified using the @abstractmethod decorator and must be implemented by any subclass."
          ]
        },
        {
          "type": "textarea",
          "text": "from abc import ABC, abstractmethod\n\n# Define an abstract class\nclass Shape(ABC):\n    @abstractmethod\n    def area(self):\n        pass  # Abstract method to be implemented by subclasses\n\n# Concrete class inheriting from the abstract class\nclass Rectangle(Shape):\n    def __init__(self, width, height):\n        self.width = width\n        self.height = height\n\n    def area(self):\n        return self.width * self.height  # Implementation of the abstract method\n\n# Create an instance of the Rectangle class\nrectangle = Rectangle(4, 5)\n\n# Call the implemented method\nprint(rectangle.area())  # Output: 20"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Subclasses:"
        },
        {
          "type": "list",
          "items": [
            "Each subclass, which inherits from an abstract class has to define all the abstract methods specified in that class.",
            "If a subclass does not implement all abstract methods, it will also be treated as an abstract class and cannot be instantiated."
          ]
        },
        {
          "type": "textarea",
          "text": "# Subclasses in Python\n\n# Define a base class\nclass Animal:\n    def speak(self):\n        return \"Animal speaks\"\n\n# Define a subclass inheriting from Animal\nclass Dog(Animal):\n    def speak(self):\n        return \"Woof!\"  # Overriding the base class method\n\n# Define another subclass inheriting from Animal\nclass Cat(Animal):\n    def speak(self):\n        return \"Meow!\"  # Overriding the base class method\n\n# Create instances of subclasses\ndog = Dog()\ncat = Cat()\n\n# Call the overridden methods\nprint(dog.speak())  # Output: Woof!\nprint(cat.speak())  # Output: Meow!"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Key Points to Remember About Abstract Classes in Python"
        },
        {
          "type": "list",
          "items": [
            "An abstract class can include both regular and abstract methods.",
            "Abstract classes are instances that cannot be initialized and thus cannot be made instances or objects.",
            "Abstraction is crucial for hiding the core logic or functionality from users, simplifying usage while maintaining flexibility in design."
          ]
        }
      ]
    },
    {
      "title": "Encapsulation",
      "description": "Encapsulation is a key concept in object-oriented programming (OOP) where data and the functions that operate on that data are combined into one unit, like a class.This helps keep related information and behavior together, making it easier to manage and protect. This approach limits direct access to certain variables and methods, which helps prevent unintended changes.",
      "sub_description": "To ensure data is only changed in a controlled way, variables are often made private and can only be modified through specific methods.",
      "additional_info": " A class itself is a great example of encapsulation, as it holds both data (variables) and functions together.The main goal of encapsulation is to protect an object's state by hiding certain information from outside access, ensuring its integrity.",
      "content": [
        {
          "type": "textarea",
          "text": "class BankAccount:\n    def __init__(self, owner, balance=0):\n        self.owner = owner        # Public attribute\n        self.__balance = balance  # Private attribute\n\n    # Method to deposit money\n    def deposit(self, amount):\n        if amount > 0:\n            self.__balance += amount\n            return f\"Deposited: {amount}\"\n        return \"Invalid amount\"\n\n    # Method to check balance\n    def get_balance(self):\n        return self.__balance\n\n# Create an instance of BankAccount\naccount = BankAccount(\"Alice\")\n\n# Deposit money and check balance\nprint(account.deposit(100))        # Output: Deposited: 100\nprint(account.get_balance())        # Output: 100\n\n# Attempt to access private attribute directly\n# print(account.__balance)  # This will raise an AttributeError"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Access Modifiers in python:"
        },
        {
          "type": "paragraph",
          "text": "Python uses naming conventions to control access to class members, though it lacks formal access modifiers like “public,” “private,” and “protected” found in other languages. We can create these levels by using underscores."
        },
        {
          "type": "paragraph",
          "text": "Access modifiers control how we access variables and methods in a class. Python has three types of access modifiers:"
        },
        {
          "type": "list",
          "items": [
            "<b>Public Member:</b>Accessible from anywhere, including outside the class.",
            "<b>Private Member:</b> It can be accessed only in the class itself.",
            "<b>Protected Member:</b>In Python, protected members are intended for use within the class and any subclasses. By convention, these are indicated with a single underscore (e.g., _variable), signaling that they shouldn't be accessed from outside the class hierarchy."
          ]
        },
        {
          "type": "textarea",
          "text": "class Car:\n    def __init__(self, make, model):\n        self.make = make   # Public member\n        self.model = model # Public member\n        self.speed = 0     # Public member\n\n    # Method to accelerate the car\n    def accelerate(self, increase):\n        self.speed += increase\n        return f\"Current speed: {self.speed} km/h\"\n\n# Create an instance of Car\nmy_car = Car(\"Toyota\", \"Corolla\")\n\n# Accessing public members directly\nprint(f\"Car Make: {my_car.make}\")    # Output: Car Make: Toyota\nprint(f\"Car Model: {my_car.model}\")  # Output: Car Model: Corolla\n\n# Using public method to accelerate\nprint(my_car.accelerate(30))          # Output: Current speed: 30 km/h"
        },
        {
          "type": "textarea",
          "text": "class BankAccount:\n    def __init__(self, owner, balance=0):\n        self.owner = owner        # Public member\n        self.__balance = balance  # Private member\n\n    # Method to deposit money\n    def deposit(self, amount):\n        if amount > 0:\n            self.__balance += amount\n            return f\"Deposited: {amount}\"\n        return \"Invalid amount\"\n\n    # Method to check balance\n    def get_balance(self):\n        return self.__balance\n\n# Create an instance of BankAccount\naccount = BankAccount(\"Alice\")\n\n# Deposit money\nprint(account.deposit(200))        # Output: Deposited: 200\n\n# Check balance using the public method\nprint(account.get_balance())        # Output: 200\n\n# Attempt to access private member directly\n# print(account.__balance)  # This will raise an AttributeError"
        },
        {
          "type": "textarea",
          "text": "class Vehicle:\n    def __init__(self, make, model):\n        self._make = make     # Protected member\n        self._model = model   # Protected member\n\n    # Method to display vehicle info\n    def display_info(self):\n        return f\"Vehicle Make: {self._make}, Model: {self._model}\"\n\n# Define a subclass inheriting from Vehicle\nclass Car(Vehicle):\n    def __init__(self, make, model, doors):\n        super().__init__(make, model)  # Call to the parent class constructor\n        self._doors = doors             # Protected member\n\n    # Method to display car info\n    def display_car_info(self):\n        return f\"{self.display_info()}, Doors: {self._doors}\"\n\n# Create an instance of Car\nmy_car = Car(\"Honda\", \"Civic\", 4)\n\n# Accessing protected members using public methods\nprint(my_car.display_car_info())  # Output: Vehicle Make: Honda, Model: Civic, Doors: 4\n\n# Accessing protected members directly (not recommended)\nprint(my_car._make)  # Output: Honda"
        },
        {
          "type": "heading",
          "level": "4",
          "text": "Getter and Setter in python"
        },
        {
          "type": "paragraph",
          "text": "To practice encapsulation properly, Python often uses getter and setter methods. A getter allows us to retrieve the value of a private variable, while a setter lets us update that value. "
        },
        {
          "type": "list",
          "items": [
            "Getters and setters methods mainly prevent direct access to private variables.",
            "Add validation when assigning values."
          ]
        },
        {
          "type": "textarea",
          "text": "# Getters in Python\n\n# Define a class with private attributes and a getter method\nclass Person:\n    def __init__(self, name, age):\n        self._name = name  # Protected attribute\n        self._age = age    # Protected attribute\n\n    # Getter for name\n    @property\n    def name(self):\n        return self._name\n\n    # Getter for age\n    @property\n    def age(self):\n        return self._age\n\n# Create an instance of Person\nperson = Person(\"Alice\", 30)\n\n# Accessing values using getters\nprint(person.name)  # Output: Alice\nprint(person.age)   # Output: 30"
        },
        {
          "type": "textarea",
          "text": "# Setters in Python\n\n# Define a class with private attributes and setter methods\nclass Person:\n    def __init__(self, name, age):\n        self._name = name  # Protected attribute\n        self._age = age    # Protected attribute\n\n    # Setter for name\n    @name.setter\n    def name(self, new_name):\n        self._name = new_name\n\n    # Setter for age\n    @age.setter\n    def age(self, new_age):\n        if new_age < 0:\n            raise ValueError(\"Age cannot be negative\")\n        self._age = new_age\n\n# Create an instance of Person\nperson = Person(\"Alice\", 30)\n\n# Modifying values using setters\nperson.name = \"Bob\"\nperson.age = 25\n\n# Accessing updated values\nprint(person.name)  # Output: Bob\nprint(person.age)   # Output: 25\n\n# Attempting to set a negative age\n# person.age = -5  # This will raise ValueError"
        },
        {
          "type": "heading",
          "level": "2",
          "text": "Advantages of Encapsulation:"
        },
        {
          "type": "list",
          "items": [
            "<b>Security:</b>Encapsulation secures data by preventing unauthorized access. It uses private and protected access levels to avoid accidental changes.",
            "<b>Data Hiding:</b> The internal workings of data handling are hidden from users, so they only interact with necessary aspects.They only use getter methods to read data and setter methods to modify it, without knowing the internal workings.",
            "<b>Simplicity:</b>It makes code easier to maintain by keeping classes separate and reducing dependencies between them.",
            "<b>Readability:</b>Encapsulation improves readability by keeping related data and functions organized within the class."
          ]
        }
      ]
    }
  ]
}