2
\$\begingroup\$

I need to write a function to build a string based on user input. when user provide one type group of input: "tab" and link variable the string should be tab_link: xxxx. when user provide one type group of input: "subtab" and link variable the string should be subtab_link: subtabxxxxx.

the logic is pretty much like following function. but do I have better way to do it then using if, else? because lets say if I have multiple group, does it mean I need to have more if, elif, elif to identify different group input and match the string?

subtab = {'subtab1': 1, 'subtab2': 2, 'subtab3': 3}
_dir = {'tab': 'tab_link:{}', 'subtab': 'subtab_link:{}'}

def func(**kwargs):
    if kwargs['_type'] == 'tab':
        print(_dir[kwargs['_type']].format(kwargs['_link']))
    else:
        print(_dir[kwargs['_type']].format(subtab[kwargs['_link']]))

func(_type='tab', _link='a')
func(_type='tab', _link='b')
func(_type='subtab', _link='subtab1')
func(_type='subtab', _link='subtab2')

#expect
tab_link:a
tab_link:b
subtab_link:1
subtab_link:2
\$\endgroup\$
  • \$\begingroup\$ Does this code work exactly as you expect it to? "the logic is pretty much like following function." makes me doubt that, and so it'd be off-topic on here. As we only review code that works as expected. \$\endgroup\$ – Peilonrayz May 1 '17 at 14:41
  • \$\begingroup\$ yes, the function "func" works and meets my purpose. but I would like to see if there is a better way to use if else \$\endgroup\$ – jacobcan118 May 1 '17 at 15:03
1
\$\begingroup\$

Why don't you break down the two long lines in func by using variables?

def func(**kwargs):
  link  = kwargs['_link']
  type_ = kwargs['_type']

  if type_ == 'tab':
      print(_dir[type_].format(link))
  else:
      print(_dir[type_].format(subtab[link]))

Then it's easy to see that you can conditionally assign the necessary value to link. If the type is subtab, just convert the link to its target. The rest will be the same in both cases:

def func(**kwargs):
  link  = kwargs['_link']
  type_ = kwargs['_type']

  if type_ == 'tab':
    link = subtab(link)

  print(_dir[type_].format(link))

However, using dicts defined outside of a function is kind of smelly and calls for use of some classes. Same goes for specifying the type by a string – enum.Enum would be more suitable, or even some more specialized class which would handle the formatting as well.


After reading your question again, I noticed what you were specifically asking about. To handle many different types elegantly, you could create a function for each type, which would transform a link according to the type.

For example:

def convert_tab_link(link):
    return link

def convert_subtab_link(link):
    return subtab(link)

link_converters = {
    'tab': convert_tab_link,
    'subtab': convert_subtab_link,
}


def func(**kwargs):
  link  = kwargs['_link']
  type_ = kwargs['_type']

  convert_func = link_converters[type_]
  link = convert_func(link)

  print(_dir[type_].format(link))

Again, this is not what you should be doing. A nicer way would be to make each type a class, which derives from some base class, eg. TabType. Each of these subclasses would then provide a format method, which would convert the link and format it, according to the type.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

You can take _type and _link as keyword arguments, and so would simply your code. This can be as simple as func(_type=None, _link=None). However you may want to only take them if they are keyword arguments, and that method would allow them to be passed as normal positional arguments. To do this you can use prepend * to the function to do this. And so you can use func(*, _type=None, _link=None).

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.