6

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.

Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
StanTastic
  • 311
  • 3
  • 18

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
  • 19,278
  • 3
  • 45
  • 60
8

This is commonly used in matplotlib, for example, where a large number of arguments can be conveniently passed using * or **:

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

Calling the function:

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

where the listed arguments 1,2,3,4,5 will go to args whereas the named arguments a=1, b=2, c=3 will go to kwargs, as a dictionary. The listed and named arguments arrive at your function as:

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

Making it convenient to use them inside the function.

Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
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
  • 588,541
  • 66
  • 880
  • 895
  • 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,794
  • 2
  • 29
  • 39
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
  • 20,415
  • 4
  • 46
  • 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,849
  • 16
  • 76
  • 93
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,147
  • 2
  • 22
  • 49