I tried to play around with the built in string type, wondering if I could use strings with the with syntax. Obviously the following will fail:
with "hello" as hello:
    print(f"{hello} world!")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: __enter__
Then, just deriving a class from str with the two needed attributes for with:
class String(str):
    def __enter__(self):
        return self
    def __exit__(self):
        ...
with String("hello") as hello:
    print(f"{hello} world!")
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: __exit__() takes 1 positional argument but 4 were given
Ok, I wonder what those arguments are.., I added *args, **kwargs to __exit__, and then tried it again:
class String(str):
    def __enter__(self):
        return self
    def __exit__(self, *args, **kwargs):
        print("args: ", args)
        print("kwargs: ", kwargs)
with String("hello") as hello:
    print(f"{hello} world!")
hello world!
args:  (None, None, None)
kwargs:  {}
Works with different types too that I guess can be normally called with str(), but what are those three arguments? How do I go about finding more information on what the three extra arguments were? I guess finally, where can I go to see the implementation of built-in types, etc...? 
 
    