9

I have a variable which can be a single string or a list of string. When the variable is a single string , the loop iterates it by char.

text = function() # the function method can return a single string or list of string
for word in text:
    print word+"/n"
# When it is a single string , it prints char by char.

I would want the loop to iterate only one time when it is a single string. I actually do not want to use other loop types. How can I do it with for each structure?

3

6 Answers 6

12

It would be cleaner if your function would always return a list even one with only one element. I would highly recommend this if you can change your code there.

Otherwise add this line before your loop:

text = text if isinstance(text, list) else [text]

Also your variable names are confusing you should call "text" "word_list" or something just to better indicate the type required.

Requiring type checking usually indicates a problem of style.

1
  • Thx, obviously, the lists confused me here:) Commented Nov 29, 2016 at 18:47
1

This should do it:

text = function() 
if isinstance(text, list):
    for word in text:
        print word + "/n"
else:
    print text + "/n"
2
  • This is not a pythonic way of doing things, since if function() returns a tuple of strings then you're code would attempt to print the entire tuple as one word.
    – A Kareem
    Commented Dec 27, 2020 at 20:23
  • From the question, it is obvious that function returns either string or list of strings... Not a tuple.
    – Fejs
    Commented Dec 29, 2020 at 4:19
1

I settled on this because it puts an emphasis on preparation for a loop rather than a fundamental loop (re)design:

if type(thing) is str:
    x = [thing]
elif type(thing) is list:
    x = thing[:]

for i in x:
   ... do stuff ....
0

Despite duck typing being the norm, sometimes you simply must check the type of something. In this case, you expect something of instance basestring.

text = function()
if isinstance(text, basestring):
    print text
else:
    for word in text:
        print word
4
  • 1
    basestring is python2 only
    – tacaswell
    Commented Nov 29, 2016 at 18:42
  • @tacaswell "python-2.7" tag
    – Brian
    Commented Nov 29, 2016 at 18:43
  • won't let me change my vote anymore. Better to use six or pies.
    – tacaswell
    Commented Nov 29, 2016 at 18:50
  • Also print statement in code, so you'll need a print_function import. We must have read different questions.
    – Brian
    Commented Nov 29, 2016 at 19:00
0

Still doable by duck typing, you just need to use a method on a list that is not in a string or vice versa, and catch the exception, for example copy() is a method of list but not str.

text = function()
try:
    temp_text = text.copy()
    for word in text:
        print word
except AttributeError:
    print text

In the above code if function() returned a string text.copy() will rise an AttributeError exception and will not go through the for loop but go to the exception block and print the text as is, on the other hand if text.copy() is successful it means it is a list and it continues to the for loop to print each word of the list.

1
  • You could just check for the attribute instead of actually executing the method: assert(hasattr(text, 'copy')). You would get an AssertionError in case that would be false. Even though it is said that raising exceptions is better than type-checking, it would be interesting which one would perform better. Commented Nov 29, 2016 at 18:55
0

You need isinstance() method to check the type of value hold by your variable which as per document:

Return true if the object argument is an instance of the classinfo argument, or of a (direct, indirect or virtual) subclass thereof.

Using that you may create your custom function as:

import collections

def my_print(my_val):
    if isinstance(my_val, str):
        print my_val
    elif isinstance(my_val, collections.Iterable):  # OR, use `list` if you just want check for list object
        # To check object is iterable ^
        for val in my_val:
            print val
    else:
       raise TypeError('Unknown value')

Sample run:

>>> my_print('Hello')
Hello
>>> my_print(['Hello', 'World'])
Hello
World

instance() checks whether the object passed is the instance of passed class or not.

>>> isinstance('hello', str)
True
>>> isinstance('hello', list)
False

Alternatively, you may check for the type of variable using type() as:

>>> type('hello') == str
True
4
  • This will fail with tuples
    – tacaswell
    Commented Nov 29, 2016 at 18:43
  • @tacaswell: Thanks for the comment. Updated it Commented Nov 29, 2016 at 18:45
  • You only really need to special case str and let duck typing take care of the rest.
    – tacaswell
    Commented Nov 29, 2016 at 18:47
  • I am handling it explicitly for cases when int or any other value is passed to the function Commented Nov 29, 2016 at 18:53

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.