-1

I'm new to programming and have a requirement wherein I have to iterate through the elements of an input. The input can be a string, a list (mostly) or a dict. I wrote some code to check if the given input is a string or a list or a dict etc., but I'm wondering if there is an easier way to do it.

For example, I check as follows:

 if isinstance(vlan, list):
      for i in  vlan:
          <<do some operation here>>
 if isinstance(vlan, string):
      <<do some operation here>>
 if isinstance(vlan, dict):
      for i in vlan.keys()
         <<do some operation here>>

This operation I have to carry out a lot of times (although I can write a function do expand and send the elements I'm just wondering if there is any alternate to it).

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
VijayS
  • 81
  • 4
  • 3
    What would be a good solution depends on *what* "do some operation" is for each type. Please add more details. – mkrieger1 Feb 20 '20 at 07:55
  • Does this answer your question? [What's the canonical way to check for type in Python?](https://stackoverflow.com/questions/152580/whats-the-canonical-way-to-check-for-type-in-python) – mkrieger1 Feb 20 '20 at 07:56
  • 1
    For example, you can iterate over strings, lists, and dictionaries using the same code without checking the type at all. This is called *duck typing*. – mkrieger1 Feb 20 '20 at 07:58

3 Answers3

1
 if isinstance(vlan, list):
     for i in  vlan:
         <<do some operation here>>
 if isinstance(vlan, dict):
     for i in vlan.keys()
         <<do some operation here>>

Python's dict iteration uses keys, so these are redundant and you can collapse then (and any other non-string iterable) as just:

for i in vlan:
    # some operation

Then, assuming "do some operation here" is always the same thing and you want to apply the operation to a string if you get a string and to each item if you get a collection of strings, just wrap the string in a list beforehand:

if isinstance(vlan, str):
    vlan = [vlan]
for i in vlan:
    # do some operation here

It's common to do this sort of special-casing / wrapping of str specifically as Python's strings are iterable but it's often desirable to treat them as atomic instead.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
1

Given this:

This operation i have to carry out a lot of times

I take it that your question is about how to avoid repeating this code pattern in multiple functions. The answer more or less depends on concrete use cases - and specially if the "do_some_operation_here" is the same for all three types or not.

In the first case, a simple generic wrapper around map(func, iterable) is the obvious simple solution:

def mapply(func, iterable):
    # first weed out the special case
    if isinstance(iterable, str):
       iterable = [iterable]
    return map(func, iterable)

But I assume your use case is a bit more complicated with slight type-specific variations in the "do_some_op" part. In this case, the template method pattern might be a good fit:

import abc

class BaseMapper(metaclass=abc.ABCMeta):
    def apply(self, obj):
        if instance(obj, list):
            return self._apply_list(obj)
        if isinstance(obj, str)
            return self._apply_str(obj)
        if isinstance(obj, dict):
            return self._apply_dict(obj)

     @abc.abstractmethod
     def _apply_list(self, obj):
         # handle a list
     @abc.abstractmethod
     def _apply_dict(self, obj):
         # handle a dict

     @abc.abstractmethod
     def _apply_str(self, obj):
         # handle a str

Then you just have to subclass this and implement the abstract methods.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
-3

Use elif instead of if:

 if isinstance(vlan, list):
      for i in  vlan:
          <<do some operation here>>
 elif isinstance(vlan, str):
      <<do some operation here>>
 elif isinstance(vlan, dict):
      for i in vlan.keys():
         <<do some operation here>>
Vaibhav Jadhav
  • 2,020
  • 1
  • 7
  • 20