PaginatedList๊ฐ€ ๋ญ์ฃ ? ๐Ÿ

rethinkingยท2023๋…„ 8์›” 30์ผ
0
post-thumbnail

์ฃผ์˜! ์ž‘์ž๋Š” ํ˜„์žฌ(2023๋…„) REST API๋ฅผ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.. ๋‚˜์ค‘์— ๋ฐฐ์šธ๊ฒŒ์š”๐Ÿ˜‰

โ˜น๏ธ์ฐพ์•„๋ณด๊ฒŒ ๋œ ๊ณ„๊ธฐ

๋Œ€ํ•™๊ฐ•์˜ ๊ด€๋ จ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด api(canvas LMS api)๋ฅผ ํŒŒ์ด์ฌ์œผ๋กœ ๋‹ค๋ฃจ๋Š” canvasapi๋ฅผ ๋‹ค๋ฃจ๋‹ค๊ฐ€ ํŠ€์–ด๋‚˜์˜จ ๋‹จ์–ด์ด๋‹ค.

์•„๋ž˜๋Š” canvasapi docs์ค‘ ์ผ๋ถ€์ด๋‹ค.
canvasapi docs ์—์„œ get_courses()์— ๋Œ€ํ•œ ์„ค๋ช…๋ฌธ
์—ฌ๊ธฐ์„œ get_courses()๋Š” ํ˜„์žฌ ๊ณ„์ •์ด ์ˆ˜๊ฐ•์ค‘์ธ ๊ฐ•์ขŒ (๊ด€๋ฆฌ์ž๋ผ๋ฉด ์šด์˜์ค‘์ธ ๊ฐ•์ขŒ)๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜์ด๋‹ค. ๋ชจ๋‘ ๊ฐ€์ ธ์˜ค๋“ฏ์ด ์ผ๋ฐ˜์ ์ธ ํŒŒ์ด์ฌ ๊ธฐ๋Šฅ์ฒ˜๋Ÿผ list์˜ ํ˜•ํƒœ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ์ค„ ์•Œ์•˜์ง€๋งŒ, canvasapi.paginated_list.PaginatedList ํ˜•์‹์„ ๋”ฐ๋ฅธ๋‹ค. ์ผ๋ฐ˜์ ์ธ list ํ˜•์‹๊ณผ ๋น„์Šทํ•œ ํ˜•์‹์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์ง€๋งŒ, ๋ญ”๊ฐ€ ์ž‘๋™ ๋ฐฉ์‹์ด ๋‹ค๋ฅธ ๋А๋‚Œ์ด์—ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค๋ฉด

import canvasapi
canvas = canvasapi.Canvas('api_url', 'token')
canvas.get_courses()[0] # ์ž‘๋™ํ•œ๋‹ค
canvas.get_courses()[:] # ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค

# ๋ชจ๋“  ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ์ด๋ ‡๊ฒŒ ํ•ด์•ผ ํ•œ๋‹ค.
courses: list = []
for course in canvas.get_courses():
	courses.append(course)

iterator ํŠน์„ฑ์„ ๊ฐ€์กŒ์ง€๋งŒ ์Šฌ๋ผ์ด์‹ฑ์€ ์•ˆ๋˜๊ณ , print๋ฅผ ํ•ด๋„ ๊ฐ์ฒด ๊ฐ’๋งŒ ๋‚ด๋ฑ‰๋Š”๋‹ค. ์‹ฌ์ง€์–ด ์ธ๋ฑ์Šค ๊ฐ’์„ ํฌ๊ฒŒ ํ•ด๋†“์œผ๋ฉด ํ•จ์ˆ˜๊ฐ€ ๋‹ค์†Œ ๋А๋ฆฌ๊ฒŒ ์ž‘๋™ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

๐Ÿ˜€๋œฏ์–ด๋ณด์ž

canvasapi/canvasapi/paginated_list.py

ํ•จ์ˆ˜ ์ค‘ __iter__() ํ•จ์ˆ˜์˜ ๋‚ด์šฉ

์ผ๋‹จ self._elements์— ์žˆ๋Š” ์š”์†Œ๋“ค์„ ๋ฐ˜ํ™˜ํ•œ ๋‹ค์Œ, ๋งˆ์ง€๋ง‰์— ๋„๋‹ฌ ํ–ˆ์„ ๋•Œ ๊นŒ์ง€ self._grow()๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ๊ทธ ์š”์†Œ๋“ค์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค

    def _grow(self):
        new_elements = self._get_next_page()
        self._elements += new_elements
        return new_elements
    def _get_next_page(self):
        response = self._requester.request(
            self._request_method,
            self._next_url,
            _url=self._url_override,
            **self._next_params,
        )
        data = response.json()
        ...
        return content

์ถ”์ธกํ•œ๊ฒŒ ๋งž์•˜๋‹ค. PaginatedList ๋Š” _grow() ์‹คํ–‰์‹œ _get_next_page() ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด์„œ ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ self._elements์— ๋„ฃ์€ ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  _get_next_page() ์—๋Š” request๋ฅผ ๋ฐ›๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ด PaginatedList ๋Š” for๋ฌธ์— ์ง‘์–ด๋„ฃ๊ณ  ์‹คํ–‰์‹œํ‚ค๋ฉด, ๊ธฐ์กด์— ๋ฏธ๋ฆฌ ๋ถˆ๋Ÿฌ์™”๋˜ ๋ฐ์ดํ„ฐ๋“ค์„ ๊ฐ€์ ธ์˜ค๊ณ , ๊ทธ ํ›„ ํ•œ๊ฐœ์”ฉ ๋„˜์–ด๊ฐˆ ๋•Œ๋งˆ๋‹ค api ์š”์ฒญ์„ ๋ณด๋‚ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์‹์œผ๋กœ ๋˜์–ด์žˆ๋‹ค.

๊ฐœ์ธ์ ์œผ๋ก (์–ด์ฒ˜ํ”ผ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์‚ฌ์šฉํ•˜๋Š”๋ฐ) list๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ๋„ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์œผ๋ฉด ํ•˜์ง€๋งŒ, ๊ทธ๋ ‡๊ธฐ์—” ์‚ฌ๋žŒ๋“ค์ด ๋งŽ์ด ์“ฐ์ง„ ์•Š์•„์„œ ๋งŒ๋“ค์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™๋‹ค.

๐Ÿค”๋‹ค๋ฅธ ๊ณณ์—์„œ๋„ ์“ฐ๋‚˜?

์ผ๋‹จ PaginatedList๊ฐ€ ์–ด๋””์„œ ๋‚˜์˜จ ๋‹จ์–ด์ธ์ง€ ๊ฒ€์ƒ‰ํ•ด๋ณด์ž

์ด ๋ฐ‘์—๋Š” ๋‚ด๊ฐ€ ๋‹ค๋ฃจ๊ณ  ์žˆ์—ˆ๋˜ canvasapi api ๋ฌธ์„œ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค ์•„๋ฌด๋ž˜๋„ ์ž˜ ์“ฐ์ง€ ์•Š๋Š” ํ˜•์‹์ธ๊ฐ€ ๋ณด๋‹ค

์•„๋งˆ์กด ๋งํฌ์™€ PyGithub(github api๋ฅผ ํŒŒ์ด์ฌ์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“œ๋Š” ํŒจํ‚ค์ง€)๊ฐ€ ๋ˆˆ์— ๋„๋‹ˆ ํ‚ตํ•ด๋‘๊ณ  ์šฉ์–ด๋ฅผ ๊ฒ€์ƒ‰ํ•ด๋ณด์ž.

Pagination : ํŽ˜์ด์ง•์ด๋ผ๊ณ ๋„ ํ•˜๋Š” ํŽ˜์ด์ง€ ๋งค๊น€์€ ๋ฌธ์„œ๋ฅผ ์ „์ž ํŽ˜์ด์ง€ ๋˜๋Š” ์ธ์‡„๋œ ํŽ˜์ด์ง€์™€ ๊ฐ™์€ ๊ฐœ๋ณ„ ํŽ˜์ด์ง€๋กœ ๋‚˜๋ˆ„๋Š” ํ”„๋กœ์„ธ์Šค์ž…๋‹ˆ๋‹ค.

ํŽ˜์ด์ง€ ํ˜•์‹..์ด๋ผ๊ณ  ํ•˜๋‹ˆ ์ˆœ์„œ๋Œ€๋กœ ์ฝ์–ด์˜ค๋Š”๊ฑด๊ฐ€? ์‹ถ๋‹ค.

์ผ๋‹จ ๋งํฌ์—์„œ ์•„๋งˆ์กดdocs ๊ธ€์€ java dynamodDB์ชฝ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ •๋ณด์ธ๊ฒƒ ๊ฐ™๋‹ค.

์ƒ๊ด€์ด ์—†์–ด๋ณด์ด์ง€๋งŒ, Iterable<T>, Collection<T>, List<T> ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

PyGithub์˜ PaginatedList.py๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค



์–ด๋А api์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ์Šฌ๋ผ์ด์‹ฑ์„ ์ง€์›ํ•œ๋‹ค ๊ทธ๋ƒฅ api๊ฐ€ ์ง€์›์•ˆํ•˜๋Š”๊ฑฐ์˜€๋‹ค..
์•„๋ฌดํŠผ __iter__ ๊ณผ์ •์„ ์‚ดํŽด๋ณด์ž. ์—ฌ๊ธฐ์„œ๋Š” self.__grow๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

	def _grow(self) -> List[T]:
        newElements = self._fetchNextPage()
        self.__elements += newElements
        return newElements
    def _fetchNextPage(self) -> List[T]:
        raise NotImplementedError

PaginatedListBase์—ฌ์„œ ์˜๋„์ ์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์ผ์œผํ‚ค๋Š” ๊ฒƒ ๊ฐ™๋‹ค(๋‚œ ๊ทธ๋ƒฅ pass ๋กœ ๋ฐฉ์น˜ํ•ด๋†จ์—ˆ๋Š”๋ฐ ์ข‹์€๊ฑฐ ์•Œ๊ณ  ๊ฐ‘๋‹ˆ๋‹ค)

class PaginatedList(PaginatedListBase[T]):
	# (์ƒ๋žต)
     def _fetchNextPage(self) -> List[T]:
        headers, data = self.__requester.requestJsonAndCheck(
            "GET", self.__nextUrl, parameters=self.__nextParams, headers=self.__headers
        )
        data = data if data else []
        return self._getPage(data, headers)

์—ฌ๊ธฐ์„œ๋„ ์ธ๋ฑ์Šค๊ฐ€ ๋Š˜์–ด๋‚  ๋•Œ๋งˆ๋‹ค self.__requester.requestJsonAndCheck๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ ์š”์ฒญ์„ ๋ฐ›์•„์˜จ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์–ป์€ ๊ฒƒ ๐Ÿ”

๊ทธ๋ƒฅ ์—†๋Š” ๊ธฐ๋Šฅ์ด๊ตฌ๋‚˜.. ํ•˜๋ฉด์„œ ๋“ค์—ฌ๋‹ค ๋ณด์•˜์ง€๋งŒ ์ƒ๊ฐ๋ณด๋‹ค ์–ป์€ ์ ์ด ์žˆ๋‹ค. ๋ฐ”๋กœ (๋ฌผ๋ก  PyGithub) ์ฝ”๋“œ๊ฐ€ ์—„์ฒญ ๊น”๋”ํ•˜๊ณ  ์ž˜ ๊ตฌ์กฐ๊ฐ€ ์ž˜ ์งœ์—ฌ์ ธ์žˆ๋‹ค๋Š” ๊ฒƒ ์ด๋‹ค..! ๋‚˜์ค‘์— ์ฐธ๊ณ ํ•ด์•ผ๊ฒ ๋‹ค.

profile
๐Ÿต ๋– ์˜ค๋ฅด๋Š”๊ฑด ๋งŽ์€๋ฐ ๊ท€์ฐฎ์•„์š” ์กธ๋ ค์š”

0๊ฐœ์˜ ๋Œ“๊ธ€