code: def notify_attribute_listeners(self, attr_name, value, cache=False):
          
          # Cached values are not re-sent if they are unchanged.
          if cache:
              if self._attribute_cache.get(attr_name) == value:
                  return
              self._attribute_cache[attr_name] = value
  
          # Notify observers.
          for fn in self._attribute_listeners.get(attr_name, []):
              try:
                  fn(self, attr_name, value)
              except Exception:
                  self._logger.exception('Exception in attribute handler for %s' % attr_name, exc_info=True)
  
          for fn in self._attribute_listeners.get('*', []):
              try:
                  fn(self, attr_name, value)
              except Exception:
                  self._logger.exception('Exception in attribute handler for %s' % attr_name, exc_info=True)
docs: This method is used to update attribute observers when the named attribute is updated.
  
          You should call it in your message listeners after updating an attribute with
          information from a vehicle message.
  
          By default the value of ``cache`` is ``False`` and every update from the vehicle is sent to listeners
          (whether or not the attribute has changed).  This is appropriate for attributes which represent sensor
          or heartbeat-type monitoring.
  
          Set ``cache=True`` to update listeners only when the value actually changes (cache the previous
          attribute value). This should be used where clients will only ever need to know the value when it has
          changed. For example, this setting has been used for notifying :py:attr:`mode` changes.
  
          See :ref:`example_create_attribute` for more information.
  
          :param String attr_name: The name of the attribute that has been updated.
          :param value: The current value of the attribute that has been updated.
          :param Boolean cache: Set ``True`` to only notify observers when the attribute value changes.