docstr: Subclass the save method, to hash ndarray subclass, rather
  than pickling them. Off course, this is a total abuse of
  the Pickler class.
docstr_tok: ["Subclass","the","save","method",",","to","hash","ndarray","subclass",",","rather","than","pickling","them",".","Off","course",",","this","is","a","total","abuse","of","the","Pickler","class","."]
code: 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.
          obj_c_contiguous = self._make_array_contiguous_if_needed(obj)
  
          try:
              self.stream.write(memoryview(obj_c_contiguous))
          except ValueError:
              self.stream.write(
                  memoryview(obj_c_contiguous.view(self.np.uint8))
              )
  
          # 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 = self._get_numpy_metadata_tuple(obj)
      elif isinstance(obj, self.np.dtype):
          # numpy.dtype consistent hashing is tricky to get right. This comes
          # from the fact that atomic np.dtype objects are interned:
          # ``np.dtype('f4') is np.dtype('f4')``. The situation is
          # complicated by the fact that this interning does not resist a
          # simple pickle.load/dump roundtrip:
          # ``pickle.loads(pickle.dumps(np.dtype('f4'))) is not
          # np.dtype('f4') Because pickle relies on memoization during
          # pickling, it is easy to
          # produce different hashes for seemingly identical objects, such as
          # ``[np.dtype('f4'), np.dtype('f4')]``
          # and ``[np.dtype('f4'), pickle.loads(pickle.dumps('f4'))]``.
          # To prevent memoization from interfering with hashing, we isolate
          # the serialization (and thus the pickle memoization) of each dtype
          # using each time a different ``pickle.dumps`` call unrelated to
          # the current Hasher instance.
          self.stream.write("_HASHED_DTYPE".encode("utf-8"))
          pickle.dump(obj, file=self.stream, protocol=self.proto)
          return
      super().save(obj)
  
imports: import hashlib
  import pickle
  import struct
  import sys
  import tempfile
  import time
  import traceback
  from pathlib import Path
  from typing import TYPE_CHECKING, Union
  from joblib.hashing import Hasher, Pickler
  from joblib.memory import MemorizedFunc, MemorizedResult, Memory, NotMemorizedResult, _format_load_msg, filter_args, format_call, format_signature, format_time, get_func_name
  from xxhash import xxh128
label_desc: Use image node_id 5 for calling the FastNumpyHasher obj's underlying member method code with example usage: obj.save(obj) without return types