본문 바로가기
코딩과 알고리즘

웹 파이썬, 파이스크립트 비기[1] ( 실시간 모듈 설치 )

이번 게시글난해한 내용을 포함하고 있습니다.
 코딩 공부중이시면 이해하지 못해도 조금도 좌절 않으셔도 됩니다.
 그냥 이런게 있구나 참고만 해주시고 복붙해 응용만 하셔도 상당히 잘하시는 겁니다 :)

파이스크립트에는 일반적으로 알려지지 않은 시크릿 코드가 존재합니다.

그 중 하나를 소개해 드리자면 '실시간 모듈 설치' 기능인데요.


파이스크립트는 기본적으로 사용할 모듈을 <py-config>... </py-config> 태그에 넣어야 사용할 수 있습니다.
이를테면 numpy 와 matplotlib 모듈을 사용하려면 아래 태그를 적어주어야 하는데요.

<py-config>
  packages = ["numpy", "matplotlib"]
</py-config>

이 태그를 적어주면 웹페이지를 로딩할 때마다 모듈을 설치합니다.
매번 로딩시마다 새로 설치하기 때문에 페이지 로딩이 느린 것이지요.

문제는 설치하는 모듈이 많으면 많을 수록 웹페이지 로딩이 초반에 느린 것입니다.
그러니까 사용할지 않을지 모르는 모듈을 모두 넣어버리면 로딩 시간이 어마어마하게 소요되는 것이지요.
한국 사람들은 대부분 로딩이 느리면 어떻게 하지요? 그냥 뒤로 가기를 눌러 버립니다 :)

필요한 모듈만 그 때마다 실시간으로 불러올 수 있을까요?
있습니다. 다만 스크립트 구성 방법에 변화를 주어야 하지요.

파이스크립트에서 실시간으로 모듈을 설치하는 명령어는 아래와 같습니다만,
( numpy :  넘파이를 설치하는 예시 )

import micropip

micropip.install('numpy')

이 명령을 실행 후 import 를 하면 오류가 납니다. 

import micropip

micropip.install('numpy')
import numpy as np

그것은 설치하는데 시간이 소요되기 때문인데요.
이러한 방법을 사용하려면 파이스크립트 작성 방법을 바꿔주어야 합니다.
그 기본형은 아래와 같습니다.

import micropip
import js
from pyodide.ffi import create_proxy

async def main():
    await micropip.install('numpy')
    import numpy as np

js.setTimeout(create_proxy(main), 0)

설명드리긴 일부 복잡합니다만 알고 싶으신 분을 위해 설명드리면 아래와 같은데요.

실시간 설치 기술을 사용하기 위해서는 3개의 모듈이 필요합니다.
바로 아래 모듈들입니다.

import micropip
import js
from pyodide.ffi import create_proxy

microip 는 모듈 설치를 담당하는 모듈이고,
js 는 웹브라우저의 자바스크립트 모듈입니다.
그리고 create_proxy 는 자바스크립트와 파이스크립트를 연결해주는 모듈이지요.

3총사힘을 합쳐야 실시간 설치를 구현할 수 있습니다.

그리고 모든 기능은 함수 안에 작성을 해주셔야 하는데요.
함수는 아래와 같이 async 를 앞에 붙여 정의해 주셔야 합니다.

 

async def main():
    await micropip.install('numpy')
    import numpy as np

함수 이름을 C언어 관습에 따라 main 을 사용했지만 main이 아니어도 무방합니다.
함수 내에 await 명령을 사용할 때는 async 를 반드시 지정해주어야 하는 데요.

함수 내에 사용한 await 는 명령어를 실행하고 기다리라는 신호입니다.
설치와 같은 일을 담당하는 micropip.install() 같은 명령은 설치를 시작하고 바로 다음 명령을 실행하거든요.
설치가 끝나지도 않았는데 그러면 안되니 설치가 끝날때까지 '기다려'라고 await를 앞에 붙여주는 것인데요
이러한 await 를 함수 안에서 사용하려면 사용하는 주체의 함수 앞에 반드시 async 를 붙여주어야 합니다.

이렇게 정의한 함수를 사용하려면 아래와 같이 사용하면 좋으련만 아쉽게도 오류가 납니다.

main()

 

혹시 아래와 같이 실행하면 될까요?

await main()

아쉽게도 이 방법도 현재 실행되지 않는데요.
미래에는 가능할지는 모르겠습니다.

우선 현재 가능한 방법은 아래와 같습니다.

js.setTimeout(create_proxy(main), 0)

자바스크립트 모듈 js를 이용하는 방법인데요.
페이지 로딩이 끝나고 0초 후에 main 함수를 실행하는 방법입니다.

지난 게시글의 그래프를 출력하는 예제는 <py-config> 태그로 구성되어 있습니다.

https://itadventure.tistory.com/636

이번에는 실시간으로 numpy 와 matplotlib 모듈을 설치하고 사용하는 예제를 제공해 드리겠습니다.

이 방법이면 <py-config> 태그 없이 동일한 작업을 할 수 있습니다.

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Third Party</title>
    <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css"/>
    <script defer src="https://pyscript.net/latest/pyscript.js"></script>
  </head>
  <body>
<!-- display 명령에서 출력할 div -->
<div id="graph"></div>
<py-script>
import micropip
import js
from pyodide.ffi import create_proxy

async def main():
  display("numpy 설치중입니다.", target='graph')
  await micropip.install('numpy')
  import numpy as np
  display("matplotlib 설치중입니다.", target='graph')
  await micropip.install('matplotlib')
  import matplotlib.pyplot as plt
  display("그래프를 그리는 중입니다.", target='graph')
  arr = np.array([5, 3, 4, 1, 2])
  plt.plot(arr)
  plt
  display(plt, target='graph')

js.setTimeout(create_proxy(main), 0)
</py-script>

  </body>
</html>

오늘은 약간 난해한 내용을 공유드렸습니다만,
필요하신 분께는 도움이 되셨으리라 믿어 의심지 않으며
오늘도 방문해주신 모든 분들께 감사드립니다 ~