BugBytes
BugBytes

Reputation: 21

How to loop over each call to a function in Python

I need to increment a variable each time a certain number of calls to a certain function is made in Python 2.7.3.

For example, feetTraveled = 0. for every 12 calls to travelOneInch(), feetTraveled += 1.

Is it optimal to use a for loop or should I be using something different? If it is optimal to use a for loop like the one above, what should be placed instead of 'every 12 calls to'?

Another example: I have four servants. They each do one task in a clock tick, and the time counter is initially time = 0. So for every four calls to servantDo(), time += 1.

Upvotes: 1

Views: 238

Answers (4)

EnricoGiampieri
EnricoGiampieri

Reputation: 6095

Probably the best implementation is to use an object to store the status and use the function to modify it:

class Position(object):
    def __init__(self):
        self.pos = 0
    def advance(self,inches=1):
        self.pos += inches
    def pos_as_foot(self):
        return self.pos // 12

If you find this approach a little to boring (even if it's the most correct one), you can try a more esoteric approach: you can use internal values of the function, i.e. treating it like an object

def foo():
    foo.value+=1
    if foo.value and not foo.value%12:
        foo.result+=1
foo.value=0
foo.result=0

for i in range(15): 
    foo()
print foo.value
#15
print foo.result
#1

It's not the most easy solution, and have problem if you need several counters, but it's interesting to know. It has the advantage to remove some cluttering code (at least in simple cases) from the class definition (that is using under the hood), and keep the state accessible whereever you will use the function, without tampering with global variables (that i reaaaly don't like)

Upvotes: 0

parkr
parkr

Reputation: 833

mgilson (above) knows what's up. If I were you, I'd do the following, to make things easier:

class Foo(object):
    def __init__(self):
        self.__inches = 0

    def travel_one_inch(self):
        self.__inches += 1

    def feetTraveled(self):
        return self.__inches // 12

But, in terms of optimality, if you're just doing this once, then you can use temporary variables:

feetTraveled = 0
inchesTraveled = 0
for i in xrange(72):
    # as in mgilson's answer
    inchesTraveled += 1
    if inchesTraveled > 11:
        inchesTraveled = 0
        feetTraveled += 1

Upvotes: 0

user1621465
user1621465

Reputation:

If you want to work in the global namespace:

inches = 0
feet   = 0

def travelOneInch(sure):
    inches += 1

    if (inches % 12) == 0:
        feet += 1
    #...

And using inches % 12 == 0 is better than inches > 12 in case you want your function to recognize the second and furher feet.

Upvotes: 0

mgilson
mgilson

Reputation: 310257

In this case, I think I'd use an instance method:

class Foo(object):
    def __init__(self):
        self.inches = 0
        self.feet = 0

    def travel_one_inch(self):
        self.inches += 1
        if self.inches > 11:
            self.inches = 0
            self.feet += 1

    def __str__(self):
        return "{feet} feet and {inches} inches".format(feet=self.feet,inches=self.inches)

a = Foo()
for _ in range(123):
    a.travel_one_inch()
print(a)

A vast majority of the time, if you want a function to remember some sort of state between calls, you're not looking for a function at all -- You're looking for a class with an instance method.

Upvotes: 3

Related Questions