Home > Back-end >  Simplifying Init Method Python
Simplifying Init Method Python

Time:09-30

Is there a better way of doing this?

def __init__(self,**kwargs):
        self.ServiceNo = kwargs["ServiceNo"]
        self.Operator = kwargs["Operator"]
        self.NextBus = kwargs["NextBus"]
        self.NextBus2 = kwargs["NextBus2"]
        self.NextBus3 = kwargs["NextBus3"]

The attributes (ServiceNo,Operator,...) always exist

CodePudding user response:

That depends on what you mean by "simpler".

For example, is what you wrote simpler than what I would write, namely

def __init__(self,ServiceNo, Operator, NextBus, NextBus2, NextBus3):
    self.ServiceNo = ServiceNo
    self.Operator = Operator
    self.NextBus = NextBus
    self.NextBus2 = NextBus2
    self.NextBus3 = NextBus3

True, I've repeated each attribute name an additional time, but I've made it much clearer which arguments are legal for __init__. The caller is not free to add any additional keyword argument they like, only to see it silently ignored.

Of course, there's a lot of boilerplate here; that's something a dataclass can address:

from dataclasses import dataclass


@dataclass
class Foo:
    ServiceNo: int
    Operator: str
    NextBus: Bus
    NextBus2: Bus
    NextBus3: Bus

(Adjust the types as necessary.)

Now each attribute is mentioned once, and you get the __init__ method shown above for free.

CodePudding user response:

Better how? You don’t really describe what problem you’re trying to solve.

If it’s error handling, you can use the dictionary .get() method in the event that key doesn’t exist.

If you just want a more succinct way of initializing variables, you could remove the ** and have the dictionary as a variable itself, then use it elsewhere in your code, but that depends on what your other methods are doing.

CodePudding user response:

A hacky solution available since the attributes and the argument names match exactly is to directly copy from the kwargs dict to the instance's dict, then check that you got all the keys you expected, e.g.:

def __init__(self,**kwargs):
    vars(self).update(kwargs)
    if vars(self).keys() != {"ServiceNo", "Operator", "NextBus", "NextBus2", "NextBus3"}:
        raise TypeError(f"{type(self).__name__} missing required arguments")

I don't recommend this; chepner's options are all superior to this sort of hackery, and they're more reliable (for example, this solution fails if you use __slots__ to prevent autovivication of attributes, as the instance won't having a backing dict you can pull with vars).

  • Related