[Tutor] pass tuples to user defined function(beginner)

Peter Otten __peter__ at web.de
Tue Nov 29 13:38:32 CET 2011


Steven D'Aprano wrote:

> bob gailer wrote:
>> On 11/28/2011 12:47 PM, James Reynolds wrote:
>>>
>>>
>>> On Mon, Nov 28, 2011 at 12:32 PM, Mayo Adams <mayoadams at gmail.com
>>> <mailto:mayoadams at gmail.com>> wrote:
>>>
>>>     I am trying to pass a set of tuple strings from a file to a
>>> function I
>>>     have defined.  Each tuple is on a separate line, and looks something
>>>     like this:
>>>      ('note',2048)
>>>
>> 
>> As already pointed out - this is a string (a representation of a tuple),
>> not a tuple.
>> 
>> Your code must parse the string to extract the string representations of
>> the values, then convert as needed to the desired Python values.
>> 
>> Tasks like this are not trivial.
> 
> 
> In general, parsing can be a hard problem. In this case though, it is easy
> to solve 95% of the problem with a hand-built converter, which may be good
> enough.
> 
> def strto2tuple(s):
>      """Convert a string like "('abc', 42)" to a tuple with two items."""
>      # Ignore leading and trailing whitespace.
>      s = s.strip()
>      # Check for round brackets (parentheses), and remove them.
>      if s[0] != '(' or s[-1] != ')':
>          raise ValueError('malformed string, missing ( or )')
>      s = s[1:-1]
>      # Split the string into exactly two pieces.
>      # FIXME this assumes that the first item contains no commas.
>      items = s.split(',')
>      n = len(items)
>      if n != 2:
>          raise ValueError('expected exactly two items but found %d' % n)
>      a, b = items
>      # Ignore spaces around each item, e.g. ( 'abc' , 42 ) => ('abc', 42)
>      a = a.strip()
>      b = b.strip()
>      # Make sure that the first item looks like a string.
>      quotes = '"\''  # FIXME no support for triple quotes yet, or raw
>      strings. assert len(quotes) == 2
>      for q in quotes:
>          if a.startswith(q) and a.endswith(q):
>              # Don't include the delimiter quotes in the string.
>              a = a[1:-1]
>              break
>      else:
>          # This executes if we don't hit a break in the for loop.
>          raise ValueError('mismatched or missing quotes')
>      assert isinstance(a, str)
>      # Make sure the second item is an integer.
>      b = int(b, 0)  # Support hex and octal formats too.
>      return (a, b)  # And return a real tuple.
> 
> 
> This untested function will convert strings in a file like these:
> 
> (  'fe', 1)
> (  'fi' ,2 )
>        ("fo",0x03)
> ( "fum"    ,   4  )
> 
> into proper tuples with a string and a number. Notice that we allow the
> user to be sloppy with spaces, but we are strict about quotation marks and
> brackets.
> 
> 
> Our converter function is both a little too strict (e.g. it forbids the
> user from including triple-quoted strings) and a little too lax (e.g. it
> allows malformed strings like ''abc'). You might not care about these
> weaknesses. If you do, you need to move up to a real parser, which is
> significantly more complex.

And here's the lazy-bastard version:

>>> lines = """(  'fe', 1)
... (  'fi' ,2 )
...        ("fo",0x03)
... ( "fum"    ,   4  )
... ("gvn", __import__("os").remove("that could be your valuable data.txt"))
... """.splitlines()
>>> import ast
>>> for line in lines:
...     print ast.literal_eval(line.strip())
...
('fe', 1)
('fi', 2)
('fo', 3)
('fum', 4)
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/lib/python2.6/ast.py", line 68, in literal_eval
    return _convert(node_or_string)
  File "/usr/lib/python2.6/ast.py", line 58, in _convert
    return tuple(map(_convert, node.elts))
  File "/usr/lib/python2.6/ast.py", line 67, in _convert
    raise ValueError('malformed string')
ValueError: malformed string




More information about the Tutor mailing list