<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def get_contacts(self, limit=100, *, query=None, order_by=None, batch=None):
 """ Gets a list of contacts from this address book When querying the Global Address List the Users endpoint will be used. Only a limited set of information will be available unless you have access to scope 'User.Read.All' which requires App Administration Consent. Also using endpoints has some limitations on the querying capabilities. To use query an order_by check the OData specification here: http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/ part2-url-conventions/odata-v4.0-errata03-os-part2-url-conventions -complete.html :param limit: max no. of contacts to get. Over 999 uses batch. :type limit: int or None :param query: applies a OData filter to the request :type query: Query or str :param order_by: orders the result set based on this condition :type order_by: Query or str :param int batch: batch size, retrieves items in batches allowing to retrieve more items than the limit. :return: list of contacts :rtype: list[Contact] or Pagination """


        if self.main_resource == GAL_MAIN_RESOURCE:
            # using Users endpoint to access the Global Address List
            url = self.build_url(self._endpoints.get('gal'))
        else:
            if self.root:
                url = self.build_url(self._endpoints.get('root_contacts'))
            else:
                url = self.build_url(
                    self._endpoints.get('folder_contacts').format(
                        id=self.folder_id))

        if limit is None or limit > self.protocol.max_top_value:
            batch = self.protocol.max_top_value

        params = {'$top': batch if batch else limit}

        if order_by:
            params['$orderby'] = order_by

        if query:
            if isinstance(query, str):
                params['$filter'] = query
            else:
                params.update(query.as_params())

        response = self.con.get(url, params=params)
        if not response:
            return iter(())

        data = response.json()

        # Everything received from cloud must be passed as self._cloud_data_key
        contacts = (self.contact_constructor(parent=self,
                                             **{self._cloud_data_key: contact})
                    for contact in data.get('value', []))

        next_link = data.get(NEXT_LINK_KEYWORD, None)

        if batch and next_link:
            return Pagination(parent=self, data=contacts,
                              constructor=self.contact_constructor,
                              next_link=next_link, limit=limit)
        else:
            return contacts