2

Basically, I have a list of classes which take in the same input parameters (either ClassX(a, **kwargs) or ClassX(**kwargs) or ClassX(b, **kwargs). I want to create a list of instantiated classes. Right now I sequentially go through each for creation.

Is there a way to use list comprehension effectively to make this cleaner? For example perhaps making a list of class objects and annotating those that require formal arguments (a and b) in addition to **kwargs? I.e. looping over something like:

[ClassA: (None, None), ClassB: (fnA, None), ClassC: (None, fnB)] to achieve the creation of:

listOfClasses.append(ClassA(**kwargs))

listOfClasses.append(ClassB(**kwargs, a=fnA))

listOfClasses.append(ClassC(**kwargs, b=fnB))

The reason I ask is because in my case I have 20-30 different classes that need to be created and appended to the list sequentially.

To illustrate better, the exact code I am using now is the following:

def method(self, **kwargs):
    chain = []
    chain.append(ClassA(**kwargs))
    chain.append(ClassB(**kwargs))
    chain.append(ClassC(a=static_method_x, **kwargs))
    chain.append(ClassD(b=static_method_y, **kwargs))
    chain.append(ClassE(**kwargs))
    chain.append(ClassF(a=static_method_z, **kwargs))
    ...

So every instantiation follows one of three types, but **kwargs is always the same. The values of a or b when they are classes which require them, however, differ, and correspond to other static methods in my class. I am wondering if there is a way to make this cleaner through list comprehension with a predefined list of sequential classes and respective arguments.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
Leeren
  • 1,931
  • 2
  • 20
  • 31

1 Answers1

0

If you create a list tuples each containing the class to instantiate along with the extra arguments, you could use a list comprehension to instantiate each one with the merge of kwargs and the extra args for that.

def method(self, **kwargs):
    to_instantiate = [
        # (Class, extra_args)
        (ClassA, {}),
        (ClassB, {}),
        (ClassC, {'a': static_method_x})
        (ClassD, {'b': static_method_y})
        (ClassE, {})
        (ClassF, {'a': static_method_z})
    ]
    chain = [C(**{**kwargs, **extra_args}) for C, extra_args in to_instantiate]

The **{**kwargs, **extra_args} part means create a new dictionary with all the entries in kwargs and extra_args, then destructure it into arguments, like you were doing with **kwargs before. Note that this syntax was introduced in python 3.5. See this question if you want to understand it better and also have solutions for older python versions.

Honestly though I think this code is uglier and harder to understand than what you have. The code you wrote might be a little more verbose, but I think it is much easier to read.