How to make function's arguments optional as a group?
I was just wondering what would be the preferred way in Python to make a group of arguments of a function optional, but only as the whole group. Meaning: they have to either all be given, or none.
For an example, let's say I want to make a print
function, that takes a message string as first positional argument and optionally a file-like object and an encoding as second and third arguments.
Now I want this function to print to stdout if no file is given, and to the file otherwise. The tricky bit is this: I want this function to always require an encoding to be specified whenever a file is used. And calling this function with an encoding, but no file should also be forbidden.
In Java, I could overload the function and give implementations for both valid variants:
public void print(string message);
public void print(string message, File f, string encoding);
This allows me to call this function in exactly the two ways I want to be possible, with either one or all three arguments.
In Python, I can make single arguments optional by supplying a default value, but I cannot group them together.
def print(msg, file=None, encoding=None)
allows me to call the function by providing a message and none, both or just any one of the other parameters:
print("test")
print("test", file=someFile)
print("test", encoding="utf-8")
print("test", file=someFile, encoding="utf-8")
These are all valid calls to the Python declaration above, even though with my implementation, setting an encoding or file without the other one might make no sense.
I am aware that I could simply check both optionals for an invalid default value and raise an Exception at runtime whenever I find only one is set, but I think that is bad for a couple of reasons:
- The Exception is raised only if the invalid call is executed, so it might not occur during testing.
- I have no way of telling that both parameters are required as a pair by just looking at the declaration or an auto-generated quick reference without diving into the implementation.
- No code analysis tool would be able to warn me about an invalid call.
So is there any better way to syntactically specify that a number of optional arguments are grouped together?
Solution 1:
Python is not supporting overloading methods. And there is not a really good way to simulate an overloading design. So best you can do is using if statements with different arguments. Like you do in your method.
Or you can use **kwargs as argument and use if only the desired argument is defined.
def a_very_important_method(**kwargs)
if kwargs["arg1"] is not None:
# logic
if kwargs["arg2"] is not None:
# another logic
a_very_important_method(arg1="value1", arg2="value2")