Test for structure

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • alex

    #1

    Test for structure

    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

  • Diez B. Roggisch

    #2
    Re: Test for structure

    import types

    v = []
    if type(v) is types.ListType:
    pass


    --
    Regards,

    Diez B. Roggisch

    Comment

    • Simon Brunning

      #3
      Re: Test for structure

      On Wed, 16 Feb 2005 07:11:08 -0800 (PST), alex
      <alexander.diet z@mpi-hd.mpg.de> wrote:[color=blue]
      > 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?[/color]

      <http://www.brunningonl ine.net/simon/blog/archives/001349.html>

      --
      Cheers,
      Simon B,
      simon@brunningo nline.net,

      Comment

      • Chris Cioffi

        #4
        Re: Test for structure

        Perhaps you're looking for the type() built in function and the types modules?
        [color=blue][color=green][color=darkred]
        >>> type('aaa')[/color][/color][/color]
        <type 'str'>[color=blue][color=green][color=darkred]
        >>> type([])[/color][/color][/color]
        <type 'list'>[color=blue][color=green][color=darkred]
        >>> import types
        >>> if type([]) is types.ListType:[/color][/color][/color]
        .... print 'is a list'
        ....
        is a list

        Chris

        On Wed, 16 Feb 2005 07:10:56 -0800 (PST), alex
        <alexander.diet z@mpi-hd.mpg.de> wrote:[color=blue]
        > 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
        >[/color]


        --
        "It is our responsibilitie s, not ourselves, that we should take
        seriously." -- Peter Ustinov

        Comment

        • Steven Bethard

          #5
          Re: Test for structure

          alex wrote:[color=blue]
          > So how can I test if a variable 'a' is either a single character string
          > or a list?[/color]

          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

          Comment

          • Michael Hartl

            #6
            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(myva r):
            # <do something>
            # else:
            # <do something else>

            Michael

            --
            Michael D. Hartl, Ph.D.
            Chief Technology Officer
            Hangzhou Quark Sports Goods Co., Ltd: Find professional pickleball paddle, padel racket, popular pickleball paddle, high spin pickleball paddle manufacturers in China here! Please feel free to wholesale high quality sports goods at competitive price from our factory. Contact us for custom service and OEM service.


            Comment

            • Steven Bethard

              #7
              Re: Test for structure

              Michael Hartl wrote:[color=blue]
              > 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(myva r):
              > # <do something>
              > # else:
              > # <do something else>[/color]

              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

              Comment

              • Ben Finney

                #8
                Re: Test for structure

                alex wrote On 17/02/05 02:08:[color=blue]
                > 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',...][/color]

                You're trying to apply the LBYL principle. My bet is that your "special
                problem" can be solved by the EAFP principle. (These terms are
                explained in the Glossary of the tutorial,
                <http://www.python.org/doc/current/tut/node18.html>.)

                If you test for a specific set of types, your code will not work with
                types that you have not considered yet behave like lists. As you
                discover more object types that you want the code to work with, it will
                sprout more cruft for checking those types.

                If you want to use some list behaviour of the object, don't check first.
                Use it, and catch the TypeError exception in the event that it's not.
                This way, *any* object that implements the functionality you need will
                work, regardless of its type.

                Comment

                • Terry Hancock

                  #9
                  Re: Test for structure

                  On Wednesday 16 February 2005 09:08 am, alex wrote:[color=blue]
                  > 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?[/color]

                  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 anansispacework s.com )
                  Anansi Spaceworks http://www.anansispaceworks.com

                  Comment

                  • Martin Miller

                    #10
                    Re: Test for structure

                    I don't believe you can use the test for a __iter__ attribute in this
                    case, for the following reason:[color=blue][color=green][color=darkred]
                    >>> c1 = 'abc'
                    >>> c2 = ['de', 'fgh', 'ijkl']
                    >>> hasattr(c1, '__iter__')[/color][/color][/color]
                    False[color=blue][color=green][color=darkred]
                    >>> hasattr(c2, '__iter__')[/color][/color][/color]
                    True[color=blue][color=green][color=darkred]
                    >>> for i in c1: print "i=%s is an element of c1" % repr(i)[/color][/color][/color]
                    ....
                    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:[color=blue]
                    > On Wednesday 16 February 2005 09:08 am, alex wrote:[color=green]
                    > > 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[/color][/color]
                    of[color=blue][color=green]
                    > > character strings line ['word1', 'word2',...]
                    > >
                    > > So how can I test if a variable 'a' is either a single character[/color][/color]
                    string[color=blue][color=green]
                    > > or a list?[/color]
                    >
                    > 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 anansispacework s.com )
                    > Anansi Spaceworks http://www.anansispaceworks.com[/color]

                    Comment

                    • Steven Bethard

                      #11
                      Re: Test for structure

                      Terry Hancock wrote:[color=blue]
                      > 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"[/color]

                      Martin Miller top-posted:[color=blue]
                      > I don't believe you can use the test for a __iter__ attribute in this
                      > case, for the following reason:
                      >[color=green][color=darkred]
                      >>>>c1 = 'abc'
                      >>>>c2 = ['de', 'fgh', 'ijkl']
                      >>>>hasattr(c 1, '__iter__')[/color][/color]
                      > False
                      >[color=green][color=darkred]
                      >>>>hasattr(c 2, '__iter__')[/color][/color]
                      > True[/color]

                      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

                      Comment

                      • Martin Miller

                        #12
                        Re: Test for structure

                        Yes, both string and lists have a __getitem__ attribute:
                        [color=blue][color=green][color=darkred]
                        >>> c1 = 'abc'
                        >>> c2 = ['de', 'fgh', 'ijkl']
                        >>> hasattr(c1, '__getitem__')[/color][/color][/color]
                        True[color=blue][color=green][color=darkred]
                        >>> hasattr(c2, '__getitem__')[/color][/color][/color]
                        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):

                        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:[color=blue]
                        > Terry Hancock wrote:[color=green]
                        > > But you probably shouldn't do that. You should probably just test[/color][/color]
                        to[color=blue][color=green]
                        > > 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"[/color]
                        >
                        > Martin Miller top-posted:[color=green]
                        > > I don't believe you can use the test for a __iter__ attribute in[/color][/color]
                        this[color=blue][color=green]
                        > > case, for the following reason:
                        > >[color=darkred]
                        > >>>>c1 = 'abc'
                        > >>>>c2 = ['de', 'fgh', 'ijkl']
                        > >>>>hasattr(c 1, '__iter__')[/color]
                        > > False
                        > >[color=darkred]
                        > >>>>hasattr(c 2, '__iter__')[/color]
                        > > True[/color]
                        >
                        > 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[/color]

                        Comment

                        • Steven Bethard

                          #13
                          Re: Test for structure

                          > Steven Bethard wrote:[color=blue][color=green]
                          >>
                          >>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[/color][/color]

                          Martin Miller broke the order of reading by top-posting:[color=blue]
                          > 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.[/color]

                          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.
                          [color=blue]
                          > Perhaps the test for an __iter__ attribute *is* the way to go because
                          > you can tell the difference between the two type.[/color]

                          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.
                          [color=blue]
                          > 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/...befd4bed517bbc
                          > namely:
                          >
                          > try:
                          > a + ''
                          > except TypeError:
                          > pass
                          > else:
                          > a= [a]
                          >
                          > would be a good usable solution, although it's not totally infallible.[/color]

                          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

                          Comment

                          • Martin Miller

                            #14
                            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
                            [color=blue]
                            > So how can I test if a variable 'a' is either a single character
                            > string or a list?[/color]

                            I think the best answer would be to use Robin Munn's suggestion (see
                            http://groups-beta.google.com/group/...befd4bed517bbc)
                            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=N one):
                            """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(itemL ist):
                            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.0099999999999 998
                            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:[color=blue]
                            > Terry Hancock wrote:[color=green]
                            > > But you probably shouldn't do that. You should probably just test[/color][/color]
                            to[color=blue][color=green]
                            > > 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"[/color]
                            >
                            > Martin Miller top-posted:[color=green]
                            > > I don't believe you can use the test for a __iter__ attribute in[/color][/color]
                            this[color=blue][color=green]
                            > > case, for the following reason:
                            > >[color=darkred]
                            > >>>>c1 = 'abc'
                            > >>>>c2 = ['de', 'fgh', 'ijkl']
                            > >>>>hasattr(c 1, '__iter__')[/color]
                            > > False
                            > >[color=darkred]
                            > >>>>hasattr(c 2, '__iter__')[/color]
                            > > True[/color]
                            >
                            > 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[/color]

                            Comment

                            • Steven Bethard

                              #15
                              Re: Test for structure

                              Martin Miller broke the order of reading again by top-posting:[color=blue]
                              > 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):[/color]
                              [snip][color=blue]
                              > 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]
                              >[/color]
                              [snip][color=blue]
                              > Can this be improved or is there anything wrong or overly limiting
                              > about it?[/color]

                              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

                              Comment

                              Working...