Using an interable in place of *args?

E

Evan Simpson

Nick said:
def pack(self):
# need some way to call struct.pack with a list/tuple of values
# built with [ self.__dict__[v] for v in self.fields ]
pass

Shouldn't this work?

struct.pack(*tuple([ self.__dict__[v] for v in self.fields ]))

Cheers,

Evan
 
N

Nick Vargish

Greetings,

I'm building a wrapper class for the struct module to help me handle
network data. The tin can on the other end of the string is probably a
C program that does pointer casts into C structures. I'd like to build
a helper class to pack and unpack these datagrams. It will rely on the
struct module for packing and unpacking the data.

I've done the unpacking method quite easily. Another one of those
tasks that makes you feel like programming is a fun and rewarding
pastime, thanks to Python. Problems show up when I try to pack the
data back into a binary string, because struct.pack's arugments are
(format, *args). The problem is, I don't know what *args will be when
I declare the class, only when an object is instantiated.

Is there a general method for calling a function that expects *args
with an iterable instead (tuple or, even better, a list)? I can see
how I could do something funky with exec, but I'd like to avoid that
if possible.

I considered hacking structmodule.c, but that would involve climbing a
certain learning curve, and I would much rather not depend on
non-standard behavior in the standard library.

Thanks for any pointers people might have...

Nick

p.s. Here's the module as it stands (minus some front matter):

import struct

class dstruct(object):

def __init__(self, structure, hasblob = False):
self.format = ''.join([ y for x, y in structure ])
self.fields = [ x for x, y in structure ]
self.hasblob = hasblob
for v in self.fields:
self.__dict__[v] = None
if hasblob:
self.blob = None
self.structsize = struct.calcsize(self.format)

def unpack(self, dat):
elements = struct.unpack(self.format, dat[:self.structsize])
for k, v in zip(self.fields, elements):
self.__dict__[k] = v
if self.hasblob:
self.blob = dat[self.structsize:]

def pack(self):
# need some way to call struct.pack with a list/tuple of values
# built with [ self.__dict__[v] for v in self.fields ]
pass
 
B

Bengt Richter

Greetings,


Is there a general method for calling a function that expects *args
with an iterable instead (tuple or, even better, a list)? I can see
how I could do something funky with exec, but I'd like to avoid that
if possible.
>>> def foo(*args): print args ...
>>> foo(*[x for x in 'You mean like this ?'.split()])
('You', 'mean', 'like', 'this', '?')

(just prefix '*' to unpack a sequence into the arg list)

You can even unpack a generator-supplied sequence:
... for x in 'You mean like this ?'.split(): yield x
... ('You', 'mean', 'like', 'this', '?')

It's not limited to passing args to *args on the receiving end either, though
the count has to match if it's fixed:
this works too
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: bar() takes exactly 3 arguments (9 given)

Regards,
Bengt Richter
 
P

Paul Rubin

Can you give an example of what you're trying to do? Your description
and code are way too confusing. But it sounds to me like your best bet
may be to use the array module and build up your string a field at a time.
 
S

sdd

Nick Vargish wrote:

.... Is there a general method for calling a function that expects *args
with an iterable instead (tuple or, even better, a list)? I can see
how I could do something funky with exec, but I'd like to avoid that
if possible.

I'm unsure of what you mean; if you explain why this doesn't solve
your problem, we'll go from there?:

I suspect you want something that can be used in the following way:
obj = dstruct(...)
...
obj.pack(5,4,3,2)

To put a little meat in, I'll have pack simply print its args:

class dstruct(object):
...
def pack(self, *args):
for element in args:
print element

This works, now what is unlike what you want?

-Scott David Daniels
(e-mail address removed)
 
N

Nick Vargish

Thanks for all the replies -- I think what I want is the *arg
idiom. Amazing that I hadn't encountered it until now!

Over my lunch break I realized that I could do what I wanted with
apply(struct.pack, tuple), but the *arg thing is much tidier.

Thanks again,

Nick
 
D

David M. Wilson

Nick Vargish said:
def __init__(self, structure, hasblob = False):
self.format = ''.join([ y for x, y in structure ])
self.fields = [ x for x, y in structure ]
self.hasblob = hasblob
for v in self.fields:
self.__dict__[v] = None


Just random passing code commentary:

def __init__(self, structure, hasblob = False):
self.format = ''
self.fields = []

for format, field in structure:
self.format += format
self.fields.append(field)
vars(self)[field] = None


That avoids the triple iteration. The vars(self) call is unnecessary,
I just think it looks cleaner. :)


David.
 
N

Nick Vargish

Just random passing code commentary: [...]
for format, field in structure: [...]
That avoids the triple iteration. The vars(self) call is unnecessary,
I just think it looks cleaner. :)

Interestingly enough, I'd already swapped out the list comprehensions
for a single for loop. :^)

Some respondants seemed confused about what I was trying to do... I'm
communicating with a C program that generates datagrams from a C
structure. Many of the datagrams have, for the last two fields,
"unisigned int datasize; char data[]". I wanted a convenient way of
extracting the fields of known size, and the data blob at the end.

If others are interested in the class I've built, I can make it
available (maybe through the Cookbook web site) when it's a little
more mature.

Again, thanks for all the pointers. Although the language itself is
the first reason, the community is a close second for why I love
programming in Python.

Nick
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,171
Messages
2,570,933
Members
47,472
Latest member
KarissaBor

Latest Threads

Top