0

I want to create a Python class with two mutually inclusive parameters that are dependent on each other. The user must either provide a value for both parameters or neither. If one parameter is specified without the other, an exception should be raised.

class TestEvent:
    def __init__(self, start_date = None, end_date = None , **kwargs):
        # Check if start_date and end_date are defined 
        pass

valid_event_1 = TestEvent()
valid_event_2 = TestEvent(start_date = '2022-07-01', end_date = '2022-08-01')
invalid_event_1 = TestEvent(start_date = '2022-07-01')  # Raise exception
invalid_event_2 = TestEvent(end_date = '2022-08-01')  # Raise exception

How can I define two mutually dependent parameters in Python?

Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
  • Does this answer your question? [Python checking \_\_init\_\_ parameter](https://stackoverflow.com/questions/10866738/python-checking-init-parameter) – Ignatius Reilly Jun 29 '22 at 19:43

4 Answers4

2

You could make them one variable, expecting a tuple of two date strings:

def __init__(self, start_end_date: Tuple[str, str] = None, **kwargs):

Or you check inside of your init function if both have been set:

def __init__(self, start_date = None, end_date = None , **kwargs):
    if start_date and not end_date:
        raise ValueError('Expected end date when a start date is specified.')
    if end_date and not start_date:
        raise ValueError('Expected start date when an end date is specified.')
MrJ
  • 198
  • 1
  • 8
  • There's no way to get the default for start_date if you've specified end_date, so the logic here could be simplified. – Mark Ransom Jun 29 '22 at 19:50
  • Yes, except if one explicitly passes None as the start_date. This covers that possibility as well. – MrJ Jun 29 '22 at 20:49
  • 1
    @MarkRansom You could get the default `start_date` with `TestEvent(end_date = '2022-08-01')`. – Stevoisiak Jun 29 '22 at 21:01
1

You could express the mutual exclusive ^-operator.

if (start_date is None) ^ (end_date is None):
   print('Error')

Here the table of values for the ^-operator

from itertools import product

def xor_table_of_values():
    """
      1   ^   1   -> 0
      1   ^   0   -> 1
      0   ^   1   -> 1
      0   ^   0   -> 0
    """
    print(*(f'{i:^5} ^ {j:^5} -> {int(i^j)}' for i, j in product((True, False), repeat=2)), sep='\n')

xor_table_of_values()

Here a (verbose) abstraction:

def test(start_date=None, end_date=None):

    is_given_sd = start_date is not None
    is_given_ed = end_date is not None

    if is_given_sd ^ is_given_ed:
        print('Error')


test(start_date='7', end_date='767')
#
test(start_date='2')
# Error
test(end_date='43')
# Error
test()
#
Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
cards
  • 3,936
  • 1
  • 7
  • 25
0

You could combine checks for "Both arguments are not filled" and "both arguments are not empty".

def __init__(start_date = None, end_date = None):
    if not all(start_date, end_date) and not (start_date is None and end_date is None):
        raise ValueError(
            "start_date and end_date are mutually dependent. "
            "You must either specify both or neither."
        )

As a class:

class TestEvent:
    def __init__(self, start_date = None, end_date = None , **kwargs):
        if not all(start_date, end_date) and not (start_date is None and end_date is None):
            raise ValueError(
                "start_date and end_date are mutually dependent. "
                "You must either specify both or neither."
            )
Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
-1

If the default values are None, and assuming None means no argument was provided, you could just check if either start_date or end_date are None and raise an exception.

MxLDevs
  • 19,048
  • 36
  • 123
  • 194
  • This would raise an exception if both parameters eqaled None. – Stevoisiak Jun 29 '22 at 21:32
  • @Stevoisiak not sure what you mean. You're the one that will be writing the condition? – MxLDevs Jun 29 '22 at 21:48
  • I only want to raise an exception if one parameter is specified but not the other. An exception should not be raised if `start_date` and `end_date` both equal None. – Stevoisiak Jun 29 '22 at 21:57
  • @Stevoisiak sure, then you would just write your condition so that at least one of the parameters is not None and the other is None. Where are you confused about? How to write conditional statements? – MxLDevs Jun 29 '22 at 22:11