{"id":23093008,"url":"https://github.com/crispengari/days-of-python","last_synced_at":"2026-04-24T23:32:25.227Z","repository":{"id":46684287,"uuid":"365562247","full_name":"CrispenGari/days-of-python","owner":"CrispenGari","description":"💎 This repository contains some cool python snippets that can be useful when working with the python language","archived":false,"fork":false,"pushed_at":"2026-03-17T12:03:11.000Z","size":11573,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-18T02:45:04.795Z","etag":null,"topics":["collections","filter","map","oop-pyth","python","python2","python3"],"latest_commit_sha":null,"homepage":"","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CrispenGari.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-08T16:32:00.000Z","updated_at":"2026-03-17T13:03:39.000Z","dependencies_parsed_at":"2024-04-24T08:50:36.102Z","dependency_job_id":"b1eb3213-8229-43b2-b99b-9a3a42b1a5da","html_url":"https://github.com/CrispenGari/days-of-python","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/CrispenGari/days-of-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrispenGari%2Fdays-of-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrispenGari%2Fdays-of-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrispenGari%2Fdays-of-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrispenGari%2Fdays-of-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CrispenGari","download_url":"https://codeload.github.com/CrispenGari/days-of-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CrispenGari%2Fdays-of-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32245118,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T13:21:15.438Z","status":"ssl_error","status_checked_at":"2026-04-24T13:21:15.005Z","response_time":64,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["collections","filter","map","oop-pyth","python","python2","python3"],"created_at":"2024-12-16T21:46:13.936Z","updated_at":"2026-04-24T23:32:25.211Z","avatar_url":"https://github.com/CrispenGari.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"### Days of python\n\nThis repository contains some cool python code examples and explanations that you can learn some cool features beginner to expect with the python language.\n\n\u003e **Hello Word!!**\n\n```py\nclass Vector:\n    def __init__(self, x, y, z) -\u003e None:\n        self.x = x\n        self.y = y\n        self.z = z\n\n    def __add__(self, other):\n        return Vector(self.x + other.x, self.y + other.y, z=self.z + other.z)\n\n    def __repr__(self) -\u003e str:\n        return \"{cn}\u003cx={x}, y={y}, z={z}\u003e\".format(\n            x=self.x, y=self.y, z=self.z, cn=self.__class__.__name__\n        )\n\n\nv1 = Vector(2, 3, 4)\nv2 = Vector(5, 6, 7)\nres = v1 + v2\nprint(res)\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/static/v1?label=language\u0026message=python\u0026color=green\"/\u003e\n\u003c/p\u003e\n\n### Argument and Keyword Augments\n\nLet's talk about how the argument and keyword arguments works and how to use them. Let's say we don't know what arguments are going to be passed to a function `hi` defining a function signature as `def hi(*args, **kwargs):` helps us to get the arguments and keyword args that were passed to the function `hi`\n\n```py\ndef hi(*args, **kwargs):\n    \"\"\"\n    args: will be a tuple of arguments passed to a function\n    kwargs: a dictionary of key word arguments passed to the function\n    \"\"\"\n    return args, kwargs\n\nargs, kwargs = hi(\"Jonh\", 10, name=\"Jonh\", age=10)\nprint(args)\nprint(kwargs)\n```\n\nResult:\n\n```shell\n('Jonh', 10)\n{'name': 'Jonh', 'age': 10}\n```\n\n### Argument Parsing\n\nIn python we can get the arguments from the terminal when running python script using the `sys` module. Let's have a look at how we can get the arguments parsed when running a python script called `main.py`\n\n```py\nimport sys\nargs = sys.argv\nprint(args)\n```\n\nRunning the command\n\n```shell\npython main.py name hello there\n```\n\nWill result in the following arguments being retrieved. `['main.py', 'name', 'hello', 'there']`\n\n\u003e Note that the first argument will be the script name that you run and anything after that in the list will be strings that you parsed after the file name. All the arguments that you parse here will be returned as strings separated by a space. If you want to escape a space you will need to use quotes `\"\"`:\n\n```shell\npython main.py message \"hello there\"\n```\n\n\u003e Result will be: `['main.py', 'message', 'hello there']`\n\nWhat if we want to use some optional arguments. We can do it as follows\n\n```py\nimport sys\nimport getopt\n# python main.py -p 3001 -h 127.0.0.1 -o https\nopts, args = getopt.getopt(sys.argv[1:], \"p:h:o:\", [\"port=\", \"host=\", \"protocol=\"])\nprint(opts, args)\n```\n\nNow if we run\n\n```shell\npython main.py -p 3001 -h 127.0.0.1 -o https\n```\n\nWe will get the following optional arguments and args that were parsed when running the script\n\n```shell\n[('-p', '3001'), ('-h', '127.0.0.1'), ('-p', 'https')] []\n```\n\nNote that you can also type required arguments in the script and run the command using `long` options names but for that you will need to use the `--` instead of a single `-`.\n\n```py\nimport sys\nimport getopt\n\n# python main.py --port 3001 --host 127.0.0.1 --protocol wss message \"hello world\"\nopts, args = getopt.getopt(sys.argv[1:], \"p:h:pt:\", [\"port=\", \"host=\", \"protocol=\"])\n\nprint(dict(opts), args)\n```\n\nRunning the command:\n\n```shell\npython main.py --port 3001 --host 127.0.0.1 --protocol wss message \"hello world\"\n```\n\nYou will get the following result:\nshell\n\n```shell\n{'--port': '3001', '--host': '127.0.0.1', '--protocol': 'wss'} ['message', 'hello world']\n```\n\n### Factory Design Patten\n\nIn python we can create interfaces for classes and implement them. For that we need to use the `abc` package that is built in in python. Let's create an `IUser` interface that will contain a class method called `hi`\n\n```py\nfrom abc import abstractmethod, ABCMeta\n\nclass IUser(metaclass=ABCMeta):\n    @classmethod\n    @abstractmethod\n    def hi(self, name: str) -\u003e str:\n        \"\"\"This is hi menthod\"\"\"\n\n\nIUser().hi(\"Bob\")\n```\n\nIf you try to do that you will get an error saying\n\n```\nTypeError: Can't instantiate abstract class IUser without an implementation for abstract method 'hi'\n```\n\nSo let's use this interface to create a class called `Student` that will inhherit from `IUser`\n\n```py\nclass Student(IUser):\n    pass\nStudent().hi(\"Bob\")\n```\n\nIf i try to do this i will get an error telling me that i haven't implemented `hi`\n\n```\nTypeError: Can't instantiate abstract class Student without an implementation for abstract method 'hi'\n```\n\nTo solve this error we are going to change our code to:\n\n```py\nclass Student(IUser):\n    def __init__(self) -\u003e None:\n        super().__init__()\n\n    def hi(self, name):\n        print(\"Hello {name}\".format(name=name))\n\nStudent().hi(\"Bob\")\n```\n\nNote that we can also define some property `staticmethod` and also `property` here is san example:\n\n```py\nfrom abc import abstractmethod, ABCMeta\n\nclass IUser(metaclass=ABCMeta):\n    @classmethod\n    @abstractmethod\n    def hi(self, name: str) -\u003e str:\n        \"\"\"This is hi menthod\"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def programmer(name):\n        \"\"\"\"\"\"\n\n    @property\n    @abstractmethod\n    def Name(self):\n        \"\"\"Name of the user\"\"\"\n\n\nclass Student(IUser):\n    def __init__(self, name: str) -\u003e None:\n        super().__init__()\n        self.__name = name\n    def hi(self, name):\n        print(\"Hello {name}\".format(name=name))\n\n    @property\n    def Name(self):\n        return self.__name\n\n    @staticmethod\n    def programmer(name):\n        return name\n\nstud = Student(name=\"Julie\")\nstud.hi(\"Bob\")\nprint(stud.Name)\nprint(stud.programmer(\"Namo\"))\n\n```\n\nWe can create different classes that inherits from our `interface` and then create a Factory class `UserFactory` that helps us to return a factory object of different objects based on the type passed.\n\n```py\nfrom abc import abstractmethod, ABCMeta\n\nclass IUser(metaclass=ABCMeta):\n    @classmethod\n    @abstractmethod\n    def hi(self, name: str) -\u003e str:\n        \"\"\"This is hi menthod\"\"\"\nclass Student(IUser):\n    def hi(self, name):\n        print(\"Student {name}\".format(name=name))\nclass Manager(IUser):\n    def hi(self, name):\n        print(\"Manager {name}\".format(name=name))\nclass Other(IUser):\n    def hi(self, name):\n        print(\"Other {name}\".format(name=name))\n\nclass UserFactory:\n    @staticmethod\n    def get_user(type: str):\n        if type.lower() == \"student\":\n            return Student()\n        if type.lower() == \"manager\":\n            return Manager()\n        return Other()\n\nUserFactory.get_user(\"student\").hi(\"Bob\")\nUserFactory.get_user(\"manager\").hi(\"Bob\")\nUserFactory.get_user(\"haha\").hi(\"Bob\")\n\n```\n\n### Proxy Design Patten\n\nThis design pattern allows us to wrap functionality among other classes in python.\n\nLet's say we have a class called person and this class has a static method to be implemented from `IUser` called `hi`. We can create a `ProxyUser` class and also make it to inherit from `IUser`\n\n```py\nfrom abc import abstractmethod, ABCMeta\nclass IUser(metaclass=ABCMeta):\n    @classmethod\n    @abstractmethod\n    def hi(self, name: str) -\u003e str:\n        \"\"\"This is hi menthod\"\"\"\nclass Student(IUser):\n    def hi(self, name):\n        print(\"Student {name}\".format(name=name))\n\nclass ProxyUser(IUser):\n    def __init__(self) -\u003e None:\n        super().__init__()\n        self.student = Student()\n    def hi(self, name: str):\n        self.student.hi(name)\n        print(f\"Hi I am a proxy class: {name}\")\n\nProxyUser().hi(\"Bob\")\n```\n\nWith this flexibility we can call the `student` object in the `Proxy` class when we call the method `hi` on `ProxyUser` we also trigger the `hi` method in the student class.\n\n### Singleton Design Pattern\n\nThe idea behind this is that we only have 1 class and this class will only have `1` instance. So let's go ahead and implement thats.\n\n```py\nfrom abc import abstractmethod, ABCMeta\n\nclass ISession(metaclass=ABCMeta):\n    @staticmethod\n    @abstractmethod\n    def get_session():\n        \"\"\"To be implemented\"\"\"\n\nclass Session:\n    __instance = None\n    @staticmethod\n    def get_instance():\n        if Session.__instance is None:\n            Session(\"localhost\", 5432)\n        return Session.__instance\n    def __init__(self, host: str, port: int) -\u003e None:\n        if Session.__instance is not None:\n            pass\n            # raise Exception(f\"{self.__class__.__name__} can only be initialized once.\")\n        else:\n            self.host = host\n            self.port = port\n            Session.__instance = self\n    @staticmethod\n    def get_session():\n        return {\"port\": Session.__instance.port, \"host\": Session.__instance.host}\n```\n\nNow we can create a single instance of a `Session` class because of this logic. If we try to check the instance of `session` and `session1` they will be located in the same memory:\n\n```py\nsession1 = Session(\"localhost\", 5432)\nprint(session1.get_session())\nprint(session1.get_instance())\nsession = Session(\"localhost\", 5432)\nprint(session.get_session())\nprint(session.get_instance())\n```\n\nOutput:\n\n```shell\n{'port': 5432, 'host': 'localhost'}\n\u003c__main__.Session object at 0x0000018C15D39FA0\u003e\n{'port': 5432, 'host': 'localhost'}\n\u003c__main__.Session object at 0x0000018C15D39FA0\u003e\n```\n\n### Composite Design Patten\n\nLet's say we have `IDepartment` which is the base interface for our departments `Testing` and `Deploying`. Each department has a method of printing the department employees. Then the base department class `Development` can print all the information about other departments including it's information. This is how it can be done.\n\n```py\nfrom abc import abstractmethod, ABCMeta\n\nclass IDepartment(metaclass=ABCMeta):\n    @abstractmethod\n    def __init__(self, employees):\n        \"\"\"To be implemented\"\"\"\n    @staticmethod\n    @abstractmethod\n    def print_department():\n        \"\"\"\"\"\"\n\nclass Testing(IDepartment):\n    def __init__(self, employees):\n        self.employees = employees\n    def print_department(self):\n        print(f\"Testing: {self.employees}\")\n\nclass Deploying(IDepartment):\n    def __init__(self, employees):\n        self.employees = employees\n    def print_department(self):\n        print(f\"Development: {self.employees}\")\n\nclass Development(IDepartment):\n    def __init__(self, employees):\n        self.employees = employees\n        self.deps = list()\n        self.all_employees = employees\n    def add_department(self, dep):\n        self.deps.append(dep)\n        self.all_employees += dep.employees\n\n    def print_department(self):\n        print(f\"Department Employees: {self.all_employees}\")\n        for dep in self.deps:\n            dep.print_department()\n        print(f\"Total Employees: {self.employees}\")\n\n```\n\n### Data Classes\n\nThese are a cool python feature that we can use on our python class so that we won't define some `__method__` as they will be defined for us once we decorate the class with the `dataclass` decorator that comes from `dataclasses`. Let's consider the following example where we have a class called `Person`\n\n```py\nfrom dataclasses import dataclass\n@dataclass\nclass Person:\n    name: str\n    age: str\n    gender: str\nperson = Person(\"bob\", 5, 7)\nprint(person) # Person(name='bob', age=5, gender=7)\n```\n\nWhen defining the person class we might want to make the `person` object immutable for that we can specify the argument when decorating our class called `frozen`:\n\n```py\n\n@dataclass(frozen=True)\nclass Person:\n    name: str\n    age: str\n    gender: str\nperson = Person(\"bob\", 5, 7)\nperson.age = 18 # this will throw an error\nprint(person)\n```\n\nWe can also specify our dataclass `Person` that it only takes in `keyword` arguments by passing the following options.\n\n```py\n@dataclass(frozen=True, kw_only=True)\nclass Person:\n    name: str\n    age: str\n    gender: str\nperson = Person(name=\"bob\", age=5, gender=\"M\") # only kwargs will be allowed\n```\n\nThe good thing with dataclasses is that you can overide the default `__method__` that are in the dataclass for example let's overide the `__repr__()` method we can do it as follows:\n\n```py\n@dataclass(frozen=True, kw_only=True)\nclass Person:\n    name: str\n    age: str\n    gender: str\n    def __repr__(self) -\u003e str:\n        return \"Person {}\".format(self.name)\nperson = Person(name=\"bob\", age=5, gender=\"M\")\nprint(person) # Person bob\n```\n\nWe can also set default values to dataclases let's have a look at the following example\n\n```py\nfrom dataclasses import dataclass, field\nimport random\nimport string\n\ndef uuid():\n    return \"\".join(random.choices(string.ascii_lowercase, k=5))\n\n@dataclass(frozen=False, kw_only=True, slots=True)\nclass Person:\n    name: str\n    age: str\n    gender: str\n    id: str = field(default_factory=uuid, init=False)\n    online: bool = True\n    colors: list[str] = field(\n        default_factory=list,\n    )\n    _search_str: str = field(init=False, repr=False)\n    def __post_init__(self):\n        self._search_str = f\"{self.name}%20{self.age}\"\nperson = Person(name=\"bob\", age=5, gender=\"M\")\nprint(person)\n\n```\n\nNow we have introduced another function called `field`. It takes in some number of arguments, for the default value of `id` we want to generate it using a function called `uuid` and for that we need to pass in an argument called `default_factory`, if we don't want to see a property in the `dander` method we can set `repr` to False. We have a `dander` method `__post_init__` which allows us to post initilize the `_search_str` when we create an instance of a `Person`. You can pass a lot of arguments in this `field` method.\n\n### Generics in Python `3.12`\n\nIn this section we are going to have a look at how we can work with generics in `python`. Let's say we have a function that returns a first element in an array and we want to make this function generic. This is how we can achieve that befor and after python `3.12`\n\nBefore:\n\n```py\nfrom typing import TypeVar\n\nT = TypeVar('T')\n\ndef get_first(ele:list[T])-\u003e T:\n    return ele[0]\nstrs = ['hi', 'hey']\nints = [2, 4]\n\nval = get_first(strs) # str\nval = get_first(ints) # int\n\n```\n\nAfter:\n\n```py\ndef get_first[T](ele: list[T]) -\u003e T:\n    return ele[0]\n\nstrs = [\"hi\", \"hey\"]\nints = [2, 4]\n\nval = get_first(strs)  # str\nval = get_first(ints)  # int\n\n```\n\nLet's have a look at an example where we can use generics in python classes\n\nBefore:\n\n```py\nfrom typing import  TypeVar, Generic\nfrom dataclasses import dataclass\n\nT = TypeVar(\"T\")\nclass Car(Generic[T]):\n    def __init__(self, car: T) -\u003e None:\n        self.car = car\n    def set_car(self, car: T) -\u003e None:\n        self.car = car\n    def get_car(self) -\u003e T:\n        return self.car\n@dataclass(kw_only=True)\nclass Vehicle:\n    name: str\n    license_plate: str\n\ncar = Car(Vehicle(name=\"Audi\", license_plate=\"DGB 56\"))\nmy_car = car.get_car() # type Vehicle\n\n```\n\nAfter:\n\n```py\nfrom dataclasses import dataclass\nclass Car[T]:\n    def __init__(self, car: T) -\u003e None:\n        self.car = car\n    def set_car(self, car: T) -\u003e None:\n        self.car = car\n    def get_car(self) -\u003e T:\n        return self.car\n@dataclass(kw_only=True)\nclass Vehicle:\n    name: str\n    license_plate: str\n\ncar = Car(Vehicle(name=\"Audi\", license_plate=\"DGB 56\"))\nmy_car = car.get_car() # type Vehicle\n```\n\nWe can restrict the type of a generic by using `bound` let's consider an example where we have a class `Plane`, `Car` and a `Boat` and all these classes are inheriting from a dataclass `Vehicle`.\n\n```py\nfrom typing import TypeVar, Generic\nfrom dataclasses import dataclass\n\n@dataclass(kw_only=True)\nclass Vehicle:\n    name: str\n    def display(self) -\u003e None:\n        print(f\"Vehicle Name: {self.name}\")\n\nclass Boat(Vehicle):\n    def display(self) -\u003e None:\n        print(f\"Boat Name: {self.name}\")\nclass Plane(Vehicle):\n    def display(self) -\u003e None:\n        print(f\"Plane Name: {self.name}\")\nclass Car(Vehicle):\n    def display(self) -\u003e None:\n        print(f\"Car Name: {self.name}\")\n```\n\nWe want to create a registry class that will set bound on a certain type of a vehicle. We can do it as follows:\n\nBefore:\n\n```py\nV = TypeVar(\"V\", bound=Vehicle)\nclass Registry(Generic[V]):\n    def __init__(self) -\u003e None:\n        self.vehicles: list[V] = []\n\n    def add(self, v: V) -\u003e None:\n        self.vehicles.append(v)\n\n    def display_all(self) -\u003e None:\n        for v in self.vehicles:\n            v.display()\n\nregistry = Registry[Car]()\nregistry.add(Car(name=\"Jeep\"))\nregistry.add(Car(name=\"Toyota\"))\nregistry.add(Plane(name=\"Jet\"))  # this is a type error\nregistry.display_all()\n```\n\nIf we want our `registry` to accept all the vehicle types and the or it subclass we can then do it as follows:\n\n```py\nregistry = Registry[Vehicle]()\nregistry.add(Car(name=\"Jeep\"))\nregistry.add(Boat(name=\"Yacht\"))\nregistry.add(Plane(name=\"Jet\"))\nregistry.display_all()\n```\n\nThat was before now after python `3.12` we can do it as follows:\n\n```py\n\nclass Registry[T: Vehicle]:\n    def __init__(self) -\u003e None:\n        self.vehicles: list[T] = []\n    def add(self, v: T) -\u003e None:\n        self.vehicles.append(v)\n    def display_all(self) -\u003e None:\n        for v in self.vehicles:\n            v.display()\n\nregistry = Registry[Car]()\nregistry.add(Car(name=\"Jeep\"))\nregistry.add(Car(name=\"Toyota\"))\nregistry.add(Plane(name=\"Jet\"))  # this is a type error\nregistry.display_all()\n\n```\n\nIf we want our `registry` to accept all the vehicle types and the or it subclass we can then do it as follows:\n\n```py\nregistry = Registry[Vehicle]()\nregistry.add(Car(name=\"Jeep\"))\nregistry.add(Boat(name=\"Yacht\"))\nregistry.add(Plane(name=\"Jet\"))\nregistry.display_all()\n```\n\nWe can also constrain our `Registry` class so that it can take a `Car` or a `Boat` as follows:\n\n```py\n\nclass Registry[T: (Car, Boat)]:\n    def __init__(self) -\u003e None:\n        self.vehicles: list[T] = []\n\n    def add(self, v: T) -\u003e None:\n        self.vehicles.append(v)\n\n    def display_all(self) -\u003e None:\n        for v in self.vehicles:\n            v.display()\n\nregistry = Registry[Car]()\nregistry.add(Car(name=\"Jeep\"))\nregistry.add(Boat(name=\"Yacht\"))\nregistry.display_all()\n```\n\n### The repository Pattern\n\nIn this example we are going to have a look at a design patten called the `Repository` Pattern. Suppose we are building a simple `orm` database that does some simple `CRUD` operations on a `Post` we could do something that looks as follows:\n\n```py\nfrom abc import ABC, abstractmethod\nfrom dataclasses import dataclass\nfrom typing import Optional\n\n@dataclass\nclass Post:\n    id: Optional[str]\n    title: str\n\n    @classmethod\n    def create_table(cls, db_name: str) -\u003e None:\n        \"\"\"Table Created\"\"\"\n    @classmethod\n    def get_post(cls, id: int, db_name: str) -\u003e \"Post\":\n        # get a post and return it\n        return Post(id=2, title=\"hello\")\n    @classmethod\n    def get_posts(cls, db_name: str) -\u003e [\"Post\"]:\n        # get all post and return it\n        return [Post(id=2, title=\"hello\")]\n    @classmethod\n    def add_post(cls, title: str, db_name: str) -\u003e \"Post\":\n        # add a post to a database\n        return Post(id=2, title=title)\n    @classmethod\n    def update_post(cls, id, title: str, db_name: str) -\u003e \"Post\":\n        # update posts\n        return Post(id=2, title=title)\n    @classmethod\n    def delete_post(cls, id, db_name: str) -\u003e None:\n        # delete post\n        pass\n\nif __name__ == \"__main__\":\n    Post.create_table(\"hello.db\")\n    Post.add_post(title=\"hey\", db_name=\"hello.db\")\n    Post.add_post(title=\"hey\", db_name=\"hello.db\")\n    for post in Post.get_posts(db_name=\"hello\"):\n        print(Post)\n\n```\n\nThat how we will do it before python `3.12`. The following example is how we will do it after this version of python.\n\n```py\nfrom abc import ABC, abstractmethod\nfrom dataclasses import dataclass\nfrom typing import Optional\nimport contextlib, sqlite3\n\n@dataclass\nclass Post:\n    id: Optional[str]\n    title: str\n\nclass IModel[T](ABC):\n    @abstractmethod\n    def get(self, id: int) -\u003e T:\n        raise NotImplemented\n    @abstractmethod\n    def get_all(self) -\u003e list[T]:\n        raise NotImplemented\n    @abstractmethod\n    def add(self, **kwargs: object) -\u003e None:\n        raise NotImplemented\n    @abstractmethod\n    def update(self, id, **kwargs: object) -\u003e None:\n        raise NotImplemented\n    @abstractmethod\n    def delete(self, id) -\u003e None:\n        raise NotImplemented\n\n```\n\nFirst things first we are creating our abstract class `IModel` that will map all the required method to be implemented to by the child class `Model`. The `Model` class will take in a generic `T` and in the `init()` we will be taking an argument of a model called `Post`\n\n```py\nclass Model[T](IModel[T]):\n    def __init__(self, model: T) -\u003e None:\n        super().__init__()\n        self._Table = model\n    def create_table(self) -\u003e None:\n        \"\"\"Table Created\"\"\"\n\n    @contextlib.contextmanager\n    def connect(self):\n        with sqlite3.connect('hello.db') as conn:\n            yield conn.cursor()\n\n    def get(self, id: int) -\u003e T:\n        with self.connect() as cursor:\n            cursor.execute(\"SELECT * FROM post WHERE id=2\")\n            res = cursor.fetchone()\n        # get a model and return it\n        return self._Table(id=2, title=\"hello\")\n    def get_all(self) -\u003e list[T]:\n        # get all model and return it\n        return [self._Table(id=2, title=\"hello\")]\n    def add(self, title: str) -\u003e T:\n        # add a model to a database\n        return self._Table(id=2, title=title)\n    def update(self, id, title: str) -\u003e T:\n        # update model\n        return self._Table(id=2, title=title)\n    def delete(self, id) -\u003e None:\n        # delete model\n        pass\n\nif __name__ == \"__main__\":\n    model = Model[Post](Post)\n    model.add(title=\"hey\")\n    model.add(title=\"hey\")\n    p = model.get(7)\n    for post in model.get_all():\n        print(post)\n```\n\nWith this we will be type safe for getting and from the model. And we made our implementation so generic that it can work with any kind of a model.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrispengari%2Fdays-of-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrispengari%2Fdays-of-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrispengari%2Fdays-of-python/lists"}