Trong bài đăng này, chúng ta sẽ hiểu Lazy import trong Python là gì? . Hãy xem các câu lệnh nhập bên dưới bằng Python
import numpy as np import pandas as pd import matplotlib.pyplot as plt import sklearn import nltk import os import sys import re import seaborn as sns import pickle
Và danh sách được tiếp tục. Thông thường trong một dự án khoa học dữ liệu lớn, chúng tôi cần nhập thêm nhiều thư viện vào mã của mình. Trong những trường hợp như vậy, chúng ta có thể tránh sử dụng nhiều câu lệnh nhập bằng cách sử dụng một câu lệnh nhập duy nhất sẽ nhập thư viện pyforest. Thư viện này, sau khi được nhập, sẽ lười nhập gần như tất cả thư viện khoa học dữ liệu mà chúng tôi sẽ phải sử dụng trong dự án của mình
Để sử dụng thư viện này, trước tiên chúng ta cần cài đặt nó trong hệ thống của mình. Sử dụng lệnh sau để cài đặt pyforest
pip install pyforest
Để lười nhập tất cả các thư viện có sẵn trong pyforest, chúng ta sẽ cần nhập nó vào chương trình của mình như trong đoạn mã dưới đây
Một trong những tính năng mới trong Python 3. 7 là PEP 562 bổ sung hỗ trợ cho __getattr__[]
và __dir__[]
trên các mô-đun. Cả hai đều mở ra một số khả năng thú vị. Chẳng hạn, với __dir__[]
, giờ đây bạn có thể có
pip install pyforest0 chỉ hiển thị những gì mà
pip install pyforest1 định nghĩa
Nhưng quá đắm chìm trong hệ thống nhập của Python, mối quan tâm của tôi nằm ở __getattr__[]
và cách nó có thể được sử dụng để nhập chậm. Bây giờ tôi sẽ bắt đầu bài đăng này bằng cách tuyên bố rằng hầu hết mọi người không cần nhập khẩu lười biếng. Chỉ khi chi phí ban đầu là tối quan trọng thì điều này mới phát huy tác dụng, e. g. Các ứng dụng CLI có thời gian chạy ngắn. Đối với hầu hết mọi người, những tiêu cực đối với việc lười tải là không đáng, e. g. biết nhiều sau này khi nhập không thành công thay vì khởi chạy ứng dụng
Theo truyền thống, có hai cách để thực hiện nhập chậm/chậm. Cái cũ nhất đang thực hiện nhập cục bộ thay vì nhập toàn cầu [i. e. nhập trong chức năng của bạn thay vì ở đầu mô-đun của bạn]. Mặc dù điều này có tác dụng trì hoãn quá trình nhập cho đến khi bạn chạy mã thực sự cần mô-đun mà bạn đang nhập, nhưng nó lại gây bất lợi khi phải viết đi viết lại cùng một câu lệnh nhập. Và nếu bạn chỉ thực hiện một số nhập cục bộ, bạn sẽ dễ dàng quên những cái bạn đang cố tránh và sau đó vô tình nhập mô-đun trên toàn cầu. Vì vậy, phương pháp này hoạt động, nó chỉ không lý tưởng
Cách tiếp cận khác là sử dụng lazy loader được cung cấp trong
pip install pyforest3. Giờ đây, nhiều người như Google, Facebook và Mercurial đã sử dụng thành công trình tải chậm này. Hai người đầu tiên thích nó để giảm thiểu chi phí khi chạy thử nghiệm trong khi người cuối cùng muốn khởi động nhanh. Một ưu điểm đối với trình tải lười biếng so với nhập cục bộ là bạn có thể kích hoạt sớm
# In pkg/__init__.py with a pkg/sub.py.
mod, __getattr__ = lazy_import[__name__, {'sys', '.sub as thingy'}]
def test1[]:
return mod.sys
def test2[]:
return mod.thingy.answer
0 khi việc tìm kiếm một mô-đun được thực hiện một cách háo hức, chỉ là quá trình tải bị hoãn lạiHầu hết mọi người cũng thiết lập nó để mọi thứ được tải một cách lười biếng. Bây giờ đó là một điều tốt và xấu. Nó tốt ở chỗ bạn phải làm rất ít để khiến mọi thứ tải một cách lười biếng. Điều tồi tệ là khi bạn làm điều gì đó không rõ ràng, cuối cùng bạn có thể phá vỡ những kỳ vọng mà mã đó có [có một lý do là "rõ ràng tốt hơn là không rõ ràng"]. Nếu một mô-đun mong muốn được tải háo hức thì nó có thể bị hỏng nặng khi được tải một cách lười biếng. Mercurial thực sự đã phát triển một danh sách đen các mô-đun không tải một cách lười biếng để giải quyết vấn đề này, nhưng họ phải đảm bảo luôn cập nhật nó để nó không phải là một giải pháp hoàn hảo
Trong Trăn 3. 7, các mô-đun hiện có thể có __getattr__[]
được xác định trên chúng, cho phép một người viết một hàm sẽ nhập một mô-đun khi nó không có sẵn dưới dạng thuộc tính trên mô-đun. Điều này có nhược điểm là làm cho nó trở thành một quá trình nhập lười biếng thay vì tải và do đó phát hiện ra rất muộn nếu một
# In pkg/__init__.py with a pkg/sub.py.
mod, __getattr__ = lazy_import[__name__, {'sys', '.sub as thingy'}]
def test1[]:
return mod.sys
def test2[]:
return mod.thingy.answer
0 sẽ được nâng lên. Nhưng nó rõ ràng và vẫn được xác định trên toàn cầu cho mô-đun của bạn, vì vậy việc kiểm soát sẽ dễ dàng hơnBản thân mã thực sự không phức tạp
import importlib
def lazy_import[importer_name, to_import]:
"""Return the importing module and a callable for lazy importing.
The module named by importer_name represents the module performing the
import to help facilitate resolving relative imports.
to_import is an iterable of the modules to be potentially imported [absolute
or relative]. The `as` form of importing is also supported,
e.g. `pkg.mod as spam`.
This function returns a tuple of two items. The first is the importer
module for easy reference within itself. The second item is a callable to be
set to `__getattr__`.
"""
module = importlib.import_module[importer_name]
import_mapping = {}
for name in to_import:
importing, _, binding = name.partition[' as ']
if not binding:
_, _, binding = importing.rpartition['.']
import_mapping[binding] = importing
def __getattr__[name]:
if name not in import_mapping:
message = f'module {importer_name!r} has no attribute {name!r}'
raise AttributeError[message]
importing = import_mapping[name]
# imortlib.import_module[] implicitly sets submodules on this module as
# appropriate for direct imports.
imported = importlib.import_module[importing,
module.__spec__.parent]
setattr[module, name, imported]
return imported
return module, __getattr__
Để sử dụng nó, bạn có thể làm như sau
# In pkg/__init__.py with a pkg/sub.py.
mod, __getattr__ = lazy_import[__name__, {'sys', '.sub as thingy'}]
def test1[]:
return mod.sys
def test2[]:
return mod.thingy.answer
Khi thiết kế cái này, phần khó nhất là làm thế nào để mô phỏng cú pháp
# In pkg/__init__.py with a pkg/sub.py.
mod, __getattr__ = lazy_import[__name__, {'sys', '.sub as thingy'}]
def test1[]:
return mod.sys
def test2[]:
return mod.thingy.answer
3 để tránh xung đột tên. Cuối cùng tôi đã chấp nhận một chuỗi gần giống với câu lệnh nhập mà bạn đã viết nếu bạn thực hiện nhập toàn cầu. Tôi có thể chia nó thành một đối số thứ ba lấy ánh xạ, nhưng tôi nghĩ điều đó là không cần thiết và tôi muốn có một API thống nhất hơnDù sao, tôi luôn hài lòng khi tôi có thể làm điều gì đó như thế này chỉ trong 20 dòng mã Python và cảm thấy như đó không phải là một vụ hack hoàn toàn. 😉