왜 그렇게 많은 파이썬이 있습니까? Python 구현 비교

게시 됨: 2022-03-11

파이썬은 놀랍습니다.

놀랍게도, 그것은 상당히 모호한 진술입니다. '파이썬'이란 무엇을 의미합니까? 파이썬 추상 인터페이스를 의미합니까? 일반적인 Python 구현 인 CPython을 의미합니까(유사하게 명명된 Cython과 혼동하지 말 것)? 아니면 완전히 다른 것을 의미합니까? 아마도 나는 비스듬히 Jython, IronPython 또는 PyPy를 언급하고 있습니다. 아니면 제가 정말로 깊은 끝에서 벗어나 RPython 또는 RubyPython(매우 매우 다른 것들)에 대해 이야기하고 있는 것일 수도 있습니다.

위에서 언급한 기술은 일반적으로 이름이 지정되고 일반적으로 참조되지만 일부는 완전히 다른 용도로 사용됩니다(또는 최소한 완전히 다른 방식으로 작동).

Python 인터페이스로 작업하는 동안 나는 이러한 .*ython 도구를 많이 사용했습니다. 그러나 최근까지 시간을 내어 그것들이 무엇인지, 어떻게 작동하는지, 왜 필요한지 이해하지 못했습니다.

이 자습서에서는 처음부터 시작하여 다양한 Python 구현을 살펴보고 언어의 미래라고 생각하는 PyPy에 대한 철저한 소개로 마무리합니다.

모든 것은 'Python'이 실제로 무엇인지 이해하는 것으로 시작됩니다.

기계어, 가상 머신 등에 대해 잘 이해하고 있다면 건너뛰어도 됩니다.

"파이썬이 해석되거나 컴파일됩니까?"

이것은 파이썬 초보자에게 일반적인 혼동 지점입니다.

비교할 때 가장 먼저 깨달아야 할 것은 '파이썬'이 인터페이스 라는 것입니다. Python 수행 해야 하는 작업과 작동 방식(모든 인터페이스에서와 같이)에 대한 사양이 있습니다. 그리고 (모든 인터페이스와 마찬가지로) 여러 구현 이 있습니다.

두 번째로 깨달아야 할 것은 'interpreted'와 'compiled'는 인터페이스 가 아니라 구현 의 속성이라는 것입니다.

따라서 질문 자체가 제대로 구성되지 않았습니다.

파이썬이 해석되거나 컴파일됩니까? 질문이 제대로 구성되지 않았습니다.

즉, 가장 일반적인 Python 구현(CPython: C로 작성, 간단히 'Python'이라고도 함, 그리고 내가 무슨 말을 하는지 모를 경우 확실히 사용하고 있는 것)의 경우 대답은 다음과 같습니다 . , 일부 컴파일과 함께. CPython은 * Python 소스 코드를 바이트 코드로 컴파일 한 다음 이 바이트 코드를 해석 하여 실행합니다.

* 참고: 이것은 단어의 전통적인 의미에서 '편집'이 아닙니다. 일반적으로 '컴파일'은 고급 언어를 기계어로 변환하는 것이라고 합니다. 그러나 그것은 일종의 '편집'이다.

해당 답변을 더 자세히 살펴보겠습니다. 게시물의 뒷부분에 나오는 몇 가지 개념을 이해하는 데 도움이 될 것입니다.

바이트코드 대 기계어 코드

바이트코드와 기계어 코드(네이티브 코드라고도 함)의 차이점을 이해하는 것은 매우 중요합니다.

  • C는 기계어로 컴파일된 다음 프로세서에서 직접 실행됩니다. 각 명령은 CPU에 물건을 옮기도록 지시합니다.
  • Java는 프로그램을 실행하는 컴퓨터의 추상화인 JVM(Java Virtual Machine)에서 실행되는 바이트코드로 컴파일됩니다. 그런 다음 각 명령은 컴퓨터와 상호 작용하는 JVM에서 처리됩니다.

아주 간단히 말해서 기계 코드는 훨씬 빠르지만 바이트 코드는 더 이식성 있고 안전 합니다.

머신 코드는 머신에 따라 다르게 보이지만 바이트 코드는 모든 머신에서 동일하게 보입니다. 기계 코드가 설정에 최적화 되어 있다고 말할 수 있습니다.

CPython 구현으로 돌아가서 도구 체인 프로세스는 다음과 같습니다.

  1. CPython은 Python 소스 코드를 바이트 코드로 컴파일합니다.
  2. 그 바이트코드는 CPython 가상 머신에서 실행됩니다.
초보자는 종종 .pyc 파일 때문에 Python이 컴파일된다고 가정합니다. 사실이 있습니다. .pyc 파일은 컴파일된 바이트코드이며 해석됩니다. 따라서 이전에 Python 코드를 실행했고 .pyc 파일이 있으면 바이트 코드를 다시 컴파일할 필요가 없으므로 두 번째로 더 빠르게 실행됩니다.

대체 VM: Jython, IronPython 등

앞서 언급했듯이 Python에는 여러 구현이 있습니다. 다시 말하지만, 앞서 언급했듯이 가장 일반적인 것은 CPython이지만 이 비교 가이드를 위해 언급해야 하는 다른 것들이 있습니다. 이것은 C로 작성된 Python 구현이며 '기본' 구현으로 간주됩니다.

그러나 대체 Python 구현은 어떻습니까? 가장 눈에 띄는 것 중 하나는 JVM을 활용하는 Java로 작성된 Python 구현인 Jython입니다. CPython이 CPython VM에서 실행할 바이트코드를 생성하는 반면, Jython은 JVM에서 실행할 Java 바이트코드 를 생성합니다(이는 Java 프로그램을 컴파일할 때 생성되는 것과 동일함).

Jython의 Java 바이트코드 사용은 이 Python 구현 다이어그램에 설명되어 있습니다.

"왜 대체 구현을 사용하겠습니까?"라고 물을 수 있습니다. 예를 들어, 이러한 다양한 Python 구현은 다양한 기술 스택과 잘 어울립니다 .

CPython을 사용하면 Python 코드에 대한 C 확장을 매우 쉽게 작성할 수 있습니다. 결국 C 인터프리터에 의해 실행되기 때문입니다. 반면에 자이썬은 다른 자바 프로그램과 작업하기가 매우 쉽습니다. 추가 노력 없이 모든 자바 클래스를 가져올 수 있으므로 자이썬 프로그램 내에서 자바 클래스를 불러오고 활용할 수 있습니다. (제외: 자세히 생각하지 않았다면 이것은 실제로 미친 짓입니다. 우리는 다른 언어를 혼합하고 으깨어 동일한 물질로 컴파일할 수 있는 시점에 있습니다. (Rostin이 언급한 것처럼, Fortran과 C 코드를 함께 사용하는 것은 오래전부터 있었습니다. 따라서 물론 이것이 반드시 새로운 것은 아닙니다. 하지만 여전히 멋집니다.))

예를 들어 다음은 유효한 Jython 코드입니다.

 [Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_51 >>> from java.util import HashSet >>> s = HashSet(5) >>> s.add("Foo") >>> s.add("Bar") >>> s [Foo, Bar]

IronPython은 완전히 C#으로 작성되고 .NET 스택을 대상으로 하는 또 다른 인기 있는 Python 구현입니다. 특히 JVM에 필적하는 Microsoft의 CLR(공용 언어 런타임)인 .NET 가상 머신에서 실행됩니다.

Jython : Java :: IronPython : C# 이라고 말할 수 있습니다. 동일한 VM에서 실행되며 IronPython 코드에서 C# 클래스를 가져오고 Jython 코드에서 Java 클래스 등을 가져올 수 있습니다.

CPython이 아닌 Python 구현을 건드리지 않고 생존하는 것은 완전히 가능합니다. 그러나 전환을 통해 얻을 수 있는 이점이 있으며 대부분은 기술 스택에 따라 다릅니다. JVM 기반 언어를 많이 사용하십니까? Jython은 당신을 위한 것일 수 있습니다. .NET 스택에 대한 모든 것? 아마도 당신은 IronPython을 시도해야 할 것입니다(그리고 아마도 당신은 이미 가지고 있을 것입니다).

이 Python 비교 차트는 Python 구현 간의 차이점을 보여줍니다.

그건 그렇고: 이것이 다른 구현을 사용하는 이유 는 아니지만 이러한 구현은 실제로 Python 소스 코드를 처리하는 방식을 넘어서는 동작이 다릅니다. 그러나 이러한 차이점은 일반적으로 미미하며 이러한 구현이 활발히 개발되고 있기 때문에 시간이 지나면서 해소되거나 나타납니다. 예를 들어 IronPython은 기본적으로 유니코드 문자열을 사용합니다. 그러나 CPython은 버전 2.x의 경우 기본적으로 ASCII를 사용하지만(ASCII가 아닌 문자의 경우 UnicodeEncodeError 실패) 3.x의 경우 기본적으로 유니코드 문자열을 지원합니다.

Just-in-Time 컴파일: PyPy와 미래

그래서 우리는 C로 작성된 Python 구현, Java로 작성된 구현 및 C#으로 작성된 구현을 가지고 있습니다. 다음 논리적 단계: Python으로 작성된 Python 구현... Python. (교육받은 독자는 이것이 약간 오해의 소지가 있음을 알 수 있습니다.)

여기에서 상황이 혼동될 수 있습니다. 먼저 JIT(Just-In-Time) 컴파일에 대해 설명하겠습니다.

JIT: 왜 그리고 어떻게

기본 기계 코드가 바이트 코드보다 훨씬 빠릅니다. 음, 바이트코드 중 일부를 컴파일한 다음 네이티브 코드로 실행할 수 있다면 어떨까요? 바이트코드(즉, 시간)를 컴파일하려면 약간의 비용을 지불해야 하지만 최종 결과가 더 빨랐다면 정말 좋았을 것입니다! 이것이 인터프리터와 컴파일러의 장점을 혼합한 하이브리드 기술인 JIT 컴파일의 동기입니다. 기본적으로 JIT는 해석된 시스템의 속도를 높이기 위해 컴파일을 활용하려고 합니다.

예를 들어 JIT가 취하는 일반적인 접근 방식은 다음과 같습니다.

  1. 자주 실행되는 바이트코드를 식별합니다.
  2. 네이티브 머신 코드로 컴파일합니다.
  3. 결과를 캐시합니다.
  4. 동일한 바이트코드가 실행되도록 설정될 때마다 미리 컴파일된 기계어 코드를 가져와서 이점(즉, 속도 향상)을 얻으십시오.

이것이 PyPy 구현의 모든 것입니다. JIT를 Python으로 가져오는 것입니다(이전 노력은 부록 참조). 물론 다른 목표도 있습니다. PyPy는 플랫폼 간, 메모리 가벼움, 스택 없는 지원을 목표로 합니다. 그러나 JIT는 실제로 판매 포인트입니다. 많은 시간 테스트에 대한 평균으로 성능을 6.27배 향상시킨다고 합니다. 분석은 PyPy Speed ​​Center의 다음 차트를 참조하십시오.

PyPy 구현을 사용하여 Python 인터페이스에 JIT를 가져오면 성능이 향상됩니다.

PyPy는 이해하기 어렵습니다

PyPy는 엄청난 잠재력을 가지고 있으며 이 시점에서 CPython과 매우 호환됩니다(따라서 Flask, Django 등을 실행할 수 있음).

그러나 PyPy와 관련하여 많은 혼란이 있습니다(예를 들어, PyPyPy를 생성하기 위한 이 무의미한 제안 참조). 제 생각에는 주로 PyPy가 실제로 두 가지이기 때문입니다.

  1. RPython으로 작성된 Python 인터프리터(Python이 아님(이전에 거짓말)). RPython은 정적 유형 지정을 사용하는 Python의 하위 집합입니다. Python에서 유형에 대해 엄격하게 추론하는 것은 "대부분 불가능"합니다(왜 그렇게 어려운가요? 다음 사실을 고려하십시오.

     x = random.choice([1, "foo"])

    유효한 Python 코드일 것입니다(Ademan에 대한 크레딧). x 의 유형은 무엇입니까? 유형이 엄격하게 적용되지 않는 경우 변수 유형에 대해 어떻게 추론할 수 있습니까?). RPython을 사용하면 약간의 유연성을 희생하지만 대신 메모리 관리 및 기타 사항에 대해 훨씬 쉽게 추론할 수 있으므로 최적화가 가능합니다.

  2. 다양한 대상에 대한 RPython 코드를 컴파일하고 JIT에 추가하는 컴파일러입니다. 기본 플랫폼은 C, 즉 RPython-to-C 컴파일러이지만 JVM 및 기타를 대상으로 할 수도 있습니다.

이 Python 비교 가이드에서는 명확성을 위해 이들을 PyPy(1) 및 PyPy(2)로 지칭하겠습니다.

왜 이 두 가지가 필요하고 같은 지붕 아래에 있어야 합니까? 이렇게 생각하십시오: PyPy(1)는 RPython으로 작성된 인터프리터입니다. 따라서 사용자의 Python 코드를 가져와 바이트 코드로 컴파일합니다. 하지만 인터프리터 자체(RPython으로 작성됨)는 실행하려면 다른 Python 구현에서 해석되어야 합니다. 그렇죠?

글쎄, 우리는 인터프리터를 실행하기 위해 CPython을 사용할 수 있습니다. 그러나 그것은 그리 빠르지 않을 것입니다.

대신 PyPy(2)(RPython Toolchain이라고 함)를 사용하여 PyPy의 인터프리터를 다른 플랫폼(예: C, JVM 또는 CLI)에서 실행할 코드로 컴파일하고 JIT를 다음과 같이 추가합니다. 잘. 마술적입니다. PyPy는 JIT를 인터프리터에 동적으로 추가하여 자체 컴파일러를 생성합니다! ( 다시 말하지만, 이것은 미쳤습니다. 우리는 인터프리터를 컴파일하고 다른 별도의 독립형 컴파일러를 추가합니다. )

결국 결과는 Python 소스 코드를 해석하고 JIT 최적화를 활용하는 독립 실행형 실행 파일입니다. 이것이 바로 우리가 원했던 것입니다! 한 입 가득하지만 아마도 이 도표가 도움이 될 것입니다.

이 다이어그램은 인터프리터, 컴파일러 및 JIT가 있는 실행 파일을 포함하여 PyPy 구현의 아름다움을 보여줍니다.

다시 말해서, PyPy의 진정한 아름다움은 JIT에 대해 걱정하지 않고 RPython에서 다양한 Python 인터프리터를 직접 작성할 수 있다는 것입니다. 그러면 PyPy는 RPython Toolchain/PyPy(2)를 사용하여 JIT를 구현 합니다.

사실, 더 추상화되면 이론적으로 모든 언어에 대한 인터프리터를 작성하고 PyPy에 공급하고 해당 언어에 대한 JIT를 얻을 수 있습니다. 이는 PyPy가 해석하는 언어의 세부 사항보다는 실제 인터프리터를 최적화하는 데 초점을 맞추기 때문입니다.

이론적으로 모든 언어에 대한 인터프리터를 작성하고 PyPy에 공급하고 해당 언어에 대한 JIT를 얻을 수 있습니다.

간단히 말해서 JIT 자체가 절대적으로 매력적이라고 ​​말씀드리고 싶습니다. 다음과 같이 실행되는 추적이라는 기술을 사용합니다.

  1. 인터프리터를 실행하고 모든 것을 해석합니다(JIT 추가 없음).
  2. 해석된 코드에 대해 약간의 프로파일링을 수행합니다.
  3. 이전에 수행한 작업을 식별합니다.
  4. 이러한 코드 비트를 기계어 코드로 컴파일하십시오.

더 많은 정보를 위해 이 문서는 접근성이 매우 높고 매우 흥미로웠습니다.

마무리: PyPy의 RPython-to-C(또는 기타 대상 플랫폼) 컴파일러를 사용하여 PyPy의 RPython 구현 인터프리터를 컴파일합니다.

마무리

Python 구현을 오랫동안 비교한 후 스스로에게 물어봐야 합니다. 이것이 왜 그렇게 훌륭한가? 이 미친 아이디어가 추구할 가치가 있는 이유는 무엇입니까? Alex Gaynor는 자신의 블로그에서 "[PyPy는 미래]입니다. 왜냐하면 [PyPy는] 더 나은 속도, 더 많은 유연성을 제공하고 Python의 성장을 위한 더 나은 플랫폼이기 때문입니다."

간단히 말해서:

  • 소스 코드를 네이티브 코드로 컴파일하기 때문에 빠릅니다 (JIT 사용).
  • 추가 작업이 거의 없이 JIT를 인터프리터에 추가하기 때문에 유연합니다 .
  • C보다 확장하기 쉬운 RPython에서 인터프리터를 작성할 수 있기 때문에 (다시) 유연합니다 .

부록: 들어봤을 수 있는 다른 Python 이름

  • Python 3000(Py3k): 2008년에 단계에 도달한 이전 버전과 호환되지 않는 주요 Python 릴리스인 Python 3.0의 대체 이름입니다. Py3k 팀은 이 새 버전이 완전히 채택되는 데 약 5년이 걸릴 것으로 예측했습니다. 그리고 대부분의 (경고: 일화적인 주장) Python 개발자는 Python 2.x를 계속 사용하지만 사람들은 Py3k에 대해 점점 더 의식하고 있습니다.

  • Cython: C 함수를 호출하기 위한 바인딩을 포함하는 Python의 상위 집합입니다.
    • 목표: Python 코드에 대한 C 확장을 작성할 수 있습니다.
    • 또한 기존 Python 코드에 정적 입력을 추가하여 컴파일하고 C와 유사한 성능을 얻을 수 있습니다.
    • 이것은 PyPy와 유사하지만 동일하지는 않습니다. 이 경우 컴파일러에 전달하기 전에 사용자 코드를 강제로 입력합니다. PyPy를 사용하면 평범한 오래된 Python을 작성하고 컴파일러가 모든 최적화를 처리합니다.

  • Numba: 주석이 달린 Python 코드에 JIT를 추가하는 "적시 전문화 컴파일러"입니다. 가장 기본적인 용어로 힌트를 제공하면 코드의 일부 속도가 빨라집니다. Numba는 데이터 분석 및 관리를 위한 패키지 세트인 Anaconda 배포의 일부로 제공됩니다.

  • IPython: 논의된 다른 것과는 매우 다릅니다. Python을 위한 컴퓨팅 환경. GUI 툴킷 및 브라우저 경험 등을 지원하는 대화형

  • Psyco: Python 확장 모듈이자 초기 Python JIT 작업 중 하나입니다. 그러나 그 이후로 "관리되지 않고 죽은" 것으로 표시되었습니다. 실제로 Psyco의 수석 개발자인 Armin Rigo는 현재 PyPy에서 작업하고 있습니다.

파이썬 언어 바인딩

  • RubyPython: Ruby와 Python VM 간의 다리입니다. Python 코드를 Ruby 코드에 포함할 수 있습니다. Python이 시작 및 중지되는 위치를 정의하면 RubyPython이 VM 간에 데이터를 마샬링합니다.

  • PyObjc: Python과 Objective-C 간의 언어 바인딩으로, 둘 사이의 다리 역할을 합니다. 실제로, 이는 Python 코드에서 Objective-C 라이브러리(OS X 애플리케이션을 만드는 데 필요한 모든 것을 포함)를, Objective-C 코드에서 Python 모듈을 활용할 수 있음을 의미합니다. 이 경우 CPython은 Objective-C의 하위 집합인 C로 작성하는 것이 편리합니다.

  • PyQt: PyObjc가 OS X GUI 구성 요소에 대한 바인딩을 제공하는 반면 PyQt는 Qt 애플리케이션 프레임워크에 대해 동일한 작업을 수행하여 풍부한 그래픽 인터페이스를 생성하고 SQL 데이터베이스 등에 액세스할 수 있습니다. Python의 단순성을 다른 프레임워크에 가져오는 것을 목표로 하는 또 다른 도구입니다.

자바스크립트 프레임워크

  • pyjs(Pyjamas): Python에서 웹 및 데스크톱 애플리케이션을 만들기 위한 프레임워크입니다. Python-to-JavaScript 컴파일러, 위젯 세트 및 기타 도구가 포함되어 있습니다.

  • Brython: 브라우저에서 Py3k 코드를 실행할 수 있도록 JavaScript로 작성된 Python VM입니다.