<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def touch_tip(self, location: Well = None, radius: float = 1.0, v_offset: float = -1.0, speed: float = 60.0) -> 'InstrumentContext': """ Touch the pipette tip to the sides of a well, with the intent of removing left-over droplets :param location: If no location is passed, pipette will touch tip at current well's edges :type location: :py:class:`.Well` or None :param radius: Describes the proportion of the target well's radius. When `radius=1.0`, the pipette tip will move to the edge of the target well; when `radius=0.5`, it will move to 50% of the well's radius. Default: 1.0 (100%) :type radius: float :param v_offset: The offset in mm from the top of the well to touch tip A positive offset moves the tip higher above the well, while a negative offset moves it lower into the well Default: -1.0 mm :type v_offset: float :param speed: The speed for touch tip motion, in mm/s. Default: 60.0 mm/s, Max: 80.0 mm/s, Min: 20.0 mm/s :type speed: float :raises NoTipAttachedError: if no tip is attached to the pipette :raises RuntimeError: If no location is specified and location cache is None. This should happen if `touch_tip` is called without first calling a method that takes a location (eg, :py:meth:`.aspirate`, :py:meth:`dispense`) :returns: This instance .. note:: This is behavior change from legacy API (which accepts any :py:class:`.Placeable` as the ``location`` parameter) """

        if not self.hw_pipette['has_tip']:
            raise hc.NoTipAttachedError('Pipette has no tip to touch_tip()')

        if speed > 80.0:
            self._log.warning('Touch tip speed above limit. Setting to 80mm/s')
            speed = 80.0
        elif speed < 20.0:
            self._log.warning('Touch tip speed below min. Setting to 20mm/s')
            speed = 20.0

        # If location is a valid well, move to the well first
        if location is None:
            if not self._ctx.location_cache:
                raise RuntimeError('No valid current location cache present')
            else:
                location = self._ctx.location_cache.labware  # type: ignore
                # type checked below

        if isinstance(location, Well):
            if location.parent.is_tiprack:
                self._log.warning('Touch_tip being performed on a tiprack. '
                                  'Please re-check your code')
            self.move_to(location.top())
        else:
            raise TypeError(
                'location should be a Well, but it is {}'.format(location))

        # Determine the touch_tip edges/points
        offset_pt = types.Point(0, 0, v_offset)
        well_edges = [
            # right edge
            location._from_center_cartesian(x=radius, y=0, z=1) + offset_pt,
            # left edge
            location._from_center_cartesian(x=-radius, y=0, z=1) + offset_pt,
            # back edge
            location._from_center_cartesian(x=0, y=radius, z=1) + offset_pt,
            # front edge
            location._from_center_cartesian(x=0, y=-radius, z=1) + offset_pt
        ]
        for edge in well_edges:
            self._hw_manager.hardware.move_to(self._mount, edge, speed)
        return self