docs: def save(self, obj):
          """ Subclass the save method, to hash ndarray subclass, rather
              than pickling them. Off course, this is a total abuse of
              the Pickler class.
          """
          if isinstance(obj, self.np.ndarray) and not obj.dtype.hasobject:
              # Compute a hash of the object
              # The update function of the hash requires a c_contiguous buffer.
              if obj.shape == ():
                  # 0d arrays need to be flattened because viewing them as bytes
                  # raises a ValueError exception.
                  obj_c_contiguous = obj.flatten()
              elif obj.flags.c_contiguous:
                  obj_c_contiguous = obj
              elif obj.flags.f_contiguous:
                  obj_c_contiguous = obj.T
              else:
                  # Cater for non-single-segment arrays: this creates a
                  # copy, and thus aleviates this issue.
                  # XXX: There might be a more efficient way of doing this
                  obj_c_contiguous = obj.flatten()
  
              # memoryview is not supported for some dtypes, e.g. datetime64, see
              # https://github.com/numpy/numpy/issues/4983. The
              # workaround is to view the array as bytes before
              # taking the memoryview.
              self._hash.update(
                  self._getbuffer(obj_c_contiguous.view(self.np.uint8)))
  
              # We store the class, to be able to distinguish between
              # Objects with the same binary content, but different
              # classes.
              if self.coerce_mmap and isinstance(obj, self.np.memmap):
                  # We don't make the difference between memmap and
                  # normal ndarrays, to be able to reload previously
                  # computed results with memmap.
                  klass = self.np.ndarray
              else:
                  klass = obj.__class__
              # We also return the dtype and the shape, to distinguish
              # different views on the same data with different dtypes.
  
              # The object will be pickled by the pickler hashed at the end.
              obj = (klass, ('HASHED', obj.dtype, obj.shape, obj.strides))
          elif isinstance(obj, self.np.dtype):
              # Atomic dtype objects are interned by their default constructor:
              # np.dtype('f8') is np.dtype('f8')
              # This interning is not maintained by a
              # pickle.loads + pickle.dumps cycle, because __reduce__
              # uses copy=True in the dtype constructor. This
              # non-deterministic behavior causes the internal memoizer
              # of the hasher to generate different hash values
              # depending on the history of the dtype object.
              # To prevent the hash from being sensitive to this, we use
              # .descr which is a full (and never interned) description of
              # the array dtype according to the numpy doc.
              klass = obj.__class__
              obj = (klass, ('HASHED', obj.descr))
          Hasher.save(self, obj)