Tự động tải IPython không hoạt động

Bạn có thể làm việc trên một mô-đun python mới và kiểm tra nó trong môi trường máy tính xách tay. Nhưng khi mã mô-đun của bạn thay đổi, bạn phải tải lại mô-đun trong môi trường sổ ghi chép

giải pháp đơn giản. Sử dụng tính năng tự động tải lại để đảm bảo phiên bản mới nhất của mô-đun được sử dụng

Tải lại các mô-đun trong sổ ghi chép bằng cách

%load_ext autoreload
%autoreload 2

Mô-đun

# in auto.py
def my_api[model, year]:
    # dummy result
    return { 'model': model, 'year': year, }

# in auto2.py
def my_api2[model, year]:
    # dummy result
    return { 'model': model, 'year': year, }
9 không được bật theo mặc định. Vì vậy, bạn phải tải nó dưới dạng tiện ích mở rộng

Và mỗi khi bạn thực thi một số mã, IPython sẽ nhập lại tất cả các mô-đun để đảm bảo rằng bạn đang sử dụng các phiên bản mới nhất có thể

Có 3 tùy chọn cấu hình mà bạn có thể thiết lập

  • # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    0. Vô hiệu hóa tự động tải lại. Đây là thiết lập mặc định

  • # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    1. Sẽ chỉ tự động tải lại các mô-đun đã được nhập bằng hàm %aimport [e. g %aimport my_module]. Đó là một lựa chọn tốt nếu bạn chỉ muốn tự động tải lại cụ thể một mô-đun đã chọn

  • # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    2. tự động tải lại tất cả các mô-đun. Cách tuyệt vời để viết và kiểm tra các mô-đun của bạn dễ dàng hơn nhiều

    Địa chỉ email ẩn danh cho nhóm này hoặc bạn cần có quyền xem địa chỉ email thành viên để xem thư gốc

    đến Pyzo, marco. mo. @i-m3d. com

    Hi, cảm ơn bạn đã trả lời. Có, tôi đã kích hoạt nó, thật tốt khi biết rằng nó chỉ hoạt động khi chạy dưới dạng tập lệnh. Tôi đã cố gắng để nó hoạt động khi chọn một loạt các dòng và nhấn F9

    Tôi cố gắng thực hiện tất cả quá trình phát triển Python tương tác của mình bằng sổ ghi chép Jupyter hoặc phiên IPython. Một trong những lý do chính khiến tôi thích những môi trường này là 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    3 ma thuật. Điều gì đặc biệt về 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    3 và tại sao nó thường làm cho quá trình phát triển nhanh hơn và đơn giản hơn?

    Tại sao lại là IPython và Jupyter?

    Trước khi tiếp tục, nếu bạn chưa sử dụng cả IPython và Jupyter, trước tiên hãy xem hướng dẫn tương tác ipython. Giải thích lý do tại sao sử dụng IPython tốt hơn trình thông dịch Python mặc định. Nó có rất nhiều tính năng hữu ích, nhưng trong bài viết này tôi sẽ chỉ nói về một tính năng [phép thuật] và cụ thể là một trong những phép thuật đó [

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    3]. Sổ ghi chép Jupyter, như IPython, hỗ trợ hầu hết các phép thuật giống nhau, vì vậy phần lớn hướng dẫn sẽ hoạt động trong phiên IPython tương tác hoặc phiên sổ ghi chép Jupyter. Một điều cần lưu ý là tôi đang nói về Python ở đây, không phải các ngôn ngữ khác chạy trong sổ ghi chép Jupyter

    một phép thuật là gì?

    Phép thuật chỉ là các chức năng đặc biệt mà bạn có thể gọi trong phiên IPython hoặc Jupyter của mình. Chúng có hai dạng. dòng và ô. Phép thuật dòng có tiền tố là một

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    0, phép thuật ô có tiền tố là hai,
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    1. Phép thuật dòng tiêu thụ một dòng, trong khi phép thuật ô tiêu thụ các dòng bên dưới phép thuật, cho phép nhập nhiều hơn. Đối với bài viết này, chúng ta sẽ chỉ xem xét một trong các phép thuật đường nét, phép thuật 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }

    Tại sao tự động tải lại?

    Phép thuật 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    3 thay đổi phiên Python để các mô-đun được tự động tải lại trong phiên đó trước khi bắt đầu thực thi mã được nhập tại dấu nhắc IPython [hoặc ô của sổ ghi chép Jupyter]. Điều này có nghĩa là các mô-đun được tải vào phiên của bạn có thể được sửa đổi [bên ngoài phiên của bạn] và các thay đổi sẽ được phát hiện và tải lại mà bạn không cần phải khởi động lại phiên của mình

    Điều này có thể rất hữu ích. Hãy để tôi mô tả một tình huống điển hình. Giả sử bạn có một sổ ghi chép Jupyter mà bạn đã tạo và đang nâng cấp, đồng thời bạn yêu cầu dữ liệu từ một số nguồn. Bạn lấy dữ liệu bằng cách thực thi các hàm trong các mô-đun bạn nhập vào đầu phiên của mình và các mô-đun đó là mã Python mà bạn kiểm soát. Đây sẽ là một trường hợp sử dụng rất điển hình cho nhiều người dùng. Hơn nữa, giả sử trong sổ ghi chép của bạn, bạn tải tất cả dữ liệu vào bộ nhớ và quá trình này mất đủ 5 phút. Sau đó, bạn bắt đầu làm việc với dữ liệu và sớm nhận ra rằng bạn cần dữ liệu hơi khác so với một trong các chức năng của một trong các mô-đun mà bạn kiểm soát, vì vậy bạn cần thêm một tham số khác để truy vấn dữ liệu theo cách khác. làm thế nào để bạn

    1. Thực hiện thay đổi này
    2. Kiểm tra sự thay đổi này
    3. Tiếp tục công việc của bạn

    Trong hầu hết các trường hợp, bạn sẽ mở mã cơ bản trong trình chỉnh sửa hoặc IDE của mình, sửa đổi mã, kiểm tra mã đó trong một phiên khác [hoặc với kiểm tra đơn vị], sau đó tùy ý cài đặt các thay đổi cục bộ. Nhưng còn sổ ghi chép đã tải sẵn một số dữ liệu thì sao?

    Nhưng có một cách tốt hơn, sử dụng 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    4. Trong phiên Jupyter của bạn, trước tiên bạn tải tiện ích mở rộng 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    4, sử dụng phép thuật 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    6

    %load_ext autoreload

    Bây giờ, phép thuật 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    3 có sẵn trong phiên của bạn. Nó có thể lấy một đối số chỉ định cách 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    4ing của các mô-đun sẽ hoạt động. Tiện ích mở rộng cũng cung cấp một phép thuật khác, 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    9, cho phép kiểm soát chi tiết những mô-đun nào bị ảnh hưởng bởi quá trình tải lại tự động. Nếu không có đối số nào được cung cấp cho
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    3, thì nó sẽ tải lại tất cả các mô-đun ngay lập tức [ngoại trừ những mô-đun bị loại trừ bởi
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    9 như bên dưới]. Bạn có thể chạy nó một lần và sau đó sử dụng mã đã cập nhật của mình

    Đối số tùy chọn cho 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    4 có ba giá trị hợp lệ

    • 0 – tắt tải lại tự động
    • 1 – mỗi lần tải lại tất cả các mô-đun do 
      # in auto.py
      def my_api[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      
      # in auto2.py
      def my_api2[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      9 nhập trước khi thực thi mã Python đã được nhập
    • 2 – tải lại tất cả các mô-đun [ngoại trừ những mô-đun bị loại trừ bởi 
      # in auto.py
      def my_api[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      
      # in auto2.py
      def my_api2[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      9] mỗi lần trước khi thực thi mã Python đã được nhập

    Để điều chỉnh các mô-đun bị ảnh hưởng bởi 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    4, hãy sử dụng phép thuật 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    9. Nó hoạt động như sau

    • không có đối số – liệt kê các mô-đun sẽ được nhập hoặc không được nhập
    • với một đối số – mô-đun được cung cấp sẽ được nhập bằng 
      # in auto.py
      def my_api[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      
      # in auto2.py
      def my_api2[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      57
    • với các đối số được phân tách bằng dấu phẩy – tất cả các mô-đun trong danh sách sẽ được nhập bằng 
      # in auto.py
      def my_api[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      
      # in auto2.py
      def my_api2[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      57
    • với đối số 
      # in auto.py
      def my_api[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      
      # in auto2.py
      def my_api2[model, year]:
          # dummy result
          return { 'model': model, 'year': year, }
      59 trước – mô-đun đó sẽ không được tự động tải lại

    Đối với tôi, cách phổ biến nhất mà tôi sử dụng 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    3 là chỉ bao gồm mọi thứ trong quá trình phát triển ban đầu của mình khi tôi có khả năng thay đổi các mô-đun Python và mã sổ ghi chép [tôi. e. để chạy
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    81] và hoàn toàn không sử dụng nó. Nhưng có quyền kiểm soát có thể hữu ích, đặc biệt nếu bạn đang tải nhiều mô-đun

    Thí dụ

    Đối với một ví dụ cụ thể mà bạn có thể sử dụng để làm theo, hãy tạo hai tệp Python, 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    82 và 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    83, rồi lưu chúng cùng với sổ ghi chép Jupyter với các mục nhập bên dưới. Mỗi tệp Python phải có một chức năng đơn giản trong đó, như sau

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }

    Bây giờ, hãy nhập cả hai mô-đun và kiểm tra các phương thức API bằng cách sử dụng trợ giúp IPython/Jupyter bằng cách nối thêm 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    84 vào hàm. Bạn sẽ thấy mô-đun đã nhập khớp với mã của bạn trong tệp Python

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    5
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    8

    Bây giờ, trong một trình chỉnh sửa riêng biệt, hãy thêm đối số thứ ba [có thể phải nhận đối số thứ ba là

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    85] vào hàm 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    86. Lưu các tập tin. Chúng ta có thấy nó không?

    Chưa, chưa. Hãy bật tự động tải lại

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    7

    Bây giờ, khi tôi kiểm tra

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    86, tôi thấy đối số mới. Nó đã làm việc

    Bây giờ, tôi có thể sửa đổi cài đặt để chỉ mô-đun 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    88 được tải lại chứ không phải 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    89. Nhưng trước tiên, hãy xem các mô-đun để tải lại và bỏ qua. Theo mặc định, nó bao gồm tất cả các mô-đun và không bỏ qua mô-đun nào [vì tôi đã sử dụng
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    70 làm đối số ban đầu]

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    2

    Hãy tắt đi 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    89

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    4

    Bây giờ, nếu tôi sửa đổi mã trong

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    89, thì tôi sẽ không thấy các thay đổi trong phiên này. Sử dụng 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    9 bạn có thể hạn chế mã nào đang được tải lại

    Hãy cẩn thận

    Điều quan trọng cần lưu ý là tải lại mô-đun không hoàn hảo. Bạn không nên bật mã này cho mã sản xuất, nó sẽ làm mọi thứ chậm lại. Ngoài ra, nếu bạn đang chỉnh sửa trực tiếp mã của mình và để mã ở trạng thái bị hỏng, thì mã được tải thành công gần đây nhất sẽ là mã đang chạy trong phiên của bạn, vì vậy mã này có thể khiến bạn bối rối. Đây có thể không phải là cách bạn muốn sửa đổi một lượng lớn mã, nhưng khi thực hiện các thay đổi gia tăng, nó có thể hoạt động tốt

    Để quan sát mã bị hỏng trông như thế nào, hãy mở mô-đun đang được tự động tải lại [

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    83] và thêm lỗi cú pháp [ví dụ: có thể đặt dấu ngoặc không khớp ở đâu đó] và lưu tệp, sau đó thực hiện chức năng từ mô-đun đó trong sổ ghi chép . Bạn sẽ thấy 
    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    4 báo cáo truy nguyên lỗi cú pháp trong ô. Bạn sẽ chỉ thấy lỗi này một lần, nếu bạn thực hiện lại ô, nó sẽ không hiển thị cho bạn lỗi tương tự mà sẽ sử dụng phiên bản mã được tải lần cuối

    Ngoài ra, hãy lưu ý rằng có một số thứ không phải lúc nào cũng hoạt động, chẳng hạn như xóa các hàm khỏi mô-đun, thay đổi @property trong một lớp thành một phương thức thông thường hoặc tải lại các tiện ích mở rộng của C. Trong những trường hợp đó, bạn sẽ cần khởi động lại phiên của mình. Bạn có thể xem thêm chi tiết trong tài liệu

    Bản tóm tắt

    Nếu bạn chưa từng sử dụng 

    # in auto.py
    def my_api[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    
    # in auto2.py
    def my_api2[model, year]:
        # dummy result
        return { 'model': model, 'year': year, }
    3 trước đây, hãy dùng thử vào lần tới khi bạn có phiên IPython hoặc Jupyter chứa nhiều dữ liệu trong đó và muốn thực hiện một thay đổi nhỏ đối với mô-đun cục bộ. Hy vọng rằng nó sẽ giúp bạn tiết kiệm thời gian

    Bạn có thể muốn xem bài viết này về cách bạn có thể sử dụng các phép thuật khác để xem các biến của mình trong phiên Jupyter hoặc IPython

    Chia sẻ cái này

    • Twitter
    • Facebook
    • LinkedIn
    • reddit

    Đừng bỏ lỡ bất kỳ bài viết nào

    Nếu bạn thích bài viết này, hãy gửi email cho tôi và tôi sẽ gửi cho bạn các bài viết mới nhất cùng với các liên kết và mẹo hữu ích khác, tập trung vào Python, pandas và các công cụ liên quan

    Autoreload trong IPython là gì?

    autoreload tự động tải lại các mô-đun trước khi bắt đầu thực thi mã được nhập tại dấu nhắc IPython .

    autoreload jupyter là gì?

    Ma thuật %autoreload thay đổi phiên Python để các mô-đun được tự động tải lại trong phiên đó trước khi bắt đầu thực thi mã được nhập tại dấu nhắc IPython [or the Jupyter notebook cell].

    Phần mở rộng Python trong Jupyter là gì?

    Tại sao nên sử dụng Tiện ích mở rộng Jupyter? . Các phần mở rộng này có thể tự động định dạng mã, cung cấp thông tin trong khi ô đang chạy và hiển thị thông báo trình duyệt khi quá trình thực thi mã kết thúc. simple add-ons that improve the Jupyter Notebook environment's core features. These extensions can autoformat the code, provide information while the cell is running, and display a browser message when code execution is finished.

    IPython được sử dụng để làm gì?

    IPython [Interactive Python] là trình bao lệnh dành cho tính toán tương tác bằng nhiều ngôn ngữ lập trình , ban đầu được phát triển cho ngôn ngữ lập trình Python, cung cấp .

Chủ Đề