Python용 C++ 확장 만들기Create a C++ extension for Python

C++(또는 C)로 작성된 모듈은 하위 수준 운영 체제 기능에 대한 액세스를 가능하게 할 뿐만 아니라 Python 인터프리터의 기능을 확장하는 데 일반적으로 사용됩니다.Modules written in C++ (or C) are commonly used to extend the capabilities of a Python interpreter as well as to enable access to low-level operating system capabilities. 모듈은 세 가지 기본 형식이 있습니다.There are three primary types of modules:

  • 액셀러레이터 모듈: Python은 해석된 언어이기 때문에 성능 향상을 위해 특정 코드 부분을 C++로 작성할 수 있습니다.Accelerator modules: because Python is an interpreted language, certain pieces of code can be written in C++ for higher performance.
  • 래퍼 모듈: 기존 C/C++ 인터페이스를 Python 코드에 노출하거나 Python에서 사용하기 쉬운 보다 “Python” 최적화된 API를 노출합니다.Wrapper modules: expose existing C/C++ interfaces to Python code or expose a more "Pythonic" API that's easy to use from Python.
  • 하위 수준 시스템 액세스 모듈: CPython 런타임, 운영 체제 또는 기본 하드웨어의 하위 수준 기능에 액세스하기 위해 만들었습니다.Low-level system access modules: created to access lower-level features of the CPython runtime, the operating system, or the underlying hardware.

이 문서에서는 쌍곡 탄젠트를 계산하고 Python 코드에서 호출하는 CPython용 C++ 확장을 빌드하는 방법에 대해 설명합니다.This article walks through building a C++ extension module for CPython that computes a hyperbolic tangent and calls it from Python code. C++에서 동일한 루틴을 구현할 경우의 관련된 성능 향상을 보여 주기 위해 Python에서 먼저 루틴을 구현합니다.The routine is implemented first in Python to demonstrate the relative performance gain of implementing the same routine in C++.

이 문서에는 Python에서 C++를 사용할 수 있도록 만드는 두 가지 방법을 보여 줍니다.This article also demonstrates two ways to make the C++ available to Python:

이 방법과 다른 방법의 비교는 이 문서의 끝에 있는 대체 방법에 있습니다.A comparison between these and other means is found under alternative approaches at the end of this article.

이 연습에서 완료된 샘플은 python-samples-vs-cpp-extension(GitHub)에서 찾을 수 있습니다.The completed sample from this walkthrough can be found on python-samples-vs-cpp-extension (GitHub).

사전 요구 사항Prerequisites

  • 기본 옵션과 함께 설치된 C++를 사용한 데스크톱 개발Python 개발 워크로드를 모두 사용하는 Visual Studio 2017 이상.Visual Studio 2017 or later with both the Desktop Development with C++ and Python Development workloads installed with default options.

  • Python 개발 워크로드에서 Python 네이티브 개발 도구 오른쪽에 있는 상자를 선택합니다.In the Python Development workload, also select the box on the right for Python native development tools. 이 옵션은 이 문서에 설명된 대부분의 구성을 설정합니다.This option sets up most of the configuration described in this article. 이 옵션에는 C++ 워크로드도 자동으로 포함됩니다.(This option also includes the C++ workload automatically.)

    Python 네이티브 개발 도구 옵션 선택

    데이터 과학 및 분석 애플리케이션 워크로드 설치에는 Python 및 Python 네이티브 개발 도구 옵션이 기본적으로 포함됩니다.Installing the Data science and analytical applications workload also includes Python and the Python native development tools option by default.

다른 버전의 Visual Studio 사용을 포함한 자세한 내용은 Visual Studio용 Python 지원 설치를 참조하세요.For more information, see Install Python support for Visual Studio, including using other versions of Visual Studio. Python을 별도로 설치하는 경우 설치 관리자의 고급 옵션에서 디버깅 기호 다운로드디버그 버전의 이진 파일 다운로드를 선택해야 합니다.If you install Python separately, be sure to select Download debugging symbols and Download debug binaries under Advanced Options in the installer. 이 옵션은 디버그 빌드를 수행하도록 선택할 경우 필요한 디버그 라이브러리를 사용할 수 있도록 합니다.This option ensures that you have the necessary debug libraries available if you choose to do a debug build.

Python 애플리케이션 만들기Create the Python application

  1. 파일 > 새로 만들기 > 프로젝트를 선택하여 Visual Studio에서 새 Python 프로젝트를 만듭니다.Create a new Python project in Visual Studio by selecting File > New > Project. “Python”을 검색하고 Python 애플리케이션 템플릿을 선택한 다음 적합한 이름과 위치를 지정하고 확인을 선택합니다.Search for "Python", select the Python Application template, give it a suitable name and location, and select OK.

  2. C++로 작업하려면 32비트 Python 인터프리터(Python 3.6 이상 권장)를 사용해야 합니다.Working with C++ requires that you use a 32-bit Python interpreter (Python 3.6 or above recommended). Visual Studio의 솔루션 탐색기 창에서 프로젝트 노드를 확장한 다음, Python 환경 노드를 확장합니다.In the Solution Explorer window of Visual Studio, expand the project node, then expand the Python Environments node. 32비트 환경이 기본값으로 표시(굵게 표시 또는 전역 기본값 레이블 지정)되지 않는 경우 프로젝트에 대한 Python 환경 선택의 지침을 따르세요.If you don't see a 32-bit environment as the default (either in bold, or labeled with global default), then follow the instructions on Select a Python environment for a project. 32비트 인터프리터가 설치되지 않은 경우 Python 인터프리터 설치를 참조하세요.If you don't have a 32-bit interpreter installed, see Install Python interpreters.

  3. 프로젝트의 .py 파일에서 쌍곡 탄젠트 계산을 벤치마크하는 다음 코드(비교하기 쉽도록 수학 라이브러리를 사용하지 않고 구현됨)를 붙여넣습니다.In the project's .py file, paste the following code that benchmarks the computation of a hyperbolic tangent (implemented without using the math library for easier comparison). 언제든지 코드를 수동으로 입력하여 Python 편집 기능의 일부를 경험해 보세요.Feel free to enter the code manually to experience some of the Python editing features.

    from itertools import islice
    from random import random
    from time import perf_counter
    
    COUNT = 500000  # Change this value depending on the speed of your computer
    DATA = list(islice(iter(lambda: (random() - 0.5) * 3.0, None), COUNT))
    
    e = 2.7182818284590452353602874713527
    
    def sinh(x):
        return (1 - (e ** (-2 * x))) / (2 * (e ** -x))
    
    def cosh(x):
        return (1 + (e ** (-2 * x))) / (2 * (e ** -x))
    
    def tanh(x):
        tanh_x = sinh(x) / cosh(x)
        return tanh_x
    
    def test(fn, name):
        start = perf_counter()
        result = fn(DATA)
        duration = perf_counter() - start
        print('{} took {:.3f} seconds\n\n'.format(name, duration))
    
        for d in result:
            assert -1 <= d <= 1, " incorrect values"
    
    if __name__ == "__main__":
        print('Running benchmarks with COUNT = {}'.format(COUNT))
    
        test(lambda d: [tanh(x) for x in d], '[tanh(x) for x in d] (Python implementation)')
    
  4. 디버그 > 디버깅하지 않고 시작(Ctrl+F5)을 사용하여 프로그램을 실행하고 결과를 확인합니다.Run the program using Debug > Start without Debugging (Ctrl+F5) to see the results. COUNT 변수를 조정하여 벤치 마크를 실행할 시간을 변경할 수 있습니다.You can adjust the COUNT variable to change how long the benchmark takes to run. 이 연습의 목적을 위해 벤치마크에 약 2초가 걸리도록 수를 설정합니다.For the purposes of this walkthrough, set the count so that the benchmark take around two seconds.

벤치 마크를 실행할 때는 항상 디버깅 > 디버깅하지 않고 시작을 사용하여 Visual Studio 디버거 내에서 코드를 실행할 때 발생하는 오버헤드를 방지합니다.When running benchmarks, always use Debug > Start without Debugging to avoid the overhead incurred when running code within the Visual Studio debugger.

핵심 C++ 프로젝트 만들기Create the core C++ projects

"superfastcode" 및 "superfastcode2"라는 두 개의 동일한 C++ 프로젝트를 만들려면 이 섹션의 지침을 따릅니다.Follow the instructions in this section to create two identical C++ projects named "superfastcode" and "superfastcode2". 나중에 각 프로젝트에서 다른 방법을 사용하여 Python에 C++ 코드를 공개할 수 있습니다.Later you'll use different means in each project to expose the C++ code to Python.

  1. PYTHONHOME 환경 변수가 사용하려는 Python 인터프리터로 설정되어 있는지 확인합니다.Make sure the PYTHONHOME environment variable is set to the Python interpreter you want to use. Visual Studio의 C++ 프로젝트는 이 변수를 사용하여 Python 확장을 만들 때 사용되는 python.h와 같은 파일을 찾습니다.The C++ projects in Visual Studio rely on this variable to locate files such as python.h, which are used when creating a Python extension.

  2. 솔루션 탐색기에서 솔루션을 마우스 오른쪽 단추로 클릭하고 추가 > 새 프로젝트를 선택합니다.Right-click the solution in Solution Explorer and select Add > New Project. Visual Studio 솔루션은 Python 및 C++ 프로젝트를 모두 함께 포함합니다(Python용 Visual Studio 사용에 대한 이점 중 하나).A Visual Studio solution can contain both Python and C++ projects together (which is one of the advantages of using Visual Studio for Python).

  3. "C++"를 검색하고, 빈 프로젝트를 선택하고, 이름을 "superfastcode"(두 번째 프로젝트는 "superfastcode2")로 지정하고 확인을 선택합니다.Search on "C++", select Empty project, specify the name "superfastcode" ("superfastcode2" for the second project), and select OK.

    Visual Studio에 설치된 Python 네이티브 개발 도구를 사용하면 아래 설명된 내용이 이미 많이 포함되어 있는 Python 확장 모듈 템플릿으로 시작할 수 있습니다.With the Python native development tools installed in Visual Studio, you can start with the Python Extension Module template instead, which has much of what's described below already in place. 그러나 이 연습에서는 빈 프로젝트로 시작하여 확장 모듈 빌드를 단계별로 보여 줍니다.For this walkthrough, though, starting with an empty project demonstrates building the extension module step by step. 프로세스를 이해하고 나면 사용자 고유의 확장을 작성할 때 템플릿으로 시간을 절약할 수 있습니다.Once you understand the process, the template saves you time when writing your own extensions.

  4. 새 프로젝트에서 소스 파일 노드를 마우스 오른쪽 단추로 클릭하여 C++ 파일을 만들고 추가 > 새 항목을 선택한 다음, C++ 파일을 선택하여 이름을 module.cpp로 지정하고 확인을 선택합니다.Create a C++ file in the new project by right-clicking the Source Files node, then select Add > New Item, select C++ File, name it module.cpp, and select OK.

    중요

    이어지는 다음 단계에서 C++ 속성 페이지를 켜려면 .cpp 확장명을 가진 파일이 필요합니다.A file with the .cpp extension is necessary to turn on the C++ property pages in the steps that follow.

  5. 솔루션 탐색기에서 C++ 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다.Right-click the C++ project in Solution Explorer, select Properties.

  6. 표시되는 속성 페이지 대화 상자의 맨 위에서 구성모든 구성으로, 플랫폼Win32로 설정합니다.At the top of the Property Pages dialog that appears, set Configuration to All Configurations and Platform to Win32.

  7. 다음 표에 설명된 대로 특정 속성을 설정한 다음, 확인을 선택합니다.Set the specific properties as described in the following table, then select OK.

    Tab 속성Property Value
    일반General 일반 > 대상 이름General > Target Name from...import 문의 Python에서 참조하려는 모듈의 이름을 지정합니다.Specify the name of the module as you want to refer to it from Python in from...import statements. Python에 대한 모듈을 정의하는 경우 C++에서 이 동일한 이름을 사용합니다.You use this same name in the C++ when defining the module for Python. 프로젝트 이름을 모듈 이름으로 사용하려는 경우 $(ProjectName) 기본값을 그대로 둡니다.If you want to use the name of the project as the module name, leave the default value of $(ProjectName).
    일반 > 대상 확장명General > Target Extension .pyd.pyd
    프로젝트 기본값 > 구성 형식Project Defaults > Configuration Type 동적 라이브러리(.dll)Dynamic Library (.dll)
    C/C++ > 일반C/C++ > General 추가 포함 디렉터리Additional Include Directories 설치에 맞게 Python include 폴더를 추가합니다(예: c:\Python36\include).Add the Python include folder as appropriate for your installation, for example, c:\Python36\include.
    C/C++ > 전처리기C/C++ > Preprocessor 전처리기 정의Preprocessor Definitions CPython만: Py_LIMITED_API;를 문자열의 시작 부분에 추가합니다(세미콜론 포함).CPython only: add Py_LIMITED_API; to the beginning of the string (including the semicolon). 이 정의로 Python에서 호출할 수 있는 일부 함수가 제한되고 다른 버전의 Python 간 코드 이식성이 향상됩니다.This definition restricts some of the functions you can call from Python and makes the code more portable between different versions of Python. PyBind11을 사용하는 경우 이 정의를 추가하지 마세요. 추가하면 빌드 오류가 표시됩니다.If you're working with PyBind11, don't add this definition, otherwise you'll see build errors.
    C/C++ > 코드 생성C/C++ > Code Generation 런타임 라이브러리Runtime Library 다중 스레드 DLL(/MD) (아래 경고 참조)Multi-threaded DLL (/MD) (see Warning below)
    링커 > 일반Linker > General 추가 라이브러리 디렉터리Additional Library Directories .lib 파일을 포함하는 Python libs 폴더를 설치에 맞게 추가합니다(예: c:\Python36\libs).Add the Python libs folder containing .lib files as appropriate for your installation, for example, c:\Python36\libs. .py 파일을 포함하는 Lib 폴더가 ‘아니라’ .lib 파일을 포함하는 libs 폴더를 가리켜야 합니다. (Be sure to point to the libs folder that contains .lib files, and not the Lib folder that contains .py files.)

    프로젝트 속성에서 C/C++ 탭이 표시되지 않는 경우 프로젝트에 C/C++ 소스 파일로 식별되는 파일이 포함되어 있지 않기 때문입니다.If you don't see the C/C++ tab in the project properties, it's because the project doesn't contain any files that it identifies as C/C++ source files. .c 또는 .cpp 확장명을 사용하지 않고 소스 파일을 만드는 경우 이런 상태가 발생할 수 있습니다.This condition can occur if you create a source file without a .c or .cpp extension. 예를 들어 이전의 새 항목 대화 상자에서 실수로 module.cpp 대신 module.coo를 입력한 경우 Visual Studio에서 파일을 만들지만, C/C++ 속성 탭을 활성화하는 “C/C++ 코드”로 파일 형식을 설정하지 않습니다. 파일 이름을 .cpp로 변경하는 경우에도 여전히 잘못 식별됩니다.For example, if you accidentally entered module.coo instead of module.cpp in the new item dialog earlier, then Visual Studio creates the file but doesn't set the file type to "C/C+ Code," which is what activates the C/C++ properties tab. Such misidentification remains the case even if you rename the file with .cpp. 파일 형식을 제대로 설정하려면 솔루션 탐색기에서 파일을 마우스 오른쪽 단추로 클릭하고 속성을 선택한 다음, 파일 형식C/C++ 코드로 설정합니다.To set the file type properly, right-click the file in Solution Explorer, select Properties, then set File Type to C/C++ Code.

    경고

    디버그 구성에 대해서도 C/C++ > 코드 생성 > 런타임 라이브러리 옵션을 항상 다중 스레드 DLL(/MD) 로 설정합니다. 이 설정은 디버그가 아닌 Python 이진을 빌드할 때 사용되기 때문입니다.Always set the C/C++ > Code Generation > Runtime Library option to Multi-threaded DLL (/MD), even for a debug configuration, because this setting is what the non-debug Python binaries are built with. CPython에서는 다중 스레드 디버그 DLL(/MDd) 옵션을 설정하는 경우 디버그 구성을 빌드하면 C1189: Py_LIMITED_API는 Py_DEBUG, Py_TRACE_REFS 및 Py_REF_DEBUG와 호환되지 않음 오류가 발생합니다.With CPython, if you happen to set the Multi-threaded Debug DLL (/MDd) option, building a Debug configuration produces error C1189: Py_LIMITED_API is incompatible with Py_DEBUG, Py_TRACE_REFS, and Py_REF_DEBUG. 또한 빌드 오류를 방지하기 위해 Py_LIMITED_API(CPython에는 필요하지만 PyBind11에는 필요하지 않음)를 제거하는 경우 모듈을 가져오려고 하면 Python이 충돌합니다.Furthermore, if you remove Py_LIMITED_API (which is required with CPython, but not PyBind11) to avoid the build error, Python crashes when attempting to import the module. (뒷부분에 설명된 대로 크래시는 DLL의 PyModule_Create 호출 내에서 발생하고 심각한 Python 오류: PyThreadState_Get: 현재 스레드 없음이라는 메시지가 출력됩니다.)(The crash happens within the DLL's call to PyModule_Create as described later, with the output message of Fatal Python error: PyThreadState_Get: no current thread.)

    /MDd 옵션은 Python 디버그 이진 파일(예: python_d.exe)을 빌드하는 데 사용되지만 확장 DLL용으로 선택하면 Py_LIMITED_API에서 빌드 오류가 발생합니다.The /MDd option is used to build the Python debug binaries (such as python_d.exe), but selecting it for an extension DLL still causes the build error with Py_LIMITED_API.

  8. C++ 프로젝트를 마우스 오른쪽 단추로 클릭하고 빌드를 선택하여 구성(디버그릴리스)을 테스트합니다.Right-click the C++ project and select Build to test your configurations (both Debug and Release). .pyd 파일은 C++ 프로젝트 폴더 자체가 아니라 디버그릴리스 아래의 솔루션 폴더에 있습니다.The .pyd files are located in the solution folder under Debug and Release, not the C++ project folder itself.

  9. C++ 프로젝트의 주 module.cpp 파일에 다음 코드를 추가합니다.Add the following code to the C++ project's module.cpp file:

    #include <Windows.h>
    #include <cmath>
    
    const double e = 2.7182818284590452353602874713527;
    
    double sinh_impl(double x) {
        return (1 - pow(e, (-2 * x))) / (2 * pow(e, -x));
    }
    
    double cosh_impl(double x) {
        return (1 + pow(e, (-2 * x))) / (2 * pow(e, -x));
    }
    
    double tanh_impl(double x) {
        return sinh_impl(x) / cosh_impl(x);
    }
    
  10. C++ 프로젝트를 다시 빌드하여 코드가 올바른지 확인합니다.Build the C++ project again to confirm that your code is correct.

  11. 아직 만들지 않았다면 위의 단계를 반복하여 동일한 콘텐츠의 "superfastcode2"라는 두 번째 프로젝트를 만듭니다.If you haven't already done so, repeat the steps above to create a second project named "superfastcode2" with identical contents.

C++ 프로젝트를 Python용 확장으로 변환Convert the C++ projects to extensions for Python

C++ DLL을 Python용 확장으로 만들려면 먼저 내보낸 메서드를 Python 형식과 상호 작용하도록 수정해야 합니다.To make the C++ DLL into an extension for Python, you first modify the exported methods to interact with Python types. 그런 다음 모듈의 메서드 정의와 함께 모듈을 내보내는 함수를 추가해야 합니다.You then add a function that exports the module, along with definitions of the module's methods.

이어지는 섹션에서는 CPython 확장과 PyBind11을 사용하여 이러한 단계를 수행하는 방법에 대해 설명합니다.The sections that follow explain how to perform these steps using both the CPython extensions and PyBind11.

CPython 확장CPython extensions

Python 3.x에 대해 이 섹션에 표시된 기능의 배경은 Python/C API 참조 설명서 및 특히 python.org에 있는 모듈 개체를 참조하세요(올바른 설명서를 보려면 오른쪽 위에 있는 드롭다운 컨트롤에서 Python의 버전을 선택해야 함).For background on what's shown in this section for Python 3.x, refer to the Python/C API Reference Manual and especially Module Objects on python.org (remember to select your version of Python from the drop-down control on the upper right to view the correct documentation).

Python 2.7로 작업하는 경우 Extending Python 2.7 with C or C++(C 또는 C++를 사용하여 Python 2.7 확장) 및 Porting Extension Modules to Python 3(확장 모듈을 Python 3에 이식) (python.org)을 참조하세요.If you're working with Python 2.7, refer instead to Extending Python 2.7 with C or C++ and Porting Extension Modules to Python 3 (python.org).

  1. module.cpp의 맨 위에 Python.h를 포함시킵니다.At the top of module.cpp, include Python.h:

    #include <Python.h>
    
  2. Python 형식을 허용하고 반환하도록 tanh_impl 메서드를 수정합니다(즉, PyObject*).Modify the tanh_impl method to accept and return Python types (a PyObject*, that is):

    PyObject* tanh_impl(PyObject *, PyObject* o) {
        double x = PyFloat_AsDouble(o);
        double tanh_x = sinh_impl(x) / cosh_impl(x);
        return PyFloat_FromDouble(tanh_x);
    }
    
  3. C++ tanh_impl 함수가 Python에 표시되는 방식을 정의하는 구조체를 추가합니다.Add a structure that defines how the C++ tanh_impl function is presented to Python:

    static PyMethodDef superfastcode_methods[] = {
        // The first property is the name exposed to Python, fast_tanh, the second is the C++
        // function name that contains the implementation.
        { "fast_tanh", (PyCFunction)tanh_impl, METH_O, nullptr },
    
        // Terminate the array with an object containing nulls.
        { nullptr, nullptr, 0, nullptr }
    };
    
  4. 특히 from...import 문을 사용할 때 Python 코드에서 참조하려는 모듈을 정의하는 구조를 추가합니다.Add a structure that defines the module as you want to refer to it in your Python code, specifically when using the from...import statement. 이 항목이 구성 속성 > 일반 > 대상 이름 아래의 프로젝트 속성 값과 일치하도록 합니다. 다음 예제에서 "superfastcode" 모듈 이름은 Python에서 from superfastcode import fast_tanh를 사용할 수 있다는 뜻입니다. fast_tanhsuperfastcode_methods 안에 정의되었기 때문입니다.(Make this match the value in the project properties under Configuration Properties > General > Target Name.) In the following example, the "superfastcode" module name means you can use from superfastcode import fast_tanh in Python, because fast_tanh is defined within superfastcode_methods. module.cpp와 같은 C++ 프로젝트 내부의 파일 이름은 중요하지 않습니다.(Filenames internal to the C++ project, like module.cpp, are inconsequential.)

    static PyModuleDef superfastcode_module = {
        PyModuleDef_HEAD_INIT,
        "superfastcode",                        // Module name to use with Python import statements
        "Provides some functions, but faster",  // Module description
        0,
        superfastcode_methods                   // Structure that defines the methods of the module
    };
    
  5. Python에서 이름이 PyInit_<module-name>인 모듈을 로드할 때 호출하는 메서드를 추가합니다. 여기서 <module-name>은 C++ 프로젝트의 일반 > 대상 이름 속성과 정확하게 일치합니다. 즉, 프로젝트에서 빌드된 .pyd의 파일 이름과 일치합니다.Add a method that Python calls when it loads the module, which must be named PyInit_<module-name>, where <module-name> exactly matches the C++ project's General > Target Name property (that is, it matches the filename of the .pyd built by the project).

    PyMODINIT_FUNC PyInit_superfastcode() {
        return PyModule_Create(&superfastcode_module);
    }
    
  6. 대상 구성을 릴리스로 설정하고 C++ 프로젝트를 다시 빌드하여 코드를 확인합니다.Set the target configuration to Release and build the C++ project again to verify your code. 오류가 발생할 경우 아래의 문제 해결 섹션을 참조하세요.If you encounter errors, see the Troubleshooting section below.

PyBind11PyBind11

이전 섹션에서 단계를 완료한 경우 C++ 코드에 필요한 모듈 구조체를 만들기 위해 많은 상용구 코드를 사용했음을 알 수 있습니다.If you completed the steps in the previous section, you certainly noticed that you used lots of boilerplate code to create the necessary module structures for the C++ code. PyBind11에서는 C++ 헤더 파일에서 훨씬 적은 코드를 사용하여 동일한 결과를 달성하는 매크로를 통해 프로세스를 간소화합니다.PyBind11 simplifies the process through macros in a C++ header file that accomplish the same result with much less code. 이 섹션에 나온 배경 지식은 PyBind11 기본(github.com)을 참조하세요.For background on what's shown in this section, see PyBind11 basics (github.com).

  1. pip(pip install pybind11 또는 py -m pip install pybind11)를 사용하여 PyBind11을 설치합니다.Install PyBind11 using pip: pip install pybind11 or py -m pip install pybind11.

  2. module.cpp의 맨 위에 pybind11.h를 포함시킵니다.At the top of module.cpp, include pybind11.h:

    #include <pybind11/pybind11.h>
    
  3. module.cpp의 맨 아래에서 PYBIND11_MODULE 매크로를 사용하여 C++ 함수에 대한 진입점을 정의합니다.At the bottom of module.cpp, use the PYBIND11_MODULE macro to define the entrypoint to the C++ function:

    namespace py = pybind11;
    
    PYBIND11_MODULE(superfastcode2, m) {
        m.def("fast_tanh2", &tanh_impl, R"pbdoc(
            Compute a hyperbolic tangent of a single argument expressed in radians.
        )pbdoc");
    
    #ifdef VERSION_INFO
        m.attr("__version__") = VERSION_INFO;
    #else
        m.attr("__version__") = "dev";
    #endif
    }
    
  4. 대상 구성을 릴리스로 설정하고 C++ 프로젝트를 빌드하여 코드를 확인합니다.Set the target configuration to Release and build the C++ project to verify your code. 오류가 발생할 경우 다음의 문제 해결 섹션을 참조하세요.If you encounter errors, see the next section on troubleshooting.

문제 해결Troubleshooting

C++ 모듈은 다음과 같은 이유로 컴파일에 실패할 수 있습니다.The C++ module may fail to compile for the following reasons:

  • Python.h를 찾을 수 없음(E1696: 원본 파일 "Python.h" 및/또는 C1083: 포함 파일을 열 수 없습니다. "Python.h": 해당 파일 또는 디렉터리 없음): 프로젝트 속성에서 C/C++ > 일반 > 추가 포함 디렉터리의 경로가 Python 설치의 include 폴더를 가리키는지 확인합니다.Unable to locate Python.h (E1696: cannot open source file "Python.h" and/or C1083: Cannot open include file: "Python.h": No such file or directory): verify that the path in C/C++ > General > Additional Include Directories in the project properties points to your Python installation's include folder. 핵심 C++ 프로젝트 만들기의 6단계를 참조하세요.See step 6 under Create the core C++ project.

  • Python 라이브러리를 찾을 수 없음: 프로젝트 속성에서 링커 > 일반 > 추가 라이브러리 디렉터리의 경로가 Python 설치의 libs 폴더를 가리키는지 확인합니다.Unable to locate Python libraries: verify that the path in Linker > General > Additional Library Directories in the project properties points to your Python installation's libs folder. 핵심 C++ 프로젝트 만들기의 6단계를 참조하세요.See step 6 under Create the core C++ project.

  • 대상 아키텍처와 관련된 링커 오류: C++ 대상 프로젝트 아키텍처를 Python 설치에 맞게 변경합니다.Linker errors related to target architecture: change the C++ target's project architecture to match that of your Python installation. 예를 들어 C++ 프로젝트에서 x64를 대상으로 지정하지만 Python 설치가 x86인 경우 C++ 프로젝트를 변경하여 x86을 대상으로 지정합니다.For example, if you're targeting x64 with the C++ project but your Python installation is x86, change the C++ project to target x86.

코드를 테스트하고 결과 비교Test the code and compare the results

DLL을 Python 확장으로 구조화했으므로 Python 프로젝트에서 이를 참조하고, 모듈을 가져오고, 해당 메서드를 사용할 수 있습니다.Now that you have the DLLs structured as Python extensions, you can refer to them from the Python project, import the modules, and use their methods.

Python에서 DLL을 사용할 수 있도록 설정Make the DLL available to Python

Python에서 DLL을 사용할 수 있도록 설정하는 방법은 두 가지가 있습니다.There are two ways to make the DLL available to Python.

Python 프로젝트와 C++ 프로젝트가 같은 솔루션에 있는 경우 첫 번째 방법을 사용할 수 있습니다.The first method works if the Python project and the C++ project are in the same solution. 솔루션 탐색기로 이동하여 Python 프로젝트에서 참조 노드를 마우스 오른쪽 단추로 클릭한 다음, 참조 추가를 선택합니다.Go to Solution Explorer, right-click the References node in your Python project, and then select Add Reference. 표시되는 대화 상자에서 프로젝트 탭을 선택하고 superfastcodesuperfastcode2 프로젝트를 모두 선택한 다음, 확인을 선택합니다.In the dialog that appears, select the Projects tab, select both the superfastcode and superfastcode2 projects, and then select OK.

superfastcode 프로젝트에 참조 추가

다음 단계에 설명된 두 번째 방법은 다른 Python 프로젝트에서도 사용 가능하도록 모듈을 전역 Python 환경에 설치합니다.The alternate method, described in the following steps, installs the module in the global Python environment, making it available to other Python projects as well. (이 경우 Visual Studio 2017 버전 15.5 및 이전 버전에서는 일반적으로 해당 환경에 대한 IntelliSense 완성 데이터베이스를 새로 고쳐야 합니다.(Doing so typically requires that you refresh the IntelliSense completion database for that environment in Visual Studio 2017 version 15.5 and earlier. 환경에서 모듈을 제거하는 경우에도 새로 고침이 필요합니다.)Refreshing is also necessary when removing the module from the environment.)

  1. Visual Studio 2017 이상을 사용하고 있는 경우 Visual Studio 설치 관리자를 실행하고 수정을 선택한 다음, 개별 구성 요소 > 컴파일러, 빌드 도구 및 런타임 > Visual C++ 2015.3 v140 도구 집합을 선택합니다.If you're using Visual Studio 2017 or later, run the Visual Studio installer, select Modify, select Individual Components > Compilers, build tools, and runtimes > Visual C++ 2015.3 v140 toolset. 이 단계가 필요한 이유는 Python(Windows용) 자체는 Visual Studio 2015(버전 14.0)로 빌드되며 여기에 설명된 메서드를 통해 확장을 빌드할 경우 이러한 도구를 사용할 수 있다고 예상하기 때문입니다.This step is necessary because Python (for Windows) is itself built with Visual Studio 2015 (version 14.0) and expects that those tools are available when building an extension through the method described here. (Python의 32비트 버전을 설치하고 DLL 대상을 x64가 아닌 Win32로 지정해야 할 수 있습니다.)(Note that you may need to install a 32-bit version of Python and target the DLL to Win32 and not x64.)

  2. 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가 > 새 항목을 선택하여 C++ 프로젝트에서 setup.py라는 파일을 만듭니다.Create a file named setup.py in the C++ project by right-clicking the project and selecting Add > New Item. 그런 다음, C++ 파일(.cpp) 을 선택하고 파일 이름을 setup.py로 변경한 다음, 확인을 선택합니다( .py 확장명을 사용하여 파일 이름을 지정하면 C++ 파일 템플릿을 사용해도 Visual Studio에서 Python으로 인식함).Then select C++ File (.cpp), name the file setup.py, and select OK (naming the file with the .py extension makes Visual Studio recognize it as Python despite using the C++ file template). 편집기에 파일이 표시되면 확장 메서드에 적절하게 다음 코드를 붙여넣습니다.When the file appears in the editor, paste the following code into it as appropriate to the extension method:

    CPython 확장(superfastcode 프로젝트):CPython extensions (superfastcode project):

    from distutils.core import setup, Extension, DEBUG
    
    sfc_module = Extension('superfastcode', sources = ['module.cpp'])
    
    setup(name = 'superfastcode', version = '1.0',
        description = 'Python Package with superfastcode C++ extension',
        ext_modules = [sfc_module]
        )
    

    이 스크립트에 대한 설명서는 C 및 C++ 확장 빌드(python.org)를 참조하세요.See Building C and C++ extensions (python.org) for documentation on this script.

    PyBind11(superfastcode2 프로젝트):PyBind11 (superfastcode2 project):

    import os, sys
    
    from distutils.core import setup, Extension
    from distutils import sysconfig
    
    cpp_args = ['-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.7']
    
    sfc_module = Extension(
        'superfastcode2', sources = ['module.cpp'],
        include_dirs=['pybind11/include'],
        language='c++',
        extra_compile_args = cpp_args,
        )
    
    setup(
        name = 'superfastcode2',
        version = '1.0',
        description = 'Python package with superfastcode2 C++ extension (PyBind11)',
        ext_modules = [sfc_module],
    )
    
  3. setup.py 코드는 명령줄에서 사용되는 경우 Visual Studio 2015 C++ 도구 집합을 사용하여 확장을 빌드하도록 Python에 지시합니다.The setup.py code instructs Python to build the extension using the Visual Studio 2015 C++ toolset when used from the command line. 관리자 권한 명령 프롬프트를 열고 C++ 프로젝트를 포함하는 폴더(즉, setup.py를 포함하는 폴더)로 이동한 후 다음 명령을 입력합니다.Open an elevated command prompt, navigate to the folder containing the C++ project (that is, the folder that contains setup.py), and enter the following command:

    pip install .
    

    또는or:

    py -m pip install .
    

Python에서 DLL 호출Call the DLL from Python

이전 섹션에서 설명한 대로 Python에 사용할 수 있는 DLL을 만들었으면 이제 Python 코드에서 superfastcode.fast_tanhsuperfastcode2.fast_tanh2 함수를 호출하여 Python 구현과 성능을 비교할 수 있습니다.After you've made the DLL available to Python as described in the previous section, you can now call the superfastcode.fast_tanh and superfastcode2.fast_tanh2 functions from Python code and compare their performance to the Python implementation:

  1. .py 파일에 다음 줄을 추가하여 DLL에서 가져온 메서드를 호출하고 출력을 표시합니다.Add the following lines in your .py file to call methods exported from the DLLs and display their outputs:

    from superfastcode import fast_tanh
    test(lambda d: [fast_tanh(x) for x in d], '[fast_tanh(x) for x in d] (CPython C++ extension)')
    
    from superfastcode2 import fast_tanh2
    test(lambda d: [fast_tanh2(x) for x in d], '[fast_tanh2(x) for x in d] (PyBind11 C++ extension)')
    
  2. Python 프로그램을 실행하고(디버깅 > 디버깅하지 않고 시작 또는 Ctrl+F5) C++ 루틴이 Python 구현보다 대략 5~20배 빠르게 실행되는지 확인합니다.Run the Python program (Debug > Start without Debugging or Ctrl+F5) and observe that the C++ routines run approximately five to twenty times faster than the Python implementation. 일반적인 출력은 다음과 같습니다.Typical output appears as follows:

    Running benchmarks with COUNT = 500000
    [tanh(x) for x in d] (Python implementation) took 0.758 seconds
    
    [fast_tanh(x) for x in d] (CPython C++ extension) took 0.076 seconds
    
    [fast_tanh2(x) for x in d] (PyBind11 C++ extension) took 0.204 seconds
    

    디버깅하지 않고 시작 명령이 비활성화된 경우 솔루션 탐색기에서 Python 프로젝트를 마우스 오른쪽 단추로 클릭하고 시작 프로젝트로 설정을 선택합니다.If the Start Without Debugging command is disabled, right-click the Python project in Solution Explorer and select Set as Startup Project.

  3. 차이가 더 분명해지도록 COUNT 변수를 늘려 보세요.Try increasing the COUNT variable so that the differences are more pronounced. 또한 디버그 빌드는 덜 최적화되고 다양한 오류 검사를 포함하기 때문에 C++ 모듈의 디버그 빌드가 릴리스 빌드보다 더 느리게 실행됩니다.A Debug build of the C++ module also runs slower than a Release build because the Debug build is less optimized and contains various error checks. 그러한 구성을 자유롭게 전환하여 비교해 보세요.Feel free to switch between those configurations for comparison.

참고

출력에서 보면 직접 Python 구현하는 것보다는 훨씬 빠르지만 PyBind11 확장이 CPython 확장 만큼 빠르지 않음을 알 수 있습니다.In the output, you can see that the PyBind11 extension isn't as fast as the CPython extension, though it's still significantly faster than the straight Python implementation. 해당 C++ 인터페이스를 더 간단하게 만들기 위해 PyBind11에서 도입한 호출당 오버헤드의 양이 적기 때문에 차이가 발생합니다.The difference is due to a small amount of per-call overhead that PyBind11 introduces in order to make its C++ interface dramatically simpler. 이 호출별 차이점은 실제로는 상당히 미미합니다. 여기에 표시된 결과는 테스트 코드가 확장 함수를 500,000번 호출하기 때문에 오버헤드를 크게 확대합니다.This per-call difference is actually quite negligible: because the test code calls the extension functions 500,000 times, the results you see here greatly amplify that overhead! 일반적으로 C++ 함수는 여기에서 사용된 간단한 fast_tanh[2] 메서드보다 훨씬 많은 작업을 수행하므로 오버헤드가 발생해도 중요하지 않습니다.Typically, a C++ function does much more work than the trivial fast_tanh[2] methods used here, in which case the overhead is unimportant. 그러나 초당 수천 번 호출될 수 있는 메서드를 구현하는 경우 CPython 방식을 사용하면PyBind11보다 성능이 향상될 수 있습니다.However, if you're implementing methods that might be called thousands of times per second, using the CPython approach can result in better performance than PyBind11.

C++ 코드 디버그Debug the C++ code

Visual Studio는 디버깅 Python 및 C++ 코드를 함께 지원합니다.Visual Studio supports debugging Python and C++ code together. 이 섹션에서는 superfastcode 프로젝트를 사용하여 프로세스를 설명하며, 단계는 superfastcode2 프로젝트에서도 동일합니다.This section walks through the process using the superfastcode project; the steps are the same for the superfastcode2 project.

  1. 솔루션 탐색기에서 Python 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성, 디버그 탭을 차례로 선택한 다음, 디버그 > 네이티브 코드 디버깅 사용 옵션을 선택합니다.Right-click the Python project in Solution Explorer, select Properties, select the Debug tab, and then select the Debug > Enable native code debugging option.

    네이티브 코드 디버깅을 사용하면 프로그램이 완료되었을 때 일반적인 계속하려면 아무 키나 누르세요. 일시 중지를 제공하지 않고 Python 출력 창이 바로 사라질 수 있습니다.When you enable native code debugging, the Python output window may disappear immediately when the program has completed without giving you the usual Press any key to continue pause. 강제로 일시 중지하려면 네이티브 코드 디버깅을 사용할 때 디버그 탭의 실행 > 인터프리터 인수 필드에 -i 옵션을 추가합니다.To force a pause, add the -i option to the Run > Interpreter Arguments field on the Debug tab when you enable native code debugging. 이 인수는 코드가 마무리된 후에 Python 인터프리터를 대화형 모드로 전환하며, 이때 Ctrl+Z > Enter 키를 눌러 종료할 때까지 대기합니다.This argument puts the Python interpreter into interactive mode after the code finishes, at which point it waits for you to press Ctrl+Z > Enter to exit. 또는 Python 코드를 수정하지 않으려면 프로그램의 끝에 import osos.system("pause") 문을 추가할 수 있습니다.(Alternately, if you don't mind modifying your Python code, you can add import os and os.system("pause") statements at the end of your program. 이 코드는 원래 일시 중지 프롬프트를 복제합니다.This code duplicates the original pause prompt.)

  2. 파일 > 저장을 선택하여 속성 변경 내용을 저장합니다.Select File > Save to save the property changes.

  3. Visual Studio 도구 모음에서 빌드 구성을 디버그로 설정합니다.Set the build configuration to Debug in the Visual Studio toolbar.

    빌드 구성을 디버그로 설정

  4. 일반적으로 디버거에서 코드를 실행하는 데 더 많은 시간이 걸리기 때문에 .py 파일의 COUNT 변수를 약 5배 작은 값으로 변경하는 것이 좋습니다(예: 500000에서 100000으로 변경).Because code generally takes longer to run in the debugger, you may want to change the COUNT variable in your .py file to a value that's about five times smaller (for example, change it from 500000 to 100000).

  5. C++ 코드에서는 tanh_impl 메서드의 첫 줄에 중단점을 설정한 다음 디버거를 시작합니다(F5 또는 디버그 > 디버깅 시작).In your C++ code, set a breakpoint on the first line of the tanh_impl method, then start the debugger (F5 or Debug > Start Debugging). 해당 코드가 호출되면 디버거가 중지합니다.The debugger stops when that code is called. 중단점이 적중되지 않는 경우 구성이 디버그로 설정되어 있는지, 프로젝트를 저장했는지 확인합니다(디버거를 시작할 때 자동으로 수행되지 않음).If the breakpoint is not hit, check that the configuration is set to Debug and that you've saved the project (which does not happen automatically when starting the debugger).

    C++ 코드의 중단점에서 중지

  6. 이때 C++ 코드를 단계별로 실행하고 변수를 검사하는 등의 작업을 수행할 수 있습니다.At this point you can step through the C++ code, examine variables, and so on. 이러한 기능은 C++ 및 Python 디버그에 자세히 설명되어 있습니다.These features are detailed in Debug C++ and Python together.

대체 방법Alternative approaches

아래 표에 설명된 대로 다른 방법으로 Python 확장을 만들 수 있습니다.There are a variety of means to create Python extensions as described in the following table. CPython 및 PyBind11에 대한 처음 두 항목은 이 문서에서 이미 설명했습니다.The first two entries for CPython and PyBind11 are what has been discussed in this article already.

방법Approach 연도Vintage 담당자Representative user(s) 장점Pro(s) 단점Con(s)
CPython용 C/C++ 확장 모듈C/C++ extension modules for CPython 19911991 표준 라이브러리Standard Library 광범위한 설명서 및 자습서.Extensive documentation and tutorials. 전체 제어.Total control. 컴파일, 이식성, 참조 관리.Compilation, portability, reference management. 높은 C 지식.High C knowledge.
PyBind11(C++에 권장됨)PyBind11 (Recommended for C++) 20152015 기존 C++ 코드의 Python 바인딩을 만드는 간단한 헤더 전용 라이브러리.Lightweight, header-only library for creating Python bindings of existing C++ code. 약간의 종속성.Few dependencies. PyPy 호환성.PyPy compatibility. 더 새롭고 완성도 낮음.Newer, less mature. C++11 기능 사용 빈도 높음.Heavy use of C++11 features. 몇 가지 지원되는 컴파일러(Visual Studio 포함).Short list of supported compilers (Visual Studio is included).
Cython(C에 권장됨)Cython (Recommended for C) 20072007 gevent, kivygevent, kivy Python과 유사.Python-like. 높은 완성도.Highly mature. 고성능.High performance. 컴파일, 새 구문 및 새 도구 체인.Compilation, new syntax, new toolchain.
Boost.PythonBoost.Python 20022002 모든 C++ 컴파일러와 작동.Works with just about every C++ compiler. 대규모의 복잡한 라이브러리 모음으로 이전 컴파일러에 대한 많은 대안을 포함.Large and complex suite of libraries; contains many workarounds for old compilers.
ctypesctypes 20032003 oscryptooscrypto 컴파일 안 함, 광범위한 가용성.No compilation, wide availability. 번거로운 C 구조체 액세스 및 변경과 오류 발생 가능성.Accessing and mutating C structures cumbersome and error prone.
SWIGSWIG 19961996 crfsuitecrfsuite 한 번에 여러 언어에 대한 바인딩 생성.Generate bindings for many languages at once. Python이 유일한 대상일 경우 과도한 오버헤드.Excessive overhead if Python is the only target.
cfficffi 20132013 cryptography, pypycryptography, pypy 간편한 통합, PyPy 호환성.Ease of integration, PyPy compatibility. 더 새롭고 완성도 낮음.Newer, less mature.
cppyycppyy 20172017 C++를 사용한 cffi와 유사합니다.Similar to cffi using C++. 최신 기능이며, VS 2017에서는 몇 가지 문제가 발생할 수 있습니다.Newer, may have some issues with VS 2017.

참조See also

이 연습에서 완료된 샘플은 python-samples-vs-cpp-extension(GitHub)에서 찾을 수 있습니다.The completed sample from this walkthrough can be found on python-samples-vs-cpp-extension (GitHub).