[Tutor] Concatenating numeric data in Python 3.3

Prasad, Ramit ramit.prasad at jpmorgan.com
Wed Apr 24 22:21:18 CEST 2013


Thank you for not replying above, but please continue to CC the tutor list.

sparkle Plenty wrote:
> 
> On Wed, Apr 24, 2013 at 2:45 PM, Prasad, Ramit <ramit.prasad at jpmorgan.com> wrote:
> Please post your response *after* the quoted context.
> 
> sparkle Plenty wrote:
> >
> > Thanks to both of you for your assistance.
> > Since the completed message must be in hex, I also have an issue with losing high order zeros during
> > conversions, although the binary shift works well for adding on to the end of the string.  I cannot
> > pack string data, and I cannot concatenate numbers, so the conversions, although smelly, were what I
> > knew to try.  I welcome the idea of abandoning that course of action.  It didn't work anyway.
> >
> >  I will have an unknown number of instances, each of which consists of 3 numeric values.  I tried
> > packing each instance using struct.pack, then converting to  a tuple, then concatenating.  This ran,
> > but introduced errors: in some instances, high order truncation of a leading zero in the first of
> the
> > 3 values.  This throws off the position of all data that follows.  Error messages and error code are
> > dependent on which technique is being tried.  The most recent ones are:
> > TypeError: can't concat bytes to str
> > TypeError: Can't convert 'tuple' object to str implicitly
> >
> >
> Can you give us the format and samples of the input and the output? We do not
> need real data, often you can just use data of the same type but change values.
> 
> If you need hex, you can turn numbers into hex str by using the hex() built-in.
> 
> >>> ''.join([hex(15), hex(1239393), hex(49494)])
> '0xf0x12e9610xc156' # Need to handle formatting
> 
> You may want to also look at the binascii module for some functions for
> converting data. Again, if you provide some sample output (and hopefully input)
> then we can help you better.
> 
> 
> ~Ramit
> 
> 
> This email is confidential and subject to important disclaimers and
> conditions including on offers for the purchase or sale of
> securities, accuracy and completeness of information, viruses,
> confidentiality, legal privilege, and legal entity disclaimers,
> available at http://www.jpmorgan.com/pages/disclosures/email.
> 
> Input is from  a gui so the first value is obtained from the identifier for the control the user
> changed:
> 1234
> The second value is associated with the first.
> 01
> The third value is, for instance, a switch on/off
> 01 or 00, let's say it's 00.
> 
> the output for this instance would need to be
> 0x04d20x010x00.

Are you sure you want the starting '0x' for each byte?

> 
> Here is my function as it stands now:
> 
>   def conCatNumbers(numOne, numTwo, numThree):
>     global instanceGroup, lengthCounter, instanceCounter
>     print("Pre Pack:  ", numOne, " ", numTwo, " ", numThree)
>     packValues = struct.pack("HBB", numOne, numTwo, numThree)
>     print("Post Pack: ", packValues)
>     instanceValues = (packValues, )
>     print(instanceValues)
>     instanceGroup = (instanceGroup, )
>     instanceGroup = instanceGroup + instanceValues
>     lengthCounter += 4
>     instanceCounter += 1
>     return (instanceGroup, lengthCounter, instanceCounter)
> 
> It is the first function I have written, and it is an ugly little spud.

Why are you using global variables? What purpose do they serve?
If you can provide the rationale for the global variables, chances
are we can suggest a better way to do that. I think you would be
better off having instanceGroup as a list and append to the list.
As it is right now instanceGroup is a weirdly nested list. Look at 
difference between the following two sets of code and output.

>>> blah = ()
>>> def foo():
...     global blah
...     instanceValues = ('\x04\xd2\x01\x00', )
...     blah = (blah,)
...     blah = blah + instanceValues
...     print blah
...     
>>> foo()
((), '\x04\xd2\x01\x00')
>>> foo()
(((), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00')
>>> foo()
((((), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00')
>>> foo()
(((((), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00')
>>> foo()
((((((), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00'), '\x04\xd2\x01\x00')

>>> blah = [] 
>>> def foo():
...     instanceValues = '\x04\xd2\x01\x00'
...     blah.append( instanceValues ) # module level object can be mutated without global keyword, 
                                      # just not reassigned (name binding).
...     print blah
...     
>>> foo()
['\x04\xd2\x01\x00']
>>> foo()
['\x04\xd2\x01\x00', '\x04\xd2\x01\x00']
>>> foo()
['\x04\xd2\x01\x00', '\x04\xd2\x01\x00', '\x04\xd2\x01\x00']
>>> foo()
['\x04\xd2\x01\x00', '\x04\xd2\x01\x00', '\x04\xd2\x01\x00', '\x04\xd2\x01\x00']


Your struct.pack() line seems fine, but you might want to specify
endian-ness as the default value may vary by architecture. 
(See http://en.wikipedia.org/wiki/Endian )

>>> struct.pack('>HBB', 1234,1,0 )
'\x04\xd2\x01\x00' # note location of 4 and d2
>>> struct.pack('<HBB', 1234,1,0 )
'\xd2\x04\x01\x00' # note location of 4 and d2 are swapped


[copied from above]
>     lengthCounter += 4
>     instanceCounter += 1
>     return (instanceGroup, lengthCounter, instanceCounter)

It is seems like that you are using these to keep track of length
or iterating over them. If you switch to list you can do something like:

for instance in instanceGroup:
   do_task(instance)
for index, instance in enumerate(instanceGroup): # useful if you want to know iteration number
    do_task(instance)
    if not index % 100: # log heartbeat every 100 iterations
        print('Went through {} iterations'.format(index))
instanceCounter = len(instanceGroup)
lengthCounter = instanceCounter*4 


~Ramit




More information about the Tutor mailing list