tags:

views:

48

answers:

2

Hi Everyones,

I'm trying to use this library : pastebin.com/xgPXpGtw (an example of use: pastebin.com/fNFAW3Fh) I have some issues since I dont want to split in an array all the byte as he does.

My test script looks like this:

import random
from random import *

def onerand(packet):
    pack  = packet[:]
    byte = str(chr(choice(range(256))))
    pack[choice(range(len(packet)))]= byte
    print "fuzzing rand byte:%s\n" % (byte.encode("hex"))
    return pack

test = "\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63"

while True:
   print onerand(test)

And actually returns :

Traceback (most recent call last):
  File "test.py", line 14, in <module> 
    print onerand(test)
  File "test.py", line 7, in onerand
    pack[choice(range(len(packet)))]= byte
TypeError: 'str' object does not support item assignment

So what should i do to be able to use that function on the test parameters ?

Thanks !

+1  A: 

instead of pack = packet[:], use pack = list(packet), and then return ''.join(pack) at the end.

you can't replace a single byte of a string, but you can convert it to a list of characters, replace one item, and then convert back.

teepark
+3  A: 

In Python, strings are immutable. You pass to function onerand a string, argument name packet, copy it giving a local name pack (still a string, still therefore immutable), then you try to do

pack[whatever] = byte

the index doesn't matter: you're trying to modify the immutable string. That's what the error message is telling you, as clearly as possible it seems to me: you can't do that.

I dont want to split in an array all the byte

Well you surely can't use a string, if you need to assign some of them. What do you have against arrays, anyway? import array, use pack = array.array('c', packet) instead of pack = packet[:], and live happily ever after -- an array.array is very compact and speedy, and mutable too!

Edit: you could do it with a list, as in the accepted answer, but that's only at a truly steep relative cost in performance. Consider, for example:

$ py26 -mtimeit -s's="".join([str(x)[0] for x in range(99)]); import array
> ' 'a=array.array("c",s); a[23]="b"; b=a.tostring()'
1000000 loops, best of 3: 1.09 usec per loop
$ py26 -mtimeit -s's="".join([str(x)[0] for x in range(99)]); import array
> ' 'a=list(s); a[23]="b"; b="".join(a)'
100000 loops, best of 3: 7.68 usec per loop

A list is a much more general structure than the array.array you really need here, whence the more-than-seven-times slowdown in choosing the wrong data structure. (It's less terrible in Python 2.7, "only" a 4-times-plus slowdown -- but, think how much it would cost you to buy a machine four times faster than your current one, and maybe you'll agree that even speeding things up by "just" 4+ times, instead of 7+ times, is still a well-worthwhile byproduct;-).

Alex Martelli
`'b=s[:23]+"b"+s[24:]'` is almost twice as fast again
gnibbler
@gnibbler, yep, if you need to set only one byte in a string of moderate length. `array` scales up better for longer strings and/or more byte-assignments required.
Alex Martelli
the trick is that its the *relative* performance cost. fast enough is fast enough, and unless he's maxing out his current machine's CPU turning strings into lists, he can save his money (he isn't - on my machine with linux running python 2.6 just the `choice(range(256))` takes twice as long as the `list` wrap, replacement, and unwrap).another metric here though is readability/understandability, and you can't beat `list` for a widely known, widely understood, unsurprising data structure.nonetheless, great reminder about the `array` module. it is really unfortunate that it is so obscure.
teepark