def _create_reference(
        factory_self, reference_model, resource_name, service_context
    ):
        """
        Creates a new property on the resource to lazy-load a reference.
        """
        # References are essentially an action with no request
        # or response, so we can re-use the response handlers to
        # build up resources from identifiers and data members.
        handler = ResourceHandler(
            search_path=reference_model.resource.path,
            factory=factory_self,
            resource_model=reference_model.resource,
            service_context=service_context,
        )

        # Are there any identifiers that need access to data members?
        # This is important when building the resource below since
        # it requires the data to be loaded.
        needs_data = any(
            i.source == 'data' for i in reference_model.resource.identifiers
        )

        def get_reference(self):
            # We need to lazy-evaluate the reference to handle circular
            # references between resources. We do this by loading the class
            # when first accessed.
            # This is using a *response handler* so we need to make sure
            # our data is loaded (if possible) and pass that data into
            # the handler as if it were a response. This allows references
            # to have their data loaded properly.
            if needs_data and self.meta.data is None and hasattr(self, 'load'):
                self.load()
            return handler(self, {}, self.meta.data)

        get_reference.__name__ = str(reference_model.name)
        get_reference.__doc__ = docstring.ReferenceDocstring(
            reference_model=reference_model, include_signature=False
        )
        return property(get_reference)

        Creates a new property on the resource to lazy-load a reference.
        
boto3/resources/factory.py