1. Проблема устаревания
В Python 3.7 я загружаю большой файл из URL
, используя функцию urllib.request.urlretrieve(..)
. В документации (https://docs.python.org/3/library/urllib.request.html) я прочитал следующее чуть выше urllib.request.urlretrieve(..)
документов:
Устаревший интерфейс
Следующие функции и классы портированы из urllib модуля Python 2 (в отличие от urllib2). Они могут устареть в какой-то момент в будущем.
2. Поиск альтернативы
Чтобы сохранить мой код в будущем, я ищу альтернативу. В официальных документах по Python конкретный документ не упоминается, но, похоже, urllib.request.urlopen(..)
- самый простой кандидат. Это вверху страницы документации.
К сожалению, альтернативы, такие как urlopen(..)
- , не предоставляют аргумент reporthook
. Этот аргумент может быть вызван функцией urlretrieve(..)
. В свою очередь, urlretrieve(..)
регулярно вызывает его со следующими аргументами:
- номер блока.
- размер блока
- общий размер файла
Я использую его для обновления индикатора выполнения. Вот почему я пропускаю аргумент reporthook
в альтернативах.
3. urlretrieve (..) и urlopen (..)
Я обнаружил, что urlretrieve(..)
просто использует urlopen(..)
. См. Файл кода request.py
в установке Python 3.7 (Python37 / Lib / urllib / request.py):
_url_tempfiles = []
def urlretrieve(url, filename=None, reporthook=None, data=None):
"""
Retrieve a URL into a temporary location on disk.
Requires a URL argument. If a filename is passed, it is used as
the temporary file location. The reporthook argument should be
a callable that accepts a block number, a read size, and the
total file size of the URL target. The data argument should be
valid URL encoded data.
If a filename is passed and the URL points to a local resource,
the result is a copy from local file to new file.
Returns a tuple containing the path to the newly created
data file as well as the resulting HTTPMessage object.
"""
url_type, path = splittype(url)
with contextlib.closing(urlopen(url, data)) as fp:
headers = fp.info()
# Just return the local path and the "headers" for file://
# URLs. No sense in performing a copy unless requested.
if url_type == "file" and not filename:
return os.path.normpath(path), headers
# Handle temporary file setup.
if filename:
tfp = open(filename, 'wb')
else:
tfp = tempfile.NamedTemporaryFile(delete=False)
filename = tfp.name
_url_tempfiles.append(filename)
with tfp:
result = filename, headers
bs = 1024*8
size = -1
read = 0
blocknum = 0
if "content-length" in headers:
size = int(headers["Content-Length"])
if reporthook:
reporthook(blocknum, bs, size)
while True:
block = fp.read(bs)
if not block:
break
read += len(block)
tfp.write(block)
blocknum += 1
if reporthook:
reporthook(blocknum, bs, size)
if size >= 0 and read < size:
raise ContentTooShortError(
"retrieval incomplete: got only %i out of %i bytes"
% (read, size), result)
return result
4. Заключение
Из всего этого я вижу три возможных решения:
Я сохраняю свой код без изменений . Будем надеяться, что функция urlretrieve(..)
не устареет в ближайшее время.
Я пишу себе замещающую функцию , которая ведет себя как urlretrieve(..)
снаружи и использует urlopen(..)
внутри. На самом деле, такая функция была бы копией кода выше. Это кажется нечистым - по сравнению с использованием официального urlretrieve(..)
.
Я пишу себе функцию замены , которая ведет себя как urlretrieve(..)
снаружи и использует что-то совершенно иное внутри. Но эй, зачем мне это делать? urlopen(..)
не считается устаревшим, так почему бы не использовать его?
Какое решение вы бы приняли?