Hi Marcus,

Thank you very much for your response!

I just tried implementing the functions using lambdas in Python and ran into 
another issue I've seen before:

gr::log :ERROR: thread_body_wrapper - ERROR thread[thread-per-block[3]: <block 
msg_mux(1)>]: AttributeError: 'gnuradio.gr.gr_python.block_gateway' object has 
no attribute '<lambda>'

At:
  /usr/local/lib/python3.9/dist-packages/gnuradio/gr/gateway.py(133): 
__getattr__


Based on some similar errors I was getting while experimenting using the 
partial methods, I started to get curious on how set_msg_handler actually 
stores the function used for the callback and stumbled upon an issue recently 
opened: https://github.com/gnuradio/gnuradio/issues/5781

It turns out that GNU Radio actually stores a string reference to the callback 
function, not the function object itself.

While I was hoping this would be a relatively simple block to implement in 
Python, I'll probably just try to implement it in C++ using lambdas as you 
suggested since this seems like an open issue.

Thanks again!
Jason

On Jun 29, 2022, at 2:59 PM, Marcus Müller 
<mmuel...@gnuradio.org<mailto:mmuel...@gnuradio.org>> wrote:

Hi Merlo,

On 29.06.22 18:53, Merlo, Jason wrote:
A separate function can be registered for each input, however I would need to 
dynamically generate functions based on the number of inputs a user has 
configured, which has been giving me trouble. Ideally, the function handler 
callback would provide auxiliary arguments to pass to the callback function as 
arguments that can be bound at instantiation (such as index), but I don't think 
this is possible.

It definitely is! It's what lambdas are for.
I've written a small illustration for you: 
https://urldefense.com/v3/__https://gcc.godbolt.org/z/cssn8hMno__;!!HXCxUKc!zwvnRKxB5ayC3GoeYEHbJHIo2hjoTP4O-0gr-GppICyBqdk1fIi3gop6MC4RciSBlEhkAwtE07yogpP-faQ$
Here, "float divide(int, int)" is your function that takes an extra argument 
(in case of your universal message handler, that might be the name of the 
handler).

with [capture](arguments) { return something; } you can write an anonymous 
function (a lambda) that "knows" its "captured" values, and still takes 
arguments.

Presently, I've looked into the functools package |partialmethod| to create 
separate instances of the |process_msg(self, msg, idx)| method with the 
|ch_idx| argument set, effectively creating |process_msg_idx(self, msg)| 
dynamically based on the number of inputs the user desires like:
Oh, this is python. Makes it a bit easier;

handler_name = something
lambda argument: underlying_function(argument, handler_name)

curries underlying function to have its second argument already set, i.e. down 
to a function of a single variable.

Best regards,
Marcus


Reply via email to