38

Possible Duplicate:
Static class variables in Python
What is the Python equivalent of static variables inside a function?

How can I use static fields in Python ?

for example i want to count how many times the function has been called - how can i do this ?

Community
  • 1
  • 1
Patryk
  • 22,602
  • 44
  • 128
  • 244
  • @PaulManta: I disagree. Your link is not related to class static fields (as OP says), but to " _the static member at the function level, as opposed to the class level_ ", as stated by OP within the question you gave use link to. – Tadeck Nov 13 '11 at 14:11
  • 2
    @Tadeck The word 'class' doesn't even appear in the question... But the phrase 'static member **of a function**' does. – Paul Manta Nov 13 '11 at 16:49
  • @PaulManta: Please read the question you linked to again - there are both words: " _class_ " **and** " _function_ ". In the current question (this question) there is a reference to " _static fields_ ". Because of that, and because I have never heard of " _static fields_ " in reference to static variables within function, but I have heard of " _static fields_ " in reference to static member variables of a class, I assumed the current question is about static member variables of a class. Unless you will prove otherwise, I suppose the upvotes of my first comment mean some support in this matter. – Tadeck Nov 13 '11 at 17:47
  • @Tadeck Regarding votes: Good for you, here are two internet credits. Seriously, what's the argument about? The example is clear, he wants to know how to count how many times a function was called. In lack of a better term he used the rather incorrect 'static fields', but his intention is still clear from the example and title. Where's the problem? – Paul Manta Nov 13 '11 at 21:01
  • @Tadeck The word 'class' [appears](http://stackoverflow.com/questions/279561/what-is-the-python-equivalent-of-static-variables-inside-a-function) in this context, 'how does one implement the static member at the function level, **as opposed to the class level**'. Lol at you making such a big deal out of this. – Paul Manta Nov 13 '11 at 21:03
  • @PaulManta: You may be right, but chances are that I am right. I was not making this a "big deal", you did (I just followed). And the upvotes usually mean support. Got it? Now, OP **clearly** refers to static fields and mentions **example use**: " _**for example** i want to count how many (...)_ ". Got it? He tries to clarify what he meant by giving some example usage. My solution also fits for this use case scenario, thus I still think your claim (that my interpretation is incorrect and yours is correct) is baseless. Thanks. – Tadeck Nov 13 '11 at 22:01
  • @Tadeck Now we're getting trolls on SO as well? – Paul Manta Nov 14 '11 at 07:48
  • @PaulManta: Please talk about the actual problem OP had, if you are able to help. And use **real** arguments in order to support what you are saying. Otherwise what you are doing is indeed [trolling](http://en.wikipedia.org/wiki/Troll_(Internet)). Regards. – Tadeck Nov 14 '11 at 08:14
  • @Tadeck I did try to help. What I don't get is why you're so argumentative about this. – Paul Manta Nov 14 '11 at 08:18
  • @PaulManta: We have two different opinions and you did not convince me. Do not treat this discussion personally, it is great if many people have different opinions. For me it would be enough to see the list of possible duplicates on the top of the question (as it is now), so anyone can have own judgement. But since you started discussion, I have just replied by mentioning, why I disagree. Is it offending to you? Or is it trolling? I do not think so, unless you stop giving reasonable arguments and start treating this personally. Deal with the fact that other people may have different opinions. – Tadeck Nov 14 '11 at 08:25

4 Answers4

9

If you wish to count how many times a method has been called, no matter which instance called it, you could use a class member like this:

class Foo(object):
    calls=0            # <--- call is a class member
    def baz(self):
        Foo.calls+=1

foo=Foo()
bar=Foo()
for i in range(100): 
    foo.baz()
    bar.baz()
print('Foo.baz was called {n} times'.format(n=foo.calls))
# Foo.baz was called 200 times

When you define calls this way:

class Foo(object):
    calls=0            

Python places the key-value pair ('calls', 0) in Foo.__dict__.

It can be accessed with Foo.calls. Instances of Foo, such as foo=Foo(), can access it with foo.calls as well.

To assign new values to Foo.calls you must use Foo.calls = .... Instances can not use foo.calls = ... because that causes Python to place a new and different key-value pair in foo.__dict__, where instance members are kept.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
5

Here's a decorator adding counting to a function.

import functools

def count_calls(func):
    @functools.wraps(func)
    def decor(*args, **kwargs):
        decor.count += 1
        return func(*args, **kwargs)
    decor.count = 0
    return decor

Usage:

>>> @count_calls
... def foo():
...     pass
...
>>> foo.count
0
>>> foo()
>>> foo.count
1
yak
  • 8,851
  • 2
  • 29
  • 23
  • the decorator might be better called `count_calls` – jfs Nov 14 '11 at 02:33
  • It's quite the most complicated way of doing it, isn't it ? – Patryk Nov 14 '11 at 13:04
  • @Patryk: Not at all; defining a decorator means you can count calls on any number of functions by adding a single line prefixing the function definition. Using the class attribute to count calls to a method doesn't generalize like that (it could, but it would end up equivalent to the decorator solution, more verbose, and likely somewhat slower). – ShadowRanger Apr 19 '17 at 00:21
4

Here is some example counting the number of calls of all objects of the same class:

class Swallow():
    i = 0 # will be used for counting calls of fly()
    def fly(self):
        Swallow.i += 1

And this is the proof:

>>> a = Swallow()
>>> b = Swallow()
>>> a.fly()
>>> a.i
1
>>> Swallow.i
1
>>> b.fly()
>>> b.i
2
>>> Swallow.i
2

so you can read it by giving the object name or class name.

Tadeck
  • 132,510
  • 28
  • 152
  • 198
2

Here's one simplistic way to do it:

def func():
    if not hasattr(func, 'counter'):
        func.counter = 0
    func.counter += 1
    counter = 0 # Not the same as `func.counter`
    print(func.counter)

Or if you don't like the if being executed on every call, you can do:

def func():
    func.counter += 1
    print(func.counter)
func.counter = 0
Paul Manta
  • 30,618
  • 31
  • 128
  • 208