0

I am writing a function which gets users from database and returns a list of user objects. Function signature is as given below:

def select_users(self,userid,firstname,lastname,emailid,tenants,groups):
    result = self.authservice.select_users(userid,firstname,lastname,emailid,tenants,groups)

In this function, I call select_users method of authservice object which will return a list of custom user objects. But if any of input parameters has '' value then it must be converted to None because self.authservice.select_users cannot handle empty strings. I can check each element value and convert it to None if it is empty, but I want it to be generic and reusable. If I could write a different function which can give me updated list of input parameters it would be very helpful. Please let me know how do I do that?

gliese581g
  • 433
  • 8
  • 21

4 Answers4

2

Evil way:

def select_users(self, *args):
    new_args = [(None if arg == '' else arg) for arg in args]
    result = self.authservice.select_users(*new_args)

Decorator solution is also pretty evil: changing function arguments to spare writing a couple of function calls doesn't seem such a great idea.

In the real life I would go with the explicit:

def never_blank(s):
    return None if s == '' else s

def select_users(self, userid,firstname,lastname,emailid,tenants,groups):
   result = self.authservice.select_users(userid,never_blank(firstname),never_blank(lastname),emailid,
                          never_blank(tenants),groups)

Tedious? Sure. Clean? Yep. Will bite you in the ass in the future? Nope.

Nigel Tufnel
  • 11,146
  • 4
  • 35
  • 31
  • It is helpful, but I do not want to edit my function signature, but I want to have other function which can be called from this function as well as other functions to get updated list of parameters. – gliese581g Jan 16 '14 at 15:25
  • 3
    What if `arg` is `False`, `0` or `[]`? – thefourtheye Jan 16 '14 at 15:27
2

I would write a generic decorator, like this

def convert_empty_to_none(func):
    def inner_function(*args, **kwargs):
        args = (None if item == "" else item for item in args)
        kwargs = {k:(None if v == "" else v) for k, v in kwargs.items()}
        return func(*args, **kwargs)
    return inner_function

@convert_empty_to_none
def test_function(a, b, c):
    print a, b, c

test_function("", "", "")

Output

None None None
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • 1
    @gliese581g You are welcome :) I would strongly recommend you to read [this excellent answer](http://stackoverflow.com/a/1594484/1903116) to learn more about decorators. – thefourtheye Jan 16 '14 at 15:50
1

Create a function and use it like a function type decorator

def sanitize(func):
    def handler(*args, **kwargs):
        args = (e if e != '' else None for e in args)
        kwargs = {k:(v if v != '' else None) for k, v in kwargs.items()}
        return func(*args, **kwargs)
    return handler

@sanitize
def select_users(self,userid,firstname,lastname,emailid,tenants,groups):
    result = self.authservice.select_users(userid,firstname,lastname,emailid,tenants,groups)

Benifits

  1. You do not need to modify the signature
  2. The caller would still have clear idea, what parameters the function expects
  3. Generic and can be used for any function call
  4. Is a decorator, so can easily be used in a non-intrusive fashion
Abhijit
  • 62,056
  • 18
  • 131
  • 204
1

You could use a decorator to create a generic wrapper that will replace every empty string with None.

def none_for_empty_string(func):

    def wrapper(*args, **kwargs):

        args = tuple(arg if arg != '' else None for arg in args)
        kwargs = {k : v if v != '' else None for k, v in kwargs.iteritems()}
        return func(*args, **kwargs)

    return wrapper

@none_for_empty_string
def select_users(self,userid,firstname,lastname,emailid,tenants,groups):
    ...
Silas Ray
  • 25,682
  • 5
  • 48
  • 63