Во-первых, давайте разберемся, почему то, что вы пытаетесь достичь, сложно.Что должна сделать функция op_assgn(a, b)
, которая каким-то образом заменяет присвоение a=b
?Основная трудность заключается в том, что ему нужно знать имя объекта, который вызывающий объект передал в качестве аргумента a
.Фактически, объект, связанный с a
в данный момент времени, совершенно не имеет значения, но это то, что доступно для op_assgn
.Таким образом, если бы мы были склонны к тому, чтобы заставить это работать, функция должна была бы просмотреть один кадр, найти оператор вызова, каким-то образом получить те аргументы, которые были переданы, и привязать значение к имени вне его (функции) области.Вероятно, это можно сделать, но не без значительного количества черной магии.
Так что, возможно, разумнее не трогать само задание и делать упаковку непосредственно перед этим.Вот простая реализация этой идеи.
def op1(b, c):
return c
op2 = np.ndarray.__iadd__
c = np.array((1,2))
b = np.array((0,0))
Обратите внимание, что мы присваиваем новую переменную d
просто для того, чтобы увидеть, что именно происходит.В конечном счете, вы захотите присвоить b
.
# 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])
Итак, в основном это делает то, что вы хотите (как только вы заменили d
на b
), за исключением того, что это включает в себя чуть-чутьбольше ввода и его эквивалент, если предложение if будет выглядеть примерно так:
if a:
b = c
else:
b += c
b = b
с этим немного уродливым избыточным назначением в последней строке.
Обратите внимание, что это в основном эстетическая проблема, так какназначение --- выполняется по ссылке --- дешево:
def f1():
global c
c.__iadd__(b)
def f2():
global c
c = c.__iadd__(b)
timeit(f1)
# 1.4087995890295133
timeit(f2)
# 1.4474492500303313