eliben a écrit :
On Jun 20, 9:17 am, Bruno Desthuilliers <bruno.
[EMAIL PROTECTED]> wrote:
eliben a écrit :> Hello,

In a Python program I'm writing I need to dynamically generate
functions[*]
(snip)

[*] I know that each time a code generation question comes up people
suggest that there's a better way to achieve this, without using exec,
eval, etc.
Just to make things clear: you do know that you can dynamically build
functions without exec, do you ?


Yes, but the other options for doing so are significantly less
flexible than exec.

Let's see...

But in my case, for reasons too long to fully lay out, I
really need to generate non-trivial functions with a lot of hard-coded
actions for performance.
Just out of curiousity : could you tell a bit more about your use case
and what makes a simple closure not an option ?

Okay.

I work in the field of embedded programming, and one of the main uses
I have for Python (and previously Perl) is writing GUIs for
controlling embedded systems. The communication protocols are usually
ad-hoc messages (headear, footer, data, crc) built on top of serial
communication (RS232).

ok

The packets that arrive have a known format. For example (YAMLish
syntax):

packet_length: 10
fields:
  - name: header
    offset: 0
    length: 1
  - name: time_tag
    offset: 1
    length: 1
    transform: val * 2048
    units: ms
  - name: counter
    offset: 2
    length: 4
    bytes-msb-first: true
  - name: bitmask
    offset: 6
    length: 1
    bit_from: 0
    bit_to: 5
...

This is a partial capability display. Fields have defined offsets and
lengths, can be only several bits long, can have defined
transformations and units for convenient display.

ok

I have a program that should receive such packets from the serial port
and display their contents in tabular form. I want the user to be able
to specify the format of his packets in a file similar to above.

ok

Now, in previous versions of this code, written in Perl, I found out
that the procedure of extracting field values from packets is very
inefficient. I've rewritten it using a dynamically generated procedure
for each field, that does hard coded access to its data. For example:

def get_counter(packet):
  data = packet[2:6]
  data.reverse()
  return data

This gave me a huge speedup, because each field now had its specific
function sitting in a dict that quickly extracted the field's data
from a given packet.

ok. So if I get it right, you build the function's code as a string based on the YAML specification.

If so, well, I can't think of anything really better[1] - at least *if* dynamically generated procedures are really better performance wise, which may *or not* be the case in Python.

[1] except using compile to build a code object with the function's body, then instanciate a function object using this code, but I'm not sure whether it will buy you much more performance-wise. I'd personnaly prefer this because I find it more explicit and readable, but YMMV.

Now I'm rewriting this program in Python and am wondering about the
idiomatic way to use exec (in Perl, eval() replaces both eval and exec
of Python).

Well... So far, the most pythonic way to use exec is to avoid using it - unless it's the right tool for the job !-)


--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to