1

I'm creating a Python class that will use its parameters to define two other classes within this class. For example, ClassA contains ClassB and ClassC. Because of this, ClassA has a lot of parameters.

I'm currently solving this using **kwargs for classB and classC arguments, and saving only the input parameters for classA parameters. For example:

class A:
    def __init__(self, a1, a2, a3, **kwargs):
        self.a1 = a1
        self.a2 = a2
        self.a3 = a3

        # Get B and C kwargs
        default_params = {
            'b1': kwargs.get('b1', 1),
            'b2': kwargs.get('b1', 2),
            'c1': kwargs.get('c1', 1),
            'c2': kwargs.get('c1', 2),          
        }
        for param in default_params:
            self.__dict__[param] = default_params[param]

        B = classB(a1=self.a1, b1=self.b1, b2=self.b2)
        C = classC(a2=self.a2, c1=self.c1, c2=self.c2)

Is this a worse solution compared to the below?

class A:
    def __init__(
        self,
        a1, a2, a3,
        b1, b2, c1, c2):
        self.a1 = a1
        self.a2 = a2
        self.a3 = a3
        self.b1 = b1
        self.b2 = b2
        self.c1 = c1
        self.c2 = c2

My concern is if arguments for class B and C are super numerous, then class A's attributes seems too many. On the other hand, the first approach seems to take up more lines anyway.

Another way is if I pass only kwargs to classB and classC, but this will have an error when there are some parameters not present in one of the classes.

Is there a pythonic way I'm failing to see here for classes with many attributes and utilising this kind of design pattern?

4
  • Some parts of this design seem weird, can you clarify them? Why do you take **kwargs, when the rest of the code explicitly works with b1, b2, c1, c2 arguments (indirectly as keys)? Why do you store the arguments (self.b1, ...) when you just want to pass them on? Commented Jul 27, 2020 at 7:42
  • Note that style question may be more appropriate for CodeReview. Make sure to check their How To Ask page to provide all relevant information. Commented Jul 27, 2020 at 7:44
  • That's a good question. For using **kwargs*, I was thinking if a user gives a specific value for b1` for example, then I can get it from kwargs without defining the long list of attributes. For the 2nd question, I was planning to log the parameters in a separate file, although you're right I don't think I actually need to store it as self.b1 Commented Jul 27, 2020 at 7:47
  • I have tried codereview previously, but they require real project code which I'm not able to provide. I've created a minimal reproducible example here which is more widely accepted in SO. Commented Jul 27, 2020 at 7:48

1 Answer 1

1

Your primary criteria should be to avoid emulating what Python provides natively – namely parameters and defaults, as well as instance attributes.

Since __init__ already knows all the attributes and defaults it expects (via default_params), add them to the signature directly. Avoid storing arguments for classB and classC on A – if needed, fetch them from the instances.

class A:
    # handle parameters/defaults natively
    def __init__(self, a1, a2, a3, b1=1, b2=2, c1=1, c2=2):
        self.a1 = a1
        self.a2 = a2
        self.a3 = a3
        # do not store B/C attributes, store B/C directly
        self.b = classB(a1=self.a1, b1=b1, b2=b2)
        self.c = classC(a2=self.a2, c1=c1, c2=c2)

This is functionally equivalent to the first case (minus exposing all arguments) but uses native Python functionality.


If A has to provide additional functionality, add them explicitly:

  • If A should take (and ignore) additional parameters, have an additional catch-all **kwargs:

    class A:
        # discard additional parameters/defaults explicitly
        def __init__(self, a1, a2, a3, b1=1, b2=2, c1=1, c2=2, **_):
            ...
    
  • If A should expose classB and/or classC fields, provide them from the instances.

    class A:
        ...
    
        @property
        def b1(self):
            return self.b.b1
    
Sign up to request clarification or add additional context in comments.

1 Comment

This is very helpful and informative, thank you! Could you point out where I should go to for learning these useful code styles?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.