Issue
I am working on a python library where I want to give some flexibility to the user. I am facing below challenge.
Let's say I exposed the class Client
to the user, which is defined like below:
class Client:
def __init__(self, path=None):
self.file_obj = FileOpener(path = path)
And my FileOpener
class is:
class FileOpener:
def __init__(self, path='my/default/path'):
# My logic
pass
In above code, the issue is, if the user initialized the Client
object as c = Client()
, my underlying FileOpener
class receives None
as the path. But I want that even if None
is passed, it should pick the default path.
Here are few solutions for this problem that I came up with, but they are somewhat flawed:
The most basic approach - filter the arguments and pass only those which are not
None
. I don't want to put a if - else ladder or create any unnecessarydict
to store the values. Its not maintainable / readable and new coders can mess up easily.I can define the default value in
Client
class itself. If the user doesn't pass anything, it will receive the default value. The issue is, suppose I have multiple layers, and in future I want to change the default value, I will need to change it everywhere. Hence this approach is not maintainable at all.Second thing that came to my mind was, using
**kwargs
, that I can pass easily to underlying objects. This will not passNone
by default if user didn't explicitly pass it. But now my user doesn't know what args my class is taking. He will need to go through the docs every time and won't be able to take advantage of his code editor (example - in VS Code you can use auto complete).
I want to understand if there is any standard approach for resolving this issue. Or any suggestions to get rid of the flaws in my approach. I want to have a maintainable solution so that if anyone in future comes to contribute, he can understand just by looking at the code and doesn't mess up.
Solution
I came up with another approach, which is maintainable and flexible. Though it still doesn't make the default value of keyword args useful. It just makes them optional. Use a class attribute to define the default path in the underlying FileOpener
class. This way, the default value is centralized and easily modifiable. Here's an example:
class FileOpener:
default_path = 'my/default/path'
def __init__(self, path=None):
self.path = path or self.default_path
# my logic here
pass
class Client:
def __init__(self, path=None):
self.file_obj = FileOpener(path=path)
This approach allows you to set the default path in one place (FileOpener
class) and avoids cluttering the Client
class with default values. It's maintainable, readable, and provides a clear structure for future contributors.
Now, if you want to change the default path, you only need to update it in the FileOpener
class. This design has better code maintainability and readability without sacrificing flexibility.
Answered By - Mukul Bindal
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.