A quite efficient way to do this is to use functools.partial
, but as has been pointed out, partial
only lets you "freeze" final args. If you need something else, you can easily implement your own version using a closure.
This approach is actually a little more efficient than using a partial
object, since when you call the partial
it still has to call the original function that you pass in, so each call of the partial
results in two calls, and Python function / method calls are relatively slow. If you're curious, take a look at the Python source code for functools.partial
.
In this example, I've made A
the second (pseudo) parameter of the function, since partial
nicely handles the case where it's the last arg.
def my_partial(param):
A = param
print('Creating two_arg_func with A ==', A)
def two_arg_func(t, y):
# Do something with all the args
return 'args', t, A, y
return two_arg_func
def test(f):
for u in range(10, 50, 10):
print(f(u, u + 5))
test(my_partial(7))
output
Creating two_arg_func with A == 7
('args', 10, 7, 15)
('args', 20, 7, 25)
('args', 30, 7, 35)
('args', 40, 7, 45)
We don't really need param
in my_partial
, we can just use the passed in arg, since that's local to my_partial
:
def my_partial(A):
print('Creating two_arg_func with A ==', A)
def two_arg_func(t, y):
return 'args', t, A, y
return two_arg_func
From your comments, I now understand that you want to be able to vary A
. Of course you can do that by calling partial
or my_partial
again, but if you want to modify A
a lot that's not so efficient.
Your comments indicate that you want to modify A
in the global context, so you might as well just use a global. You don't need to actually put the code modifying A
into the global context, you can wrap it in a function, but of course you will need to use the global
directive in the function that modifies A
. You do not need the global
directive in any function which merely reads the value of A
, though.
Here's a short demo.
def two_arg_func(t, y):
# Do something with the args and with A
return 'args', t, A, y
def solve(f):
for u in range(10, 40, 10):
print('SOLVER', f(u, u + 5))
def test(f):
global A
for A in range(7, 10):
print(A)
solve(f)
test(two_arg_func)
output
7
SOLVER ('args', 10, 7, 15)
SOLVER ('args', 20, 7, 25)
SOLVER ('args', 30, 7, 35)
8
SOLVER ('args', 10, 8, 15)
SOLVER ('args', 20, 8, 25)
SOLVER ('args', 30, 8, 35)
9
SOLVER ('args', 10, 9, 15)
SOLVER ('args', 20, 9, 25)
SOLVER ('args', 30, 9, 35)
However, that previous solution is somewhat unsatisfactory, since the main thrust of your question was how to do this without using a global. So here's a slight variation on that code. Instead of putting A
in the global namespace, we attach it to two_arg_func
as a function attribute. We can do this because a Python function is an object, and it already has a whole bunch of attributes; two you may be familiar with are __name__
and __doc__
. Anyway, here's the new code, it prints the same output as the previous version.
def two_arg_func(t, y):
A = two_arg_func.A
# Do something with the args and with A
return 'args', t, A, y
def solve(f):
for u in range(10, 40, 10):
print('SOLVER', f(u, u + 5))
def test(f):
for A in range(7, 10):
print(A)
f.A = A
solve(f)
test(two_arg_func)