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}
MAXScript arrays and dictionaries can be created and manipulated in pymxs. In 3ds Max 2021 and later you can manipulate a MAXScript Array directly.
This example illustrates how to create and manipulate MAXScript arrays and dictionaries in pymxs:
# MAXScript Collections in pymxs from pymxs import runtime as rt import pymxs py_array = rt.Array(1,2,3) # 3ds Max 2020 and earlier requires rt.append rt.append(py_array, 4) try: # In 3ds Max 2021, we can do this directly: # adding an arbitrary element will created "undefined" intermediary elements: py_array[5] = 5 except: print('Direct access is available in 3ds Max 2021+') py_dict = rt.Dictionary(("one",1), ("two",2)) py_dict["three"] = 3 # you could also use rt.SetDictValue(py_dict, 'three', 3) print("py_array: ", py_array) print("py_dict: ", py_dict)
Results:
py_array: #(1, 2, 3, 4, undefined, 5) py_dict: Dictionary #string (DataPair "three" 3) (DataPair "one" 1) (DataPair "two" 2)
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.