user3050527
user3050527

Reputation: 931

is there a way to track the number of times a function is called?

So i'm trying to make a function that keeps track how many times a method is called. for example:

a = [1,2,3,4]
a.pop()

i want to know how many times a.pop() was called so far so for this example, i would get 1. Is there a way to do this?

Upvotes: 60

Views: 132440

Answers (14)

Yilmaz
Yilmaz

Reputation: 49291

I solve this with closure. This is a generic function:

def counter(fn):
    cnt=0
    def inner(*args,**kwargs):
        nonlocal cnt
        cnt+=1
        print('{0} has been called {1} times'.format(fn.__name__,cnt))
        return fn(*args,**kwargs)
    return inner

a=[1,2,3,4]
a_pop=counter(a.pop)

enter image description here

Upvotes: 0

mohammad eunus
mohammad eunus

Reputation: 69

i guess the following code will be helpful to you. you just need to make local variable global in order to access the global variable from a method

MYGLOBAL = 5

def func1():
    global MYGLOBAL
    MYGLOBAL +=10
        
def func2():
    print (MYGLOBAL)

func1()     #called the func1 three time thus the value of MYGLOBAL WILL increase 10*3=30
func1()     #called the func1 three time thus the value of MYGLOBAL WILL increase 10*3=30
func1()     #called the func1 three time thus the value of MYGLOBAL WILL increase 10*3=30

func2()     #this will printout 5+30=35

Upvotes: 2

EStark
EStark

Reputation: 193

An example from Datacamp, using decorators:

def counter(func):
  def wrapper(*args, **kwargs):
    wrapper.count += 1
    # Call the function being decorated and return the result
    return func(*args, **kwargs)
  wrapper.count = 0
  # Return the new decorated function
  return wrapper

# Decorate foo() with the counter() decorator
@counter
def foo():
  print('calling foo()')
  
foo()
foo()

print('foo() was called {} times.'.format(foo.count))

# output
calling foo()
calling foo()
foo() was called 2 times. 

Upvotes: 0

I did it copying the way JavaScript console.count() method works. That's my code:

class Terminal(object):
    __count_names = []
    def count(self, name='default'):
        # check if name already exists
        i = next((self.__count_names.index(item) for item in self.__count_names if item['name'] == name), None)
        # if name argument does not exist register it
        if i is None:
            dictionary = { 'name': name, 'count': 1 }
            self.__count_names.append(dictionary)
        # if exists increment 'count'
        else:
            dictionary = self.__count_names[i]
            dictionary['count'] += 1
            self.__count_names[i] = dictionary
        # finally print name and count
        print(f"{dictionary['name']} : {dictionary['count']}")

Your code should look like this:

terminal = Terminal()
def myFunc():
    terminal.count("myFunc")

myFunc()
myFunc()
myFunc("myFunc")

Output:

myFunc: 1
myFunc: 2
myFunc: 3
myFunc: 4

Upvotes: 0

Vincent Hunter
Vincent Hunter

Reputation: 11

Just define a global statement in your function.

count = 1
def your_func():
  global count
  print(count)
  count= count +1

Upvotes: 1

fralau
fralau

Reputation: 3819

Here is a simple and elegant solution for a self counting function, without any decorators, global variables, etc:

def hello():
    hello.counter += 1
    print(hello.counter)
hello.counter = 0

Each time you call hello(), it will print 1, 2, etc.

Let's not forget that, in Python, a function is a first-class citizen and it has rights. And one of them is to have attributes!

If you are willing to include your method call in a function, it can be easy:

def pop_counted(a):
    pop_counted.counter += 1
    return a.pop()
pop_counted.counter = 0

Voilà!

Comment

This works because a Python function "knows" itself (this is a necessary feature, so that functions can call themselves recursively if desired).

If you wish to keep some information about a function, it might be better to keep it where it belongs: in an attribute of the function.

The advantage of not using a global variable is scope:

  • no risk of name collisions in the global namespace
  • the information you were keeping will vanish as soon as the function is taken off the stack, which is what you want -- no garbage left.

A bonus is that this approach will work in cases where a global variable is not really a good option, typically for nested functions where you can't declare a "global" in the outer function.

Upvotes: 10

ABHISHEK SRIVASTAVA
ABHISHEK SRIVASTAVA

Reputation: 57

Just define a global variable and increment it inside function.

a = 0
def some_function():
    global a
    a+=1
    <..Your code.>

This will automatically be incremented as function is used and you can access it globally.

Upvotes: 0

iiiir.com
iiiir.com

Reputation: 345

i used the following little trick to track how many times the function was called

def myfun(s,i=[0]):    
    print(s)    
    i[0]+=1 # mutable variable get evaluated ONCE
    return i[0]

>>> myfun('aaa')
aaa
1
>>> myfun('bbb')
bbb
2

Upvotes: 30

Matthew Trevor
Matthew Trevor

Reputation: 14962

One approach is to create a proxy of the instance for which you want to count attribute access:

from collections import Counter

class CountingProxy():
    def __init__(self, instance):
        self._instance = instance
        self.count = Counter()

    def __getattr__(self, key):
        if hasattr(self._instance, key):
            self.count[key] += 1
        return getattr(self._instance, key)


>>> l = [1,2,3,4,5]
>>> cl = CountingProxy(l)
>>> cl.pop()
5
>>> cl.append(10)
>>> cl.index(3)
2
>>> cl.reverse()
>>> cl.reverse()
>>> cl.count
Counter({'reverse': 2, 'pop': 1, 'append': 1, 'index': 1})

Upvotes: 4

jiminy_crist
jiminy_crist

Reputation: 2445

For kicks, I wrote up an answer using a decorator:

class counter:
    #wraps a function, to keep a running count of how many
    #times it's been called
    def __init__(self, func):
        self.func = func
        self.count = count

    def __call__(self, *args, **kwargs):
        self.count += 1
        return self.func(*args, **kwargs)

To use it, simply decorate a function. You can then check how many times that function has been run by examining the "count" attribute. Doing it this way is nice because:

1.) No global variables. The count is associated directly with the function.

2.) You can wrap builtin functions easily, by calling the class directly:

sum_wrapped = counter(sum)
sum_wrapped([1, 2 ,3, 4])
#outputs 10
print sum_wrapped.count
#outputs 1

Of course, this could be improved by using the Decorators module to keep the docstrings and other good things intact. Also, for an excellent overview of what decorators are, and how they work, check out this stackoverflow answer.

Upvotes: 5

castaway2000
castaway2000

Reputation: 314

counter = 0

def pop():
  counter += 1
  print counter
  #other function code

a = [1,2,3,4]  
a.pop()

this should solve your issue and you should be able to see whats being counted. + every time you call the function the counter is going to be increased and printed with every pass of the function.

IF ITS BUILT IN:

    counter = 0
    def newfunction():
      a = [1,2,3,4]  
      a.pop()
      counter += 1
      print counter

the logic in this is that it will call your new function go into the function that is premade then step out of the built in function and then go on to mark the counter as increased. the output your counter.

Upvotes: 1

FogleBird
FogleBird

Reputation: 76762

You could use a decorator that tracks how many times the function is called. Since list is a built-in, you can't decorate or replace its pop method so you'd have to use your own list class, for example.

def counted(f):
    def wrapped(*args, **kwargs):
        wrapped.calls += 1
        return f(*args, **kwargs)
    wrapped.calls = 0
    return wrapped

class MyList(list):
    @counted
    def pop(self, *args, **kwargs):
        return list.pop(self, *args, **kwargs)

x = MyList([1, 2, 3, 4, 5])
for i in range(3):
    x.pop()

print x.pop.calls # prints 3

Upvotes: 60

mhlester
mhlester

Reputation: 23221

This doesn't work for builtin functions, but an interesting approach would be:

def myfunction():
    myfunction.counter += 1
myfunction.counter = 0

You're giving the function an attribute, so every call that attribute is updated. No global variables needed.

Built-ins are read-only. They cannot be modified.

Upvotes: 84

aidnani8
aidnani8

Reputation: 2127

A simple way to do this is to increment a global variable each time you call the function.

counter = 0

a = [1,2,3,4]    
a.pop()
counter += 1

Upvotes: 2

Related Questions