Python3.4与3.6中TypeError差异问题及兼容方案问询
Let's break down the issue and fix it step by step.
The Problem
You've got a B64LZMA class that extends str to handle base64-encoded LZMA data. It works fine in Python 3.6+ but throws TypeError: string argument without an encoding in Python 3.4. The problematic line is in the __str__ method:
return bytes(self).decode()
Why the Behavior Difference?
The root cause is a change in how Python's bytes() function handles subclasses of str:
- Python 3.4: When you call
bytes(obj)on a subclass ofstr, Python treats it as a regular string. It expects you to provide an encoding argument (likebytes(obj, 'utf-8')) and does not invoke the object's__bytes__method. This is why you get the "string argument without an encoding" error—Python thinks you're trying to convert a string to bytes, not using your custom__bytes__implementation. - Python 3.6+: The
bytes()function was updated to prioritize calling an object's__bytes__method first, even if the object is a subclass ofstr. Sobytes(self)correctly triggers your custom decompression logic instead of treatingselfas a plain string.
How to Fix Compatibility with Python 3.4
To make the code work across both versions, avoid relying on bytes(self) to invoke your __bytes__ method. Instead, call __bytes__() directly in the __str__ method:
from base64 import b64decode from lzma import LZMADecompressor class B64LZMA(str): """A string of base64 encoded, LZMA compressed data.""" def __bytes__(self): """Returns the decompressed data.""" return LZMADecompressor().decompress(b64decode(self.encode())) def __str__(self): """Returns the string decoded from __bytes__.""" # Directly call __bytes__() instead of using bytes(self) return self.__bytes__().decode() TEST_STR = B64LZMA('/Td6WFoAAATm1rRGAgAhARYAAAB0L+WjAQALSGVsbG8gd29ybGQuAGt+oFiSvoAYAAEkDKYY2NgftvN9AQAAAAAEWVo=') if __name__ == '__main__': print(TEST_STR)
Alternatively, you could rewrite the __str__ method to compute the decoded string directly without relying on __bytes__, but calling self.__bytes__() keeps your code DRY (Don't Repeat Yourself) and maintains separation of concerns.
This change ensures that both Python 3.4 and 3.6+ use your custom decompression logic correctly, avoiding the TypeError in older versions.
内容的提问来源于stack exchange,提问作者user3515670

