|
1778 | 1778 | "print(f\"The largest number in the array is: {largest}\")"
|
1779 | 1779 | ]
|
1780 | 1780 | },
|
| 1781 | + { |
| 1782 | + "cell_type": "markdown", |
| 1783 | + "metadata": {}, |
| 1784 | + "source": [ |
| 1785 | + "## OOPs" |
| 1786 | + ] |
| 1787 | + }, |
| 1788 | + { |
| 1789 | + "cell_type": "code", |
| 1790 | + "execution_count": null, |
| 1791 | + "metadata": {}, |
| 1792 | + "outputs": [], |
| 1793 | + "source": [ |
| 1794 | + "class Person:\n", |
| 1795 | + "\n", |
| 1796 | + " # Dunder Methods: Pre-defined functions for any class, starts and ends with \"__\"\n", |
| 1797 | + " # __init__ # Constructor: Initializes the class\n", |
| 1798 | + " def __init__(self, full_name: str, occ: str, age: int,networth: int) -> None:\n", |
| 1799 | + " self.name = Name(full_name) # Using the Name class to split the name this is called Composition of classes (defined below)\n", |
| 1800 | + " self.occ = occ\n", |
| 1801 | + " self.age = age\n", |
| 1802 | + " self.networth = networth\n", |
| 1803 | + "\n", |
| 1804 | + " # __setattr__ # Setter: Sets the value of an attribute\n", |
| 1805 | + " def __setattr__(self, name, value) -> None:\n", |
| 1806 | + " # Define expected types for each attribute\n", |
| 1807 | + " type_hints = {\n", |
| 1808 | + " \"name\": Name, # compare the type of value \"name\" with the type of Name class\n", |
| 1809 | + " \"occ\": str, # compare the type of value \"occ\" with the type of str\n", |
| 1810 | + " \"age\": int, # compare the type of value \"age\" with the type of int\n", |
| 1811 | + " \"networth\": int, # compare the type of value \"networth\" with the type of int\n", |
| 1812 | + " } \n", |
| 1813 | + "\n", |
| 1814 | + " if name in type_hints: # Check if the attribute has a type hint\n", |
| 1815 | + " expected_type = type_hints[name]\n", |
| 1816 | + " if not isinstance(value, expected_type):\n", |
| 1817 | + " raise TypeError(f\"Attribute '{name}' must be of type {expected_type.__name__}, got {type(value).__name__}\")\n", |
| 1818 | + " \n", |
| 1819 | + " super().__setattr__(name, value) # Use this as the default behavior to set the attribute\n", |
| 1820 | + "\n", |
| 1821 | + " # __str__ # String representation of the class\n", |
| 1822 | + " def __str__(self):\n", |
| 1823 | + " return f\"{self.name}, Age: {self.age}\"\n", |
| 1824 | + "\n", |
| 1825 | + " # __eq__ # Equality: Compares two objects made from this class\n", |
| 1826 | + " def __eq__(self, other):\n", |
| 1827 | + " return self.name == other.name and self.age == other.age\n", |
| 1828 | + "\n", |
| 1829 | + " # Decorators: Modify a function\n", |
| 1830 | + " def hello(fx):\n", |
| 1831 | + " def mfx(*args, **kwargs):\n", |
| 1832 | + " print(f\"Hello from {fx.__name__}\")\n", |
| 1833 | + " func = fx(*args, **kwargs)\n", |
| 1834 | + " return func\n", |
| 1835 | + " return mfx\n", |
| 1836 | + "\n", |
| 1837 | + " # Functions of class\n", |
| 1838 | + " @hello # Decorator modifing a function\n", |
| 1839 | + " def info(self) -> str:\n", |
| 1840 | + " return f\"I am {self.name.name} {self.name.surname}, I am a {self.occ}\"\n", |
| 1841 | + " \n", |
| 1842 | + " # Function without a decorator \n", |
| 1843 | + " def actualincome(self) -> str:\n", |
| 1844 | + " taxslab = round(self.networth, 2) if (self.networth < 250000) else round(self.networth * 0.2, 2) if (self.networth > 250000 and self.networth) < 500000 else round(self.networth * 0.3, 2)\n", |
| 1845 | + " ipa = round(self.networth - taxslab, 2)\n", |
| 1846 | + " ipm = round(ipa/12, 2)\n", |
| 1847 | + " return f\"{self.name.name} {self.name.surname} earns {self.networth}\\n\\t pays {taxslab}\\n\\t accounting to {ipa} per annum \\n\\t accounting to {ipm} per month\"\n", |
| 1848 | + " \n", |
| 1849 | + " # Getter and Setter\n", |
| 1850 | + " @property # Getter: Gets networth in a function \"income\"\n", |
| 1851 | + " def income(self) -> int:\n", |
| 1852 | + " return self.networth\n", |
| 1853 | + "\n", |
| 1854 | + " @income.setter # Setter: Sets newnetworth to self.networth using a function \"newincome\"\n", |
| 1855 | + " def newincome(self, newnetworth) -> None:\n", |
| 1856 | + " self.networth = newnetworth\n", |
| 1857 | + "\n", |
| 1858 | + " @property # Getter: Gets name in a function \"name\" \n", |
| 1859 | + " def name(self) -> str: \n", |
| 1860 | + " return self._name\n", |
| 1861 | + "\n", |
| 1862 | + " @name.setter # Setter: Sets name to self.name using a function \"name\" used as name.name from \".name\" Name class then \".name\" Person class\n", |
| 1863 | + " def name(self, value: str) -> None:\n", |
| 1864 | + " self._name = value\n", |
| 1865 | + "\n", |
| 1866 | + " @property # Getter: Gets surname in a function \"surname\" \n", |
| 1867 | + " def surname(self) -> str:\n", |
| 1868 | + " return self._surname\n", |
| 1869 | + "\n", |
| 1870 | + " @surname.setter # Setter: Sets surname to self.surname using a function \"surname\" used as name.surname from \".name\" Name Person class then \".surname \"Name class\n", |
| 1871 | + " def surname(self, value: str) -> None:\n", |
| 1872 | + " self._surname = value\n", |
| 1873 | + "\n", |
| 1874 | + "\n", |
| 1875 | + "\n", |
| 1876 | + "# Helping Class\n", |
| 1877 | + "\n", |
| 1878 | + "# Name class to split the name and use it in Person class\n", |
| 1879 | + "class Name:\n", |
| 1880 | + " def __init__(self, full_name: str) -> None:\n", |
| 1881 | + " name_parts = full_name.split()\n", |
| 1882 | + " self._name = name_parts[0]\n", |
| 1883 | + " self._surname = name_parts[1] if len(name_parts) > 1 else \"\"\n", |
| 1884 | + "\n", |
| 1885 | + " @property\n", |
| 1886 | + " def name(self) -> str:\n", |
| 1887 | + " return self._name\n", |
| 1888 | + "\n", |
| 1889 | + " @name.setter\n", |
| 1890 | + " def name(self, value: str) -> None:\n", |
| 1891 | + " self._name = value\n", |
| 1892 | + "\n", |
| 1893 | + " @property\n", |
| 1894 | + " def surname(self) -> str:\n", |
| 1895 | + " return self._surname\n", |
| 1896 | + "\n", |
| 1897 | + " @surname.setter\n", |
| 1898 | + " def surname(self, value: str) -> None:\n", |
| 1899 | + " self._surname = value\n", |
| 1900 | + "\n", |
| 1901 | + " def __str__(self) -> str:\n", |
| 1902 | + " return f\"{self._name} {self._surname}\".strip() # Handles cases with missing surname" |
| 1903 | + ] |
| 1904 | + }, |
| 1905 | + { |
| 1906 | + "cell_type": "code", |
| 1907 | + "execution_count": null, |
| 1908 | + "metadata": {}, |
| 1909 | + "outputs": [], |
| 1910 | + "source": [ |
| 1911 | + "# Subclass Employee inherits from Person\n", |
| 1912 | + "class Employee(Person):\n", |
| 1913 | + " def __init__(self, full_name: str, occ: str, age: int, networth: int, position: str) -> None:\n", |
| 1914 | + " # Call the parent class's constructor to initialize inherited attributes\n", |
| 1915 | + " super().__init__(full_name, occ, age, networth)\n", |
| 1916 | + " self.position = position\n", |
| 1917 | + "\n", |
| 1918 | + " # Overriding __setattr__ to include type checking for 'position'\n", |
| 1919 | + " def __setattr__(self, name, value) -> None:\n", |
| 1920 | + " # Extend the type hints from the parent class\n", |
| 1921 | + " type_hints = {\n", |
| 1922 | + " \"position\": str, # Add type checking for 'position'\n", |
| 1923 | + " }\n", |
| 1924 | + "\n", |
| 1925 | + " # Combine parent type hints with the current class's type hints\n", |
| 1926 | + " parent_type_hints = getattr(super(), \"__setattr__\").__annotations__ if hasattr(super(), \"__setattr__\") else {}\n", |
| 1927 | + " type_hints.update(parent_type_hints)\n", |
| 1928 | + "\n", |
| 1929 | + " # Check for type validation\n", |
| 1930 | + " if name in type_hints:\n", |
| 1931 | + " expected_type = type_hints[name]\n", |
| 1932 | + " if not isinstance(value, expected_type):\n", |
| 1933 | + " raise TypeError(f\"Attribute '{name}' must be of type {expected_type.__name__}, got {type(value).__name__}\")\n", |
| 1934 | + "\n", |
| 1935 | + " # Call the parent class's __setattr__ to set the attribute\n", |
| 1936 | + " super().__setattr__(name, value)\n", |
| 1937 | + "\n", |
| 1938 | + " # Overriding the __str__ method to include position\n", |
| 1939 | + " def __str__(self):\n", |
| 1940 | + " return f\"{self.name}, Age: {self.age}, Position: {self.position}\"\n", |
| 1941 | + "\n", |
| 1942 | + " # Adding a new method specific to Employee\n", |
| 1943 | + " def promote(self, new_position: str) -> None:\n", |
| 1944 | + " old_position = self.position\n", |
| 1945 | + " self.position = new_position\n", |
| 1946 | + " print(f\"{self.name.name} {self.name.surname} has been promoted from {old_position} to {new_position}.\")" |
| 1947 | + ] |
| 1948 | + }, |
| 1949 | + { |
| 1950 | + "cell_type": "code", |
| 1951 | + "execution_count": null, |
| 1952 | + "metadata": {}, |
| 1953 | + "outputs": [], |
| 1954 | + "source": [ |
| 1955 | + "# Making an object a using class Person\n", |
| 1956 | + "a = Person(\"Anmol\", \"Developer\", 16, 150)\n", |
| 1957 | + "\n", |
| 1958 | + "# Using getter and setter to get and set a value\n", |
| 1959 | + "print(f\"Using getter to see networth, Networth is {a.income} before Setter\")\n", |
| 1960 | + "a.newincome = 70000000\n", |
| 1961 | + "\n", |
| 1962 | + "a.name.surname = \"Raj\"\n", |
| 1963 | + "\n", |
| 1964 | + "print(dir(a)) # shows all function of a class\n", |
| 1965 | + "\n", |
| 1966 | + "# Using methods of class\n", |
| 1967 | + "print(a.info())\n", |
| 1968 | + "print(a.actualincome())\n", |
| 1969 | + "\n", |
| 1970 | + "# Dunder Methods\n", |
| 1971 | + "p1 = Person(\"Ujjwal\", \"Developer\", 15, 150)\n", |
| 1972 | + "p2 = Person(\"Joy\", \"Developer\", 15, 150)\n", |
| 1973 | + "\n", |
| 1974 | + "print(p1) # Calls __str__\n", |
| 1975 | + "print(p1 == p2) # Calls __eq__\n", |
| 1976 | + "\n", |
| 1977 | + "# Create an instance of Employee\n", |
| 1978 | + "employee = Employee(\"Anmol Raj\", \"Developer\", 16, 7000000, \"Junior Developer\")\n", |
| 1979 | + "\n", |
| 1980 | + "# Demonstrate the new functionality\n", |
| 1981 | + "print(employee) # Calls overridden __str__\n", |
| 1982 | + "\n", |
| 1983 | + "# Promote the employee\n", |
| 1984 | + "employee.promote(\"Senior Developer\")" |
| 1985 | + ] |
| 1986 | + }, |
1781 | 1987 | {
|
1782 | 1988 | "cell_type": "markdown",
|
1783 | 1989 | "metadata": {},
|
|
0 commit comments