'Decorator for attribute listeners.
The decorated function (``observer``) is invoked differently depending on the *type of attribute*.
Attributes that represent sensor values or which are used to monitor connection status are updated
whenever a message is received from the vehicle. Attributes which reflect vehicle "state" are
only updated when their values change (for example :py:func:`Vehicle.system_status`,
:py:attr:`Vehicle.armed`, and :py:attr:`Vehicle.mode`).
The argument list for the callback is ``observer(object, attr_name, attribute_value)``
* ``self`` - the associated :py:class:`Vehicle`. This may be compared to a global vehicle handle
to implement vehicle-specific callback handling (if needed).
* ``attr_name`` - the attribute name. This can be used to infer which attribute has triggered
if the same callback is used for watching several attributes.
* ``msg`` - the attribute value (so you don\'t need to re-query the vehicle object).
.. note::
There is no way to remove an attribute listener added with this decorator. Use
:py:func:`add_attribute_listener` if you need to be able to remove
the :py:func:`attribute listener <remove_attribute_listener>`.
The code fragment below shows how you can create a listener for the attitude attribute.
.. code:: python
@vehicle.on_attribute(\'attitude\')
def attitude_listener(self, name, msg):
print \'%s attribute is: %s\' % (name, msg)
See :ref:`vehicle_state_observe_attributes` for more information.
:param String attr_name: The name of the attribute to watch (or \'*\' to watch all attributes).
:param observer: The callback to invoke when a change in the attribute is detected.'

def on_attribute(self, name):

    def decorator(fn):
        if isinstance(name, list):
            for n in name:
                self.add_attribute_listener(n, fn)
        else:
            self.add_attribute_listener(name, fn)
    return decorator
