M
Modular4mo ago
tzl

Why is this in-place operation not modifying the Python object in-place?

from python import Python

def do_numpy_stuff(ar: PythonObject) -> PythonObject:
ar.__iadd__(3)
print("inside function:\n", ar)

return ar


fn main() raises:
var np = Python.import_module("numpy")
var ar = np.arange(15).reshape(3, 5)
print(ar)

print("do_numpy_stuff:")
do_numpy_stuff(ar)
print("outside function:\n", ar)
from python import Python

def do_numpy_stuff(ar: PythonObject) -> PythonObject:
ar.__iadd__(3)
print("inside function:\n", ar)

return ar


fn main() raises:
var np = Python.import_module("numpy")
var ar = np.arange(15).reshape(3, 5)
print(ar)

print("do_numpy_stuff:")
do_numpy_stuff(ar)
print("outside function:\n", ar)
I would expect the outside function ar print to print the modified ar, because the ar is passed as object reference. But I got this:
> mojo do_numpy_stuff.mojo
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
do_numpy_stuff:
inside function:
[[ 3 4 5 6 7]
[ 8 9 10 11 12]
[13 14 15 16 17]]
outside function:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
> mojo do_numpy_stuff.mojo
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
do_numpy_stuff:
inside function:
[[ 3 4 5 6 7]
[ 8 9 10 11 12]
[13 14 15 16 17]]
outside function:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
6 Replies
Michael K
Michael K4mo ago
Your signature needs to be def do_numpy_stuff(inout ar: PythonObject) -> PythonObject:. Note the addition of inout. That means changes to ar inside the function also show up outside the function. Otherwise you are working with a copy and as you see the changes don't get reflected. I am not sure if this will always be the case for def functions since the expectation in Python is that everything is inout.
tzl
tzl4mo ago
I understand with inout it would be mutated. But inout is when regarding a Mojo variable, one could reassign this variable (lvalue) to anything of the same type:
from python import Python

def do_numpy_stuff(inout ar: PythonObject) -> PythonObject:
ar = Python.list()
print("inside function:\n", ar)

return ar


fn main() raises:
var np = Python.import_module("numpy")
var ar = np.arange(15).reshape(3, 5)
print(ar)

print("do_numpy_stuff:")
do_numpy_stuff(ar)
print("outside function:\n", ar)
from python import Python

def do_numpy_stuff(inout ar: PythonObject) -> PythonObject:
ar = Python.list()
print("inside function:\n", ar)

return ar


fn main() raises:
var np = Python.import_module("numpy")
var ar = np.arange(15).reshape(3, 5)
print(ar)

print("do_numpy_stuff:")
do_numpy_stuff(ar)
print("outside function:\n", ar)
prints out
> mojo do_numpy_stuff.mojo
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
do_numpy_stuff:
inside function:
[]
outside function:
[]
> mojo do_numpy_stuff.mojo
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
do_numpy_stuff:
inside function:
[]
outside function:
[]
Any PythonObject would do. This is a separate point from what I was trying to show up there in the orignal post. What I was expressing in the original post was more similar to when PythonObject is a list. This would mutate the Python object internally.
from python import Python

def do_py_stuff(li: PythonObject) -> PythonObject:
li.append(1)
print("inside function:\n", li)

return li


fn main() raises:
var li = Python.list()
print(li)

print("do_py_stuff:")
do_py_stuff(li)
print("outside function:\n", li)
from python import Python

def do_py_stuff(li: PythonObject) -> PythonObject:
li.append(1)
print("inside function:\n", li)

return li


fn main() raises:
var li = Python.list()
print(li)

print("do_py_stuff:")
do_py_stuff(li)
print("outside function:\n", li)
mojo do_numpy_stuff.mojo
[]
do_py_stuff:
inside function:
[1]
outside function:
[1]
mojo do_numpy_stuff.mojo
[]
do_py_stuff:
inside function:
[1]
outside function:
[1]
sora
sora4mo ago
I think this is a bug. Please consider file an issue on GH.
Jack Clayton
Jack Clayton4mo ago
Hey yeah @tzl this mutation should definetly be visible in the caller side as well even without inout as it is in Python, if you can please raise an issue
tzl
tzl4mo ago
GitHub
[BUG] NumPy array in-place operation over a copied object reference...
Bug description from python import Python def do_numpy_stuff(ar: PythonObject) -> PythonObject: ar.iadd(3) print("inside function:\n", ar) return ar fn main() raises: var np = Pyth...
Jack Clayton
Jack Clayton4mo ago
Thanks heaps for that @tzl
Want results from more Discord servers?
Add your server