diff --git a/deepkit/__init__.py b/deepkit/__init__.py
index 6615344..023fd72 100644
--- a/deepkit/__init__.py
+++ b/deepkit/__init__.py
@@ -59,19 +59,32 @@ class StdHook:
         def __init__(self, s):
             self.s = s
 
-        def fileno(self):
-            return self.s.fileno()
-
-        def isatty(self):
-            return self.s.isatty()
-
-        def flush(self):
-            self.s.flush()
-
         def write(self, s):
             self.s.write(s)
             log(s)
 
+        def __getattr__(self, name):
+            """Forward the __getattr__ call to the wrapped object.
+
+            From https://docs.python.org/3/reference/datamodel.html#object.__getattr__:
+            > Note that if the attribute is found through the normal mechanism,
+            > __getattr__() is not called.
+
+            Therefore, `self.s` does not run into a recursion error.
+            """
+            return getattr(self.s, name)
+
+        def __setattr__(self, name, value):
+            """Set an attribute on the wrapped object.
+
+            Taken from: https://stackoverflow.com/a/17020163/15235649
+
+            Note: `super(StdHook, self).__setattr__` returns the method from
+                  `object.__setattr__.
+            """
+            if name == "s":
+                return super(StdHook, self).__setattr__(name, value)
+            return setattr(self.s, name, value)
 
     sys.stdout = StdHook(sys.__stdout__)
     sys.stderr = StdHook(sys.__stderr__)