Over a million developers have joined DZone.

Python — How to Tell if a Function Has Been Called

DZone's Guide to

Python — How to Tell if a Function Has Been Called

For the Raspberry Pi devs: how to know for sure if a function has been called in your Python code.

· IoT Zone
Free Resource

Address your IoT software testing needs – improve quality, security, safety, and compliance across the development lifecycle.

Last year I ran into a situation where I needed to know if a function had been called. Basically we were trying to prevent shutting down a Twisted event loop twice or starting two of them. Anyway, in my research I stumbled across a fun post on StackOverflow that showed a couple of ways to do this.

The first made use of the fact that everything in Python is an object, including the function itself. Let’s take a look at a simple example:

def self_aware_function(a, b):
    self_aware_function.has_been_called = True
    return a + b

if __name__ == '__main__':
    self_aware_function.has_been_called = False

    for i in range(2):
        if self_aware_function.has_been_called:
            print 'function already called'
            print 'function not called'

        self_aware_function(1, 2)

In this example, we create an attribute on the function that we named has_been_called. We set it to True when the function is called. When you start your program, you will want to initialize that attribute to False, which we do above. Then we use a for loop to loop twice. The first time through it will check if the function has been called. Since it hasn’t, you will see it fall to the else statement. Now that we called the function, the second time through the loop the first part of the if statement executes.

That StackOverflow post also mentions a neat way to use a decorator to track function calls. Here’s an example I wrote:

import functools

def calltracker(func):
    def wrapper(*args):
        wrapper.has_been_called = True
        return func(*args)
    wrapper.has_been_called = False
    return wrapper

def doubler(number):
    return number * 2

if __name__ == '__main__':
    if not doubler.has_been_called:
        print "You haven't called this function yet"

    if doubler.has_been_called:
        print 'doubler has been called!'

In this example, I import functools and create a decorator that I dubbed calltracker. In this function, we set up the same attribute that we did in the previous example, but in this case we attach it to our wrapper (i.e. the decorator). Then we decorate a function and give our code a try. The first if statement checks to see if the function has been called yet. It hasn’t, so we go ahead and call it. Then we confirm that the function was called in our second if statement.

Wrapping Up

While this stuff is certainly useful at runtime, you can also do similar things using Python’s trace module to trace through the execution of your code. This sort of thing is also done via coverage tools. You will also find this kind of functionality in Python Mock objects as a Mock can tell when it has been called.

Anyway, you will hopefully find this exercise as interesting as I did. While I already knew that everything in Python was an object, I hadn’t thought about using that functionality to add attributes to functions.

Accelerate the delivery of high-quality software in the connected IoT era through an integrated analysis, testing, security, and analytics platform. Parasoft's comprehensive portfolio of testing toolsautomates time-consuming testing tasks and provides management with intelligent analytics and reporting so they can focus on what matters.

python ,functions ,web dev ,iot

Published at DZone with permission of Mike Driscoll, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.


Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}