Home > Enterprise >  Passing args and kwargs to base python object
Passing args and kwargs to base python object

Time:11-30

I have some data I need to marshal, of which there are two main types with some base behavior. In order to avoid all the duplicate logic of actually marshaling the data, I decided to use inheritance. I figured objects would also be a good choice since I can add type hints, and make all the arguments required (say vs. a dict, which is what we are currently using and is prone to typos/field omission). I am also aware of TypedDict but since there is a tiny bit of behavior associated with the data I didn't feel it would be a good choice. A dataclass seems like a good middle ground except it's not so great with inheritance and exposes some fields that should remain hidden from the caller. All I really care about is enforcing required arguments and types.

So let's say I have these classes

class Base:
    def __init__(self, id: str, **kwargs):
        self.id = id # the caller doesn't need to know about this field.
        # data really just needs to be collected into this dict with arg names as keys
        self.properties = kwargs or {}


class A(Base):
    def __init__(self, a: str, b: str, c: datetime):
        super().__init__(foo_id, a=a, b=b, c=c)

This is fine when there are three arguments, but some have ten, and there's just a ton of boilerplate. Is there a way to remove all the arg passing to Base, or even just collect args into kwargs and pass that down?

CodePudding user response:

You could use the default method of passing all arguments in python:


class A(Base):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

This is standard python to catch and then pass all arguments.

However, separate question for you: are you needing to define your own init processing steps?

...In your example above, your child class's init isn't doing anything except calling the parent's init.

If you don't define an __init__ method in a child class, when an instance is created python will automatically call __init__ in the parent class. So you don't need to define init anywhere unless you need to for some class specific steps.

Eg:

class Base: 
    def __init__(self, arg1 = "argument one"): 
        self.arg1 = arg1 
     
         
class Derived(Base): 
    pass 
     
b = Base() 
print b.arg1 
 
d = Derived() 
print d.arg1 

# output:
argument one 
argument one 

CodePudding user response:

A class should extract the keyword arguments it expects, and pass the rest upstream, assuming that somebody needs them. It's the caller's responsibility to pass all required arguments.

class Base:
    def __init__(self, *, id: str, **kwargs):
        super.__init__(**kwargs)
        self.id = id
        self.properties = {}

class A(Base):
    def __init__(self, *, a: str, b: str, c: datetime, **kwargs):
        super().__init__(**kwargs)
        # self.properties is guaranteed to exist at this point
        self.properties['a'] = a
        self.properties['b'] = b
        self.properties['c'] = c

a = A(id=foo_id, a="baz", b="bar", c=datetime.datetime.now())

If you really want A.__init__ to hard-code foo_id as the id attribute for Base, you can:

class A(Base):
    def __init__(self, *, a: str, b: str, c: datetime, **kwargs):
        super().__init__(id=foo_id, **kwargs)
        self.properties['a'] = a
        self.properties['b'] = b
        self.properties['c'] = c

a = A(a="baz", b="bar", c=datetime.datetime.now())
  • Related