Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning a counter outside of a Python Function

Tags:

python

counter

I am trying to build some code and I have defined a function as this to test how a counter works inside of the function:

def errorPrinting(x):
    x += 1
    return x

I then use the function in some conditional logic where I want the counter to increase if the conditions are met.

x = 1

for row in arcpy.SearchCursor(fc):              

    if not row.INCLUSION_TYPE or len(row.TYPE.strip()) == 0:
        errorPrinting(x)
        print x

    elif len(row.TYPE) not in range(2,5):
        errorPrinting(x)
        print x

    elif row.INCLUSION_TYPE.upper() not in [y.upper() for y in TableList]:
        errorPrinting(x)
        print x

I'm still fairly new with using functions, so maybe I am not understanding how to return the value back outside of the function to be used in the next iteration of the for loop. It keeps returning 1 on me. Can anyone show me how to return the x outside of the function after it has been increased by one x+= 1?

Thanks, Mike

like image 784
Mike Avatar asked Feb 02 '26 08:02

Mike


2 Answers

You're not incrementing your global x, you're incrementing the local paramater that also happens to be named x! (Your parameter to errorPrinting could have been named anything. I'm calling it xLocal.)

As you can see here, x isn't incremented by the function.

>>> def inc(xLocal):
...     xLocal += 1
...     return xLocal
... 
>>> x = 4
>>> inc(x)
5
>>> x
4

You need to reassign the value of x to the return value of the function each time. Like this

x = 1
for row in arcpy.SearchCursor(fc):              

    if not row.INCLUSION_TYPE or len(row.TYPE.strip()) == 0:
        x = errorPrinting(x) # <=== here
        print x

    elif len(row.TYPE) not in range(2,5):
        x = errorPrinting(x) # <=== here
        print x

    elif row.INCLUSION_TYPE.upper() not in [y.upper() for y in TableList]:
        x = errorPrinting(x) # <=== here
        print x

Integral parameters and other primitives aren't normally passed by reference in Python. (Lists, dicts, etc. are. Modifying lists unintentionally is actually a very common mistake in Python.)

Edit: passing by "reference" and "value" isn't really correct to talk about in Python. See this nice question for more details.

So, using my previous example:

>>> x = 4
>>> x = inc(x)
>>> x
5

Note that if this had been parameter that is passed by reference, like a list, this strategy would have worked.

>>> def incList(xList):
...     for i in range(len(xList)):
...         xList[i] += 1
... 
>>> xList
[1]
>>> incList(xList)
>>> xList
[2]

Note that normal, Pythonic syntax:

for i in xList:
    i += 1

would not increment the global value.

Note: If you're looking to keep tabs on a lot of things, I also recommend the logging module that @SB. mentioned. It's super useful and makes debugging large programs a lot easier. You can get time, type of message, etc.

like image 134
vroomfondel Avatar answered Feb 04 '26 23:02

vroomfondel


You're bit by scope. You may want to check out this link for a quick primer.

You can do something simple and say x = errorPrinting(x) in all cases you call errorPrinting and get what you want. But I think there are better solutions where you'll learn more.

Consider implementing an error logger object that maintains a count for you. Then you can do logger.errorPrinting() and your instance of logger will manage the counter. You may also want to look into python's built in logging facilities.

like image 38
NG. Avatar answered Feb 04 '26 21:02

NG.