为什么函数在没有指定参数的情

时间:2017-04-12 13:00:10

标签: python python-3.x function

在下面的代码中,当download_progress_hook方法中调用参数时,我不明白为什么maybe_download无法传递参数。

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

以下是完整代码:

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)

3 个答案:

答案 0 :(得分:6)

  

我得到了所有内容,但是从函数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)。它将在开始时调用一次,并在从网络读取每个数据块之后调用。

答案 1 :(得分:1)

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)

答案 2 :(得分:0)

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

=COUNTIFS($A:$A,$E2,$C:$C,RIGHT(F$1,LEN(F$1)-LEN("# of items ")))

它输出:

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!')