69

In python 2.6, the following code:

import urlparse
qsdata = "test=test&test2=test2&test2=test3"
qs = urlparse.parse_qs(qsdata)
print qs

Gives the following output:

{'test': ['test'], 'test2': ['test2', 'test3']}

Which means that even though there is only one value for test, it is still being parsed into a list. Is there a way to ensure that if there's only one value, it is not parsed into a list, so that the result would look like this?

{'test': 'test', 'test2': ['test2', 'test3']}
3
  • 13
    isn't it more consistent that all values are list and you do not have to worry if it is a list or a single value, why would you want otherwise? Commented Jun 21, 2009 at 15:30
  • 3
    The HTTP standard means it has to be a list. There don't seem to be a lot of alternatives. Commented Jun 21, 2009 at 20:51
  • All of urls I met so far were something like " https:// www.example.com/api/v1/resource?queryA=1&queryB=2". I don't understand why the HTTP standard insists the value should be a "list". I think a string is enough. Could anyone give me an instance, please? Commented Dec 26, 2020 at 17:06

3 Answers 3

177

A sidenote for someone just wanting a simple dictionary and never needing multiple values with the same key, try:

dict(urlparse.parse_qsl('foo=bar&baz=qux'))

This will give you a nice {'foo': 'bar', 'baz': 'qux'}. Please note that if there are multiple values for the same key, you'll only get the last one.

Sign up to request clarification or add additional context in comments.

5 Comments

Doesn't parse_qsl() give you a list of key-value pairs (and not a dict)?
@MisterBhoot Yes, that's why I have the dict(...) call around it. :)
My bad, sorry. I should start sleeping early now.
that doesn't work, it's still a dict of query_params to lists
Note: The urlparse module is renamed to urllib.parse in Python 3; hence, urllib.parse.parse_qsl(). Most important, the above approach wouldn't work in a scenario where a query param expects a list of values and may appear multiple times in the URL. For instance, this dict(urllib.parse.parse_qsl('foo=2&bar=7&foo=10')) would return {"foo":"10","bar":"7"} instead of {"foo":["2","10"],"bar":"7"}. The approach described in this answer, however, takes care of that.
31

You could fix it afterwards...

import urlparse
qsdata = "test=test&test2=test2&test2=test3"
qs = dict( (k, v if len(v)>1 else v[0] ) 
           for k, v in urlparse.parse_qs(qsdata).iteritems() )
print qs

However, I don't think I would want this. If a parameter that is normally a list happens to arrive with only one item set, then I would have a string instead of the list of strings I normally receive.

Comments

0

Expanding on @SingleNegationElimination answer a bit. If you do something like this, you can use only the last instance of a query parameter.

from urllib.parse import parse_qs
qsdata = "test=test&test2=test2&test2=test3"
dict((k, v[-1] if isinstance(v, list) else v)
      for k, v in parse_qs(qsdata).items())

# Returns: {'test': 'test', 'test2': 'test3'}

Or you can retain only the first instance of a url parameter with the following:

from urllib.parse import parse_qs
qsdata = "test=test&test2=test2&test2=test3"
dict((k, v[0] if isinstance(v, list) else v)
      for k, v in parse_qs(qsdata).items())

# Returns: {'test': 'test', 'test2': 'test2'}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.