First, let us work out why what you are trying to achieve is difficult. What would function op_assgn(a, b)
that somehow replaces assignment a=b
need to do? The main difficulty is that it would need to know the name of the object the caller passed for argument a
. In fact, the object bound to a
at this point in time is completely irrelevant, yet that is what is available to op_assgn
. So, if we were hellbent on getting this to work the function would have to peek up one frame, find the call statement, somehow get hold of what arguments were passed and bind a value to a name outside its (the function's) scope. It probably can be done but not without a considerable amount of black magic.
So maybe it is wiser to not touch the assignment itself and do the packaging just before. Here is a simple implementation of this idea.
def op1(b, c):
return c
op2 = np.ndarray.__iadd__
c = np.array((1,2))
b = np.array((0,0))
Note that we are assigning to a new variable d
merely to be able to see what exactly is going on. Ultimately, you would want to assign to b
instead.
# this is straight-forward
d = op1(b, c)
d is c
# True
d is b
# False
d
# array([1, 2])
# this works because .__iadd__ does the inplace op AND
# returns the modified object
d = op2(b, c)
d is c
# False
d is b
# True
d
# array([1, 2])
So, basically this does what you want (once you have replaced d
with b
) except that it involves a tiny bit more typing and that its equivalent if clause would be something like
if a:
b = c
else:
b += c
b = b
with that slightly ugly redundant assignment in the last line.
Please note that this is mostly an aesthetical problem, since the assignment---being done by reference---is cheap:
def f1():
global c
c.__iadd__(b)
def f2():
global c
c = c.__iadd__(b)
timeit(f1)
# 1.4087995890295133
timeit(f2)
# 1.4474492500303313