Pythonic Way To Convert Variable To List
Solution 1:
Typically, strings (plain and unicode) are the only iterables that you want to nevertheless consider as "single elements" -- the basestring builtin exists SPECIFICALLY to let you test for either kind of strings with isinstance, so it's very UN-grotty for that special case;-).
So my suggested approach for the most general case is:
ifisinstance(input, basestring): input = [input]
else:
try: iter(input)
except TypeError: input = [input]
else: input = list(input)
This is THE way to treat EVERY iterable EXCEPT strings as a list directly, strings and numbers and other non-iterables as scalars (to be normalized into single-item lists).
I'm explicitly making a list out of every kind of iterable so you KNOW you can further on perform EVERY kind of list trick - sorting, iterating more than once, adding or removing items to facilitate iteration, etc, all without altering the ACTUAL input list (if list indeed it was;-). If all you need is a single plain for loop then that last step is unnecessary (and indeed unhelpful if e.g. input is a huge open file) and I'd suggest an auxiliary generator instead:
defjustLoopOn(input):
ifisinstance(input, basestring):
yieldinputelse:
try:
for item ininput:
yield item
except TypeError:
yieldinputnow in every single one of your functions needing such argument normalization, you just use:
for item in justLoopOn(input):
You can use an auxiliary normalizing-function even in the other case (where you need a real list for further nefarious purposes); actually, in such (rarer) cases, you can just do:
thelistforme = list(justLoopOn(input))
so that the (inevitably) somewhat-hairy normalization logic is just in ONE place, just as it should be!-)
Solution 2:
I like Andrei Vajna's suggestion of hasattr(var,'__iter__'). Note these results from some typical Python types:
>>> hasattr("abc","__iter__")
False>>> hasattr((0,),"__iter__")
True>>> hasattr({},"__iter__")
True>>> hasattr(set(),"__iter__")
TrueThis has the added advantage of treating a string as a non-iterable - strings are a grey area, as sometimes you want to treat them as an element, other times as a sequence of characters.
Note that in Python 3 the str type does have the __iter__ attribute and this does not work:
>>> hasattr("abc", "__iter__")
TrueSolution 3:
First, there is no general method that could tell a "single element" from "list of elements" since by definition list can be an element of another list.
I would say you need to define what kinds of data you might have, so that you might have:
- any descendant of
listagainst anything else- Test with
isinstance(input, list)(so your example is correct)
- Test with
- any sequence type except strings (
basestringin Python 2.x,strin Python 3.x)- Use sequence metaclass:
isinstance(myvar, collections.Sequence) and not isinstance(myvar, str)
- Use sequence metaclass:
- some sequence type against known cases, like
int,str,MyClass- Test with
isinstance(input, (int, str, MyClass))
- Test with
- any iterable except strings:
- Test with
.
try:
input = iter(input) ifnotisinstance(input, str) else [input]
except TypeError:
input = [input]
Solution 4:
You can put * before your argument, this way you'll always get a tuple:
defa(*p):
printtype(p)
print p
a(4)
>>> <type'tuple'>
>>> (4,)
a(4, 5)
>>> <type'tuple'>
>>> (4,5,)
But that will force you to call your function with variable parameters, I don't know if that 's acceptable for you.
Solution 5:
You can do direct type comparisons using type().
defmy_func(input):
ifnottype(input) islist:
input = [input]
for e ininput:
# do somethingHowever, the way you have it will allow any type derived from the list type to be passed through. Thus preventing the any derived types from accidentally being wrapped.
Post a Comment for "Pythonic Way To Convert Variable To List"