Matthew Cassell
Matthew Cassell

Reputation: 279

Increment function name in Python

I apologise if there is already an answer to my question, I've searched stack overflow for a while but found nothing that I could use.

I'm learning how to create classes at the moment and I've constructed classes for the explicit Runge-Kutta methods 1-4. The names of the classes are 'RK_1', 'RK_2', 'RK_3' and 'RK_4'. In order to test my code, I decided to solve the Legendre differential equation, which I also created a class for called 'Legendre'.

Now I wanted to solve the problem, so I wrote a function that uses a particular RK scheme and solves the Legendre problem. I wanted to do this for each one of my RK schemes, so I wrote the same function 4 times i.e

def solve_Legendre_1(p,Tmax,init,dt=0.001):

    f      = Legendre(p)
    solver = RK_1(init,f)

    while solver.now() < Tmax:
        solver(dt)

    return solver.state()

def solve_Legendre_2(p,Tmax,init,dt=0.001):

    f      = Legendre(p)
    solver = RK_2(init,f)

    while solver.now() < Tmax:
        solver(dt)

    return solver.state()

def solve_Legendre_3(p,Tmax,init,dt=0.001):

    f      = Legendre(p)
    solver = RK_3(init,f)

    while solver.now() < Tmax:
        solver(dt)

    return solver.state()

def solve_Legendre_4(p,Tmax,init,dt=0.001):

    f      = Legendre(p)
    solver = RK_4(init,f)

    while solver.now() < Tmax:
        solver(dt)

    return solver.state()

However, I realised there must be an easier way to do this. So I thought I might be able to use a loop and str.format() to change the name of the function and get it to take in its corresponding RK scheme, something like

for j in range(4):
    def solve_Legendre_%s(p,Tmax,init,dt=0.001) % (j+1):

        f      = Legendre(p)
        solver = RK_%s(init,f) % (j+1)

        while solver.now() < Tmax:
            solver(dt)

        return solver.state()

but obviously this won't work. Does anyone know how I should approach this?

Thanks for your help.

Upvotes: 1

Views: 1225

Answers (4)

Nab Ilovich
Nab Ilovich

Reputation: 360

You should add a parameter to you function. So you have one function to solve all your schemes :

def solve_Legendre(p,Tmax,init,dt=0.001, RK):

    f      = Legendre(p)
    solver = RK(init,f)

    while solver.now() < Tmax:
        solver(dt)

    return solver.state()

You can set a default value for RK if you want :

def solve_Legendre(p,Tmax,init,dt=0.001, RK=RK_1):

Upvotes: 1

Radosław Cybulski
Radosław Cybulski

Reputation: 2992

Your functions differ only by RK_x function, which you can simply pass by additional variable. This will minimize code redundancy:

def solve_Legendre(RK_func, p,Tmax,init,dt=0.001):

    f      = Legendre(p)
    solver = RK_func(init,f)

    while solver.now() < Tmax:
        solver(dt)

    return solver.state()

Now to your question - you can query globals for this. globals() function will return map with every object defined at global scope keyed by identifier. So you could write (using my previous function):

for j in range(4):
    globals()['solve_Legendre_%d' % (j + 1)] = lambda *args, **kw_args: solve_Legendre(globals()['RK_%d' % (j + 1)], *args, **kw_args)

Upvotes: 1

Christian K&#246;nig
Christian K&#246;nig

Reputation: 3570

You can use arguments not only to give "usual" things, like numbers, lists or strings to a function, you can also use functions themselves as parameters:

>>> def test1():
    print(1)

>>> def test2():
    print(2)

>>> def solve_with_func(funcname):
    funcname()

>>> solve_with_func(test1)
1
>>> solve_with_func(test2)
2

This way you can use the same logic in solve_with_func and simply swap out the function that is executed.

This can of course be extended to lists of functions:

>>> def execute_all(funclist):
    for f in funclist:
        f()


>>> execute_all([test1, test2])
1
2

Upvotes: 1

Duncan
Duncan

Reputation: 95742

You can simply pass the RK_n() function in as a parameter to avoid duplicating the other function:

def solve_Legendre(p,Tmax,init,dt=0.001, RK=RK_1):

    f      = Legendre(p)
    solver = RK(init,f)

    while solver.now() < Tmax:
        solver(dt)

    return solver.state()

and if you want you can bind that last parameter in advance:

import functools
solve_Legendre_1 = functools.partial(solve_Legendre, RK=RK_1)
solve_Legendre_2 = functools.partial(solve_Legendre, RK=RK_2)
...

Upvotes: 7

Related Questions