Harish Sridharan
Harish Sridharan

Reputation: 53

Make a function behave differently between first and subsequent calls

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

As you can see, I have a hard coded value of upgrade that is set to true. In this script, it always does a tftp download.

How do I change the script to do tftp download at the first iteration and in the next iteration when the function download is called, it does a http download?

Upvotes: 1

Views: 720

Answers (7)

Samuel Chen
Samuel Chen

Reputation: 2273

Since @Alex 's answer is good, but it need a extra step to construct an instance. You will also to store the instance globally.

So I made some change to it. Then you can import it and use it as function.

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 (using it)

from .util import download

download()
download()

This may not thread safe. And if you run it in different processes (e.g. webserver backend), you'd better use a remote storage for the flag (e.g. redis/oss).

Upvotes: -1

White Wolf
White Wolf

Reputation: 1

You could structure your code in the following:

def download(upgrade = False):

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

download()

This will go through them once and exit the program after. The print statements are just a guide to show you what's happening and when it ends.

Upvotes: -2

Chris_Rands
Chris_Rands

Reputation: 41248

Probably you can (and should) just take this logic outside of your function, but if you want to pass the same argument each time but still change the behaviour after the first call, you could use the 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

The advantage of using itertools.count rather than say a list is that you don't accumulate memory with each call.

Upvotes: 1

Alex
Alex

Reputation: 19124

For completeness here is the class solution:

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

This allows you to store state in a non-hackish way across invocations.

Upvotes: 6

data princess
data princess

Reputation: 1158

If I understand you correctly in you only need the literal first call to do thtp, you could make upgrade a global variable. Then, when the download function is called, you globally set it to False, and it will remain that way for subsequent calls.

Note that this answer is based on a certain reading of OP's question. I am assuming that the script calling this function does not know how many times the function has been called.

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

Upvotes: -1

cdarke
cdarke

Reputation: 44434

You can use a closure, that is, have an inner function which is returned, and this retains an outer state. This assumes 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()

Gives:

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

Upvotes: 3

jpp
jpp

Reputation: 164843

Restructure your code as below:

def download(upgrade=True):

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

In your second iteration, when you call download, use upgrade=False as a parameter:

download(False)  # download via HTTP

Upvotes: 2

Related Questions