You actually can overwrite builtins, but there is almost always a better way to do it. Typically subclassing the builtin is that better path. That being said, without knowing your use case I can't say for certain that it would be bad to overwrite the builtin, so here ya go.
Try this runnable example
#!/usr/bin/env python
import builtins
class WackyStr(str):
def __new__(cls, s):
if s.isnumeric():
return int(s)
if s.replace('.','').isnumeric():
return float(s)
return super().__new__(cls, s)
builtins.str = WackyStr
if __name__ == "__main__":
a = str("two")
b = str("2.0")
c = str("2")
print(f"{a=}, {type(a)=}")
print(f"{b=}, {type(b)=}")
print(f"{c=}, {type(c)=}")
<script src="https://modularizer.github.io/pyprez/pyprez.min.js"></script>
My recommendation though would be to not overwrite the builtin and just use your new class
#!/usr/bin/env python
class WackyStr(str):
def __new__(cls, s):
if s.isnumeric():
return int(s)
if s.replace('.','').isnumeric():
return float(s)
return super().__new__(cls, s)
if __name__ == "__main__":
a = WackyStr("two")
b = WackyStr("2.0")
c = WackyStr("2")
print(f"{a=}, {type(a)=}")
print(f"{b=}, {type(b)=}")
print(f"{c=}, {type(c)=}")
<script src="https://modularizer.github.io/pyprez/pyprez.min.js"></script>