docs: def copy(self, deep=True, data=None):
          """Returns a copy of this object.
  
          If `deep=True`, the data array is loaded into memory and copied onto
          the new object. Dimensions, attributes and encodings are always copied.
  
          Use `data` to create a new object with the same structure as
          original but entirely new data.
  
          Parameters
          ----------
          deep : bool, optional
              Whether the data array is loaded into memory and copied onto
              the new object. Default is True.
          data : array_like, optional
              Data to use in the new object. Must have same shape as original.
              When `data` is used, `deep` is ignored.
  
          Returns
          -------
          object : Variable
              New object with dimensions, attributes, encodings, and optionally
              data copied from original.
  
          Examples
          --------
  
          Shallow copy versus deep copy
  
          >>> var = xr.Variable(data=[1, 2, 3], dims='x')
          >>> var.copy()
          <xarray.Variable (x: 3)>
          array([1, 2, 3])
          >>> var_0 = var.copy(deep=False)
          >>> var_0[0] = 7
          >>> var_0
          <xarray.Variable (x: 3)>
          array([7, 2, 3])
          >>> var
          <xarray.Variable (x: 3)>
          array([7, 2, 3])
  
          Changing the data using the ``data`` argument maintains the
          structure of the original object, but with the new data. Original
          object is unaffected.
  
          >>> var.copy(data=[0.1, 0.2, 0.3])
          <xarray.Variable (x: 3)>
          array([ 0.1,  0.2,  0.3])
          >>> var
          <xarray.Variable (x: 3)>
          array([7, 2, 3])
  
          See Also
          --------
          pandas.DataFrame.copy
          """
          if data is None:
              data = self._data
  
              if isinstance(data, indexing.MemoryCachedArray):
                  # don't share caching between copies
                  data = indexing.MemoryCachedArray(data.array)
  
              if deep:
                  if isinstance(data, dask_array_type):
                      data = data.copy()
                  elif not isinstance(data, PandasIndexAdapter):
                      # pandas.Index is immutable
                      data = np.array(data)
          else:
              data = as_compatible_data(data)
              if self.shape != data.shape:
                  raise ValueError("Data shape {} must match shape of object {}"
                                   .format(data.shape, self.shape))
  
          # note:
          # dims is already an immutable tuple
          # attributes and encoding will be copied when the new Array is created
          return type(self)(self.dims, data, self._attrs, self._encoding,
                            fastpath=True)