Mathematica에서 Python 추상 구문 트리 (AST)를 어셈블하는 방법은 무엇입니까?

Python “ ast.Module “객체를 다음 예를 통해 Python에 제출합니다. ExternalEvaluate["exec(astObject)"].

Python 마지막 , parse , eval , exec 컴파일 함수는 모두 “ ast.Module “개체, 출력하거나 입력으로 가져옵니다. 그러나 Mathematica / WL 내에서 astObject 를 조립하는 방법을 모르겠습니다. 그런 다음 ExternalEvaluate를 통해 Python으로 보냅니다.

MMA (유전 알고리즘 용)에서 Python 코드를 프로그래밍 방식으로 생성 한 다음 Python에 제출하려고합니다. 평가를 위해 파이썬 코드 문자열을 조합 할 수는 있지만 모든 들여 쓰기를 처리해야하는데 고통스러워 보입니다.

예를 들어 Python에서는 다음을 수행 할 수 있습니다.

import ast pythonString="X3=X1*X2" astObject=ast.parse(pythonString) X1=3 X2=4 exec(compile(astObject,"","exec")) print(X3) -> 12 

물론 MMA에서 다음을 수행 할 수 있습니다.

session=StartExternalSession["Python"] ExternalEvaluate[session, {"import ast","X1=3","X2=4", "exec(compile(ast.parse(\"X3=X1*X2\"),\"\",\"exec\"))"} ] 

결과 (예 : 12).

하지만 Python 코드 ("X1=3", "X2=4", "X3=X1*X2") Mathematica에서이 부분은 충분히 간단하지만 완전한 프로그램, 즉 문과 표현식을 메타 프로그래밍 방식으로 생성하려고합니다 (!). 이렇게하려면 다음을 수행해야합니다. 파이썬의 성가신 들여 쓰기를 파싱하는 방법을 알아 내십시오. 물론 이것이 하나의 표현식 세트를 다음 표현식과 구별하는 방법과 그 종속성이 무엇인지입니다. 그렇게하는 것이 싫고 ast 구조에서 작동하는 것이 더 쉬울 것이라고 생각했습니다.

원래 중간 문자열 형식을 사용할 수 있다고 생각했습니다. 다음과 같은 Python의 ast.dump() 함수 :

astString = ast.dump(pythonString) -> "Module(Body=[Assign(targets=[Name(id="X3",ctx=Store())],value=BinOp(left=Name(id="X1", ctx=Load()),op=Mult(),right=Name(id="X2",ctx=Load())))])" 

이후 astString는 기본적으로 astObject를 직렬화합니다. 대신 생성 할 수도 있습니다.하지만 Python이이 astString.

위의 astObject처럼 Mathematica 쪽에서 이런 종류의 Python 객체를 생성 할 수 있습니까?

B

PS : 다음은 “ ast.Module “개체에 대한 설명입니다. https://greentreesnakes.readthedocs.io/en/latest/tofrom.html

PPS : Wolfram 커뮤니티에 교차 게시했습니다 : https://community.wolfram.com/groups/-/m/t/2070851

댓글

  • ” 그런 다음 Python ‘의 성가신 들여 쓰기를 구문 분석하는 방법을 알아 내야합니다. […] “-AST 사용을 요청하는 것을 알고 있지만 Python ‘ 들여 쓰기를 다루는 답변도 관심이있을 수 있습니다.
  • 예, Anton, 맞습니다. 전적으로 문자열 기반 솔루션도 검토하고 있습니다. 그리고 그 라인을 따라 나는 Python ‘의 EBNF 문법을 자동으로 가져 와서 아마도 내가 pseudo-Python-with-explicit-bracketing을 생성 할 수 있도록하는 방법으로 FunctionalParsers.m 패키지를보고있었습니다. , 또는 물론 적절한 브라케팅이있는 Hy 코드 (Python으로 작성된 Lisp)를 생성 할 수 있습니다. 누군가가 들여 쓰기를 기반으로 언어를 만드는 이유 또는 다른 ‘이 언어를 계속 사용하는 이유를 ‘ 이해할 수 없습니다. …
  • ” ‘ 누군가가 들여 쓰기를 기반으로 언어를 만드는 이유를 이해할 수 없습니다. 다른 ‘가 계속 사용하는 이유 … “-LOL! 많은 사람들이 그것에 대해 의아해하고 있습니다!
  • ” FunctionalParsers.m “를 사용하는 것은 흥미로운 아이디어이지만 추구합니다. 쉬운 작업과는 거리가 멀 수도 있습니다 …
  • 워크 플로 디자인이 동일한 두 개의 소프트웨어 모나드 (하나는 WL로, 다른 하나는 Python으로 프로그래밍)를 프로그래밍하는 것이 좋습니다. 그런 다음 사소한 코드 변경으로 이들간에 전송합니다. 또한 Python에 대한 특별한 형식이 필요하지 않습니다. 다음은 LSAMon 라는 모나드를 사용한 예입니다. (아래로 스크롤하십시오.)

답변

정확히 무엇을 찾고 있는지 잘 모르겠습니다. 귀하의 질문에 대한 답은 다음과 같습니다.

MMA에서 Python 코드를 프로그래밍 방식으로 생성하려고합니다 …] 그런 다음 평가를 위해 Python에 제출합니다. Python 코드 문자열을 조합 할 수는 있지만 모든 들여 쓰기를 처리해야하는데 고통스러워 보입니다.

Mathematica 측에서 이런 종류의 Python 객체를 만드는 것이 가능합니까?

ExternalEvaluate 및 Python의 ” ast

라이브러리.

예 :

code = ""[i**2 for i in range(10)]""; astTemplate = StringTemplate["import ast; eval(compile(ast.parse(`1`, mode="eval"), "", "eval"))"]; astTemplate[code] (* "import ast; eval(compile(ast.parse("[i**2 for i in range(10)]", mode="eval"), "", "eval"))" *) ExternalEvaluate["Python", astTemplate[code]] (* {0, 1, 4, 9, 16, 25, 36, 49, 64, 81} *) 

(iv id =를 사용했습니다. eval는 값을 반환하므로 exec 대신 “30ec86f1e9”>

.)

댓글

  • Anton에게 감사합니다. 예, 더 명확 할 수있었습니다. 질문을 조금 업데이트하겠습니다. 기본적으로 ” ‘ [i ** 2 for i in range (10)] ‘ ” MMA 측의 답변에 포함되지만 Python 문자열이 아니라 컴파일 및 평가 및 exec에 연결할 수있는 ast.Module 개체로 포함됩니다.

답변

Python 코드를 문자열로 컴파일하는 것이 실제로 제안한 것보다 더 간단하다고 생각합니다. 그러나 나는 또한 “아무도 설득하지 못할 것이므로 여기에 예”라고 말하는 것도 알고 있습니다.

우리는 Mathematica에서 Python 프로그램을 나타내는 몇 가지 상징적 머리와 렌더링 할 함수를 정의합니다. 이러한 기호 머리가있는 표현식 :

ToPythonString[statements_List] := StringRiffle[ToPythonString /@ statements, "\n"] ToPythonString[PyBlock[statement_, children_, indent_ : 0]] := StringJoin[ StringRepeat[" ", indent], statement, ":\n", ToPythonString[PyIndent /@ children] ] ToPythonString[PyStatement[statement_, indent_ : 0]] := StringJoin[ StringRepeat[" ", indent], statement ] PyIndent[PyBlock[statement_, children_, indent_ : 0]] := PyBlock[ statement, PyIndent /@ children, indent + 1 ] PyIndent[PyStatement[statement_, indent_ : 0]] := PyStatement[ statement, indent + 1 ] 

이 함수를 사용하면 들여 쓰기에 대해 생각하지 않고 Mathematica에서 Python 코드를 작성할 수 있습니다. ast 모듈로 Python 코드를 빌드합니다.

다음은 기호 표현식을 문자열로 렌더링하는 예입니다.

prog = { PyStatement["a = 1"], PyStatement["b = 2"], PyBlock["If a > b", { PyStatement["Print("a is larger than b")"] }], PyBlock["def f(x)", { PyStatement["Print("executing f")"], PyBlock["if x > 0", { PyStatement["Print("x is larger than 0")"] }] }] }; ToPythonString[prog] 

Out :

a = 1 b = 2 If a > b: Print("a is larger than b") def f(x): Print("executing f") if x > 0: Print("x is larger than 0") 

이것을 쉽게 구축하고 Python 프로그램의 상징적 표현을보다 설명 적으로 만들 수 있습니다.

PyAssign[lhs_, rhs_] := PyStatement[lhs <> " = " <> rhs] PyPrint[text_] := PyStatement["Print(" <> text <> ")"] PyFunction[name_, args_, statements_] := PyBlock[ "def " <> name <> "(" <> StringRiffle[args, ", "] <> ")", statements ] PyIf[cond_, statements_] := PyBlock[ "If " <> cond, statements ] PyIf[cond_, statements_, elseStatements_] := { PyBlock[ "If " <> cond, statements ], PyBlock[ "else", elseStatements ] } 

이러한 도우미 정의를 사용하여 이제 매우 읽기 쉬운 스타일로 다음 프로그램을 작성할 수 있습니다.

prog = { PyAssign["a", "1"], PyAssign["b", "2"], PyIf[ "a > b", { PyPrint["a is larger than b"] }], PyFunction["f", {"x"}, PyIf[ "x > 0", {PyPrint["x is larger than 0"]}, {PyPrint["x is not larger than 0"]} ] ] }; ToPythonString[prog] 

Out :

a = 1 b = 2 If a > b: Print(a is larger than b) def f(x): If x > 0: Print(x is larger than 0) else: Print(x is not larger than 0) 

아직 보지 않았다면 ” 기호 C 기본적으로 Mathematica에서 C 언어 프로그램을위한 AST를 구축 한 다음 실행 가능한 C 코드로 변환 할 수있는 방법입니다. 그것이 기본적으로 우리가이 코드로 향하고있는 곳입니다. 비록 제가 이와 같은 완전한 구현을 만들려고한다면 이것이 정확히 이렇지 않을 것입니다 (아스트 모듈은 확실히 연구 할 가치가 있습니다). / p>

요점으로 돌아가서 :이 답변으로 전달하고 싶은 것은 질문에서 언급 한 들여 쓰기 문제를 어느 정도 해결하는 작은 프레임 워크를 구축하는 데 많은 시간을 소비 할 필요가 없다는 것입니다. .

댓글

  • 예 CE 이것은 구현하기 위해 고문이 될 것이라고 상상했던 것과 매우 흡사합니다. 당신이 맞습니다. 아주 간단합니다. 아톰과 연산자,리스트와 튜플 등을 다루기 위해이 방식으로 언어를 잎사귀쪽으로 아래로 확장해야하지만이 프레임 워크는 모든 들여 쓰기를 처리하고 가능해야합니다.
  • @berniethejet이 예에서는 PyIf를 다른 것으로 평가되는 것으로 정의했습니다. 대신 ToPythonString (예 : ToPythonString[PyIf[...]] :=)에 정의를 추가하는 것을 고려할 수 있습니다. 이렇게하면 ToPythonString를 호출 할 때까지 평가되지 않고 기호 형식으로 전체 프로그램을 검사 할 수 있습니다.
  • 감사합니다. 당신의 프레임 워크는 내가 함께 뭉친 어떤 것보다 확실히 낫습니다 (필연적으로 Guido ‘의 들여 쓰기 십자군에 짜증이 났을 것입니다).

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다