Thêm mô-đun vào pythonpath

Bộ xử lý Mac M1 mới khá tuyệt và đủ để chuyển đổi người dùng Linux cũ thành Mac. Vì Mac M1, M2, v. v. đều dựa trên cánh tay, có một số khác biệt cần nhận thức khi cài đặt môi trường Python của bạn. Một số hướng dẫn tôi đã thấy đề xuất cài đặt các gói x86 (Intel), nhưng có một số lỗi nghiêm trọng khi chương trình X86 được Rosetta2 giải thích để hoạt động trên máy Mac M1. Thay vào đó, các hướng dẫn này sẽ giúp bạn có một môi trường Python khoa học đầy đủ hoạt động tự nhiên trên kiến ​​trúc M1

Chúng tôi sẽ sử dụng

import sys
sys.path.append("/home/me/mydir")
2 và
import sys
sys.path.append("/home/me/mydir")
3 để cài đặt các gói
  1. Tải xuống và cài đặt phiên bản Pygplate mới nhất tương thích với kiến ​​trúc hệ thống của bạn (Mac M1 Arm) và lưu thư mục cài đặt và đường dẫn Python
  2. Cài đặt Conda (chúng tôi đề xuất Miniforge) và tạo một môi trường mới, ví dụ. Conda Tạo -N Pygplate Python = 3. 9

    “Cấu trúc” có nghĩa là các quyết định bạn đưa ra liên quan đến cách dự án của bạn đáp ứng tốt nhất mục tiêu của nó. Chúng ta cần xem xét cách tận dụng tốt nhất các tính năng của Python để tạo mã rõ ràng, hiệu quả. Về mặt thực tế, “cấu trúc” có nghĩa là tạo mã sạch có logic và các phần phụ thuộc rõ ràng cũng như cách các tệp và thư mục được tổ chức trong hệ thống tệp

    Những chức năng nào nên đi vào những mô-đun nào?

    Trong phần này, chúng ta xem xét kỹ hơn các mô-đun của Python và các hệ thống nhập vì chúng là các yếu tố trung tâm để thực thi cấu trúc trong dự án của bạn. Sau đó, chúng tôi thảo luận về các quan điểm khác nhau về cách xây dựng mã có thể được mở rộng và kiểm tra một cách đáng tin cậy

    Cấu trúc của Kho lưu trữ¶

    Nó quan trọng. ¶

    Giống như Kiểu mã, Thiết kế API và Tự động hóa là điều cần thiết cho một chu kỳ phát triển lành mạnh. Cấu trúc kho lưu trữ là một phần quan trọng trong kiến ​​trúc dự án của bạn

    Khi một người dùng hoặc cộng tác viên tiềm năng truy cập vào trang của kho lưu trữ của bạn, họ sẽ thấy một số điều

    • Tên dự án
    • mô tả dự án
    • Tập tin Bunch O'

    Chỉ khi họ cuộn xuống dưới màn hình đầu tiên thì người dùng mới thấy README của dự án của bạn

    Nếu kho lưu trữ của bạn là một đống tệp khổng lồ hoặc một mớ hỗn độn các thư mục, họ có thể tìm ở nơi khác trước khi đọc tài liệu đẹp mắt của bạn

    Ăn mặc cho công việc bạn muốn, không phải công việc bạn có

    Tất nhiên, ấn tượng đầu tiên không phải là tất cả. Bạn và đồng nghiệp của mình sẽ dành vô số thời gian làm việc với kho lưu trữ này, cuối cùng sẽ trở nên quen thuộc với mọi ngóc ngách. Bố cục là quan trọng

    Kho lưu trữ mẫu¶

    tl;dr. Đây là những gì Kenneth Reitz đề xuất vào năm 2013

    Kho lưu trữ này có sẵn trên GitHub

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    

    Hãy đi vào một số chi tiết cụ thể

    Mô-đun thực tế¶

    Vị trí
    ./sample.py
    
    9 hoặc
    ./test_sample.py
    
    0Mục đíchMã quan tâm

    Gói mô-đun của bạn là trọng tâm cốt lõi của kho lưu trữ. Nó không nên được giấu đi

    ./sample/
    

    Nếu mô-đun của bạn chỉ bao gồm một tệp duy nhất, bạn có thể đặt nó trực tiếp vào thư mục gốc của kho lưu trữ của mình

    ./sample.py
    

    Thư viện của bạn không thuộc thư mục con src hoặc python mơ hồ

    Giấy phép¶

    Địa điểm
    ./test_sample.py
    
    1Mục đích Xây dựng luật

    Đây được cho là phần quan trọng nhất trong kho lưu trữ của bạn, ngoài bản thân mã nguồn. Toàn bộ văn bản giấy phép và khiếu nại bản quyền phải tồn tại trong tệp này

    Nếu bạn không chắc mình nên sử dụng giấy phép nào cho dự án của mình, hãy xem chọnalicense. com

    Tất nhiên, bạn cũng có thể tự do xuất bản mã mà không cần giấy phép, nhưng điều này sẽ ngăn nhiều người có khả năng sử dụng hoặc đóng góp cho mã của bạn

    Thành lập. py¶

    Địa điểm
    ./test_sample.py
    
    2Mục đích Quản lý gói hàng và phân phối

    Nếu gói mô-đun của bạn nằm ở thư mục gốc của kho lưu trữ, thì rõ ràng gói này cũng phải ở thư mục gốc

    Hồ sơ yêu cầu¶

    Vị trí
    ./test_sample.py
    
    3Mục đích Phụ thuộc phát triển

    Tệp yêu cầu pip phải được đặt ở thư mục gốc của kho lưu trữ. Nó nên chỉ định các phụ thuộc cần thiết để đóng góp cho dự án. thử nghiệm, xây dựng và tạo tài liệu

    Nếu dự án của bạn không có phần phụ thuộc phát triển hoặc nếu bạn muốn thiết lập môi trường phát triển qua

    ./test_sample.py
    
    4, tệp này có thể không cần thiết

    Tài liệu¶

    Vị trí
    ./test_sample.py
    
    5Mục đích Tài liệu tham khảo gói

    Có rất ít lý do để điều này tồn tại ở nơi khác

    Bộ kiểm tra¶

    Để được tư vấn về cách viết bài kiểm tra của bạn, hãy xem Kiểm tra mã của bạn .

    Địa điểm
    ./test_sample.py
    
    6 hoặc
    ./test_sample.py
    
    7Mục đíchTích hợp gói và kiểm tra đơn vị

    Khi mới bắt đầu, một bộ thử nghiệm nhỏ thường sẽ tồn tại trong một tệp duy nhất

    ./test_sample.py
    

    Khi bộ thử nghiệm phát triển, bạn có thể di chuyển các thử nghiệm của mình vào một thư mục, như vậy

    import sys
    sys.path.append("/home/me/mydir")
    
    5

    Rõ ràng, các mô-đun thử nghiệm này phải nhập mô-đun đã đóng gói của bạn để kiểm tra nó. Bạn có thể làm điều này một vài cách

    • Yêu cầu gói được cài đặt trong gói trang web
    • Sử dụng sửa đổi đường dẫn đơn giản (nhưng rõ ràng) để giải quyết gói đúng cách

    Tôi đánh giá cao cái sau. Yêu cầu nhà phát triển chạy

    ./test_sample.py
    
    8 để kiểm tra cơ sở mã thay đổi tích cực cũng yêu cầu họ phải thiết lập môi trường biệt lập cho từng phiên bản của cơ sở mã

    Để cung cấp ngữ cảnh nhập cho các bài kiểm tra riêng lẻ, hãy tạo tệp

    ./test_sample.py
    
    9

    import sys
    sys.path.append("/home/me/mydir")
    
    8

    Sau đó, trong các mô-đun thử nghiệm riêng lẻ, hãy nhập mô-đun như vậy

    import sys
    sys.path.append("/home/me/mydir")
    
    9

    Điều này sẽ luôn hoạt động như mong đợi, bất kể phương pháp cài đặt

    Một số người sẽ khẳng định rằng bạn nên phân phối các bài kiểm tra của mình trong chính mô-đun của mình – tôi không đồng ý. Nó thường làm tăng độ phức tạp cho người dùng của bạn;

    Makefile¶

    Vị trí
    import sys
    sys.path.append("/home/me/mydir")
    
    50Mục đíchNhiệm vụ quản lý chung

    Nếu bạn xem hầu hết các dự án của tôi hoặc bất kỳ dự án Pocoo nào, bạn sẽ nhận thấy một Makefile nằm xung quanh. Tại sao?

    Makefile mẫu

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    1

    Các tập lệnh quản lý chung khác (e. g.

    import sys
    sys.path.append("/home/me/mydir")
    
    51 hoặc
    import sys
    sys.path.append("/home/me/mydir")
    
    52) cũng thuộc thư mục gốc của kho lưu trữ

    Về ứng dụng Django¶

    Tôi đã nhận thấy một xu hướng mới trong các ứng dụng Django kể từ khi phát hành Django 1. 4. Nhiều nhà phát triển đang cấu trúc kho lưu trữ của họ kém do các mẫu ứng dụng đi kèm mới

    Làm sao?

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    4

    Cấu trúc kho lưu trữ kết quả trông như thế này

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    5

    Đừng làm điều này

    Các đường dẫn lặp đi lặp lại gây nhầm lẫn cho cả công cụ và nhà phát triển của bạn. Việc lồng nhau không cần thiết không giúp được gì cho bất kỳ ai (trừ khi họ hoài cổ về các kho lưu trữ SVN nguyên khối)

    Hãy làm điều đó đúng cách

    ./sample/
    
    0

    Lưu ý “

    import sys
    sys.path.append("/home/me/mydir")
    
    53”

    Cấu trúc kết quả

    ./sample/
    
    1

    Cấu trúc mã là chìa khóa¶

    Nhờ cách nhập và mô-đun được xử lý trong Python, việc cấu trúc một dự án Python tương đối dễ dàng. Dễ dàng ở đây có nghĩa là bạn không có nhiều ràng buộc và mô hình nhập mô-đun dễ nắm bắt. Do đó, bạn chỉ còn lại nhiệm vụ kiến ​​trúc thuần túy là tạo ra các phần khác nhau của dự án và các tương tác của chúng.

    Cấu trúc dễ dàng của một dự án có nghĩa là nó cũng dễ dàng thực hiện nó một cách kém cỏi. Một số dấu hiệu của một dự án có cấu trúc kém bao gồm

    • Phụ thuộc vòng tròn nhiều và lộn xộn. Nếu các lớp Bàn ghế trong
      import sys
      sys.path.append("/home/me/mydir")
      
      54 cần nhập Carpenter từ
      import sys
      sys.path.append("/home/me/mydir")
      
      55 để trả lời một câu hỏi chẳng hạn như
      import sys
      sys.path.append("/home/me/mydir")
      
      56 và nếu ngược lại, lớp Carpenter cần nhập Bàn ghế để trả lời câu hỏi
      import sys
      sys.path.append("/home/me/mydir")
      
      57, thì bạn có một phụ thuộc vòng. Trong trường hợp này, bạn sẽ phải dùng đến các thủ thuật hack mỏng manh, chẳng hạn như sử dụng các câu lệnh nhập bên trong các phương thức hoặc chức năng của mình
    • khớp nối ẩn. Mỗi và mọi thay đổi trong quá trình triển khai của Table đều phá vỡ 20 bài kiểm tra trong các trường hợp kiểm tra không liên quan vì nó phá vỡ mã của Carpenter, điều này đòi hỏi phải phẫu thuật rất cẩn thận để thích ứng với thay đổi. Điều này có nghĩa là bạn có quá nhiều giả định về Bảng trong mã Carpenter hoặc ngược lại
    • Sử dụng nhiều trạng thái hoặc bối cảnh toàn cầu. Thay vì truyền rõ ràng
      import sys
      sys.path.append("/home/me/mydir")
      
      58 cho nhau, Table và Carpenter dựa vào các biến toàn cục có thể được sửa đổi và được sửa đổi nhanh chóng bởi các tác nhân khác nhau. Bạn cần xem xét kỹ lưỡng tất cả quyền truy cập vào các biến toàn cục này để hiểu tại sao một bảng hình chữ nhật lại trở thành một hình vuông và phát hiện ra rằng mã mẫu từ xa cũng đang sửa đổi bối cảnh này, làm rối tung các kích thước của bảng
    • mã spaghetti. nhiều trang chứa các mệnh đề if và vòng lặp lồng nhau với nhiều mã thủ tục được sao chép và không có phân đoạn thích hợp được gọi là mã spaghetti. Sự thụt lề có ý nghĩa của Python (một trong những tính năng gây tranh cãi nhất của nó) khiến cho việc duy trì loại mã này trở nên rất khó khăn. Tin tốt là bạn có thể không thấy quá nhiều
    • Mã Ravioli có nhiều khả năng bằng Python. nó bao gồm hàng trăm mảnh logic nhỏ giống nhau, thường là các lớp hoặc đối tượng, không có cấu trúc phù hợp. Nếu bạn không bao giờ có thể nhớ, nếu bạn phải sử dụng FurnitureTable, AssetTable hoặc Table, hoặc thậm chí TableNew cho nhiệm vụ của mình, thì bạn có thể đang bơi trong mã ravioli

    Mô-đun¶

    Các mô-đun Python là một trong những lớp trừu tượng chính có sẵn và có lẽ là lớp tự nhiên nhất. Các lớp trừu tượng cho phép tách mã thành các phần chứa dữ liệu và chức năng liên quan

    Ví dụ: một lớp của dự án có thể xử lý giao tiếp với hành động của người dùng, trong khi lớp khác sẽ xử lý thao tác dữ liệu ở mức độ thấp. Cách tự nhiên nhất để tách hai lớp này là tập hợp lại tất cả các chức năng giao tiếp trong một tệp và tất cả các hoạt động cấp thấp trong một tệp khác. Trong trường hợp này, tệp giao diện cần nhập tệp cấp thấp. Điều này được thực hiện với các câu lệnh

    import sys
    sys.path.append("/home/me/mydir")
    
    59 và
    import sys
    sys.path.append("/home/me/mydir")
    
    80

    Ngay khi bạn sử dụng câu lệnh nhập, bạn sử dụng các mô-đun. Đây có thể là các mô-đun tích hợp sẵn như os và sys, mô-đun bên thứ ba mà bạn đã cài đặt trong môi trường của mình hoặc mô-đun nội bộ của dự án của bạn

    Để phù hợp với hướng dẫn về phong cách, hãy đặt tên mô-đun ngắn, viết thường và đảm bảo tránh sử dụng các ký hiệu đặc biệt như dấu chấm (. ) hoặc dấu chấm hỏi (?). Tên tệp như

    import sys
    sys.path.append("/home/me/mydir")
    
    81 là tên bạn nên tránh. Đặt tên theo cách này sẽ cản trở cách Python tìm kiếm các mô-đun

    trong trường hợp của tôi. Thư rác. py Python hy vọng sẽ tìm thấy tệp

    import sys
    sys.path.append("/home/me/mydir")
    
    82 trong thư mục có tên
    import sys
    sys.path.append("/home/me/mydir")
    
    83, đây không phải là trường hợp. Có một ví dụ về cách sử dụng ký hiệu dấu chấm trong tài liệu Python

    Nếu muốn, bạn có thể đặt tên cho mô-đun của mình là

    import sys
    sys.path.append("/home/me/mydir")
    
    84, nhưng ngay cả dấu gạch dưới, người bạn đáng tin cậy của chúng ta, cũng không nên xuất hiện thường xuyên trong tên mô-đun. Tuy nhiên, việc sử dụng các ký tự khác (dấu cách hoặc dấu gạch ngang) trong tên mô-đun sẽ ngăn quá trình nhập (- là toán tử trừ). Cố gắng giữ tên mô-đun ngắn để không cần phải tách các từ. Và, trên hết, không có không gian tên với dấu gạch dưới;

    ./sample/
    
    2

    Ngoài một số hạn chế đặt tên, không có gì đặc biệt cần thiết để tệp Python trở thành một mô-đun. Nhưng bạn cần hiểu cơ chế nhập để sử dụng đúng khái niệm này và tránh một số vấn đề

    Cụ thể, câu lệnh

    import sys
    sys.path.append("/home/me/mydir")
    
    85 sẽ tìm tệp thích hợp, đó là
    import sys
    sys.path.append("/home/me/mydir")
    
    86 trong cùng thư mục với người gọi, nếu nó tồn tại. Nếu không tìm thấy, trình thông dịch Python sẽ tìm kiếm
    import sys
    sys.path.append("/home/me/mydir")
    
    86 trong “đường dẫn” theo cách đệ quy và đưa ra một ngoại lệ ImportError khi không tìm thấy

    Khi tìm thấy

    import sys
    sys.path.append("/home/me/mydir")
    
    86, trình thông dịch Python sẽ thực thi mô-đun trong một phạm vi biệt lập. Mọi câu lệnh cấp cao nhất trong
    import sys
    sys.path.append("/home/me/mydir")
    
    86 sẽ được thực thi, bao gồm cả các lần nhập khác nếu có. Định nghĩa chức năng và lớp được lưu trữ trong từ điển của mô-đun

    Sau đó, các biến, hàm và lớp của mô-đun sẽ có sẵn cho người gọi thông qua không gian tên của mô-đun, một khái niệm trung tâm trong lập trình đặc biệt hữu ích và mạnh mẽ trong Python

    Trong nhiều ngôn ngữ, một lệnh

    import sys
    sys.path.append("/home/me/mydir")
    
    90 được bộ tiền xử lý sử dụng để lấy tất cả mã được tìm thấy trong tệp và 'sao chép' mã đó vào mã của người gọi. Nó khác với Python. mã đi kèm được tách biệt trong một không gian tên mô-đun, điều đó có nghĩa là bạn thường không phải lo lắng rằng mã đi kèm có thể có tác dụng không mong muốn, e. g. ghi đè một chức năng hiện có cùng tên

    Có thể mô phỏng hành vi tiêu chuẩn hơn bằng cách sử dụng cú pháp đặc biệt của câu lệnh nhập.

    import sys
    sys.path.append("/home/me/mydir")
    
    91. Điều này thường được coi là thực hành xấu. Sử dụng
    import sys
    sys.path.append("/home/me/mydir")
    
    92 làm cho mã khó đọc hơn và làm cho các phần phụ thuộc ít bị ngăn cách hơn

    Sử dụng

    import sys
    sys.path.append("/home/me/mydir")
    
    93 là một cách để xác định chức năng bạn muốn nhập và đặt nó vào không gian tên cục bộ. Mặc dù ít gây hại hơn nhiều so với
    import sys
    sys.path.append("/home/me/mydir")
    
    92 vì nó hiển thị rõ ràng những gì được nhập trong không gian tên cục bộ, nhưng ưu điểm duy nhất của nó so với
    import sys
    sys.path.append("/home/me/mydir")
    
    85 đơn giản hơn là nó sẽ tiết kiệm được một chút thao tác gõ

    Rất tệ

    ./sample/
    
    3

    Tốt hơn

    ./sample/
    
    4

    Tốt nhất

    ./sample/
    
    5

    Như đã đề cập trong phần Kiểu mã , khả năng đọc là một trong những tính năng chính của Python. Khả năng đọc có nghĩa là tránh văn bản soạn sẵn vô dụng và lộn xộn; . Nhưng sự ngắn gọn và tối nghĩa là giới hạn mà sự ngắn gọn nên dừng lại. Có thể biết ngay lập tức một lớp hoặc chức năng đến từ đâu, như trong thành ngữ

    import sys
    sys.path.append("/home/me/mydir")
    
    96, cải thiện đáng kể khả năng đọc và hiểu mã trong tất cả trừ các dự án tệp đơn giản nhất.

    Gói¶

    Python cung cấp một hệ thống đóng gói rất đơn giản, nó chỉ đơn giản là một phần mở rộng của cơ chế mô-đun cho một thư mục

    Bất kỳ thư mục nào có tệp

    import sys
    sys.path.append("/home/me/mydir")
    
    97 đều được coi là gói Python. Các mô-đun khác nhau trong gói được nhập theo cách tương tự như các mô-đun đơn giản, nhưng có hành vi đặc biệt đối với tệp
    import sys
    sys.path.append("/home/me/mydir")
    
    97, được sử dụng để thu thập tất cả các định nghĩa trên toàn gói

    Tệp

    import sys
    sys.path.append("/home/me/mydir")
    
    86 trong thư mục
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    10 được nhập với câu lệnh
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    11. Câu lệnh này sẽ tìm tệp
    import sys
    sys.path.append("/home/me/mydir")
    
    97 trong
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    13 và thực hiện tất cả các câu lệnh cấp cao nhất của nó. Sau đó, nó sẽ tìm một tệp có tên
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    14 và thực thi tất cả các câu lệnh cấp cao nhất của nó. Sau các thao tác này, mọi biến, hàm hoặc lớp được xác định trong
    import sys
    sys.path.append("/home/me/mydir")
    
    86 đều có sẵn trong gói. không gian tên modu

    Một vấn đề thường thấy là thêm quá nhiều mã vào tệp

    import sys
    sys.path.append("/home/me/mydir")
    
    97. Khi độ phức tạp của dự án tăng lên, có thể có các gói con và gói con trong cấu trúc thư mục sâu. Trong trường hợp này, việc nhập một mặt hàng từ gói con phụ sẽ yêu cầu thực thi tất cả các tệp
    import sys
    sys.path.append("/home/me/mydir")
    
    97 đã gặp khi duyệt qua cây

    Để trống tệp

    import sys
    sys.path.append("/home/me/mydir")
    
    97 được coi là thông lệ bình thường và thậm chí là tốt, nếu các mô-đun và gói con của gói không cần chia sẻ bất kỳ mã nào

    Cuối cùng, có sẵn một cú pháp thuận tiện để nhập các gói được lồng sâu.

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    19. Điều này cho phép bạn sử dụng mod thay cho sự lặp lại dài dòng của
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    40

    Lập trình hướng đối tượng¶

    Python đôi khi được mô tả là ngôn ngữ lập trình hướng đối tượng. Điều này có thể gây hiểu nhầm và cần làm rõ thêm

    Trong Python, mọi thứ đều là một đối tượng và có thể được xử lý như vậy. Đây là ý nghĩa khi chúng ta nói, ví dụ, các hàm là đối tượng hạng nhất. Hàm, lớp, chuỗi và thậm chí cả kiểu là các đối tượng trong Python. giống như bất kỳ đối tượng nào, chúng có một loại, chúng có thể được truyền dưới dạng đối số hàm và chúng có thể có các phương thức và thuộc tính. Theo cách hiểu này, Python có thể được coi là một ngôn ngữ hướng đối tượng

    Tuy nhiên, không giống như Java, Python không áp đặt lập trình hướng đối tượng làm mô hình lập trình chính. Hoàn toàn khả thi đối với một dự án Python không hướng đối tượng, tôi. e. không sử dụng hoặc sử dụng rất ít định nghĩa lớp, kế thừa lớp hoặc bất kỳ cơ chế nào khác dành riêng cho ngôn ngữ lập trình hướng đối tượng

    Ngoài ra, như đã thấy trong phần mô-đun, cách Python xử lý các mô-đun và không gian tên cung cấp cho nhà phát triển một cách tự nhiên để đảm bảo việc đóng gói và phân tách các lớp trừu tượng, cả hai đều là những lý do phổ biến nhất để sử dụng hướng đối tượng. Do đó, các lập trình viên Python có nhiều quyền hạn hơn để không sử dụng hướng đối tượng, khi nó không được yêu cầu bởi mô hình kinh doanh

    Có một số lý do để tránh hướng đối tượng không cần thiết. Việc xác định các lớp tùy chỉnh rất hữu ích khi chúng ta muốn gắn một số trạng thái và một số chức năng lại với nhau. Vấn đề, như đã chỉ ra trong các cuộc thảo luận về lập trình chức năng, xuất phát từ phần "trạng thái" của phương trình

    Trong một số kiến ​​trúc, điển hình là các ứng dụng web, nhiều phiên bản của các quy trình Python được sinh ra như một phản hồi đối với các yêu cầu bên ngoài xảy ra đồng thời. Trong trường hợp này, việc giữ một số trạng thái trong các đối tượng được khởi tạo, có nghĩa là giữ một số thông tin tĩnh về thế giới, dễ xảy ra các vấn đề tương tranh hoặc điều kiện chủng tộc. Đôi khi, giữa việc khởi tạo trạng thái của một đối tượng (thường được thực hiện với phương thức

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    41) và việc sử dụng thực tế trạng thái của đối tượng thông qua một trong các phương thức của nó, thế giới có thể đã thay đổi và trạng thái được giữ lại có thể đã lỗi thời. Ví dụ: một yêu cầu có thể tải một mục trong bộ nhớ và đánh dấu nó là đã đọc bởi người dùng. Nếu một yêu cầu khác yêu cầu xóa mục này cùng lúc, thì việc xóa có thể thực sự xảy ra sau khi quá trình đầu tiên tải mục đó và sau đó chúng tôi phải đánh dấu đối tượng đã xóa là đã đọc

    Vấn đề này và các vấn đề khác đã dẫn đến ý tưởng rằng sử dụng các hàm không trạng thái là một mô hình lập trình tốt hơn

    Một cách khác để nói điều tương tự là đề xuất sử dụng các hàm và thủ tục với càng ít ngữ cảnh ngầm và tác dụng phụ càng tốt. Bối cảnh ẩn của hàm được tạo thành từ bất kỳ biến toàn cục hoặc mục nào trong lớp lưu trữ được truy cập từ bên trong hàm. Tác dụng phụ là những thay đổi mà một hàm tạo ra đối với ngữ cảnh ẩn của nó. Nếu một chức năng lưu hoặc xóa dữ liệu trong một biến toàn cục hoặc trong lớp lưu trữ lâu dài, thì nó được cho là có tác dụng phụ

    Việc cô lập cẩn thận các chức năng có ngữ cảnh và tác dụng phụ khỏi các chức năng có logic (được gọi là các chức năng thuần túy) mang lại những lợi ích sau

    • Các chức năng thuần túy là xác định. đưa ra một đầu vào cố định, đầu ra sẽ luôn giống nhau
    • Các chức năng thuần túy dễ thay đổi hoặc thay thế hơn nhiều nếu chúng cần được cấu trúc lại hoặc tối ưu hóa
    • Các hàm thuần túy dễ kiểm tra hơn với các bài kiểm tra đơn vị. Ít cần thiết lập bối cảnh phức tạp và làm sạch dữ liệu sau đó
    • Các chức năng thuần túy dễ thao tác, trang trí và truyền lại hơn

    Tóm lại, các hàm thuần túy là các khối xây dựng hiệu quả hơn các lớp và đối tượng đối với một số kiến ​​trúc vì chúng không có ngữ cảnh hoặc tác dụng phụ

    Rõ ràng, hướng đối tượng là hữu ích và thậm chí cần thiết trong nhiều trường hợp, ví dụ như khi phát triển các ứng dụng hoặc trò chơi đồ họa trên máy tính để bàn, trong đó những thứ được thao tác (cửa sổ, nút, hình đại diện, phương tiện) có thời gian tồn tại tương đối lâu trong máy tính.

    Đồ trang trí¶

    Ngôn ngữ Python cung cấp một cú pháp đơn giản nhưng mạnh mẽ được gọi là 'decorators'. Trình trang trí là một hàm hoặc một lớp bao bọc (hoặc trang trí) một hàm hoặc một phương thức. Hàm hoặc phương thức 'được trang trí' sẽ thay thế hàm hoặc phương thức 'không được trang trí' ban đầu. Bởi vì các hàm là đối tượng hạng nhất trong Python, điều này có thể được thực hiện 'thủ công', nhưng sử dụng cú pháp @decorator sẽ rõ ràng hơn và do đó được ưu tiên hơn

    ./sample/
    
    6

    Cơ chế này rất hữu ích để phân tách các mối quan tâm và tránh logic không liên quan bên ngoài 'làm ô nhiễm' logic cốt lõi của hàm hoặc phương thức. Một ví dụ điển hình về một phần chức năng được xử lý tốt hơn với trang trí là ghi nhớ hoặc lưu vào bộ nhớ đệm. bạn muốn lưu trữ kết quả của một hàm đắt tiền trong một bảng và sử dụng chúng trực tiếp thay vì tính toán lại chúng khi chúng đã được tính toán. Đây rõ ràng không phải là một phần của logic chức năng

    Trình quản lý ngữ cảnh¶

    Trình quản lý bối cảnh là một đối tượng Python cung cấp thêm thông tin theo ngữ cảnh cho một hành động. Thông tin bổ sung này có dạng chạy một hàm có thể gọi được khi bắt đầu ngữ cảnh bằng cách sử dụng câu lệnh

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    42, cũng như chạy một hàm có thể gọi được khi hoàn thành tất cả mã bên trong khối
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    42. Ví dụ nổi tiếng nhất về việc sử dụng trình quản lý ngữ cảnh được hiển thị ở đây, mở trên một tệp

    ./sample/
    
    7

    Bất kỳ ai quen thuộc với mẫu này đều biết rằng việc gọi

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    44 theo cách này đảm bảo rằng phương thức
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    46 của
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    45 sẽ được gọi tại một thời điểm nào đó. Điều này làm giảm tải nhận thức của nhà phát triển và làm cho mã dễ đọc hơn

    Có hai cách dễ dàng để tự thực hiện chức năng này. sử dụng một lớp hoặc sử dụng một trình tạo. Hãy tự triển khai các chức năng trên, bắt đầu với cách tiếp cận lớp

    ./sample/
    
    8

    Đây chỉ là một đối tượng Python thông thường với hai phương thức bổ sung được sử dụng bởi câu lệnh

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    42. Đầu tiên, CustomOpen được khởi tạo và sau đó phương thức
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    48 của nó được gọi và bất kỳ giá trị trả về nào của
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    48 đều được gán cho
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    45 trong phần
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    51 của câu lệnh. Khi nội dung của khối
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    42 được thực thi xong, phương thức
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    53 sau đó được gọi

    Và bây giờ, cách tiếp cận trình tạo bằng ngữ cảnh riêng của Python

    ./sample/
    
    9

    Điều này hoạt động theo cách chính xác giống như ví dụ về lớp ở trên, mặc dù nó ngắn gọn hơn. Hàm

    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    54 thực thi cho đến khi gặp câu lệnh
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    55. Sau đó, nó trao quyền kiểm soát trở lại câu lệnh
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    42, câu lệnh này gán bất kỳ thứ gì đã được
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    55'ed cho f trong phần
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    51. Mệnh đề
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    59 đảm bảo rằng
    ./sample/
    
    00 được gọi cho dù có ngoại lệ bên trong
    README.rst
    LICENSE
    setup.py
    requirements.txt
    sample/__init__.py
    sample/core.py
    sample/helpers.py
    docs/conf.py
    docs/index.rst
    tests/test_basic.py
    tests/test_advanced.py
    
    42 hay không

    Vì hai cách tiếp cận có vẻ giống nhau, chúng ta nên tuân theo Thiền của Python để quyết định khi nào nên sử dụng cách nào. Cách tiếp cận lớp có thể tốt hơn nếu có một lượng logic đáng kể để đóng gói. Cách tiếp cận chức năng có thể tốt hơn cho các tình huống mà chúng ta đang xử lý một hành động đơn giản

    Nhập động¶

    Python được gõ động, có nghĩa là các biến không có kiểu cố định. Trên thực tế, trong Python, các biến rất khác so với các biến trong nhiều ngôn ngữ khác, cụ thể là các ngôn ngữ được nhập tĩnh. Các biến không phải là một phân đoạn của bộ nhớ máy tính nơi một số giá trị được ghi, chúng là 'thẻ' hoặc 'tên' trỏ đến các đối tượng. Do đó, biến 'a' có thể được đặt thành giá trị 1, sau đó là giá trị 'a string', thành hàm

    Kiểu gõ động của Python thường được coi là một điểm yếu và thực sự nó có thể dẫn đến sự phức tạp và mã khó gỡ lỗi. Một cái gì đó có tên 'a' có thể được đặt thành nhiều thứ khác nhau và nhà phát triển hoặc người bảo trì cần theo dõi tên này trong mã để đảm bảo rằng nó không được đặt thành một đối tượng hoàn toàn không liên quan

    Một số hướng dẫn giúp tránh vấn đề này

    • Tránh sử dụng cùng một tên biến cho những thứ khác nhau

    Xấu

    ./sample.py
    
    0

    Tốt

    ./sample.py
    
    1

    Sử dụng các hàm hoặc phương thức ngắn giúp giảm nguy cơ sử dụng cùng tên cho hai thứ không liên quan

    Tốt hơn là sử dụng các tên khác nhau ngay cả đối với những thứ có liên quan, khi chúng có một loại khác

    Xấu

    ./sample.py
    
    2

    Không có hiệu quả đạt được khi sử dụng lại tên. các bài tập sẽ phải tạo các đối tượng mới. Tuy nhiên, khi độ phức tạp tăng lên và mỗi phép gán được phân tách bằng các dòng mã khác, bao gồm các nhánh và vòng lặp 'nếu', thì việc xác định loại biến đã cho trở nên khó khăn hơn.

    Một số phương pháp mã hóa, chẳng hạn như lập trình chức năng, khuyến nghị không bao giờ gán lại một biến. Trong Java, điều này được thực hiện với từ khóa cuối cùng. Python không có từ khóa cuối cùng và dù sao nó cũng đi ngược lại triết lý của nó. Tuy nhiên, có thể là một kỷ luật tốt để tránh gán cho một biến nhiều lần và nó giúp nắm bắt được khái niệm về các loại có thể thay đổi và không thể thay đổi

    Các loại có thể thay đổi và không thể thay đổi¶

    Python has two kinds of built-in or user-defined types

    Mutable types are those that allow in-place modification of the content. Typical mutables are lists and dictionaries. All lists have mutating methods, like

    ./sample/
    
    02 or
    ./sample/
    
    03, and can be modified in place. The same goes for dictionaries

    Immutable types provide no method for changing their content. For instance, the variable x set to the integer 6 has no “increment” method. If you want to compute x + 1, you have to create another integer and give it a name

    ./sample.py
    
    3

    One consequence of this difference in behavior is that mutable types are not “stable”, and therefore cannot be used as dictionary keys

    Using properly mutable types for things that are mutable in nature and immutable types for things that are fixed in nature helps to clarify the intent of the code

    For example, the immutable equivalent of a list is the tuple, created with

    ./sample/
    
    04. This tuple is a pair that cannot be changed in-place, and can be used as a key for a dictionary

    One peculiarity of Python that can surprise beginners is that strings are immutable. This means that when constructing a string from its parts, appending each part to the string is inefficient because the entirety of the string is copied on each append. Instead, it is much more efficient to accumulate the parts in a list, which is mutable, and then glue (

    ./sample/
    
    05) the parts together when the full string is needed. List comprehensions are usually the fastest and most idiomatic way to do this

    Xấu

    ./sample.py
    
    4

    Tốt hơn

    ./sample.py
    
    5

    Tốt nhất

    ./sample.py
    
    6

    One final thing to mention about strings is that using

    ./sample/
    
    06 is not always best. In the instances where you are creating a new string from a pre-determined number of strings, using the addition operator is actually faster. Nhưng trong những trường hợp như trên hoặc trong trường hợp bạn đang thêm vào một chuỗi hiện có, thì sử dụng
    ./sample/
    
    06 sẽ là phương pháp ưa thích của bạn