By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,676 Members | 2,249 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,676 IT Pros & Developers. It's quick & easy.

succint representation of struct arguments

P: 3
I want to import some binary data with the struct module, edit it, then export it again. The problem is that I can't find a shorthand way to represent my list of data without having to write it twice. The simple way to do this is:
Expand|Select|Wrap|Line Numbers
  1. [mass,speed,width] = struct.unpack("BBB", "\x01\x02\x03")
  2. mass+=1
  3. struct.pack("BBB", mass, speed, width)
  4.  
The problem is that I have to write my variables twice, which poses problems for maintenence (my real program has many more elements). The ideal solution would be one that only requires me to write out my elements once. With the C preprocessor I could something like this:
Expand|Select|Wrap|Line Numbers
  1. #define args mass,speed,width
  2. [args] = struct.unpack("BBB", "\x01\x02\x03")
  3. mass += 1
  4. struct.pack("BBB", args)
  5.  
Of course, python doesn't have a text preprocessor. Doing things the python way, the major obstacles are:
1) Deal with the variable argument list. I can do that with struct.unpack("BBB", *args)
2) Pass my elements by reference. This is where I'm stuck. If mass, speed, and width were objects, then I could pass them by reference as in the first example and all would be fine. But they can't be objects; they must be ints. The best syntax I can come up with is
Expand|Select|Wrap|Line Numbers
  1. format = {'mass':0,'speed':1,'width':2}
  2. foo = list(struct.unpack("BBB", "\x01\x02\x03"))
  3. foo[format['mass']] += 1
  4. struct.pack("BBB", *foo)
  5.  
But the dictionary references are ugly and unintuitive. Is there a more natural way to do this in python?

In fact, I'm still representing my list twice, because I define its members in one place (format) and its layout in another "BBB". An even better solution would combine those, but I don't see how.
May 3 '07 #1
Share this Question
Share on Google+
5 Replies


bvdet
Expert Mod 2.5K+
P: 2,851
I want to import some binary data with the struct module, edit it, then export it again. The problem is that I can't find a shorthand way to represent my list of data without having to write it twice. The simple way to do this is:
Expand|Select|Wrap|Line Numbers
  1. [mass,speed,width] = struct.unpack("BBB", "\x01\x02\x03")
  2. mass+=1
  3. struct.pack("BBB", mass, speed, width)
  4.  
The problem is that I have to write my variables twice, which poses problems for maintenence (my real program has many more elements). The ideal solution would be one that only requires me to write out my elements once. With the C preprocessor I could something like this:
Expand|Select|Wrap|Line Numbers
  1. #define args mass,speed,width
  2. [args] = struct.unpack("BBB", "\x01\x02\x03")
  3. mass += 1
  4. struct.pack("BBB", args)
  5.  
Of course, python doesn't have a text preprocessor. Doing things the python way, the major obstacles are:
1) Deal with the variable argument list. I can do that with struct.unpack("BBB", *args)
2) Pass my elements by reference. This is where I'm stuck. If mass, speed, and width were objects, then I could pass them by reference as in the first example and all would be fine. But they can't be objects; they must be ints. The best syntax I can come up with is
Expand|Select|Wrap|Line Numbers
  1. format = {'mass':0,'speed':1,'width':2}
  2. foo = list(struct.unpack("BBB", "\x01\x02\x03"))
  3. foo[format['mass']] += 1
  4. struct.pack("BBB", *foo)
  5.  
But the dictionary references are ugly and unintuitive. Is there a more natural way to do this in python?

In fact, I'm still representing my list twice, because I define its members in one place (format) and its layout in another "BBB". An even better solution would combine those, but I don't see how.
Is this any better?
Expand|Select|Wrap|Line Numbers
  1. varList = 'mass','speed','width'
  2. dd = dict(zip(varList, struct.unpack("BBB", "\x01\x02\x03")))
  3. dd['mass']+= 1
  4. struct.pack("BBB", *[dd[key] for key in varList])
May 3 '07 #2

P: 3
Is this any better?
Expand|Select|Wrap|Line Numbers
  1. varList = 'mass','speed','width'
  2. dd = dict(zip(varList, struct.unpack("BBB", "\x01\x02\x03")))
  3. dd['mass']+= 1
  4. struct.pack("BBB", *[dd[key] for key in varList])
That is better. I never thought to use a dictionary like that. There is still dd though. Is there any way to copy simple types by reference, something like
Expand|Select|Wrap|Line Numbers
  1. a=5
  2. b=ref(a)
  3. b+=1
  4. a==6
  5.  
May 3 '07 #3

P: 3
I think I've found the best solution now. I'm still using dd as suggested by bvdet, along with another new trick to clean up the syntax. This is all happening within a class, of course, so I can overload __getattr__ to hide dd from the user of the class. I just write
Expand|Select|Wrap|Line Numbers
  1. def __getattr__(self, name):
  2.     try:
  3.         return self.dd[name]
  4.     except KeyError:
  5.         raise AttributeError
  6.  
within the class, and then programs can refer to the struct arguments as if they were class attributes, e.g. myclass.mass instead of myclass.dd['mass']. This is my final solution.
May 21 '07 #4

bartonc
Expert 5K+
P: 6,596
I think I've found the best solution now. I'm still using dd as suggested by bvdet, along with another new trick to clean up the syntax. This is all happening within a class, of course, so I can overload __getattr__ to hide dd from the user of the class. I just write
Expand|Select|Wrap|Line Numbers
  1. def __getattr__(self, name):
  2.     try:
  3.         return self.dd[name]
  4.     except KeyError:
  5.         raise AttributeError
  6.  
within the class, and then programs can refer to the struct arguments as if they were class attributes, e.g. myclass.mass instead of myclass.dd['mass']. This is my final solution.
Very Pythonic! Thanks for the update to you very elegant solution.
May 21 '07 #5

bvdet
Expert Mod 2.5K+
P: 2,851
I think I've found the best solution now. I'm still using dd as suggested by bvdet, along with another new trick to clean up the syntax. This is all happening within a class, of course, so I can overload __getattr__ to hide dd from the user of the class. I just write
Expand|Select|Wrap|Line Numbers
  1. def __getattr__(self, name):
  2.     try:
  3.         return self.dd[name]
  4.     except KeyError:
  5.         raise AttributeError
  6.  
within the class, and then programs can refer to the struct arguments as if they were class attributes, e.g. myclass.mass instead of myclass.dd['mass']. This is my final solution.
Thank you for sharing your solution with us.
May 21 '07 #6

Post your reply

Sign in to post your reply or Sign up for a free account.