0

Many times I have had a need to have a simple function do something different when first called. There are many reasons, but usually I would need a variable initialized differently if the first run through. Sometimes I could handle the problem outside the function or inside, but things could sometimes get messy, and I don't like to use "globals" if I can avoid them.

My solution came from generators. I found that I could "initialize" a function, or "prime" a function as I call it, by using a next() call in the program combined with a reveresed "yield" above a loop in the function. Works like a charm.

Now my question is: Is there a better way that I may be missing?

A WoNUX--working, but non-useful exammple:

o_PrintList = g_PrintThis() ## Creates func object
o_PrintList.next() ## 'Primes' the func
o_PrintList.send(9) ## Sends argument to the func
o_PrintList.send(10) ## Another argument to the func

def g_PrintThis():
    v_PrintList = [] ## Inits the variable. If stnd func call this would happen everytime
    print("Initialized")
    v_Num = yield ## Waits for first send argument
    while True: ## Infinite loop. Could be a for loop, etc.
        v_PrintList.append(v_Num) ## Reason v_PrintList needs 'primed'
        if not v_PrintList:
            print("PrintList is empty:")
        else:
            print("Printlist: %s") %(v_PrintList)
        v_Num = yield ## Waits for next send argument, if ever one comes

Thanks.

Raw_Input
  • 341
  • 1
  • 5
  • 12
  • 1
    Look at http://stackoverflow.com/questions/279561/what-is-the-python-equivalent-of-static-variables-inside-a-function – Wojtek Surowka Jul 10 '14 at 09:06
  • If you're explicitly calling `next` to prime it, you might as well just have a separate `setup_printing` function and call that for first-time setup. – user2357112 Jul 10 '14 at 09:12

3 Answers3

3

One option is to just use an actual class. You can implement __call__ to define the appropriate behaviour when called:

class PrintThis(object):

    def __init__(self, print_list=None):
        if print_list is None:
            print_list = []
        self.print_list = print_list

    def __call__(self):
        if self.print_list:
            print("Print list: {0}".format(self.print_list))
        else:
            print("Print list empty.")

    def send(self, item):
        self.print_list.append(item)

In use:

>>> p = PrintThis()
>>> p()
Print list empty.
>>> p.send(9)
>>> p.send(10)
>>> p()
Print list: [9, 10]
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • @jonsharpe Thanks. Certainly a class would work, however for a simple function it becomes a lot of code and more complex. I also tend to classify and use functions as "tasks" and classes as "entities." I send stuff to tasks to be done and returned and I send entities to go and do and hold things. For a simple task, do I really want to create an entity? Food for thought. – Raw_Input Jul 10 '14 at 17:08
  • @Raw_Input your task and entity distinction doesn't really apply in Python generally or your example specifically; in this case, you want your task to also hold things! – jonrsharpe Jul 10 '14 at 17:09
1

In Python functions can have attributes, so testing whether a given attribute exists will allow you to determine whether initialization is required:

def f(args):
    if not hasattr(f, "guard"):
        print "Initializing"
        f.guard = None
    print "Called with", args

f("one")
f("two")

prints

Initializing
Called with one
Called with two

This avoids the use of global variables, which often represent troublesome potential problems (what if other code uses the same global variable, to ask only one pertinent question).

holdenweb
  • 33,305
  • 7
  • 57
  • 77
  • Settings attributes on a function from within the function's body is brittle at best. If you need state, use a class (or eventually a closure...). – bruno desthuilliers Jul 10 '14 at 10:37
  • @holdenweb Thanks. This is a form of a solution that I often resulted to. However it could get complex at times and/or break on subsequent calls. – Raw_Input Jul 10 '14 at 17:01
  • Explain, please? I rather disagree with Bruno about the brittleness of this solution, and particularly find it objectionable to have to declare a class of which I know there'll be only one instance. – holdenweb Jul 10 '14 at 17:04
1

Functions are classes too (first class, to be exact). When you call a function, you actually call the function's class' __call__ method which is also a class.

Like what jonrsharpe said, create a class and implement __init__and __call__ methods.

Cediddi
  • 130
  • 1
  • 8
  • 2
    Much of what you say is correct, but if functions were classes we would be able to inherit from them. They are instances of the function type. – holdenweb Jul 10 '14 at 10:52
  • And you *can't* inherit `types.FunctionType`. – jonrsharpe Jul 10 '14 at 11:27
  • Yes, it's remarkably difficult to build a functin on the fly (as it is a module). They may be first-class object, but they aren't really first-class types – holdenweb Jul 10 '14 at 17:06