Re: Test for structure
At the end of his last post, Steve Bethard wrote: That said, I find that in most cases, the better option is to use *args in the original function though. For example: def f(arg): args = aslist(arg) ... f(42) f(['spam', 'eggs', 'ham']) could probably be more easily written as: def f(*args): ... f(42) f('spam', 'eggs', 'ham') Of course this won't work if you have multiple list arguments. Very interesting, but it also doesn't let you specify a default argument value...however this gave me the idea that it would be possible to use the *args idea to greatly simplify the proposed aslist() function -- when one was needed to allow default argument values and/or for handling multiple list arguments. Namely: def aslist(*args): return list(args) def f(arg=None): args = aslist(arg) ... f() f(42) f('tanstaafl') f(['spam', 'eggs', 'ham']) This seems fairly lean and mean, with no if, isinstance, hasattr, or try/excepts required -- although aslist() might need a check for the single argument of None case, depending on whether it should return [] or something besides [None] in that situation. Best, Martin -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Ooops. I left out an * on a statement in the new aslist() function. I should have written: def aslist(*args): return list(*args) # corrected def f(arg): args = aslist(arg) ... Sorry, Martin -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Nope, that isn't right either, in the sense that it handles all the cases properly, including single string vs list of strings'. Guess this overly simplistic aslist() does not work after. I should have been more suspicious and cautious before posting. Sorry. Martin -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Yes, both string and lists have a __getitem__ attribute: c1 = 'abc' c2 = ['de', 'fgh', 'ijkl'] hasattr(c1, '__getitem__') True hasattr(c2, '__getitem__') True In other words you could index elements of either one using []. Likewise, both a string and list would produce a usable iterator using the following logic: try: itr = iter(a) except TypeError: # 'a' is not iterable else: # 'a' is iterable In either case, you can't tell a string and list apart, which is what the OP wanted to know, namely how to differentiate the two. EAPF is fine, but what operation would answer the string vs list question? Perhaps the test for an __iter__ attribute *is* the way to go because you can tell the difference between the two type. Again I don't know because the OP doesn't give enough information. I suspect, but don't know, that it could be so that either one string or a list of strings as an argument could treated as a list of 0 or more strings and accessed by indices by most of the rest of the code. I think the technique suggested by Robin Munn nearly a year ago (and referenced by the link in Simon Brunning's post): http://groups-beta.google.com/group/comp.lang.python/msg/c8befd4bed517bbc namely: try: a + '' except TypeError: pass else: a= [a] would be a good usable solution, although it's not totally infallible. It may not be possible to give a better answer without more real information about the desired usage. Martin = Steven Bethard wrote: Terry Hancock wrote: But you probably shouldn't do that. You should probably just test to see if the object is iterable --- does it have an __iter__ method? Which might look like this: if hasattr(a, '__iter__'): print 'a' quacks like a duck Martin Miller top-posted: I don't believe you can use the test for a __iter__ attribute in this case, for the following reason: c1 = 'abc' c2 = ['de', 'fgh', 'ijkl'] hasattr(c1, '__iter__') False hasattr(c2, '__iter__') True Right. str and unicode objects support iteration through the old __getitem__ protocol, not the __iter__ protocol. If you want to use something as an iterable, just use it and catch the exception: try: itr = iter(a) except TypeError: # 'a' is not iterable else: # 'a' is iterable Another lesson in why EAPF is often better than LBYL in Python[1]. STeVe [1] http://www.python.org/moin/PythonGlossary -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Steven Bethard wrote: Right. str and unicode objects support iteration through the old __getitem__ protocol, not the __iter__ protocol. If you want to use something as an iterable, just use it and catch the exception: try: itr = iter(a) except TypeError: # 'a' is not iterable else: # 'a' is iterable Martin Miller broke the order of reading by top-posting: In either case, you can't tell a string and list apart, which is what the OP wanted to know, namely how to differentiate the two. Yes, sorry, I should have marked my post OT. It was an answer to Terry Hancock's post suggesting hasattr(x, '__iter__'), not the OP. Perhaps the test for an __iter__ attribute *is* the way to go because you can tell the difference between the two type. I've seen this done before, e.g.: try: itr = iter(x) except TypeError: # is not iterable else: if hasattr(x, '__iter__'): # is other iterable else: # is str or unicode I don't like this idea much because it depends on str and unicode _not_ having a particular function. I haven't seen any guarantee anywhere that str or unicode won't ever grow an __iter__ method. So this code seems dangerous as far as future compatibility goes. I think the technique suggested by Robin Munn nearly a year ago (and referenced by the link in Simon Brunning's post): http://groups-beta.google.com/group/comp.lang.python/msg/c8befd4bed517bbc namely: try: a + '' except TypeError: pass else: a= [a] would be a good usable solution, although it's not totally infallible. Yup, if I had to do this kind of type-checking (which I don't think I ever do), I'd probably go with something along these lines. STeVe -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Testing for the '__iter__' (or even '__getitem__') attribute doesn't really address the problem, nor does trying to execute the statement 'itr = iter(a)'. To use EAPF and answer the OP's original question, which was So how can I test if a variable 'a' is either a single character string or a list? I think the best answer would be to use Robin Munn's suggestion (see http://groups-beta.google.com/group/comp.lang.python/msg/c8befd4bed517bbc) as mentioned in the link in Simon Brunning's post) namely: try: a + '' except TypeError: pass else: a = [a] However, to handle the more general problem of allow *any* argument to be either a single item or a list seems to require a combination of both EAPF and LBYL. This is the best solution I've been able to come up with so far: def asList(arg): Makes sure the argument it is passed is a Python list. If it is, it is just returned, otherwise a (possibly empty) list is created and returned with the single item in it. asList() can used to create flexible interfaces which allow arguments to be passed to them that are either single items or lists of items. By applying this function before using the values in arguments, single and multi-valued cases can be handled by general list-handling code in the function or method. As a special case, a single argument with the value None is converted into an empty list (instead of converted into the list [None]). asList(arg) == list if arg is None: return [] elif isinstance(arg, basestring): # special case strings (to # avoid list(string)) return [arg] else: try: return list(arg) except TypeError: return [arg] if __name__ == __main__: def example(items=None): Sample function that can be called with a single argument that can be a single or list of items. itemList = asList(items) if not itemList: print example() called with empty list or None argument else: print example() called with argument containing %d \ thing%s % \ (len(itemList), ('','s')[len(itemList)1]) for i, item in enumerate(itemList): print items[%d] = %s % (i, repr(item)) example(42) example((1,2,3)) example([4,5,6,7]) example('abc') example(u'def') example([aaa, 111, (4,5), 2.01]) example(None) # Note that this will become an empty list example() # same in this case Which produces the following output: example() called with argument containing 1 thing items[0] = 42 example() called with argument containing 3 things items[0] = 1 items[1] = 2 items[2] = 3 example() called with argument containing 4 things items[0] = 4 items[1] = 5 items[2] = 6 items[3] = 7 example() called with argument containing 1 thing items[0] = 'abc' example() called with argument containing 1 thing items[0] = u'def' example() called with argument containing 4 things items[0] = 'aaa' items[1] = 111 items[2] = (4, 5) items[3] = 2.0098 example() called with empty list or None argument example() called with empty list or None argument Can this be improved or is there anything wrong or overly limiting about it? TIA, Martin = Steven Bethard wrote: Terry Hancock wrote: But you probably shouldn't do that. You should probably just test to see if the object is iterable --- does it have an __iter__ method? Which might look like this: if hasattr(a, '__iter__'): print 'a' quacks like a duck Martin Miller top-posted: I don't believe you can use the test for a __iter__ attribute in this case, for the following reason: c1 = 'abc' c2 = ['de', 'fgh', 'ijkl'] hasattr(c1, '__iter__') False hasattr(c2, '__iter__') True Right. str and unicode objects support iteration through the old __getitem__ protocol, not the __iter__ protocol. If you want to use something as an iterable, just use it and catch the exception: try: itr = iter(a) except TypeError: # 'a' is not iterable else: # 'a' is iterable Another lesson in why EAPF is often better than LBYL in Python[1]. STeVe [1] http://www.python.org/moin/PythonGlossary -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Martin Miller broke the order of reading again by top-posting: However, to handle the more general problem of allow *any* argument to be either a single item or a list seems to require a combination of both EAPF and LBYL. This is the best solution I've been able to come up with so far: def asList(arg): [snip] if arg is None: return [] elif isinstance(arg, basestring): # special case strings (to # avoid list(string)) return [arg] else: try: return list(arg) except TypeError: return [arg] [snip] Can this be improved or is there anything wrong or overly limiting about it? I don't think you're going to do a whole lot better than that, though you can try something like the following if you're really afraid of the isinstance: def aslist(arg): # you don't need to test None; it will be caught by the list branch try: arg + '' except TypeError: return [arg] try: return list(arg) except TypeError: return [arg] That said, I find that in most cases, the better option is to use *args in the original function though. For example: def f(arg): args = aslist(arg) ... f(42) f(['spam', 'eggs', 'ham']) could probably be more easily written as: def f(*args): ... f(42) f('spam', 'eggs', 'ham') Of course this won't work if you have multiple list arguments. STeVe -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Steven Bethard [EMAIL PROTECTED] wrote in message news:[EMAIL PROTECTED] I don't like this idea much because it depends on str and unicode _not_ having a particular function. I haven't seen any guarantee anywhere that str or unicode won't ever grow an __iter__ method. So this code seems dangerous as far as future compatibility goes. When CPython's support for the old iteration protocol goes away, which I expects it will someday, strings will have to grow an __iter__ method. Even now, I think this difference between strings and lists is more of an accident than a logical design. So the test is opaque and specific to current CPython. The validity of something like a = a+'', however, is inherent to the nature of strings. Terry J. Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
I don't believe you can use the test for a __iter__ attribute in this case, for the following reason: c1 = 'abc' c2 = ['de', 'fgh', 'ijkl'] hasattr(c1, '__iter__') False hasattr(c2, '__iter__') True for i in c1: print i=%s is an element of c1 % repr(i) ... i='a' is an element of c1 i='b' is an element of c1 i='c' is an element of c1 In other words, even though the c1 single string variable does not have an __iter__ attribute, it can still be used in a for loop. I think the right answer would depend on what exactly the OP intends to do with the argument when it is a list (or is list-like in some way) -- i.e. he didn't say specifically that he wanted use it in a for loop. -Martin Terry Hancock wrote: On Wednesday 16 February 2005 09:08 am, alex wrote: how can I check if a variable is a structure (i.e. a list)? For my special problem the variable is either a character string OR a list of character strings line ['word1', 'word2',...] So how can I test if a variable 'a' is either a single character string or a list? The literally correct but actually wrong answer is: if type(a) == type([]): print 'a' is a duck But you probably shouldn't do that. You should probably just test to see if the object is iterable --- does it have an __iter__ method? Which might look like this: if hasattr(a, '__iter__'): print 'a' quacks like a duck That way your function will also work if a happens to be a tuple, a dictionary, or a user-defined class instance which is happens to be iterable. Being iterable means that code like: for i in a: print i=%s is an element of a % repr(i) works. Which is probably why you wanted to know, right? Cheers, Terry -- -- Terry Hancock ( hancock at anansispaceworks.com ) Anansi Spaceworks http://www.anansispaceworks.com -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Terry Hancock wrote: But you probably shouldn't do that. You should probably just test to see if the object is iterable --- does it have an __iter__ method? Which might look like this: if hasattr(a, '__iter__'): print 'a' quacks like a duck Martin Miller top-posted: I don't believe you can use the test for a __iter__ attribute in this case, for the following reason: c1 = 'abc' c2 = ['de', 'fgh', 'ijkl'] hasattr(c1, '__iter__') False hasattr(c2, '__iter__') True Right. str and unicode objects support iteration through the old __getitem__ protocol, not the __iter__ protocol. If you want to use something as an iterable, just use it and catch the exception: try: itr = iter(a) except TypeError: # 'a' is not iterable else: # 'a' is iterable Another lesson in why EAPF is often better than LBYL in Python[1]. STeVe [1] http://www.python.org/moin/PythonGlossary -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
On Wednesday 16 February 2005 09:08 am, alex wrote: how can I check if a variable is a structure (i.e. a list)? For my special problem the variable is either a character string OR a list of character strings line ['word1', 'word2',...] So how can I test if a variable 'a' is either a single character string or a list? The literally correct but actually wrong answer is: if type(a) == type([]): print 'a' is a duck But you probably shouldn't do that. You should probably just test to see if the object is iterable --- does it have an __iter__ method? Which might look like this: if hasattr(a, '__iter__'): print 'a' quacks like a duck That way your function will also work if a happens to be a tuple, a dictionary, or a user-defined class instance which is happens to be iterable. Being iterable means that code like: for i in a: print i=%s is an element of a % repr(i) works. Which is probably why you wanted to know, right? Cheers, Terry -- -- Terry Hancock ( hancock at anansispaceworks.com ) Anansi Spaceworks http://www.anansispaceworks.com -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
On Wed, 16 Feb 2005 07:11:08 -0800 (PST), alex [EMAIL PROTECTED] wrote: how can I check if a variable is a structure (i.e. a list)? For my special problem the variable is either a character string OR a list of character strings line ['word1', 'word2',...] So how can I test if a variable 'a' is either a single character string or a list? I tried: if a is list: but that does not work. I also looked in the tutorial and used google to find an answer, but I did not. Has anyone an idea about that? http://www.brunningonline.net/simon/blog/archives/001349.html -- Cheers, Simon B, [EMAIL PROTECTED], http://www.brunningonline.net/simon/blog/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Perhaps you're looking for the type() built in function and the types modules? type('aaa') type 'str' type([]) type 'list' import types if type([]) is types.ListType: ... print 'is a list' ... is a list Chris On Wed, 16 Feb 2005 07:10:56 -0800 (PST), alex [EMAIL PROTECTED] wrote: Hi there, how can I check if a variable is a structure (i.e. a list)? For my special problem the variable is either a character string OR a list of character strings line ['word1', 'word2',...] So how can I test if a variable 'a' is either a single character string or a list? I tried: if a is list: but that does not work. I also looked in the tutorial and used google to find an answer, but I did not. Has anyone an idea about that? Alex -- http://mail.python.org/mailman/listinfo/python-list -- It is our responsibilities, not ourselves, that we should take seriously. -- Peter Ustinov -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
import types v = [] if type(v) is types.ListType: pass -- Regards, Diez B. Roggisch -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
alex wrote: So how can I test if a variable 'a' is either a single character string or a list? py def test(x): ... return (isinstance(x, list) or ... isinstance(x, basestring) and len(x) == 1) ... py test('a') True py test('ab') False py test([]) True py test(['a', 'b']) True But definitely read Simon Brunning's post - you probably don't actually want to do this test. Why do you think you want to test this? What's your use case? STeVe -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
I use a function isListLike in cases such as this one: # def isListLike(L): # Return True if L is list-like, False otherwise. # try: # L + [] # return True # except: # return False Then you can use a standard if-else construct: # if isListLike(myvar): # do something # else: # do something else Michael -- Michael D. Hartl, Ph.D. Chief Technology Officer http://quarksports.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Test for structure
Michael Hartl wrote: I use a function isListLike in cases such as this one: # def isListLike(L): # Return True if L is list-like, False otherwise. # try: # L + [] # return True # except: # return False Then you can use a standard if-else construct: # if isListLike(myvar): # do something # else: # do something else What kind of situations do you use this for? I almost never have to do this kind of typechecking. If it's supposed to be a list, I just use it as a list... STeVe -- http://mail.python.org/mailman/listinfo/python-list