2

Is there any simple way to get consistent results in both Python 2 and Python 3 for operatioIn like "give me N-th byte in byte string"? Getting either byte-as-integer or byte-as-character will do for me, as long as that will be consistent.

I.e. given

s = b"123"

Naïve approach yields:

s[1] # => Python 2: '2', <type 'str'>
s[1] # => Python 3: 50, <class 'int'>

Wrapping that in ord(...) yields an error in Python 3:

ord(s[1]) # => Python 2: 50, <type 'int'> 
ord(s[1]) # => Python 3: TypeError: ord() expected string of length 1, but int found

I can think of a fairly complicated compat solution:

ord(s[1]) if (type(s[1]) == type("str")) else s[1] # 50 in both Python 2 and 3

... but may be there's an easier way which I just don't notice?

4
  • Related What does the 'b' character do in front of a string literal? Commented Oct 16, 2019 at 10:40
  • 2
    You are aware that support for 2.x is about to be officially dropped, yes? Commented Oct 16, 2019 at 11:01
  • 1
    @KarlKnechtel Yes, and I'm totally aware of tons of our users potentially using Python 2, so unless there's something very dire, I'd like to keep our Python 2 support too. Commented Oct 16, 2019 at 14:14
  • Ouch, sorry to hear about that. I wish you the best of luck in avoiding people yelling at you about it in the future. Maintenance is never fun IMX. Commented Oct 17, 2019 at 3:12

3 Answers 3

3

A length-1 slice will be also be a byte-sequence in either 2.x or 3.x:

s = b'123'
s[1:2] # 3.x: b'2'; 2.x: '2', which is the same thing but the repr() rules are different.
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, that seems to be the most elegant choice in my case — no bulky code and no extra libraries to require!
2

If you use (converting if needed) the bytearray type, behavior will be identical on both versions, always matching Python 3 behavior of bytes. That's because bytearray is actually a distinct type on Python 2 (with Python 3 behavior), where bytes is just an alias for str there.

The more typical solution would be to use the six compatibility library, which provides six.indexbytes, so on either version of Python, you could do:

>>> six.indexbytes(s, 1)
50

Comments

0

What about something like this?

import sys

if sys.version_info.major == 3:
    def index(s, n):
        return s[n]
elif sys.version_info.major == 2:
    def index(s, n):
        return ord(s[n])
else:
    raise NotImplementedError

5 Comments

For the record, this is exactly what six.indexbytes does.
Definitely, six is a nice arrow in your quiver when writing Python 2/3 code.
Looks like a recipe for bugs if Python ever goes to v4.
@Holloway Fixed. But TBH I hardly think that it was relevant for the problem at hand.
The reason for my question is exactly to avoid rolling such a lengthy construct myself every time I need it. Using six.indexbytes or, better yet, length slice approach suggested in stackoverflow.com/a/58411754/487064 is what I was looking for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.