This topic covers how Python and MAXScript values and types interoperate with pymxs.
For simple types such as integers, floats and strings, pymxs has a direct reference to the data, and these values can be obtained and set directly.
For complex types such as Array, pymxs wraps these objects with a MXSWrapper object, pymxs.MXSWrapperBase. For example:
import pymxs rt = pymxs.runtime # Create and visit a MaxScript Array gma = rt.array(*(1,2,3)) print(gma) #output: #(1,2,3) print(len(gma)) #output: 3 gma[1] = 999 print(gma[1]) #output: 999 l = list(gma) #[1,999,3] l[2] = 888 print(l) #output: [1, 888, 3] print(gma) # output: #(1, 999, 3)
For a demonstration of how to create, manipulate and cast complex MAXScript types in Python, see the demoPyMXSTypeInterop.py example.
MAXScript introduced the Dictionary type in 3ds Max 2017.1, and by default uses name literals for key values.
Consider this MAXScript dictionary:
my_dict = Dictionary #(#one, 1) #(#two, 2)
In pymxs, this value is wrapped, and can be used like a MAXScript dictionary, for example getting the keys property:
>>> my_py_dict = pymxs.runtime.my_dict <Dictionary<Dictionary #name one:1 two:2 >> >>> my_py_dict.keys <Array<#(#one, #two)>>
In some cases, it may be more convenient to convert the MAXScript Dictionary to a native Python Dict:
my_py_dict = {str(key):myd[key] for key in pymxs.runtime.my_dict.keys} # yields: {'two': 2, 'one': 1}
As of 3ds Max 2019 Update 1, you can use some pymxs objects (such as scene nodes) as key values in native Python dictionaries (though not in MAXScript Dictionaries). For example:
from pymxs import runtime as rt t1 = rt.teapot() t2 = rt.teapot(pos=rt.point3(20,20,0)) t2.parent = t1 node_dict = {t1:"Teapot 1", t2:"Teapot2"} print(node_dict.keys()) print(node_dict.values())
To determine whether a MAXScript object can be used as a Python dictionary key, you can check whether it implements the python __hash__() function.