Tại sao python không biên dịch được

Chọn một trang web để nhận nội dung đã dịch nếu có và xem các sự kiện và ưu đãi tại địa phương. Dựa trên vị trí của bạn, chúng tôi khuyên bạn nên chọn.

Bạn cũng có thể chọn một trang web từ danh sách sau

Làm thế nào để có được hiệu suất trang web tốt nhất

Chọn trang Trung Quốc [bằng tiếng Trung hoặc tiếng Anh] để có hiệu suất trang tốt nhất. Các trang web quốc gia khác của MathWorks không được tối ưu hóa cho các lượt truy cập từ vị trí của bạn

Cú pháp

>>> import helloworld
Hello World
7 cụ thể của Cython, được thiết kế để khai báo kiểu ngắn gọn và dễ đọc từ góc độ C/C++

  • Cú pháp Python thuần túy cho phép khai báo kiểu Cython tĩnh trong mã Python thuần túy , tuân theo gợi ý loại PEP-484 và chú thích biến PEP 526.

    Để sử dụng các kiểu dữ liệu C trong cú pháp Python, bạn cần nhập mô-đun

    >>> import helloworld
    Hello World
    
    8 đặc biệt trong mô-đun Python mà bạn muốn biên dịch, e. g

    import cython
    

    Nếu bạn sử dụng cú pháp Python thuần túy, chúng tôi thực sự khuyên bạn nên sử dụng bản phát hành Cython 3 gần đây, vì những cải tiến đáng kể đã được thực hiện ở đây so với phiên bản 0. 29. x phát hành

  • Khái niệm cơ bản về Cython¶

    Bản chất cơ bản của Cython có thể được tóm tắt như sau. Cython là Python với kiểu dữ liệu C

    Cython là Python. Hầu như bất kỳ đoạn mã Python nào cũng là mã Cython hợp lệ. [Có một vài Hạn chế , nhưng phép tính gần đúng này tạm thời. ] Trình biên dịch Cython sẽ chuyển đổi nó thành mã C để thực hiện các lệnh gọi tương đương với API Python/C.

    Nhưng Cython còn hơn thế nữa, bởi vì các tham số và biến có thể được khai báo theo kiểu dữ liệu C. Mã thao tác giá trị Python và giá trị C có thể được tự do trộn lẫn với nhau, với các chuyển đổi diễn ra tự động bất cứ khi nào có thể. Bảo trì số lượng tham chiếu và kiểm tra lỗi của các hoạt động Python cũng tự động và toàn bộ sức mạnh của các phương tiện xử lý ngoại lệ của Python, bao gồm các câu lệnh thử ngoại trừ và thử cuối cùng, có sẵn cho bạn – ngay cả khi đang thao tác với dữ liệu C.

    Cython Xin chào thế giới¶

    Vì Cython có thể chấp nhận hầu hết mọi tệp nguồn python hợp lệ, một trong những điều khó nhất khi bắt đầu chỉ là tìm cách biên dịch tiện ích mở rộng của bạn

    Vì vậy, hãy bắt đầu với con trăn kinh điển xin chào thế giới

    print["Hello World"]
    

    Lưu mã này vào tệp có tên

    >>> import helloworld
    Hello World
    
    9. Bây giờ chúng ta cần tạo
    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    0, giống như tệp Makefile của trăn [để biết thêm thông tin, hãy xem Tệp nguồn và trình biên dịch ].
    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    0 của bạn sẽ trông giống như.

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    

    Để sử dụng điều này để xây dựng tệp Cython của bạn, hãy sử dụng các tùy chọn dòng lệnh

    ________số 8

    Điều này sẽ để lại một tệp trong thư mục cục bộ của bạn có tên là

    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    2 trong unix hoặc
    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    3 trong Windows. Bây giờ để sử dụng tập tin này. bắt đầu trình thông dịch python và chỉ cần nhập nó như thể nó là một mô-đun python thông thường

    >>> import helloworld
    Hello World
    

    Xin chúc mừng. Bây giờ bạn đã biết cách xây dựng tiện ích mở rộng Cython. Nhưng cho đến nay, ví dụ này không thực sự mang lại cảm giác tại sao một người lại muốn sử dụng Cython, vì vậy hãy tạo một ví dụ thực tế hơn

    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    4. Biên dịch Cython dành cho nhà phát triển¶

    Nếu mô-đun của bạn không yêu cầu bất kỳ thư viện C bổ sung nào hoặc thiết lập bản dựng đặc biệt, thì bạn có thể sử dụng mô-đun pyximport, do Paul Prescod phát triển ban đầu, để tải. pyx trực tiếp khi nhập mà không phải chạy tệp

    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    0 của bạn mỗi khi bạn thay đổi mã của mình. Nó được vận chuyển và cài đặt với Cython và có thể được sử dụng như thế này

    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    

    Mô-đun Pyximport cũng có hỗ trợ biên dịch thử nghiệm cho các mô-đun Python bình thường. Điều này cho phép bạn tự động chạy Cython trên mọi. pyx và. py mà Python nhập vào, bao gồm thư viện chuẩn và các gói đã cài đặt. Cython vẫn sẽ không biên dịch được nhiều mô-đun Python, trong trường hợp đó, cơ chế nhập sẽ chuyển sang tải các mô-đun nguồn Python thay thế. Các. cơ chế nhập py được cài đặt như thế này.

    >>> import helloworld
    Hello World
    
    5

    Lưu ý rằng không nên để Pyximport mã xây dựng ở phía người dùng cuối khi mã này kết nối với hệ thống nhập của họ. Cách tốt nhất để phục vụ người dùng cuối là cung cấp các gói nhị phân dựng sẵn ở định dạng đóng gói bánh xe.

    Fibonacci Fun¶

    Từ hướng dẫn Python chính thức, một hàm fibonacci đơn giản được định nghĩa là

    >>> import helloworld
    Hello World
    
    6

    Bây giờ làm theo các bước cho ví dụ Hello World, trước tiên chúng ta đổi tên tệp để có một. pyx, giả sử là

    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    6, sau đó chúng tôi tạo tệp
    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    0. Sử dụng tệp được tạo cho ví dụ Hello World, tất cả những gì bạn cần thay đổi là tên của tên tệp Cython và tên mô-đun kết quả, làm như vậy chúng ta có

    >>> import helloworld
    Hello World
    
    9

    Xây dựng tiện ích mở rộng với cùng một lệnh được sử dụng cho helloworld. pyx

    ________số 8

    Và sử dụng tiện ích mở rộng mới với

    print["Hello World"]
    
    0

    Số nguyên tố¶

    Đây là một ví dụ nhỏ cho thấy một số điều có thể được thực hiện. Đó là một thói quen để tìm số nguyên tố. Bạn cho nó biết bạn muốn bao nhiêu số nguyên tố và nó trả về chúng dưới dạng danh sách Python

    Python nguyên chấtCython

    số nguyên tố. py

    print["Hello World"]
    
    1

    print["Hello World"]
    
    2

    số nguyên tố. pyx

    print["Hello World"]
    
    1

    print["Hello World"]
    
    4

    Bạn sẽ thấy rằng nó bắt đầu giống như một định nghĩa hàm Python bình thường, ngoại trừ tham số

    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    8 được khai báo là kiểu
    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    9. Điều này có nghĩa là đối tượng được truyền sẽ được chuyển đổi thành số nguyên C [hoặc
    >>> import helloworld
    Hello World
    
    50 sẽ được nâng lên nếu không thể]

    Bây giờ, hãy đi sâu vào cốt lõi của chức năng

    Python nguyên chấtCython

    print["Hello World"]
    
    5

    print["Hello World"]
    
    6

    print["Hello World"]
    
    7

    print["Hello World"]
    
    8

    Các dòng 2, 3, 11 và 12 sử dụng chú thích biến để xác định một số biến C cục bộ. Kết quả được lưu trữ trong mảng C

    >>> import helloworld
    Hello World
    
    51 trong quá trình xử lý và sẽ được sao chép vào danh sách Python ở cuối [dòng 26]

    print["Hello World"]
    
    5

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    0

    Dòng 2 và 3 sử dụng câu lệnh

    >>> import helloworld
    Hello World
    
    7 để xác định một số biến C cục bộ. Kết quả được lưu trữ trong mảng C
    >>> import helloworld
    Hello World
    
    51 trong quá trình xử lý và sẽ được sao chép vào danh sách Python ở cuối [dòng 26]

    Ghi chú

    Bạn không thể tạo các mảng rất lớn theo cách này, bởi vì chúng được cấp phát trong lệnh gọi hàm C stack , đây là một lệnh khá quý giá và . Để yêu cầu các mảng lớn hơn hoặc thậm chí là các mảng có độ dài chỉ được biết khi chạy, bạn có thể tìm hiểu cách sử dụng hiệu quả Cấp phát bộ nhớ C , Python arrays or NumPy arrays with Cython.

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    1

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    2

    Như trong C, khai báo một mảng tĩnh yêu cầu biết kích thước tại thời điểm biên dịch. Chúng tôi đảm bảo rằng người dùng không đặt giá trị trên 1000 [hoặc chúng tôi sẽ gặp lỗi phân đoạn, giống như trong C]

    Python nguyên chấtCython

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    3

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    4

    Khi chúng tôi chạy mã này từ Python, chúng tôi phải khởi tạo các mục trong mảng. Điều này được thực hiện dễ dàng nhất bằng cách điền nó bằng số 0 [như đã thấy ở dòng 8-9]. Mặt khác, khi chúng ta biên dịch cái này với Cython, mảng sẽ hoạt động như trong C. Nó được phân bổ trên ngăn xếp lệnh gọi hàm với độ dài cố định là 1000 mục chứa dữ liệu tùy ý từ lần cuối bộ nhớ đó được sử dụng. Sau đó, chúng tôi sẽ ghi đè lên các mục đó trong tính toán của chúng tôi

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    5

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    6

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    5

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    8

    Các dòng 11-13 thiết lập một vòng lặp while sẽ kiểm tra các ứng cử viên số thành số nguyên tố cho đến khi tìm thấy số lượng số nguyên tố cần thiết

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup[
        ext_modules = cythonize["helloworld.pyx"]
    ]
    
    9

    $ python setup.py build_ext --inplace
    
    0

    Các dòng 15-16, cố gắng chia một ứng cử viên cho tất cả các số nguyên tố được tìm thấy cho đến nay, được đặc biệt quan tâm. Bởi vì không có đối tượng Python nào được tham chiếu, vòng lặp được dịch hoàn toàn sang mã C và do đó chạy rất nhanh. Bạn sẽ nhận thấy cách chúng tôi lặp qua mảng

    >>> import helloworld
    Hello World
    
    51 C

    $ python setup.py build_ext --inplace
    
    1

    $ python setup.py build_ext --inplace
    
    2

    Vòng lặp được dịch thành vòng lặp C nhanh và hoạt động giống như lặp qua danh sách Python hoặc mảng NumPy. Nếu bạn không cắt mảng C bằng

    >>> import helloworld
    Hello World
    
    55, thì Cython sẽ lặp qua 1000 phần tử của mảng

    $ python setup.py build_ext --inplace
    
    3

    $ python setup.py build_ext --inplace
    
    4

    Nếu không xảy ra ngắt, điều đó có nghĩa là chúng tôi đã tìm thấy số nguyên tố và khối mã sau dòng 20 của

    >>> import helloworld
    Hello World
    
    56 sẽ được thực thi. Chúng tôi thêm số nguyên tố được tìm thấy vào
    >>> import helloworld
    Hello World
    
    51. Nếu bạn thấy có một
    >>> import helloworld
    Hello World
    
    56 sau vòng lặp for là lạ, chỉ cần biết rằng đó là một tính năng ít được biết đến của ngôn ngữ Python và Cython sẽ thực thi nó ở tốc độ C cho bạn. Nếu cú ​​pháp for-else làm bạn bối rối, hãy xem bài đăng trên blog tuyệt vời này

    $ python setup.py build_ext --inplace
    
    5

    $ python setup.py build_ext --inplace
    
    6

    Ở dòng 26, trước khi trả về kết quả, chúng ta cần sao chép mảng C của mình vào danh sách Python, vì Python không đọc được mảng C. Cython có thể tự động chuyển đổi nhiều loại C từ và sang các loại Python, như được mô tả trong tài liệu về chuyển đổi loại , vì vậy chúng tôi có thể sử dụng cách hiểu danh sách đơn giản tại đây để . Bạn cũng có thể lặp lại thủ công trên mảng C và sử dụng

    >>> import helloworld
    Hello World
    
    61, kết quả sẽ giống như vậy.

    Bạn sẽ nhận thấy rằng chúng tôi khai báo một danh sách Python giống hệt như trong Python. Vì biến

    >>> import helloworld
    Hello World
    
    62 chưa được khai báo rõ ràng với một loại, nên nó được giả định là chứa một đối tượng Python và từ phép gán, Cython cũng biết rằng loại chính xác là một danh sách Python

    Cuối cùng, ở dòng 27, một câu lệnh return Python bình thường trả về danh sách kết quả

    Python nguyên chấtCython

    tổng hợp số nguyên tố. py với trình biên dịch Cython tạo ra một mô-đun mở rộng mà chúng ta có thể dùng thử trong trình thông dịch tương tác như sau

    tổng hợp số nguyên tố. pyx với trình biên dịch Cython tạo ra một mô-đun mở rộng mà chúng ta có thể dùng thử trong trình thông dịch tương tác như sau

    $ python setup.py build_ext --inplace
    
    7

    Xem, nó hoạt động. Và nếu bạn tò mò về khối lượng công việc mà Cython đã tiết kiệm cho bạn, hãy xem mã C được tạo cho mô-đun này

    Cython có một cách để trực quan hóa nơi diễn ra tương tác với các đối tượng Python và C-API của Python. Đối với điều này, hãy chuyển tham số

    >>> import helloworld
    Hello World
    
    63 cho
    >>> import helloworld
    Hello World
    
    64. Nó tạo ra một tệp HTML. Hãy xem nào

    Python nguyên chấtCython

    Nếu một dòng màu trắng, điều đó có nghĩa là mã được tạo không tương tác với Python, vì vậy sẽ chạy nhanh như mã C bình thường. Màu vàng càng đậm thì càng có nhiều tương tác Python trong dòng đó. Những dòng màu vàng đó thường sẽ hoạt động trên các đối tượng Python, đưa ra các ngoại lệ hoặc thực hiện các loại hoạt động cấp cao hơn những gì có thể dễ dàng dịch sang mã C đơn giản và nhanh chóng. Việc khai báo và trả về hàm sử dụng trình thông dịch Python nên các dòng đó có màu vàng là hợp lý. Tương tự đối với việc hiểu danh sách vì nó liên quan đến việc tạo đối tượng Python. Nhưng dòng

    >>> import helloworld
    Hello World
    
    65, tại sao?

    Chúng tôi có thể thấy rằng một số kiểm tra xảy ra. Vì Cython mặc định hành vi của Python nên ngôn ngữ này sẽ thực hiện kiểm tra phép chia trong thời gian chạy, giống như Python đã làm. Bạn có thể hủy kích hoạt các kiểm tra đó bằng cách sử dụng chỉ thị trình biên dịch .

    Bây giờ hãy xem liệu chúng ta có tăng tốc độ ngay cả khi có kiểm tra bộ phận không. Hãy viết cùng một chương trình, nhưng bằng Python

    primes_python. py / primes_python_compiled. py

    $ python setup.py build_ext --inplace
    
    8

    Có thể lấy một tệp

    >>> import helloworld
    Hello World
    
    66 đơn giản [không được chú thích] và biên dịch nó bằng Cython. Hãy tạo một bản sao của
    >>> import helloworld
    Hello World
    
    67 và đặt tên là
    >>> import helloworld
    Hello World
    
    68 để có thể so sánh nó với mô-đun Python [không được biên dịch]. Sau đó, chúng tôi biên dịch tệp đó bằng Cython mà không thay đổi mã. Bây giờ
    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    0 trông như thế này

    Python nguyên chấtCython

    $ python setup.py build_ext --inplace
    
    9

    >>> import helloworld
    Hello World
    
    0

    Bây giờ chúng ta có thể đảm bảo rằng hai chương trình đó xuất ra các giá trị giống nhau

    >>> import helloworld
    Hello World
    
    1

    Có thể so sánh tốc độ bây giờ

    >>> import helloworld
    Hello World
    
    2

    Phiên bản cythonize của

    >>> import helloworld
    Hello World
    
    67 nhanh hơn 2 lần so với phiên bản Python mà không thay đổi một dòng mã nào. Phiên bản Cython nhanh hơn 13 lần so với phiên bản Python. Điều gì có thể giải thích điều này?

    Nhiều thứ
    • Trong chương trình này, rất ít tính toán xảy ra ở mỗi dòng. Vì vậy, chi phí hoạt động của trình thông dịch python là rất quan trọng. Sẽ rất khác nếu bạn tính toán nhiều ở mỗi dòng. Sử dụng NumPy chẳng hạn

    • Vị trí dữ liệu. Có khả năng sẽ có nhiều thứ hơn có thể phù hợp với bộ đệm CPU khi sử dụng C so với khi sử dụng Python. Bởi vì mọi thứ trong python là một đối tượng và mọi đối tượng được triển khai dưới dạng từ điển, nên điều này không thân thiện lắm với bộ đệm

    Thông thường tốc độ tăng từ 2x đến 1000x. Nó phụ thuộc vào mức độ bạn gọi trình thông dịch Python. Như mọi khi, hãy nhớ lập hồ sơ trước khi thêm các loại ở mọi nơi. Việc thêm các loại làm cho mã của bạn khó đọc hơn, vì vậy hãy sử dụng chúng một cách có chừng mực

    Số nguyên tố với C++¶

    Với Cython, cũng có thể tận dụng lợi thế của ngôn ngữ C++, đáng chú ý là một phần của thư viện chuẩn C++ có thể nhập trực tiếp từ mã Cython

    Hãy xem mã của chúng ta sẽ như thế nào khi sử dụng vector từ thư viện chuẩn C++

    Ghi chú

    Vector trong C++ là cấu trúc dữ liệu triển khai danh sách hoặc ngăn xếp dựa trên mảng C có thể thay đổi kích thước. Nó tương tự như loại

    >>> import helloworld
    Hello World
    
    91 của Python trong mô-đun thư viện chuẩn
    >>> import helloworld
    Hello World
    
    91. Có sẵn một phương thức dự trữ sẽ tránh được các bản sao nếu bạn biết trước có bao nhiêu phần tử bạn sẽ đưa vào vectơ. Để biết thêm chi tiết xem trang này từ cppreference

    Python nguyên chấtCython

    >>> import helloworld
    Hello World
    
    3

    >>> import helloworld
    Hello World
    
    4

    Cảnh báo

    Mã được cung cấp ở trên / trên trang này sử dụng thư viện gốc bên ngoài [không phải Python] thông qua

    >>> import helloworld
    Hello World
    
    93 [
    >>> import helloworld
    Hello World
    
    94]. Quá trình biên dịch Cython cho phép điều này, nhưng không có hỗ trợ nào cho điều này từ Python thuần túy. Cố gắng chạy mã này từ Python [không biên dịch] sẽ không thành công khi truy cập thư viện bên ngoài. Điều này được mô tả chi tiết hơn trong Gọi hàm C .

    >>> import helloworld
    Hello World
    
    3

    >>> import helloworld
    Hello World
    
    6

    Dòng đầu tiên là chỉ thị của trình biên dịch. Nó yêu cầu Cython biên dịch mã của bạn thành C++. Điều này sẽ cho phép sử dụng các tính năng của ngôn ngữ C++ và thư viện chuẩn C++. Lưu ý rằng không thể biên dịch mã Cython thành C++ bằng pyximport. Bạn nên sử dụng

    >>> import pyximport; pyximport.install[]
    >>> import helloworld
    Hello World
    
    0 hoặc sổ ghi chép để chạy ví dụ này

    Bạn có thể thấy rằng API của vectơ tương tự như API của danh sách Python và đôi khi có thể được sử dụng làm thay thế thả xuống trong Cython

    Tại sao Python không thể được biên dịch?

    Không có cách nào để nắm bắt mã máy đó vì nó không tồn tại . Mã byte được thực thi bởi trình thông dịch. Mã máy đó nằm trong trình thông dịch. Mã byte được biên dịch, được chạy thông qua trình thông dịch vì Python là ngôn ngữ được thông dịch.

    Python có thể được biên dịch không?

    Phần lớn, Python là ngôn ngữ được thông dịch chứ không phải ngôn ngữ được biên dịch , mặc dù biên dịch là một bước. Mã Python, được viết bằng. py trước tiên được biên dịch thành mã byte [được thảo luận chi tiết hơn] được lưu trữ với một. pyc hoặc.

    Python có được biên dịch nhanh như C không?

    Tuy nhiên, Python có một nhược điểm lớn. Nó chậm hơn nhiều so với các ngôn ngữ được biên dịch như C hoặc C++ .

    Chủ Đề