How can I write cleanly __init__ method in python?

Question:

I want write cleanly init method in python.

my init method is very long and dirty.

I don’t know how can clean it.

and its my dirty code:

class Detect:
    """Class to show frames"""

    def __init__(self,
                 main_target,
                 target_object,
                 camera,
                 sms_class,
                 qr_code_class,
                 cuda="CPU"):
        self.main_target = main_target
        self.target_object = target_object
        self.camera = camera
        self.sms_class = sms_class
        self.qr_code_class = qr_code_class
        self.cuda = cuda

        self.classes_names = []
        self.previous_time = 0
        self.authorised = True
        self.first_time = 0
        self.first_detect_time = 0
        self.color = (255, 0, 255)
        self.capture = cv.VideoCapture(self.camera)
        self.conf_threshold = 0.5
        self.nms_threshold = 0.3
Asked By: Novin.Nouri

||

Answers:

You can place some of your attributes outside __init__:

class Detect:
    """Class to show frames"""
    classes_names = []
    previous_time = 0
    authorised = True
    first_time = 0
    first_detect_time = 0
    color = (255, 0, 255)
    capture = cv.VideoCapture(self.camera)
    conf_threshold = 0.5
    nms_threshold = 0.3


    def __init__(self,
             main_target,
             target_object,
             camera,
             sms_class,
             qr_code_class,
             cuda="CPU"):
        self.main_target = main_target
        self.target_object = target_object
        self.camera = camera
        self.sms_class = sms_class
        self.qr_code_class = qr_code_class
        self.cuda = cuda
Answered By: DiogoAlmeida

There are multiple ways to go about it, one is to define a base class and assign all those default values in the base class, and inherit Detect from it. I’ve even further reduced the first part using **kwargs and setattr method:

class BaseDetect:
    def __init__(self):
        self.classes_names = []
        self.previous_time = 0
        self.authorised = True
        self.first_time = 0
        self.first_detect_time = 0
        self.color = (255, 0, 255)
        self.conf_threshold = 0.5
        self.nms_threshold = 0.3


class Detect(BaseDetect):
    """Class to show frames"""
    def __init__(self, cuda = "CPU", **kwargs):
        self.cuda = cuda
        super().__init__()
        for key, value in kwargs.items():
            setattr(self, key, value)
        
        self.capture = cv.VideoCapture(self.camera)

It still has those codes of course but doesn’t the child class look much cleaner now? Also, if those values are static and not going to change, it’s just better to make them class variable, or global constants. That’s also something you can try.

Answered By: ThePyGuy

They are there for some reasons right? It’s normal for your class instances to have a lot of attributes.

But if you have inheritance hierarchy in your design, you can initialize them in the parents. It’s makes the children’s __init__ cleaner.

Answered By: S.B

I think you should use python dataclasses for this :
https://docs.python.org/3/library/dataclasses.html

which would result in something like this

from dataclasses import dataclass, field
from typing import List, Any, Tuple


@dataclass
class Detect:
    """Class to show frames"""
    main_target: str
    target_object: str
    camera: str
    sms_class: Any
    qr_code_class: Any
    cuda: str

    classes_names: List = field(default_factory=list)
    previous_time: int = 0
    authorised: bool = True
    first_time: int = 0
    first_detect_time: int = 0
    color: Tuple[int] = (255, 0, 255)
    conf_threshold: float = 0.5
    nms_threshold: float = 0.3

    def __post_init__(self):
        self.capture = cv.VideoCapture(self.camera)
Answered By: DeaX StormZ
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.