itsource

파이썬의 구문에 새로운 문을 추가할 수 있습니까?

mycopycode 2023. 8. 5. 10:07
반응형

파이썬의 구문에 새로운 문을 추가할 수 있습니까?

문장을할 수 예:print,raise,with 파이썬의 구문으로?

예를 들어, 허락하는 것은

mystatement "Something"

아니면.

new_if True:
    print "example"

필요하다면 그렇게 많이는 아니지만, 오히려 가능하다면 (파이썬 인터프리터 코드를 수정하는 것보다).)

Python 내부: Python에 새 문을 추가하는 것이 유용할 것입니다. 여기에 인용되어 있습니다.


이 기사는 Python의 프런트 엔드가 어떻게 작동하는지 더 잘 이해하기 위한 시도입니다.설명서와 소스 코드를 읽는 것만으로도 다소 지루할 수 있으므로 여기서는 직접적인 접근 방식을 취하고 있습니다.저는 다음을 추가하려고 합니다.untilPython에 대한 진술.

이 기사에 대한 모든 코딩은 Python Mercurial 저장소 미러의 최첨단 Py3k 분기에 대해 수행되었습니다.

until

루비와 같은 몇몇 언어들은,until은 보는진술하완을다음진▁toment의 .while(until num == 0는 와동합다니등다에 합니다.while num != 0루비에서 저는 다음과 같이 쓸 수 있습니다.

num = 3
until num == 0 do
  puts num
  num -= 1
end

다음과 같이 인쇄됩니다.

3
2
1

그래서 저는 파이썬과 비슷한 기능을 추가하고 싶습니다.즉, 다음을 작성할 수 있습니다.

num = 3
until num == 0:
  print(num)
  num -= 1

언어 옹호적 편견.

이 문서는 다음 항목을 추가할 것을 제안하지 않습니다.untilPython에 대한 진술.비록 저는 그러한 진술이 약간의 코드를 더 명확하게 만들 것이라고 생각하고, 이 기사는 추가하는 것이 얼마나 쉬운지 보여주지만, 저는 파이썬의 미니멀리즘 철학을 전적으로 존중합니다.제가 여기서 하려는 것은 파이썬의 내부 작동에 대한 통찰력을 얻는 것입니다.

문법 수정

은 Python이라는 사용자 정의 합니다.pgenPython 소스 코드를 구문 분석 트리로 변환하는 LL(1) 파서입니다. " " " 입니다.Grammar/Grammar. Python의 문법을 지정하는 간단한 텍스트 파일입니다.

: 여기서부터 Python 소스의 파일에 대한 참조는 python을 빌드하기 위해 configure를 실행하고 만드는 디렉터리인 소스 트리의 루트에 상대적으로 주어집니다.

문법 파일을 두 가지 수정해야 합니다.첫 번째는 다음에 대한 정의를 추가하는 것입니다.until진술.나는 어디서 발견했습니다.while정의되었습니다.while_stmt됨), 추가됨until_stmt[2] 이하:

compound_stmt: if_stmt | while_stmt | until_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite]
until_stmt: 'until' test ':' suite

: 익숙하지 않은 소스 코드를 수정할 때 사용하는 일반적인 기법인 유사성에 의한 작업을 보여줍니다.이 원칙이 당신의 모든 문제를 해결하지는 않겠지만, 그것은 확실히 과정을 쉽게 할 수 있습니다.우리가 해야 할 모든 일들이while또한 다음을 위해 수행해야 합니다.until그것은 꽤 좋은 지침 역할을 합니다.

참고로 저는 다음을 제외하기로 결정했습니다.else▁my의 절.until단지 조금 다르게 만들기 위해 (그리고 솔직히 나는 그것을 싫어하기 때문입니다.else루프의 절이며 파이썬의 젠과 잘 맞지 않는다고 생각합니다.

두 번째 변경 사항은 다음에 대한 규칙을 수정하는 것입니다.compound_stmt▁to를 until_stmt위의 스니펫에서 볼 수 있듯이.바로다니다입음 바로 while_stmt 시다.

을 할 때make수정한 Grammar/Grammar하세요.pgen프로그램이 다시 생성되도록 실행됩니다.Include/graminit.h그리고.Python/graminit.c여러 개의 파일이 다시 생성됩니다.

AST 생성 코드 수정

Python 파서가 구문 분석 트리를 만든 후에는 AST가 컴파일 프로세스의 후속 단계에서 작업하기 훨씬간단하기 때문에 이 트리가 AST로 변환됩니다.

그래서 저희가 방문을 방문하려고 합니다.Parser/Python.asdl Python의 AST 합니다.until문, 다시 바로 아래에 있습니다.while:

| While(expr test, stmt* body, stmt* orelse)
| Until(expr test, stmt* body)

지금 실행하는 경우make많은 파일을 컴파일하기 전에Parser/asdl_c.py를 실행하여 AST 정의 파일에서 C 코드를 생성합니다.: 이거예:Grammar/Grammar을 단순화하기 언어하는 파이썬 의 또 는 프로그래밍을 단순화하기 위해 미니 언어(즉 DSL)를 사용하는 파이썬 소스 코드의 또 다른 예입니다.또한 그 이후로Parser/asdl_c.pyPython 스크립트이며, 이것은 일종의 부트스트래핑입니다. Python을 처음부터 구축하려면 Python을 이미 사용할 수 있어야 합니다.

하는 동안에Parser/asdl_c.py노드를 했습니다.Include/Python-ast.h그리고.Python/Python-ast.c), 우리는 여전히 손으로 관련 구문 분석 트리 노드를 변환하는 코드를 작성해야 합니다.이 작업은 파일에서 수행됩니다.Python/ast.c거기서, 다음과 같은 이름의 함수가ast_for_stmt문에 대한 구문 분석 트리 노드를 AST 노드로 변환합니다.다시, 우리의 오랜 친구에 의해 안내됩니다.while우리는 바로 큰 곳으로 뛰어듭니다.switch할 때 하고, 합진처다대음한절추다을니가에 대한 합니다.until_stmt:

case while_stmt:
    return ast_for_while_stmt(c, ch);
case until_stmt:
    return ast_for_until_stmt(c, ch);

는 이제구야합다니를 시행해야 .ast_for_until_stmt여기 있습니다.

static stmt_ty
ast_for_until_stmt(struct compiling *c, const node *n)
{
    /* until_stmt: 'until' test ':' suite */
    REQ(n, until_stmt);

    if (NCH(n) == 4) {
        expr_ty expression;
        asdl_seq *suite_seq;

        expression = ast_for_expr(c, CHILD(n, 1));
        if (!expression)
            return NULL;
        suite_seq = ast_for_suite(c, CHILD(n, 3));
        if (!suite_seq)
            return NULL;
        return Until(expression, suite_seq, LINENO(n), n->n_col_offset, c->c_arena);
    }

    PyErr_Format(PyExc_SystemError,
                 "wrong number of tokens for 'until' statement: %d",
                 NCH(n));
    return NULL;
}

다시 말하지만, 이것은 동등한 것을 자세히 보는 동안 코드화되었습니다.ast_for_while_stmt…에 …의 차액으로 until나는 지지하지 않기로 결정했습니다.else 예대로는, AST 생성 기능을 사용하여 됩니다.ast_for_expr 및 조건표식및현의 ast_for_suite 위을하여의 .until진술.마지막으로, 새로운 노드는 다음과 같습니다.Until반환됩니다.

node "에 .n 같은 일부 매크로 NCH그리고.CHILD이것들은 이해할 가치가 있습니다 - 그들의 코드는 다음에 있습니다.Include/node.h.

디지션: AST 구성

새로운 유형의 AST를 생성하기로 결정했습니다.until진술, 하지만 사실 이것은 필요하지 않습니다.다음과 같은 이유로 기존 AST 노드의 구성을 사용하여 작업을 절약하고 새로운 기능을 구현할 수 있었습니다.

until condition:
   # do stuff

기능적으로 다음과 같습니다.

while not condition:
  # do stuff

를 만드는 Until에 매듭짓다.ast_for_until_stmt나는 그것을 만들 수 있었습니다.Not노드를 사용합니다.While 노드를 있기 .AST 컴파일러는 이미 이러한 노드를 처리하는 방법을 알고 있으므로 프로세스의 다음 단계를 건너뛸 수 있습니다.

AST를 바이트 코드로 컴파일

다음 단계는 AST를 Python 바이트 코드로 컴파일하는 것입니다.컴파일은 CFG(Control Flow Graph)인 중간 결과를 가지고 있지만, 동일한 코드가 처리하기 때문에 이 세부 사항은 일단 무시하고 다른 기사로 남겨두겠습니다.

는 다으로살코드는볼입니다.Python/compile.c의 .while 우는함를찾습다니수리▁function▁the다니를 찾습니다.compiler_visit_stmt명령문을 바이트코드로 컴파일하는 역할을 담당합니다.다음에 대한 조항을 추가합니다.Until:

case While_kind:
    return compiler_while(c, s);
case Until_kind:
    return compiler_until(c, s);

이 궁금하다면,Until_kind즉, 그것은 상수입니다(값을 계산합니다)._stmt_kind 정의 되어 열거정) AST로 전송됩니다.Include/Python-ast.h어쨌든, 우리는 전화를 합니다.compiler_until물론, 아직 존재하지 않는 것입니다.잠시 얘기를 해보겠습니다.

럼궁금면다하그, ▁that▁▁you▁notice'll,.compiler_visit_stmt특이합니다.의 양이 없음grep-소스 트리를 ping하면 호출된 위치가 표시됩니다.이 경우 C macro-fu 옵션만 남아 있습니다.실제로, 짧은 조사는 우리를 다음과 같이 이끌었습니다.VISITPython/compile.c:

#define VISIT(C, TYPE, V) {\
    if (!compiler_visit_ ## TYPE((C), (V))) \
        return 0; \

호출할 때 사용합니다.compiler_visit_stmtcompiler_body하지만 다시 우리 일로 돌아가서,

약속대로, 여기 있습니다.compiler_until:

static int
compiler_until(struct compiler *c, stmt_ty s)
{
    basicblock *loop, *end, *anchor = NULL;
    int constant = expr_constant(s->v.Until.test);

    if (constant == 1) {
        return 1;
    }
    loop = compiler_new_block(c);
    end = compiler_new_block(c);
    if (constant == -1) {
        anchor = compiler_new_block(c);
        if (anchor == NULL)
            return 0;
    }
    if (loop == NULL || end == NULL)
        return 0;

    ADDOP_JREL(c, SETUP_LOOP, end);
    compiler_use_next_block(c, loop);
    if (!compiler_push_fblock(c, LOOP, loop))
        return 0;
    if (constant == -1) {
        VISIT(c, expr, s->v.Until.test);
        ADDOP_JABS(c, POP_JUMP_IF_TRUE, anchor);
    }
    VISIT_SEQ(c, stmt, s->v.Until.body);
    ADDOP_JABS(c, JUMP_ABSOLUTE, loop);

    if (constant == -1) {
        compiler_use_next_block(c, anchor);
        ADDOP(c, POP_BLOCK);
    }
    compiler_pop_fblock(c, LOOP, loop);
    compiler_use_next_block(c, end);

    return 1;
}

고백할 게 있습니다. 이 코드는 파이썬 바이트 코드에 대한 깊은 이해를 바탕으로 작성된 것이 아닙니다.기사의 나머지 부분과 마찬가지로, 그것은 친척을 모방하여 만들어졌습니다.compiler_while기능 기반이라는 점을 에 두고 그나 Python VM 은스기dis모듈은 설명이 포함된 파이썬 바이트 코드 목록을 가지고 있으며, 무슨 일이 일어나고 있는지 이해할 수 있습니다.

됐어요, 우린 끝났어요...그렇지 않나요?

한 후make우리는 새로 컴파일된 파이썬을 실행하고 새로운 것을 시도할 수 있습니다.until문:

>>> until num == 0:
...   print(num)
...   num -= 1
...
3
2
1

Voila, 효과가 있어요!다음 문장을 사용하여 된 바이트 를 보겠습니다.dis모듈은 다음과 같습니다.

import dis

def myfoo(num):
    until num == 0:
        print(num)
        num -= 1

dis.dis(myfoo)

결과는 다음과 같습니다.

4           0 SETUP_LOOP              36 (to 39)
      >>    3 LOAD_FAST                0 (num)
            6 LOAD_CONST               1 (0)
            9 COMPARE_OP               2 (==)
           12 POP_JUMP_IF_TRUE        38

5          15 LOAD_NAME                0 (print)
           18 LOAD_FAST                0 (num)
           21 CALL_FUNCTION            1
           24 POP_TOP

6          25 LOAD_FAST                0 (num)
           28 LOAD_CONST               2 (1)
           31 INPLACE_SUBTRACT
           32 STORE_FAST               0 (num)
           35 JUMP_ABSOLUTE            3
      >>   38 POP_BLOCK
      >>   39 LOAD_CONST               0 (None)
           42 RETURN_VALUE

가장 흥미로운 연산은 12번입니다. 조건이 참이면 루프 뒤로 이동합니다.은 이다음대올의다니미입바른에 대한 올바른 입니다.until점프가 실행되지 않으면 루프 본체는 동작 35의 상태로 다시 점프할 때까지 계속 실행됩니다.

변화에 ) .myfoo(3)바이트 코드를 표시하는 대신.결과는 고무적이지 않았습니다.

Traceback (most recent call last):
  File "zy.py", line 9, in
    myfoo(3)
  File "zy.py", line 5, in myfoo
    print(num)
SystemError: no locals when loading 'print'

이럴 수가!그래서 뭐가 잘못됐어요?

기호 테이블이 누락된 경우

AST를 컴파일할 때 Python 컴파일러가 수행하는 단계 중 하나는 컴파일하는 코드에 대한 기호 테이블을 만드는 것입니다.:PySymtable_BuildPyAST_Compile모듈에 (호출)Python/symtable.c 함수와 코드 생성 기능과 유사한 방식으로 AST를 보행합니다.각 범위에 대한 기호 테이블을 갖는 것은 컴파일러가 어떤 변수가 글로벌하고 어떤 범위에 로컬인지와 같은 몇 가지 주요 정보를 파악하는 데 도움이 됩니다.

문제를 해결하기 위해, 우리는 수정해야 합니다.symtable_visit_stmt에서 합니다.Python/symtable.c 처리 코드 until에 대한 유사한 코드 에, 유한코드뒤에사에,ments▁state▁the뒤.while[3]:

case While_kind:
    VISIT(st, expr, s->v.While.test);
    VISIT_SEQ(st, stmt, s->v.While.body);
    if (s->v.While.orelse)
        VISIT_SEQ(st, stmt, s->v.While.orelse);
    break;
case Until_kind:
    VISIT(st, expr, s->v.Until.test);
    VISIT_SEQ(st, stmt, s->v.Until.body);
    break;

: 그나저나, 이 코드가 없으면 컴파일러에 대한 경고가 있습니다.Python/symtable.c컴파일러는 다음을 인지합니다.Until_kind 값의 스문처 에않리다니의 되지 않습니다.symtable_visit_stmt그리고 불평합니다.컴파일러 경고를 확인하는 것은 항상 중요합니다!

이제 우리는 정말로 끝이 났습니다.이 변경 후 소스를 컴파일하면 다음 작업이 수행됩니다.myfoo(3)예상대로 일을 보다

결론

이 기사에서는 Python에 새 문을 추가하는 방법을 시연했습니다.파이썬 컴파일러의 코드를 수정하는 데 상당한 노력이 필요하지만, 유사하고 기존의 문장을 지침으로 사용했기 때문에 변경 사항을 구현하는 것은 어렵지 않았습니다.

파이썬 컴파일러는 정교한 소프트웨어 덩어리이며, 저는 그것에 전문가라고 주장하지 않습니다.하지만 저는 파이썬의 내부, 특히 프론트엔드에 관심이 많습니다.따라서, 저는 이 연습이 컴파일러의 원리와 소스 코드에 대한 이론적 연구에 매우 유용한 동반자라는 것을 알게 되었습니다.그것은 컴파일러에 더 깊이 들어갈 향후 기사의 기반이 될 것입니다.

레퍼런스

저는 이 기사의 구성을 위해 몇 가지 훌륭한 참고 자료를 사용했습니다.다음은 특정 순서가 아닌 것입니다.

  • PEP 339: CPython 컴파일러의 설계 - 아마도 파이썬 컴파일러를 위한 가장 중요하고 포괄적인 공식 문서일 입니다.매우 짧기 때문에 파이썬 내부에 대한 좋은 문서가 부족하다는 것을 고통스럽게 보여줍니다.
  • "Python Compiler Internals" - Thomas Lee 기사
  • "피톤:설계 및 구현" - Guido van Rossum의 프레젠테이션
  • Python (2.5) 가상 머신, 가이드 투어 - Peter Tröger의 프레젠테이션

원출처

이와 같은 작업을 수행하는 한 가지 방법은 소스를 전처리하고 수정하여 추가된 문을 파이썬으로 변환하는 것입니다.이 접근 방식이 가져올 다양한 문제가 있으며 일반적인 용도로는 권장하지 않지만 언어 실험이나 특정 목적의 메타프로그래밍에는 가끔 유용할 수 있습니다.

예를 들어 화면에 인쇄하는 대신 특정 파일에 기록하는 "myprint" 문을 도입하려고 합니다.i:

myprint "This gets logged to file"

와 동등할 것입니다.

print >>open('/tmp/logfile.txt','a'), "This gets logged to file"

regex 대체부터 AST 생성, 구문이 기존 python과 얼마나 가까운지에 따라 자신만의 파서 작성까지 대체 방법에 대한 다양한 옵션이 있습니다.좋은 중간 접근법은 토큰화 모듈을 사용하는 것입니다.이를 통해 소스를 파이썬 인터프리터와 비슷하게 해석하면서 새로운 키워드, 제어 구조 등을 추가할 수 있으므로 조잡한 정규식 솔루션이 야기하는 손상을 방지할 수 있습니다.위의 "myprint"에 대해 다음과 같은 변환 코드를 작성할 수 있습니다.

import tokenize

LOGFILE = '/tmp/log.txt'
def translate(readline):
    for type, name,_,_,_ in tokenize.generate_tokens(readline):
        if type ==tokenize.NAME and name =='myprint':
            yield tokenize.NAME, 'print'
            yield tokenize.OP, '>>'
            yield tokenize.NAME, "open"
            yield tokenize.OP, "("
            yield tokenize.STRING, repr(LOGFILE)
            yield tokenize.OP, ","
            yield tokenize.STRING, "'a'"
            yield tokenize.OP, ")"
            yield tokenize.OP, ","
        else:
            yield type,name

(이것은 내 인쇄물을 효과적으로 키워드로 만들기 때문에 다른 곳에서 변수로 사용하면 문제가 발생할 수 있습니다.)

그렇다면 문제는 당신의 코드를 파이썬에서 사용할 수 있도록 어떻게 사용하느냐 하는 것입니다.한 가지 방법은 자신의 가져오기 기능을 작성하여 사용자 지정 언어로 작성된 코드를 로드하는 것입니다.i:

import new
def myimport(filename):
    mod = new.module(filename)
    f=open(filename)
    data = tokenize.untokenize(translate(f.readline))
    exec data in mod.__dict__
    return mod

를 위해서는 인 파이썬 some_mod = myimport("some_mod.py") 보다는""보다는import some_mod"

또 다른 꽤 깔끔한 솔루션은 이 레시피에서 보여주듯이 사용자 정의 인코딩(PEP 263 참조)을 만드는 것입니다.이를 다음과 같이 구현할 수 있습니다.

import codecs, cStringIO, encodings
from encodings import utf_8

class StreamReader(utf_8.StreamReader):
    def __init__(self, *args, **kwargs):
        codecs.StreamReader.__init__(self, *args, **kwargs)
        data = tokenize.untokenize(translate(self.stream.readline))
        self.stream = cStringIO.StringIO(data)

def search_function(s):
    if s!='mylang': return None
    utf8=encodings.search_function('utf8') # Assume utf8 encoding
    return codecs.CodecInfo(
        name='mylang',
        encode = utf8.encode,
        decode = utf8.decode,
        incrementalencoder=utf8.incrementalencoder,
        incrementaldecoder=utf8.incrementaldecoder,
        streamreader=StreamReader,
        streamwriter=utf8.streamwriter)

codecs.register(search_function)

이제 이 코드가 실행된 후(예: .vmsrc 또는 site.py 에 배치할 수 있음) "# coding: mylang" 주석으로 시작하는 모든 코드는 위의 전처리 단계를 통해 자동으로 변환됩니다.예를 들면

# coding: mylang
myprint "this gets logged to file"
for i in range(10):
    myprint "so does this : ", i, "times"
myprint ("works fine" "with arbitrary" + " syntax" 
  "and line continuations")

주의사항:

C 전처리기로 작업한 적이 있다면 아마도 익숙할 것이기 때문에 전처리기 접근 방식에는 문제가 있습니다.주요한 것은 디버깅입니다.python이 보는 모든 것은 전처리된 파일이며, 이는 스택 추적 등에 인쇄된 텍스트가 그것을 참조한다는 것을 의미합니다.중요한 번역을 수행한 경우 원본 텍스트와 매우 다를 수 있습니다.위의 예는 라인 번호 등을 변경하지 않으므로 크게 다르지는 않겠지만, 변경할수록 파악하기가 어려워집니다.

네, 어느 정도는 가능합니다.다음을 사용하는 모듈이 있습니다.sys.settrace()행할을 goto그리고.comefrom "정수":

from goto import goto, label
for i in range(1, 10):
  for j in range(1, 20):
    print i, j
    if j == 3:
      goto .end # breaking out from nested loop
label .end
print "Finished"

소스 코드를 변경하고 다시 컴파일하지 않는 한(오픈 소스에서 가능), 기본 언어를 변경하는 것은 실제로 가능하지 않습니다.

소스를 재컴파일하더라도 파이썬이 아니라 버그를 도입하지 않도록 매우 주의해야 하는 해킹된 변경 버전일 뿐입니다.

하지만, 당신이 왜 그러려는지 잘 모르겠습니다.Python의 객체 지향 기능을 사용하면 현재 언어로도 유사한 결과를 쉽게 얻을 수 있습니다.

일반적인 답변: 소스 파일을 사전 처리해야 합니다.

보다 구체적인 답변: 간편 설치확장하고 다음 단계를 수행합니다.

새 랭글릿(확장 언어) 만들기

import EasyExtend
EasyExtend.new_langlet("mystmts", prompt = "my> ", source_ext = "mypy")

추가 사양 없이 EasyExtend/langlets/mystms/ 아래에 파일 묶음이 생성됩니다.

ii) mystms/parsedef/Grammar를 엽니다.ext 및 다음 행 추가

small_stmt: (expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt |
             import_stmt | global_stmt | exec_stmt | assert_stmt | my_stmt )

my_stmt: 'mystatement' expr

이는 새 문의 구문을 정의하기에 충분합니다.small_stmt non-terminal은 Python 문법의 일부이며 새 문이 잠긴 위치입니다.이제 파서가 새 문을 인식합니다. 즉, 새 문이 포함된 원본 파일이 파싱됩니다.그래도 유효한 파이썬으로 변환해야 하기 때문에 컴파일러는 이를 거부할 것입니다.

iii) 이제 그 진술의 의미론을 추가해야 합니다.이를 위해서는 msytmts/langlet.py 을 편집하고 my_stmt 노드 방문자를 추가해야 합니다.

 def call_my_stmt(expression):
     "defines behaviour for my_stmt"
     print "my stmt called with", expression

 class LangletTransformer(Transformer):
       @transform
       def my_stmt(self, node):
           _expr = find_node(node, symbol.expr)
           return any_stmt(CST_CallFunc("call_my_stmt", [_expr]))

 __publish__ = ["call_my_stmt"]

iv) cd에서 langlet/smt 및 유형으로

python run_mystmts.py

이제 세션이 시작되고 새로 정의된 문을 사용할 수 있습니다.

__________________________________________________________________________________

 mystmts

 On Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)]
 __________________________________________________________________________________

 my> mystatement 40+2
 my stmt called with 42

사소한 진술을 하기 위해서는 꽤 많은 단계가 필요하죠, 그렇죠?문법에 신경 쓰지 않고 간단한 것을 정의할 수 있는 API는 아직 없습니다.하지만 EE는 몇몇 버그에 대해 매우 신뢰할 수 있는 모듈입니다.따라서 프로그래머가 편리한 OO 프로그래밍을 사용하여 infix 연산자나 작은 문장과 같은 편리한 것을 정의할 수 있는 API가 등장하는 것은 시간 문제입니다.랭글렛을 구축하여 파이썬에 전체 언어를 포함하는 것과 같은 더 복잡한 것들은 전체 문법 접근법을 우회할 방법이 없습니다.

여기 해석 모드에서만 새 문을 추가하는 매우 간단하지만 형편 없는 방법이 있습니다.저는 sys.displayhook만을 사용하여 유전자 주석을 편집하는 작은 1글자 명령에 사용하고 있지만, 이 질문에 대답할 수 있도록 구문 오류도 고려하여 sys.except를 추가했습니다.후자는 읽기 라인 버퍼에서 원시 코드를 가져오는 정말 못생겼습니다.이점은 이러한 방식으로 새 문을 추가하는 것이 매우 쉽다는 것입니다.


jcomeau@intrepid:~/$ cat demo.py; ./demo.py
#!/usr/bin/python -i
'load everything needed under "package", such as package.common.normalize()'
import os, sys, readline, traceback
if __name__ == '__main__':
    class t:
        @staticmethod
        def localfunction(*args):
            print 'this is a test'
            if args:
                print 'ignoring %s' % repr(args)

    def displayhook(whatever):
        if hasattr(whatever, 'localfunction'):
            return whatever.localfunction()
        else:
            print whatever

    def excepthook(exctype, value, tb):
        if exctype is SyntaxError:
            index = readline.get_current_history_length()
            item = readline.get_history_item(index)
            command = item.split()
            print 'command:', command
            if len(command[0]) == 1:
                try:
                    eval(command[0]).localfunction(*command[1:])
                except:
                    traceback.print_exception(exctype, value, tb)
        else:
            traceback.print_exception(exctype, value, tb)

    sys.displayhook = displayhook
    sys.excepthook = excepthook
>>> t
this is a test
>>> t t
command: ['t', 't']
this is a test
ignoring ('t',)
>>> ^D

새 문장을 추가하는 방법에 대한 가이드를 찾았습니다.

https://troeger.eu/files/teaching/pythonvm08lab.pdf

하려면, 은 기적으로추편합집니다야를 편집해야 .Python/ast.c(다른 것들 중에서) 파이썬 바이너리를 다시 컴파일합니다.

가능한 한 하지 마세요.함수와 클래스를 통해 거의 모든 것을 달성할 수 있습니다(스크립트를 실행하기 위해 사람들이 파이썬을 다시 컴파일할 필요가 없습니다).

간편함을 사용하여 이 작업을 수행할 수 있습니다.확장:

EE(EasyExtend)는 순수 Python으로 작성되고 CPython과 통합된 프리프로세서 생성기 및 메타프로그래밍 프레임워크입니다.EasyExtend의 주요 목적은 확장 언어를 만드는 것입니다. 즉, Python에 사용자 정의 구문 및 의미론을 추가하는 것입니다.

언어 구문에 새 문을 정확히 추가하는 것은 아니지만 매크로는 강력한 도구입니다. https://github.com/lihaoyi/macropy

어떤 것들은 장식가들과 함께 할 수 있습니다.예를 들어 Python이 사용하지 않았다고 가정해 보겠습니다.with진술.그런 다음 다음과 같은 유사한 동작을 구현할 수 있습니다.

# ====== Implementation of "mywith" decorator ======

def mywith(stream):
    def decorator(function):
        try: function(stream)
        finally: stream.close()
    return decorator

# ====== Using the decorator ======

@mywith(open("test.py","r"))
def _(infile):
    for l in infile.readlines():
        print(">>", l.rstrip())

하지만 여기서 하는 것처럼 꽤 부정한 해결책입니다.특히 장식가가 함수를 호출하고 설정하는 행동._None예기치 않은 일입니다.명확설명:한▁writingator를 쓰는 것과 .

def _(infile): ...
_ = mywith(open(...))(_) # mywith returns None.

및 장식가는 일반적으로 실행이 아닌 기능을 수정해야 합니다.

나는 이전에 스크립트에서 여러 기능의 작업 디렉터리를 임시로 설정해야 하는 방법을 사용했습니다.

구식:
Logix 웹사이트에 따르면 Logix 프로젝트는 이제 더 이상 개발되지 않고 더 이상 사용되지 않습니다.

그런 것들을 할 수 있는 Logix라는 파이썬 기반의 언어가 있습니다.한동안 개발이 진행되지 않았지만, 요청하신 기능은 최신 버전에서 작동합니다.

통역사를 수정하지 않으면 안 됩니다.지난 몇 년간 많은 언어들이 "확장 가능한" 언어로 묘사되었다는 것을 알지만, 당신이 묘사하는 방식으로는 그렇지 않습니다.함수와 클래스를 추가하여 Python을 확장합니다.

10년 전에는 그럴 수 없었고, 저는 그것이 바뀌었는지 의심스럽습니다.하지만, 만약 당신이 파이썬을 다시 컴파일할 준비가 되어 있었다면 구문을 수정하는 것은 그리 어렵지 않았고, 나는 그것도 바뀌었다고 생각하지 않습니다.

언급URL : https://stackoverflow.com/questions/214881/can-you-add-new-statements-to-pythons-syntax

반응형