Parsing a URL
Never take URLs apart with split. Encoding rules and optional parts make that fragile. urllib.parse handles them.
from urllib.parse import (
urlsplit, parse_qsl, urlencode)
u = urlsplit(
"https://a.io:8000/s?q=a+b&p=2#top")
print(u.scheme, u.hostname, u.port)
print(u.path, u.query, u.fragment)
print(parse_qsl(u.query))
# [('q', 'a b'), ('p', '2')]
print(urlencode({"q": "a b"}))
# q=a+bu.portisNonewhen the URL does not state one.parse_qsldrops parameters with blank values unless you passkeep_blank_values=True.parse_qsreturns a dict of lists, since a key may repeat.- A split URL is a named tuple, so
u._replace(query="x=1").geturl()builds a new URL with one part changed.
quote and unquote handle percent-encoding, and urljoin resolves relative links.
Your task
Write query_params(url) returning a dict from each key to its first value, keeping blank values. Write add_param(url, key, value) setting one query parameter, replacing it in place if present, otherwise appending, and leaving other URL parts alone. Write host_and_port(url) returning (host, port), using 443 for https and 80 for http when none is given.
The explanation opens here once every check passes.