bpo-37054, _pyio: Fix BytesIO and TextIOWrapper __del__() (GH-13601)


Fix destructor _pyio.BytesIO and _pyio.TextIOWrapper: initialize
their _buffer attribute as soon as possible (in the class body),
because it's used by __del__() which calls close().
(cherry picked from commit a3568417c49f36860393075b21c93996a5f6799b)

Co-authored-by: Victor Stinner <vstinner@redhat.com>
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index afbd48e..e81cc51 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -839,6 +839,10 @@
 
     """Buffered I/O implementation using an in-memory bytes buffer."""
 
+    # Initialize _buffer as soon as possible since it's used by __del__()
+    # which calls close()
+    _buffer = None
+
     def __init__(self, initial_bytes=None):
         buf = bytearray()
         if initial_bytes is not None:
@@ -866,7 +870,8 @@
         return memoryview(self._buffer)
 
     def close(self):
-        self._buffer.clear()
+        if self._buffer is not None:
+            self._buffer.clear()
         super().close()
 
     def read(self, size=-1):
@@ -1936,6 +1941,10 @@
 
     _CHUNK_SIZE = 2048
 
+    # Initialize _buffer as soon as possible since it's used by __del__()
+    # which calls close()
+    _buffer = None
+
     # The write_through argument has no effect here since this
     # implementation always writes through.  The argument is present only
     # so that the signature can match the signature of the C version.