See the question and my original answer on StackOverflow

With this type of C/C++ method:

SetValues(BSTR Keyword, SAFEARRAY * Data)

It's probable that you have this .IDL file (or any corresponding TLB or COM tooling that ends up with this C/C++ method), as .IDL requires the type of SAFEARRAY argument to be specified:

interface IMyInterface : IDispatch
{
    HRESULT SetValues(BSTR Keyword, SAFEARRAY(VARIANT) Data);
};

So, this is in fact the easiest and versatile way to pass any number of arguments of any type from Python to a COM object as PyWin32 will automatically convert Python objects into "VARIANT-type objects" (e.g: object that can be wrapped by a VARIANT struct)

So this:

handle.SetValues("PUT_IT_HERE", vals)

will simply work. In this case, the native side will get 3 VARIANTs of VT_R8 type. If you pass say ("hello", "world"), you will get 2 VARIANTs of VT_BSTR type, but you can pass arrays of arrays of variants, etc.