Python Forum
Unable to bit shift and logical OR bytes and ints? - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Unable to bit shift and logical OR bytes and ints? (/thread-29353.html)



Unable to bit shift and logical OR bytes and ints? - MysticLord - Aug-29-2020

Python 3.8.2
Windows 10
Powershell

I'm trying to grab a set of 32 bit little-endian pointers from the headers in a set of 256 files, and print them sequentially with line breaks between them.

import sys,glob

def printFileAddr(fileName):
    with open(fileName,"rb") as file:
        file.seek(36,0)
        address = file.read(1)
        address = ((file.read(1) << 8) | address)
        address = ((file.read(1) << 16) | address)
        address = ((file.read(1) << 24) | address)
        print(str(address) + "\n")

for arg in sys.argv[1:]:
    for files in glob.glob(arg):
        printFileAddr(files)
Output
PS C:\Users\pc\Projects\romhack\sagaFrontier\scripts> python .\printArc.py .\M000.ARC         
Traceback (most recent call last):                                                            
  File ".\printArc.py", line 14, in <module>                                                  
    printFileAddr(files)                                                                      
  File ".\printArc.py", line 7, in printFileAddr                                              
    address = ((file.read(1) << 8) | address)                                                 
TypeError: unsupported operand type(s) for <<: 'bytes' and 'int'                              
PS C:\Users\pc\Projects\romhack\sagaFrontier\scripts>                                         
1. Why doesn't Python allow one to bitshift numbers? Why have bitwise operators if you can't use them?

Here's what it prints when I comment out the lines with bit shifting and logical OR.
PS C:\Users\pc\Projects\romhack\sagaFrontier\scripts> python .\printArc.py .\M000.ARC         
b'`'
2. Why is it not printing the numeric value of the byte?


RE: Unable to bit shift and logical OR bytes and ints? - Gribouillis - Aug-29-2020

file.read() returns an object of type 'bytes', one of the fundamental data types of Python that you need to learn. The bytes type is an array of small integers in the range(0, 256). Your file.read(1) are arrays with a single element. Replace this by file.read(1)[0] to access the integer.
>>> b'`'[0]
96



RE: Unable to bit shift and logical OR bytes and ints? - MysticLord - Aug-29-2020

That did it, thank you.

Here's the final version, with a commented out line for printing in hexadecimal (which is sometimes easier to read).
import sys,glob

def printFileAddr(fileName):
    with open(fileName,"rb") as file:
        file.seek(36,0)
        address = file.read(1)[0]
        address = ((file.read(1)[0] << 8) | address)
        address = ((file.read(1)[0] << 16) | address)
        address = ((file.read(1)[0] << 24) | address)
        print(str(address) + "\n")
        #print(hex(address) + "\n")

for arg in sys.argv[1:]:
    for files in glob.glob(arg):
        printFileAddr(files)
Is there something like the Java Specs but for the various versions of Python?
https://docs.oracle.com/javase/7/docs/api/

It has summaries of all constructors, methods (including parameters and return values), fields, interfaces, and classes.
https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html

How do I inspect or determine return types?


RE: Unable to bit shift and logical OR bytes and ints? - buran - Aug-30-2020

https://docs.python.org/3/


RE: Unable to bit shift and logical OR bytes and ints? - Gribouillis - Aug-30-2020

You could have used this instead, to handle four bytes at a time
import struct
address = struct.unpack('I', file.read(4))[0]
You could even handle more than four bytes at a time
>>> import struct
>>> s = b'spameggsfoooquxx'
>>> struct.unpack('IIII', s)
(1835102323, 1936156517, 1869573990, 2021160305)



RE: Unable to bit shift and logical OR bytes and ints? - MysticLord - Sep-01-2020

(Aug-30-2020, 05:14 AM)Gribouillis Wrote: You could have used this instead, to handle four bytes at a time
import struct
address = struct.unpack('I', file.read(4))[0]
You could even handle more than four bytes at a time
>>> import struct
>>> s = b'spameggsfoooquxx'
>>> struct.unpack('IIII', s)
(1835102323, 1936156517, 1869573990, 2021160305)
I believe you but:
  1. I already know bitwise operations.
  2. When I look at this n years from now I want to understand it as fast as possible.
  3. No one knows if your solution will be supported in future versions of Python.
  4. I'm past the age where learning new things that don't have immediate applications, but do have simpler solutions, is fun.



RE: Unable to bit shift and logical OR bytes and ints? - Gribouillis - Sep-01-2020

MysticLord Wrote:No one knows if your solution will be supported in future versions of Python.
Ok, but this solution already worked in Python 1.5.2, released march 22, 2000, more than 20 years ago. The struct module itself is even older, the 'I' format being probably added in python 1.5. My bet is that the struct module will be here for another 20 years.


RE: Unable to bit shift and logical OR bytes and ints? - deanhystad - Sep-01-2020

Nice thing about struct.pack and unpack is it is very easy to fix bytesex problems and you can read/write arrays and structures.

Since struct is the common way to communicate with C/C++ it is going to be around as long as Python. And it is well documented.

As for readability, the shift code reads easier than this?
def header_address(filename):
    '''Return unsigned int value starting at byte 36 in the file header'''
    with open(filename, "rb") as file:
        file.seek(36, 0)
        return struct.unpack('>I', file.read(4))