Some of you may know that in LabVIEW 2022 Q3, you can now use the Python Node to pass Python objects from one call to the next. How does that work? Well that is what I decided to investigate. Part of this was prompted by a post by jennapark86 on the LabVIEW Discord. Jenna, I hope you don't mind but I "borrowed" your car example for this post.
I had heard that NI had added this feature to LV2022Q3 but I hadn't had an excuse to install the new version yet. The first time I saw it in action was on a Discord post. Jenna posted this example.
Unfortunately Jenna's example doesn't work. As James McNally points out below the issue has to do with the scope/namespacing of the get_brand method. It is a method of the Car class not the module. Several attempts were made to use various calling conventions to try and access the get_brand method, but none of them worked. As Jenna points out writing a wrapper function does work, but is rather cumbersome.
An Example on GitLab
I put together an example and posted it to GitLab here: https://gitlab.com/sas-blog/Python_Class_LV22Q3 If you clone the repo, the Class Demo.vi shows trying to call the class method directly, which doesn't work and also shows calling the wrapper, which does work.
I have to say that my initial reaction to this news was kind of negative. I immediately fit it into the narrative of NI's growing distance from it's customers. Of course anyone using this would want to call methods directly on the class object. Why could NI not see that and have anticipated it? I googled for some answers on how to use Classes with the Python Node and found basically nothing. Adding wrappers puts extra burden on your users. If NI was going to do that, they could at least let people know that was needed.
I used my main recourse when I see NI do something I disagree with, I posted it on the Champion's Forum (It's a private part of the NI forums where Champions and NI can have open discussions about various issues). I asked "How is this supposed to work? because it isn't working the way I anticipated." I did not get a response from NI (they aren't known for their communication - even on the Champion's Forum), but I did get an interesting response from Rolf, one of the other Champions.
Rolf basically said that what is currently implemented is a first step towards what I had in mind. I thought about that for a minute. On reflection I have to say that I can't fault NI for that at all. Iteratively releasing features is very much an agile process. Prove that you can return an object and pass it around first. Verify that it is possible and customers actually find it useful, then work on adding access to class methods. In the end I think they are doing things right, I just wish they would have communicated a little better about it.
That whole exchange got me thinking about what is possible now with the ability to pass Python objects back and forth using the Python Node. The immediate thing that struck me was the ability to pass functions around. Lots of Python functions, like the filter() function accept another function as an argument. Was that on NI's Roadmap? I made a post on the Champion's Forum to ask.
Everything In Python Is An Object
I had in my head that functions were a different type of object. In LabVIEW a VI reference is not a generic LabVIEW object. I was reminded during the GLA Summit on Python and LabVIEW that all things in Python are Python Objects including functions. I immediately connected those dots and said maybe it already works.
And it works!
Well I tried it out and it does in fact work! You can check out a working example here: https://gitlab.com/sas-blog/Python_Class_LV22Q3/ It is the same repository I linked above. If you open the FP Demo.vi you'll see it first creates a greater than 5 function and then uses that function to filter a list. Note I had to use a wrapper here as well.
So it appears that you can create Python Objects (including functions) and pass them into LabVIEW to hold between Python Node calls. At least for the moment, the one caveat/downside is that you can't call any built-in Python methods or directly call any methods on an object without a wrapper. So it appears you need to write a LabVIEW wrapper for your Python code that exposes any functions/methods you want to call.