使函数在第一次和后续调用之间表现不同

时间:2018-02-07 21:10:51

标签: python

def download():
    upgrade = True
    if upgrade:
        # do a download using tftp
    else:
        # do a download via HTTP

如您所见,我有一个设置为true的硬编码升级值。在此脚本中,它始终执行tftp下载。

如何在第一次迭代时更改脚本以执行tftp下载,在下一次迭代中调用函数下载时,它会进行http下载吗?

7 个答案:

答案 0 :(得分:6)

为了完整性,这里是class解决方案:

class Download(object):
    def __init__(self):
        self.executed = False

    def __call__(self):
        print('http' if self.executed else 'tftp')
        self.executed = True

download = Download()

download()  # tftp
download()  # http
download()  # http

这允许您以非hackish方式跨调用存储状态。

答案 1 :(得分:2)

您可以使用闭包,即返回一个内部函数,并保留外部状态。假设python 3:

def init_download():
    upgrade = True

    def inner():
        nonlocal upgrade
        if upgrade:
            print('do a download using tftp')
            upgrade = False
        else:
            print('do a download via HTTP')

    return inner

download = init_download()

download()
download()
download()

给出:

do a download using tftp
do a download via HTTP
do a download via HTTP

答案 2 :(得分:1)

重构您的代码,如下所示:

def download(upgrade=True):

  if upgrade:
     do a download using tftp
  else:
     do a download via HTTP

在第二次迭代中,当您致电download时,请使用upgrade=False作为参数:

download(False)  # download via HTTP

答案 3 :(得分:1)

可能你可以(并且应该)在你的函数之外使用这个逻辑,但是如果你想每次传递相同的参数但仍然在第一次调用后改变行为,你可以使用default mutable argument

from itertools import count 

def download(c=count()):
    if next(c) == 0:
        print('tftp')
    else:
        print('http')

download()
# tftp
download()
# http
download()
# http
download()
# http

使用itertools.count而不是列出清单的好处是,您不会在每次通话时累积内存。

答案 4 :(得分:0)

如果我在你身上正确理解你只需要第一次调用thtp,你就可以使upgrade成为一个全局变量。然后,当调用download函数时,全局将其设置为False,并且对于后续调用它将保持这种方式。

请注意,此答案基于对OP问题的某些解读。我假设调用此函数的脚本不知道函数被调用了多少次。

upgrade = True

def download():
  global upgrade
  if upgrade:
     print('do a download using tftp')
     upgrade = False
  else:
     print('do a download using http')

download() # do a download using tftp
download() # do a download using http

答案 5 :(得分:-1)

由于@Alex的答案很好,但是需要额外的步骤来构造实例。您还将在全局范围内存储实例。

因此,我对其进行了一些更改。然后,您可以将其导入并用作功能。

util.py

class Downloader(object):
  _upgrade = False

  @classmethod
  def call(cls):
    if cls._upgrade:
      print('upgrade via http')
    else:
      print('download via tft')
      cls._upgrade = True

def download():
  Downloader.call()

main.py(使用它)

from .util import download

download()
download()

这可能不是线程安全的。而且,如果您在其他进程(例如Web服务器后端)中运行它,则最好将远程存储用于该标志(例如redis / oss)。

答案 6 :(得分:-2)

您可以在以下内容中构建代码:

def download(upgrade = False):

    while upgrade == False:
            print("HTTP")
            break
    print("TFTP")

download()

这将经过一次,然后退出程序。打印陈述只是向您展示发生了什么以及何时结束的指南。