3

Python 3.9 introduced str.removeprefix(). I'm using it here as an example only.

Let's say, I would like to use this new feature in a library supposed to run on all supported Python versions (also 3.6, 3.7 and 3.8 as of now). I mean a direct usage: mystring.removeprefix('xy_').

I tried this:

if sys.version_info < (3,9):
    def removeprefix_compat(self, prefix):
        # implement removeprefix (or just copy it from PEP-616)
        return 'TODO'
    str.removeprefix = removeprefix_compat

but the result is: TypeError: can't set attributes of built-in/extension type 'str'.

So it seems not possible until winter 2024/2025 (3.8 will be in EOL state). Is it really so?

UPDATE1 (based on links from @buran's comment):

This breaks things:

import json, builtins

class PatchedStr(str):
    pass

builtins.str = PatchedStr

json.loads('"aaa"')
# TypeError: the JSON object must be str, bytes or bytearray, not str
VPfB
  • 14,927
  • 6
  • 41
  • 75
  • 1
    check https://stackoverflow.com/questions/6738987/extension-method-for-python-built-in-types and https://stackoverflow.com/questions/192649/can-you-monkey-patch-methods-on-core-types-in-python – buran Jun 08 '21 at 07:23
  • If you want to support older versions, you should implement your own function which _can_ use `str.removeprefix` internally if available, and otherwise use your own algorithm as fallback, and then just call it like `s = removeprefix(s)` instead of as instance method. Of course, if you're supplying your own fallback code anyway, then what's the point of conditionally using the method? Bottom line: if your code needs to be compatible with older versions, just ignore the existence of `str.removeprefix`. Only use it if you can require Python 3.9+ for your code. – deceze Sep 27 '21 at 09:40
  • @deceze That's sad. But your comment is an answer, I would accept it, if you post it. – VPfB Sep 27 '21 at 10:14
  • @deceze The point was to write code that will be standard in the future. – VPfB Sep 27 '21 at 10:34

1 Answers1

2

The facts:

  • monkey patching builtins is somewhere between hard and impossible, and that's generally a good thing
  • you need to provide a fallback implementation anyway, so what's the point of conditionally using the builtin method, risking a difference in behaviour between different Python versions

Conclusion:

If you need to support older Python versions, develop as if only the lowest version you want to support is available. I.e. if you set Python 3.6 as your minimum required version, then only use features available in Python 3.6 and treat anything in newer versions as non-existent, because in fact it does not exist in at least one version you want to support.

deceze
  • 510,633
  • 85
  • 743
  • 889