5

I've found various detailed explanations on how to pass long lists of arguments into a function, but I still kinda doubt if that's proper way to do it.

In other words, I suspect that I'm doing it wrong, but I can't see how to do it right.

The problem: I have (not very long) recurrent function, which uses quite a number of variables and needs to modify some content in at least some of them.

What I end up with is sth like this:

def myFunction(alpha, beta, gamma, zeta, alphaList, betaList, gammaList, zetaList):
    <some operations>
    myFunction(alpha, beta, modGamma, zeta, modAlphaList, betaList, gammaList, modZetaList)

...and I want to see the changes I did on original variables (in C I would just pass a reference, but I hear that in Python it's always a copy?).

Sorry if noob, I don't know how to phrase this question so I can find relevant answers.

awesoon
  • 30,028
  • 9
  • 67
  • 92
StanTastic
  • 281
  • 3
  • 17

7 Answers7

11

You could wrap up all your parameters in a class, like this:

class FooParameters:
    alpha = 1.0
    beta = 1.0
    gamma = 1.0
    zeta = 1.0
    alphaList = []
    betaList = []
    gammaList = []
    zetaList = []

and then your function takes a single parameter instance:

def myFunction(params):
    omega = params.alpha * params.beta + exp(params.gamma)
    # more magic...

calling like:

testParams = FooParameters()
testParams.gamma = 2.3
myFunction(testParams)
print params.zetaList

Because the params instance is passed by reference, changes in the function are preserved.

gavinb
  • 18,233
  • 3
  • 44
  • 55
7

This is commonly used in matplotlib, for example. They pass the long list of arguments using * or **, like:

def function(*args, **kwargs):
    do something

Calling function:

function(1,2,3,4,5, a=1, b=2, b=3)

Here 1,2,3,4,5 will go to args and a=1, b=2, c=3 will go to kwargs, as a dictionary. So that they arrive at your function like:

args = [1,2,3,4,5]
kwargs = {a:1, b:2, c:3}

And you can treat them in the way you want.

Saullo G. P. Castro
  • 53,388
  • 26
  • 170
  • 232
3

I don't know where you got the idea that Python copies values when passing into a function. That is not at all true.

On the contrary: each parameter in a function is an additional name referring to the original object. If you change the value of that object in some way - for example, if it's a list and you change one of its members - then the original will also see that change. But if you rebind the name to something else - say by doing alpha = my_completely_new_value - then the original remains unchanged.

Daniel Roseman
  • 567,968
  • 59
  • 825
  • 842
  • 1
    While it is technically correct to say *"each parameter in a function is an additional name referring to the original object"*, the behaviour for immutable types is not the one someone would expect to be for a variable passed "by reference" (as in C). If an `int` parameter is changed within the function (say, by doing `alpha += 1`), the original variable will not be affected. – E.Z. Jun 21 '13 at 12:00
  • 1
    Technically, python (just like any other major programming language, by default at least) uses "pass by value" semantics. that's where he got the idea from. And yes, it is confusing. – Elazar Jun 21 '13 at 12:33
1

You may be tempted to something akin to this:

def myFunction(*args):
    var_names = ['alpha','beta','gamma','zeta']
    locals().update(zip(var_names,args))
    myFunction(alpha,beta,gamma,zeta)

However, this 'often' won't work. I suggest introducing another namespace:

from collections import OrderedDict
def myFunction(*args):
    var_names = ['alpha','beta','gamma','zeta']
    vars = OrderedDict(zip(var_names,args))

    #get them all via vars[var_name]

    myFunction(*vars.values()) #since we used an orderedDict we can simply do *.values()
HennyH
  • 7,554
  • 2
  • 28
  • 38
1

you can capture the non-modfied values in a closure:

def myFunction(alpha, beta, gamma, zeta, alphaList, betaList, gammaList, zetaList):
    def myInner(g=gamma, al, zl):
        <some operations>
        myInner(modGamma, modAlphaList, modZetaList)
    myInner(al=alphaList, zl=zetaList)

(BTW, this is about the only way to write a truly recursive function in Python.)

Elazar
  • 18,541
  • 4
  • 43
  • 67
0

You could pass in a dictionary and return a new dictionary. Or put your method in a class and have alpha, beta etc. be attributes.

Bemmu
  • 17,091
  • 16
  • 73
  • 92
0

You should put myFunction in a class. Set up the class with the appropriate attributes and call the appropriate functions. The state is then well contained in the class.

Alex Chamberlain
  • 4,033
  • 2
  • 21
  • 48