0

I have a function

def compute_daily_quantities():
  # compute some quantities, one of which is the variable, value

After the first call to compute_daily_quantities, we need to add a constant, c to value.

How can I check if it's the first or a subsequent call to compute_daily_quantities?

I come from a C++ background, and in C++, we can introduce a static variable within the function to check. I know you can do something similar in Python, but are there other ways in which this can be done in Python?

The solution I was envisioning is:

def compute_daily_quantities():
  # compute some quantities, one of which is the variable, value
  if not hasattr(compute_daily_quantities, "is_first_call"):
    compute_daily_quantities.is_first_call = True
  else:
    value += c

  compute_daily_quantities.is_first_call = False
David
  • 619
  • 2
  • 8
  • 15

2 Answers2

0

A global variable would be the simplest way to achieve this.

g = 0

def func(val):
    global g
    val += g
    if not g:
        g = 20
    return val


print(func(10)) # 10
print(func(10)) # 30

Depending on how much persistence you want, you can even go as far as to store g inside a file.

Edit: I just thought this through a bit more, and the better way to achieve this would be a hasattr call similar to what OP was thinking of:

def func(val):
    if hasattr(func, 'g'):
        val += func.g
    else:
        func.g = 20
    return val


print(func(10)) # 10
print(func(10)) # 30
Squarish
  • 169
  • 6
  • isn't it generally considered bad practice to use global non-constant variables? – David Jun 08 '23 at 16:11
  • If `func` is the only thing that uses `g`, it's technically global, but "semantically" local to `func`. Such things are typically encapsulated using classes rather than global variables, though. – chepner Jun 08 '23 at 16:15
  • @David you are completely right. Global variables are just the first things that came to mind. – Squarish Jun 08 '23 at 16:19
  • @chepner yes attributes are usually attached to classes, but since OP has specified that it is a function, we have to assume that it is not currently encapsulated in a class. Creating an entire class just to store a single attribute is a pretty big overhead for something that can be done very easily with a less common feature. – Squarish Jun 08 '23 at 16:22
  • I would still initialize `func.g` to 0, then unconditionally add `func.g` to value *before* unconditionally setting `func.g` to 20. The custom class basically lets you hide the initialization of the attribute inside its `__init__` method. – chepner Jun 08 '23 at 16:40
-1

Rather than using a function, you might want to keep the attribute in a separate class, like this:

class Computer:
    def __init__(self):
        self.is_first_call = False

    def compute_daily_quantities():
      # compute some quantities, one of which is the variable, value
      if not self.is_first_call:
        self.is_first_call = True
      else:
        value += c

You would then need to make sure that you only instantiated a single instance of the class, otherwise your newer classes would be instantiated with the 'first value' flag as False

You might be able to use a singleton pattern, or a class attribute (rather than an instance attribute) to do this in a safer way depending on how exactly you planned to use it.

alex_danielssen
  • 1,839
  • 1
  • 8
  • 19
  • Why do you think you can't add attributes to a function? Functions are objects, they have attributes. – Barmar Jun 08 '23 at 16:03
  • You *can* add an attribute to a function. – quamrana Jun 08 '23 at 16:03
  • You *can* add function attributes, but a separate class is usually preferable. (The intialization of the attribute just needs to be done *after* the function definition, not at the end of the body, which may just have been an indentation error in the question.) – chepner Jun 08 '23 at 16:04
  • yup, you're right, answer changed. – alex_danielssen Jun 08 '23 at 16:06