【问题标题】:Why function works properly without specifying parameters?为什么函数在不指定参数的情况下正常工作?
【发布时间】:2017-04-12 13:00:09
【问题描述】:

在下面的代码中,我不明白为什么 download_progress_hook 在从 maybe_download 方法中调用时不传递参数就可以工作。

download_progress_hook 的定义表明必须传递三个参数:count, blockSize, totalSize。 但是,当从maybe_download 调用download_progress_hook 时,没有传递任何参数。为什么不失败?

这里是完整的代码:

url = 'http://commondatastorage.googleapis.com/books1000/'
last_percent_reported = None
data_root = '.' # Change me to store data elsewhere

def download_progress_hook(count, blockSize, totalSize):
  """A hook to report the progress of a download. This is mostly intended for users with
  slow internet connections. Reports every 5% change in download progress.
  """
  global last_percent_reported
  percent = int(count * blockSize * 100 / totalSize)

  if last_percent_reported != percent:
    if percent % 5 == 0:
      sys.stdout.write("%s%%" % percent)
      sys.stdout.flush()
    else:
      sys.stdout.write(".")
      sys.stdout.flush()

    last_percent_reported = percent

def maybe_download(filename, expected_bytes, force=False):
  """Download a file if not present, and make sure it's the right size."""
  dest_filename = os.path.join(data_root, filename)
  if force or not os.path.exists(dest_filename):
    print('Attempting to download:', filename) 
    filename, _ = urlretrieve(url + filename, dest_filename, reporthook=download_progress_hook)
    print('\nDownload Complete!')
  statinfo = os.stat(dest_filename)
  if statinfo.st_size == expected_bytes:
    print('Found and verified', dest_filename)
  else:
    raise Exception(
      'Failed to verify ' + dest_filename + '. Can you get to it with a browser?')
  return dest_filename

train_filename = maybe_download('notMNIST_large.tar.gz', 247336696)
test_filename = maybe_download('notMNIST_small.tar.gz', 8458043)

【问题讨论】:

  • 你的意思是urlretrieve(..., reporthook=download_progress_hook)`?该函数没有被调用

标签: python python-3.x function


【解决方案1】:

我得到了一切,但是函数 download_progress_hook 被从函数 maybe_download 中调用的那一点

那是你出错的地方。该函数未被调用。它只是被引用。那里没有(...) 调用表达式。

Python 函数是一流的对象,您可以将它们传递或分配给其他名称:

>>> def foo(bar):
...     return bar + 1
...
>>> foo
<function foo at 0x100e20410>
>>> spam = foo
>>> spam
<function foo at 0x100e20410>
>>> spam(5)
6

这里的spam 是对函数对象foo 的另一个引用。我也可以通过其他名称调用该函数对象。

所以下面的表达式:

urlretrieve(
    url + filename, dest_filename,
    reporthook=download_progress_hook) 

呼叫 download_progress_hook。它只是将该函数对象提供给urlretrieve() 函数,而该代码将在某处调用download_progress_hook(传入所需的参数)。

来自URLOpener.retrieve documentation(最终处理该钩子):

如果 reporthook 被给出,它必须是一个接受三个数字参数的函数:一个块号、读入的最大块大小和下载的总大小(如果未知,则为 -1)。它将在开始时和从网络中读取每个数据块之后调用一次。

【讨论】:

  • 非常感谢 Martijn。
【解决方案2】:
import urllib.request
import os

class Progress:
def __init__(self):
    self.old_percent = 0

def download_progress_hook(self, count, blockSize, totalSize):
    percent = int(count * blockSize * 100 / totalSize)
    if percent > self.old_percent:
        self.old_percent = percent
        os.system('cls')
        print(percent, '%')
    if percent == 100:
        os.system('cls')
        print('done!')

title = 'title'
url_mp4 = 'https://url'
progress = Progress()
urllib.request.urlretrieve(url_mp4, title + '.mp4', reporthook=progress.download_progress_hook)

【讨论】:

    【解决方案3】:

    我喜欢 ICEBURG 的回答,但 os.system('cls') 不可移植,所以我用 ASCII 制作了一个进度条:

    class ProgressBar:
        def __init__(self):
            self.old_percent = 0
            print('_' * 50)
    
        def download_progress_hook(self, count, blockSize, totalSize):
            percent = int(count * blockSize * 100 / totalSize)
            if percent >= 2 + self.old_percent:
                self.old_percent = percent
                # print(percent, '%')
                print('>', end='')
                sys.stdout.flush()
            if percent == 100:
                print('\ndone!')
    

    它输出:

    __________________________________________________
    >>>>>>>>>>>>>>>>>>>>>>>>>
    

    【讨论】:

      猜你喜欢
      • 2016-11-06
      • 2019-02-24
      • 2011-08-13
      • 1970-01-01
      • 2017-03-27
      • 1970-01-01
      • 1970-01-01
      • 2017-09-23
      • 2020-03-07
      相关资源
      最近更新 更多