Fishball Nooodles
Fishball Nooodles

Reputation: 511

Simplifying Init Method Python

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

Upvotes: 0

Views: 310

Answers (3)

ShadowRanger
ShadowRanger

Reputation: 155363

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).

Upvotes: -1

chepner
chepner

Reputation: 531055

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.

Upvotes: 2

seve
seve

Reputation: 185

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.

Upvotes: 0

Related Questions