ICW
ICW

Reputation: 5760

Check If Parameter Was Passed To Function Without Checking Value

I'm not sure if this is possible in Python and I was wondering, is there any method for checking at runtime whether a parameter is passed to a Python function without doing some sort of check on the parameter value?

def my_func(req, opt=0):
    return was_opt_passed() # Returns bool 

print(my_func(0)) # Prints False
print(my_func(0, 0)) # Prints True

This would be superior in some circumstances, if possible, because it relieves the need to remember and check for sentinel values. Is it possible?

Upvotes: 2

Views: 3164

Answers (5)

Charif DZ
Charif DZ

Reputation: 14721

Using decorator

    def check_opt_passed(methd):
        def m(req, *args, **kwarg):
            # this will check even if opt is passed as positional argument
            # and check if opt is passed not any other keyword
            if args or (kwarg and 'opt' in kwarg):
                print('opt is passed')
            else:
                print('opt is not passed')
            return methd(req, *args, **kwarg)

        return m

    @check_opt_passed
    def my_func(req, opt=0):
        # dummy expression for testing
        return req * opt


    print(my_func(1))           # opt is not passed
    print(my_func(1, 0))        # opt is passed
    print(my_func(1, opt=0))    # opt is passed

Upvotes: 0

mattbornski
mattbornski

Reputation: 12543

A great way would be to use *args or **kwargs.

def was_opt_passed(*args, **kwargs):
  return len(args) > 0 or 'opt' in kwargs

def my_func(req, *args, **kwargs):
    return was_opt_passed(*args, **kwargs) # Returns bool 

print(my_func(0)) # Prints False
print(my_func(0, 0)) # Prints True
print(my_func(0, opt=0)) # Prints True
print(my_func(0, not_opt=0)) # Prints False

*args collects any positional arguments passed to your function that are not already enumerated, while **kwargs collects any keyword arguments passed to your function that are not already enumerated. If args contains a positional argument, we assume it was opt, and it must have been passed. Otherwise, if it is in kwargs, it was passed, and then if we didn't find it in either place, it must not have been passed.

See also https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments

Upvotes: 0

Jab
Jab

Reputation: 27485

As Mark has already stated in his comment the typical convention is to use the default value None. Then you can check if it’s still None upon calling.

def my_func(req, opt=None):
    if opt is None:
        #opt wasn’t passed.
        return False
    #opt was passed
    return True

Although if you’d like to do more research on other options (most unconventional for most cases) feel free to check out these answers

Upvotes: 1

Zae Zoxol
Zae Zoxol

Reputation: 109

the standard method of detecting if an argument has been passed is sentinel values; however, if you're willing to lose your function signature, you can use **kwargs:

def my_func(**kwargs):
  return 'opt' in kwargs
print(my_func()) #=> False
print(my_func(opt=0)) $=> True

Upvotes: 1

Brian
Brian

Reputation: 1604

One solution is to use decorators/wrappers. They allow you to interface with what's being passed to your function at runtime and then handle said things as you see fit Consider this code:

def check_keywords(func):
    def wrapper(*args, **kwargs):
        if kwargs:
            print('Keyword was passed!')
        return func(*args, **kwargs)
    return wrapper

@check_keywords
def my_func(req, opt=0):
    print(req)

check_keywords captures the function and if it detects keywords being passed into my_func, it then prints something. This print statement can be converted to any arbitrary code you want.

e.g.:

my_func(1)
>>> 1

my_func(1, opt = 1)
>>> Keyword was passed!
>>> 1

Upvotes: 0

Related Questions