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
댓글
답변
정확히 무엇을 찾고 있는지 잘 모르겠습니다. 귀하의 질문에 대한 답은 다음과 같습니다.
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 ‘의 들여 쓰기 십자군에 짜증이 났을 것입니다).
LSAMon
라는 모나드를 사용한 예입니다. (아래로 스크롤하십시오.)