1

I'm looking for a way to change the variables defined inside a function after defining the function.

For example

def GetNthPower(x) :
    n = None
    return x**n

my_numbers_list = [11,23,45,56,78,98]

# now if I feel like I need the 4th power of some numbers in the list 

GetNthPower.n = 4

for x in my_numbers_list :
    print GetNthPower(x)

#  If I want 7th power then
GetNthPower.n = 7 

This obviously will not work, is there any way to do this?

N.B: I know we can achieve this by setting 'n' as an argument of the function, but I want to do it this way for a particular reason. I want my function to have only one argument (for using the function in multiprocessing.Pool.map()).

Corentin Pane
  • 4,794
  • 1
  • 12
  • 29
brownser
  • 545
  • 7
  • 25
  • 1
    you could use `functools.partial` for this. give your function an `n` argument, then generate new functions for different values of `n` using `functools.partial` – Dan Nov 08 '19 at 15:13
  • 1
    Maybe wrap the function in a class and using `self.n` and change the `self.n` accordingly? – LeoE Nov 08 '19 at 15:14

3 Answers3

3

You can define static variables inside functions, almost like you did:

def GetNthPower(x) :
    return x ** GetNthPower.n

GetNthPower.n = 3

print(GetNthPower(2)) #8

Make sure to initialize correctly your GetNthPower.n before first use though.

If you're worried about initialization, you could go for this version which uses a default value 1:

def GetNthPower(x) :
    return x ** (GetNthPower.n if hasattr(GetNthPower, "n") else 1)

I think it would still be better for you to write a function that takes two arguments, or use the predefined ** operator.

Corentin Pane
  • 4,794
  • 1
  • 12
  • 29
  • 1
    Thanks, this is working. \\ No, the function I put here is just an example. The actual function is a long function which takes a long time to complete, so I wanted to parallelize it using `Pool.map`, but couldn't do as there were some variables in the argument which aren't iterable. – brownser Nov 08 '19 at 15:21
2

Don't use one function; create a function that makes your function, using a closure.

def nth_power_maker(n):
    def _(x):
        return x ** n
    return _

my_numbers_list = [11,23,45,56,78,98]

# now if I feel like I need the 4th power of some numbers in the list 

get_4th_power = nth_power_maker(4)

for x in my_numbers_list:
    print(get_4th_power(x))

get_7th_power = nth_power_maker(7)
Corentin Pane
  • 4,794
  • 1
  • 12
  • 29
chepner
  • 497,756
  • 71
  • 530
  • 681
2

Alternatively, you could use functools.partial to bind a keyword argument to a function

from functools import partial

def get_nth_power(x, n):
    return x ** n

get_third = partial(get_nth_power, n=3)

get_third(4)
64

x = 4

# in a loop
for pow in [2, 4, 6, 8]:
    f = partial(get_nth_power, n=pow)
    f(x)
C.Nivs
  • 12,353
  • 2
  • 19
  • 44
  • I didn't know about this ! Is it like defining ``get_third = lambda x : get_nth_power(x, 3)``? it looks a lot like ocaml curryfication. – Corentin Pane Nov 08 '19 at 15:25
  • It's similar, though the use for `lambda` is generally *not* to name it in global scope. See [this post](https://stackoverflow.com/a/134638/7867968), but effectively, a lambda is supposed to be anonymous, just used in-place for sorting, filtering, etc. When you find yourself doing `f = lambda x: ...`, you're better off using `def f` – C.Nivs Nov 08 '19 at 15:28