2

I have a function that I want to use multiple times, on every use I want a variable outside of the function to increment. Along the lines of -

def funtion1(mylists,x): row=1 for elm in mylists: ws.write(row,x,elm) row+=1 x += 1 col=0 function1(mylist1,col) function1(mylist2,col) function1(mylist3,col) 

etc

I thought col would increment on every use, but it stays at 0. Should I be returning a value from the function?

3
  • When passing immutable data types, such as integers, they follow similar semantics to "pass-by-value". i.e. x is local to the function, and changing it does not affect the value of col. If it was a mutable object, and you changed a member value within the function - you would see your expected behaviour. Commented Dec 6, 2017 at 17:36
  • 2
    you could define the variable as global or return the value Commented Dec 6, 2017 at 17:37
  • 1
    good resource Commented Dec 6, 2017 at 17:49

3 Answers 3

3

You are incrementing a temporary variable x in the function namespace, therefore col is not modified. If you want to change col you can:

  • use a class with a classmethod and a class attribute
  • use a decorator as in Paul Panzer's answer
  • return the value of x and affect it to col
  • use a global statement.

If you are unfamiliar with namespace check this link

First using a class with a classmethod and a class attribute:

class functions: col = 0 @classmethod def function1(cls, mylists): row=1 for elm in mylists: ws.write(row, cls.col,elm) row+=1 cls.col += 1 functions.function1(mylist1) functions.function1(mylist2) functions.function1(mylist3) 

This would be my preferred option as the namespaces are not polluted and the code is cleaner than with returning a value.

Now returning a value:

def funtion1(mylists,x): row=1 for elm in whichlist: ws.write(row,x,elm) row=row+1 return x + 1 col = 0 col = function1(mylist1,col) col = function1(mylist2,col) col = function1(mylist3,col) 

Or with a global:

def function1(mylists): global col row=1 for elm in mylists: ws.write(row,col,elm) row+=1 col += 1 col=0 function1(mylist1) function1(mylist2) function1(mylist3) 
Sign up to request clarification or add additional context in comments.

4 Comments

Good approach, but you could also do return x + 1 instead of doing x+=1 return x in two lines
@ShailynOrtiz Thanks, amended accordingly
thanks, swear I'd tried this.. I thought it wouldn't remain as a local variable if you are using a variable from outside the function
@PTerm2 I added another option with a classmethod. I think that's a better way to achieve what you want.
2

You could create a function attribute to hold the counter. Here is a decorator that does this:

import functools as ft def I_can_count(f): @ft.wraps(f) def wrapper(*args, **kwds): wrapper.times_called += 1 return f(*args, **kwds) wrapper.times_called = 0 return wrapper @I_can_count def f(x): print x print(f.times_called) f(100) print(f.times_called) f(100) print(f.times_called) # 0 # 100 # 1 # 100 # 2 

Please note that the purpose of the decorator here is twofold: (1) it adds convenience; but more importantly (2) it protects the namespace where the function or rather its wrapper finds itself. Without that the following accident can happen:

def f(x) f.times_called += 1 print(x) f.times_called = 0 f(100) # 100 f.times_called # 1 g = f del f g(100) # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # File "<stdin>", line 2, in f # NameError: name 'f' is not defined 

2 Comments

I like that solution. Out of curiosity what advantage does it have over class encapsulation?
@JacquesGaudin I wouldn't insist on that it's better. It's a bit shorter; I'd guess a bit more light weight (I may be wrong there). OTOH the class approach tends to be a bit more readable especially when there are additional parameters (like a starting value for the counter). The point of decorators is of course that they are reusable - just add a single line before any function def and your function has the new features. In your class solution you have to retype the incrementing for each new function, or if subclassing at least call super. Finally, decorators can be created using classes.
1

Two options, pure functions which don't modify anything outside their scope, Most recommended

as our friend Jacques Gaudin has added: https://stackoverflow.com/a/47680265/7579116

the other one, less fancy, and not recommended but is what you asked for is to declare x as global

x = 0 def funtion1(mylists,x): global x row=1 for elm in whichlist: ws.write(row,x,elm) row=row+1 x += 1 function1(mylist1,col) function1(mylist2,col) function1(mylist3,col) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.