(self, mjcf_elements)
return binding
Creates a binding between this `Physics` instance and `mjcf.Element`s.

    The binding allows for easier interaction with the `Physics` data structures
    related to an MJCF element. For example, in order to access the Cartesian
    position of a geom, we can use:

    ```python
    physics.bind(geom_element).pos
    ```

    instead of the more cumbersome:

    ```python
    physics.named.model.geom_pos[geom_element.full_identifier]
    ```

    Note that the binding takes into account the type of element. This allows us
    to remove prefixes from certain common attributes in order to unify access.
    For example, we can use:

    ```python
    physics.bind(geom_element).pos = [1, 2, 3]
    physics.bind(site_element).pos = [4, 5, 6]
    ```

    instead of:

    ```python
    physics.named.model.geom_pos[geom_element.full_identifier] = [1, 2, 3]
    physics.named.model.site_pos[site_element.full_identifier] = [4, 5, 6]
    ```

    This in turn allows for the creation of common algorithms that can operate
    across a wide range of element type.

    When attribute values are modified through the binding, future queries of
    derived values are automatically recalculated if necessary. For example,
    if a joint's `qpos` is modified and a site's `xpos` is later read, the value
    of the `xpos` is updated according to the new joint configuration. This is
    done lazily when an updated value is required, so repeated value
    modifications do not incur a performance penalty.

    It is also possible to bind a sequence containing one or more elements,
    provided they are all of the same type. In this case the binding exposes
    `SynchronizingArrayWrapper`s, which are array-like objects that provide
    writeable views onto the corresponding memory addresses in MuJoCo. Writing
    into a `SynchronizingArrayWrapper` causes the underlying values in MuJoCo
    to be updated, and if necessary causes derived values to be recalculated.
    Note that in order to trigger recalculation it is necessary to reference a
    derived attribute of a binding.

    ```python
    bound_joints = physics.bind([joint1, joint2])
    bound_bodies = physics.bind([body1, body2])
    # `qpos_view` and `xpos_view` are `SynchronizingArrayWrapper`s providing
    # views onto `physics.data.qpos` and `physics.data.xpos` respectively.
    qpos_view = bound_joints.qpos
    xpos_view = bound_bodies.xpos
    # This updates the corresponding values in `physics.data.qpos`, and marks
    # derived values (such as `physics.data.xpos`) as needing recalculation.
    qpos_view[0] += 1.
    # Note: at this point `xpos_view` still contains the old values, since we
    # need to actually read the value of a derived attribute in order to
    # trigger recalculation.
    another_xpos_view = bound_bodies.xpos  # Triggers recalculation of `xpos`.
    # Now both `xpos_view` and `another_xpos_view` will contain the updated
    # values.
    ```

    Note that `SynchronizingArrayWrapper`s cannot be pickled. We also do not
    recommend holding references to them - instead hold a reference to the
    binding object, or call `physics.bind` again.

    Bindings also support numpy-style square bracket indexing. The first element
    in the indexing expression should be an attribute name, and the second
    element (if present) is used to index into the columns of the underlying
    array. Named indexing into columns is also allowed, provided that the
    corresponding field in `physics.named` supports it.

    ```python
    physics.bind([geom1, geom2])['pos'] = [[1, 2, 3], [4, 5, 6]]
    physics.bind([geom1, geom2])['pos', ['x', 'z']] = [[1, 3], [4, 6]]
    ```

    Args:
      mjcf_elements: Either an `mjcf.Element`, or an iterable of `mjcf.Element`
        of the same kind.

    Returns:
      A binding between this Physics instance an `mjcf_elements`, as described
      above.

    Raises:
      ValueError: If `mjcf_elements` cannot be bound to this Physics.
Creates a binding between this `Physics` instance and `mjcf.Element`s.
Creates a binding between this Physics instance and mjcf . Element s .
def bind(self, mjcf_elements):
    """Creates a binding between this `Physics` instance and `mjcf.Element`s.

    The binding allows for easier interaction with the `Physics` data structures
    related to an MJCF element. For example, in order to access the Cartesian
    position of a geom, we can use:

    ```python
    physics.bind(geom_element).pos
    ```

    instead of the more cumbersome:

    ```python
    physics.named.model.geom_pos[geom_element.full_identifier]
    ```

    Note that the binding takes into account the type of element. This allows us
    to remove prefixes from certain common attributes in order to unify access.
    For example, we can use:

    ```python
    physics.bind(geom_element).pos = [1, 2, 3]
    physics.bind(site_element).pos = [4, 5, 6]
    ```

    instead of:

    ```python
    physics.named.model.geom_pos[geom_element.full_identifier] = [1, 2, 3]
    physics.named.model.site_pos[site_element.full_identifier] = [4, 5, 6]
    ```

    This in turn allows for the creation of common algorithms that can operate
    across a wide range of element type.

    When attribute values are modified through the binding, future queries of
    derived values are automatically recalculated if necessary. For example,
    if a joint's `qpos` is modified and a site's `xpos` is later read, the value
    of the `xpos` is updated according to the new joint configuration. This is
    done lazily when an updated value is required, so repeated value
    modifications do not incur a performance penalty.

    It is also possible to bind a sequence containing one or more elements,
    provided they are all of the same type. In this case the binding exposes
    `SynchronizingArrayWrapper`s, which are array-like objects that provide
    writeable views onto the corresponding memory addresses in MuJoCo. Writing
    into a `SynchronizingArrayWrapper` causes the underlying values in MuJoCo
    to be updated, and if necessary causes derived values to be recalculated.
    Note that in order to trigger recalculation it is necessary to reference a
    derived attribute of a binding.

    ```python
    bound_joints = physics.bind([joint1, joint2])
    bound_bodies = physics.bind([body1, body2])
    # `qpos_view` and `xpos_view` are `SynchronizingArrayWrapper`s providing
    # views onto `physics.data.qpos` and `physics.data.xpos` respectively.
    qpos_view = bound_joints.qpos
    xpos_view = bound_bodies.xpos
    # This updates the corresponding values in `physics.data.qpos`, and marks
    # derived values (such as `physics.data.xpos`) as needing recalculation.
    qpos_view[0] += 1.
    # Note: at this point `xpos_view` still contains the old values, since we
    # need to actually read the value of a derived attribute in order to
    # trigger recalculation.
    another_xpos_view = bound_bodies.xpos  # Triggers recalculation of `xpos`.
    # Now both `xpos_view` and `another_xpos_view` will contain the updated
    # values.
    ```

    Note that `SynchronizingArrayWrapper`s cannot be pickled. We also do not
    recommend holding references to them - instead hold a reference to the
    binding object, or call `physics.bind` again.

    Bindings also support numpy-style square bracket indexing. The first element
    in the indexing expression should be an attribute name, and the second
    element (if present) is used to index into the columns of the underlying
    array. Named indexing into columns is also allowed, provided that the
    corresponding field in `physics.named` supports it.

    ```python
    physics.bind([geom1, geom2])['pos'] = [[1, 2, 3], [4, 5, 6]]
    physics.bind([geom1, geom2])['pos', ['x', 'z']] = [[1, 3], [4, 6]]
    ```

    Args:
      mjcf_elements: Either an `mjcf.Element`, or an iterable of `mjcf.Element`
        of the same kind.

    Returns:
      A binding between this Physics instance an `mjcf_elements`, as described
      above.

    Raises:
      ValueError: If `mjcf_elements` cannot be bound to this Physics.
    """
    if mjcf_elements is None:
      return None

    # To reduce overhead from processing MJCF elements and making new bindings,
    # we cache and reuse existing Binding objects. The cheapest version of
    # caching is when we can use `mjcf_elements` as key directly. However, this
    # is not always possible since `mjcf_elements` may contain weak references.
    # In this case, we fallback to using the elements' namespace and identifiers
    # as cache keys instead.

    # Checking for iterability in this way is cheaper than using `isinstance`.
    try:
      cache_key = tuple(mjcf_elements)
    except TypeError:
      # `mjcf_elements` is not iterable.
      cache_key = mjcf_elements

    needs_new_binding = False
    try:
      binding = self._bindings[cache_key]
    except KeyError:
      # This means `mjcf_elements` is hashable, so we use it as cache key.
      namespace, named_index = names_from_elements(mjcf_elements)
      needs_new_binding = True
    except TypeError:
      # This means `mjcf_elements` is unhashable, fallback to caching by name.
      namespace, named_index = names_from_elements(mjcf_elements)

      # Checking for iterability in this way is cheaper than using `isinstance`.
      try:
        cache_key = (namespace, tuple(named_index))
      except TypeError:
        # `named_index` is not iterable.
        cache_key = (namespace, named_index)

      try:
        binding = self._bindings[cache_key]
      except KeyError:
        needs_new_binding = True

    if needs_new_binding:
      binding = Binding(weakref.proxy(self), namespace, named_index)
      self._bindings[cache_key] = binding

    return binding
def bind ( self , mjcf_elements ) : if mjcf_elements is None : return None # To reduce overhead from processing MJCF elements and making new bindings, # we cache and reuse existing Binding objects. The cheapest version of # caching is when we can use `mjcf_elements` as key directly. However, this # is not always possible since `mjcf_elements` may contain weak references. # In this case, we fallback to using the elements' namespace and identifiers # as cache keys instead. # Checking for iterability in this way is cheaper than using `isinstance`. try : cache_key = tuple ( mjcf_elements ) except TypeError : # `mjcf_elements` is not iterable. cache_key = mjcf_elements needs_new_binding = False try : binding = self . _bindings [ cache_key ] except KeyError : # This means `mjcf_elements` is hashable, so we use it as cache key. namespace , named_index = names_from_elements ( mjcf_elements ) needs_new_binding = True except TypeError : # This means `mjcf_elements` is unhashable, fallback to caching by name. namespace , named_index = names_from_elements ( mjcf_elements ) # Checking for iterability in this way is cheaper than using `isinstance`. try : cache_key = ( namespace , tuple ( named_index ) ) except TypeError : # `named_index` is not iterable. cache_key = ( namespace , named_index ) try : binding = self . _bindings [ cache_key ] except KeyError : needs_new_binding = True if needs_new_binding : binding = Binding ( weakref . proxy ( self ) , namespace , named_index ) self . _bindings [ cache_key ] = binding return binding