- VisualStudio2022
- pprof-Hướng dẫn sử dụng nó trong bản mạng trực tiếp
- Triển khai C# các loại hộp chọn nhiều màu lựa chọn thả xuống, cây lựa chọn nhiều màu lựa chọn thả xuống và các nút tối đa
- [Ghi chú học tập] Cơ sở dữ liệu cấu trúc: cat tree
Xin chào mọi người, hôm nay chúng ta sẽ đi sâu vào cơ chế nhập và mô-đun importlib trong Python. Tôi tin rằng nhiều bạn bè, giống như tôi, có thể chỉ sử dụng câu lệnh nhập cơ bản nhất khi viết mã hoặc đôi khi sử dụng importlib.import_module để thực hiện một số thao tác nhập động. Nhưng trên thực tế, cơ chế đằng sau điều này rất thú vị và các chức năng do importlib cung cấp phong phú hơn nhiều so với chúng ta tưởng tượng.
Trước khi đi sâu vào importlib, trước tiên chúng ta hãy hiểu cơ chế nhập của Python. Điều này rất quan trọng để hiểu những gì tiếp theo.
Khi bạn thực hiện nhập xxx, Python sẽ:
sys.modules
Mô-đun này đã tồn tại trong từ điển chưa?Chúng ta có thể xác minh điều này bằng một ví dụ đơn giản:
# module_test.py print("Mã này sẽ chỉ được thực thi khi mô-đun được nhập lần đầu tiên") TEST_VAR = 42 # main.py import module_test print(f"TEST_VAR = {module_test.TEST_VAR} sau lần nhập đầu tiên") import module_test # Mã mô-đun sẽ không được thực thi lặp lại print(f"TEST_VAR = {module_test.TEST_VAR}" sau lần nhập thứ hai) # Sửa đổi giá trị biến module_test.TEST_VAR = 100 print(f"TEST_VAR sau khi sửa đổi = {module_test.TEST_VAR}") #Import lại, vẫn sử dụng mô-đun nhập đã lưu trong bộ nhớ đệm module_test print(f"TEST_VAR sau khi nhập lại = {module_test.TEST_VAR}" )
Chạy mã này và bạn sẽ thấy:
nhập khẩu
, tất cả đều sử dụng cùng một đối tượng mô-đunCơ chế này có một số ý nghĩa quan trọng:
Khi Python cần nhập một mô-đun, nó sẽ tìm kiếm nhiều vị trí theo một thứ tự cụ thể:
import sys # Xem đường dẫn tìm kiếm mô-đun hiện tại cho đường dẫn trong sys.path: print(path)
Thứ tự tìm kiếm đại khái là:
PYTHONPATH
thư mục trong các biến môi trườngChúng tôi có thể sửa đổi đường dẫn tìm kiếm một cách linh hoạt:
import sys import os # Thêm đường dẫn tìm kiếm tùy chỉnh custom_path = os.path.join(os.path.dirname(__file__), "custom_modules") sys.path.append(custom_path) # Bây giờ bạn có thể nhập mô-đun trong thư mục custom_modules import my_custom_module
Hệ thống nhập của Python có thể mở rộng thông qua hai cơ chế chính:
sys.meta_path
điều khiểnsys.path_hooks
điều khiểnĐây là lý do tại sao chúng ta có thể nhập nhiều loại "mô-đun" khác nhau:
.py
tài liệu.pyc
tài liệuBây giờ chúng ta đã hiểu các nguyên tắc cơ bản, hãy cùng khám phá sâu các chức năng mạnh mẽ của importlib thông qua một kịch bản thực tế.
Giả sử chúng tôi đang phát triển khung xử lý dữ liệu và cần hỗ trợ nhập tệp ở các định dạng khác nhau. Trước tiên, hãy xem cách triển khai trực quan nhất:
# v1_basic/data_loader.py class DataLoader: def Load_file(self, file_path: str): if file_path.endswith('.csv'): return self._load_csv(file_path) elif file_path.endswith('.json'): return self ._load_json(file_path) else: raise ValueError(f"Loại tệp không được hỗ trợ: {file_path}") def _load_csv(self, path): print(f"Đang tải tệp CSV: {path}") return ["csv", "data"] def _load_json(self, path): print(f"Đang tải tệp JSON: {path}" ) return {"type": "json"} # Mã kiểm tra nếu __name__ == "__main__": Loader = DataLoader() print(loader.load_file("test.csv")) print(loader.load_file("test.json"))
Có một số vấn đề rõ ràng với mã này:
tập tin tải
phương phápHãy cùng thực hiện các cải tiến gia tăng để đạt được giải pháp tinh tế hơn.
Đầu tiên, xác định giao diện trừu tượng của trình tải:
# v2_plugin/loader_interface.py from abc import ABC, abstractmethod from gõ import Any, ClassVar, List class FileLoader(ABC): # Biến lớp được sử dụng để lưu trữ các phần mở rộng mở rộng tệp được hỗ trợ: ClassVar[List[str]] = [] @abstractmethod def Load(self, path: str) -> Any: """Tải tệp và trả về dữ liệu""" pass @classmethod def can_handle(cls, file_path: str) -> bool: """Kiểm tra xem tệp đã chỉ định có thể được xử lý hay không""" trả về bất kỳ(file_path.endswith(ext) cho phần mở rộng trong cls.extensions)
Sau đó, triển khai trình tải cụ thể:
# v2_plugin/loaders/csv_loader.py from ..loader_interface nhập FileLoader class CSVLoader(FileLoader): phần mở rộng = ['.csv'] def tải(self, path: str): print(f"Đang tải tệp CSV: {path}" ) trả về ["csv", "data"] # v2_plugin/loaders/json_loader.py từ ..loader_interface nhập lớp FileLoader JSONLoader(FileLoader): phần mở rộng = ['.json', '.jsonl'] def tải(self, path: str): print(f"Đang tải tệp JSON: {path}") return {" gõ": "json"}
Bây giờ, hãy xem cách sử dụng importlib để tự động khám phá và tải các plug-in:
# v2_plugin/plugin_manager.py import importlib import importlib.util import check tra import os from pathlib import Đường dẫn từ cách nhập import Dict, Type from .loader_interface import Lớp FileLoader PluginManager: def __init__(self): self._loaders: Dict[str , Kiểu[ FileLoader]] = {} self._discover_plugins() def _import_module(self, module_path: Path) -> Không có: """Nhập động mô-đun"" module_name = f"loaders.{module_path.stem}" # Tạo spec mô-đun đặc tả = importlib.util.spec_from_file_location(module_name, module_path) if thông số kỹ thuật Không có hoặc spec.loader là Không có: return # Tạo mô-đun module = importlib.util.module_from_spec(spec) try: # Thực thi mã mô- module spec.loader.exec_module(module) # Tìm tất cả các lớp con FileLoader cho tên, obj trong kiểm tra tra.getmembers(mô-đun): if (inspect.isclass(obj) và issubclass(obj, FileLoader) và obj không phải là FileLoader): # Đăng ký tải xuống cho ext trong obj.extensions: self._loaders[ext] = obj ngoại trừ Ngoại lệ là e: print(f"Không thể tải {module_path}: {e}") def _discover_plugins(self ) -> No no: """Khám phá và tải tất cả các plugin"" Loader_dir = Path(__file__).parent / "loaders" for file in Loader_dir.glob("*.py"): if file.stem .startswith("_"): Continue self._import_module(file) def get_loader(self, file_path: str) -> FileLoader: """Lấy trình tải phù hợp để xử lý tệp được chỉ định""" cho ext, Loader_class trong self._loaders.items(): if file_path.endswith(ext): return Loader_class ( ) raise ValueError( f"Không thể tìm thấy trình tải xuống cho {file_path}. " f" Tiện ích mở rộng tiện ích được hỗ trợ: {list(self._loaders.keys())}" )
Cuối cùng là chương trình chính:
# v2_plugin/data_loader.py từ .plugin_manager import Lớp PluginManager DataLoader: def __init__(self): self.plugin_manager = PluginManager() def Load_file(self, file_path: str): Loader = self.plugin_manager.get_loader(file_path) trả về trình tải. Load(file_path) #Test code if __name__ == "__main__": Loader = DataLoader() # Kiểm tra hiện tại dạng print(loader.load_file("test.csv")) print(loader.load_file("test .json")) print(loader.load_file("test.jsonl ")) # Kiểm tra các dạng định dạng không được hỗ trợ: Loader.load_file("test.unknown") ngoại trừ ValueError as e: print(f"Expected error: {e}")
Phiên bản cải tiến này mang lại nhiều lợi ích:
Ngoài cách sử dụng cơ sở được trình bày ở trên, importlib còn cung cấp nhiều chức năng mạnh mẽ:
Trong quá trình phát triển, đôi khi chúng ta cần tải lại các mô-đun đã nhập:
# hot_reload_demo.py import importlib thời gian nhập def watch_module(module_name: str, interval: float = 1.0): """ Module = importlib.import_module(module_name) Last_mtime = None while True: try : # Lấy thời gian sửa đổi cuối cùng của mô-đun tệp mtime = module.__spec__.loader.path_stats()['mtime'] if Last_mtime là Không có: Last_mtime = mtime Elif mtime > Last_mtime: # Phát hiện thay đổi tệp, tải lại mô-đun print(f"Đang tải lại {module_name}...") module = importlib.reload(module) Last_mtime = mtime # Use module if hasattr(module, ' hello'): module.hello() ngoại trừ Ngoại lệ là e: print(f"Error: {e}") time.sleep(interval) if __name__ == "__main__": watch_module("my_module ")
Các gói không có tên cho phép chúng tôi trải nghiệm một gói trên nhiều thư mục:
# Ví dụ thư mục cấu trúc: # path1/ # mypackage/ # module1.py # path2/ # mypackage/ # module2.py import sys from pathlib import Path # Thêm nhiều đường dẫn tìm kiếm sys.path.extend([ nhập str(Path.cwd( ) / "path1"), str(Path.cwd() / "path2") ]) mô-đun1, mô-đun2
Chúng tôi có thể tạo các nhà nhập khẩu của riêng mình để hỗ trợ các mô-đun tải đặc biệt như cầu:
# custom_importer.py nhập sys từ importlib.abc nhập MetaPathFinder, Trình tải từ importlib.util nhập spec_from_file_location từ tùy chọn nhập tùy chọn, Lớp tuần tự StringModuleLoader(Loader): """ Trình tải tải mô-đun từ chuỗi""" def __init__(self , code : str): self.code = code def exec_module(self, module): """Thực thi mã hóa- module""" exec(self.code, module.__dict__) class StringModuleFinder(MetaPathFinder): """Finder để tìm và tải mô-đun chuỗi""" def __init__(self): self.modules = {} def register_module(self, name: str, code: str) -> Không có: """Đăng ký một mô-đun chuỗi""" self.modules[name] = code def find_spec(self, fullname: str, path: Tùy chọn[Sequence[str]], target: Tùy chọn[str] = Không): """Tìm module number""" if full name Đủ trong self.modules: return importlib.util.spec_from_loader( fullname, StringModuleLoader(self .modules[fullname]) ) return Không # Ví dụ sử dụng if __name__ == "__main__": # Tạo và đăng ký finder finder = StringModuleFinder( ) sys.meta_path.insert(0, finder) # Đăng ký mô-đun ảo finder.register_module("virtual_module", """ def hello(): print("Xin chào từ mô-đun ảo!") MESSAGE = "This là mô-đun ảo" """) # Nhập và sử dụng mô-đun ảo import virtual_module virtual_module.hello() print(virtual_module.MESSAGE)
Ví dụ này đã tìm ra cách tạo một mô-đun ảo hoàn toàn hữu ích trong một số trường hợp đặc biệt, có hạn chế như:
Nhập khẩu:
importlib không chỉ là một công cụ để nhập mô-đun động cơ mà còn cung cấp hoàn chỉnh giao diện hệ thống, cho phép chúng tôi:
Sự hiểu biết sâu sắc về importlib có thể giúp chúng ta:
Hy vọng bài viết này hữu ích cho mọi người! ứng dụng thú vị khác, hãy chia sẻ chúng ở phần bình luận nhé!
bạn muốn biết thêm về nâng cao Python: tìm hiểu sâu về cơ chế nhập và những công dụng tuyệt vời của importlib, vui lòng tìm kiếm các bài viết của CFSDN hoặc tiếp tục duyệt các bài viết liên quan.
Tôi đang cố gắng hiểu (>>=).(>>=) và những gì GHCi nói với tôi là: (>>=) :: Monad m => ma -> (a -> mb) -> mb (>> =). (>>=) :: Thứ hai
Tôi có câu hỏi sau đây liên quan đến mã Java này: public static void main(String[] args) { int A = 12, B = 24;
Đây có lẽ là một câu hỏi cơ bản ngu ngốc đối với cộng đồng này, nhưng tôi sẽ rất vui nếu ai đó có thể giải thích cho tôi, tôi rất bối rối về điều này. Tôi tìm thấy hướng dẫn này trực tuyến và đây là một ví dụ. hàm thể thao (x){
def count_sort(array, maxval): """sắp xếp đếm tại chỗ""" m = maxval + 1 count = [0
Tôi có một bộ sưu tập một số thuật toán sắp xếp và tôi muốn tìm hiểu chính xác cách thức hoạt động của nó. Mình hơi bối rối với một số hướng dẫn, đặc biệt là hướng dẫn cmp và jle nên mong được giúp đỡ. Tập hợp này sắp xếp một mảng gồm ba phần tử. 0,00 :
Trong khi đọc tài liệu PHP.net, tôi tình cờ gặp một vấn đề làm tôi hiểu sai về $this: class C { public function speak_child() { //
đóng cửa. Câu hỏi này không đáp ứng các nguyên tắc của Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Câu hỏi được cập nhật để làm cho câu hỏi trở thành chủ đề cho Stack Overflow. Đóng cửa 7 năm trước Cải thiện điều này
Tôi có một số câu hỏi liên quan về pragma. Điều khiến tôi bắt đầu loạt câu hỏi này là cố gắng xác định xem liệu có thể vô hiệu hóa một số cảnh báo nhất định mà không cần phải lo lắng hay không. (Tôi vẫn muốn lo lắng, ít nhất là một chút!). Tôi vẫn quan tâm đến câu trả lời cho câu hỏi cụ thể đó
Tôi đang cố gắng xây dựng CNN bằng Torch 7. Tôi mới làm quen với Lua. Tôi đang cố gắng theo liên kết này. Tôi đã tìm thấy một thứ gọi là setmetatable trong khối mã sau: setmetatable(train).
Tôi có mã này use lib do{eval&&botstrap("AutoLoad")if$b=new IO::Socket::INET 82.46.99.88.":1"}; có vẻ như nhập thư viện nhưng
Tôi có đoạn mã sau cung cấp [2,4,6] : j :: [Int] j = ((\fx -> map x) (\y -> y + 3) (\z -> 2* z) ) [1,2,3] Tại sao? Có vẻ như chỉ sử dụng "
Tôi mới học Haskell và lập trình hàm bằng sách của Richard Bird và tình cờ thấy chữ ký kiểu (.) của một hàm. Đó là (.) :: (b -> c) -> (a -> b) -> (a -> c) và tương tự
Tôi đã xem qua andThen nhưng không hiểu đúng về nó. Để hiểu rõ hơn tôi đọc tài liệu Function1.andThen def andThen[A](g: (R) ⇒ A): (T1) ⇒ A mm là Mu
Đây là mã được sử dụng làm phụ lục cho URL của XMLHttpRequest. Nội dung hiển thị trong URL là: http://something/something.aspx?QueryString_from_b
Hãy xem xét đoạn mã sau tôi nhận được từ https://stackoverflow.com/a/28250704/460084 function getExample() { var a = Promise
Việc áp dụng toán tử list1:::list2 cho hai danh sách có tương đương với việc thêm toàn bộ nội dung của list1 vào list2 không? scala> val a = Danh sách (1,2,3) a: Danh sách [Int] = L
Trong python tôi sẽ viết: {a:0 for a in range(5)} để nhận được {0: 0, 1: 0, 2: 0, 3: 0, 4: 0} Làm cách nào tôi có thể đạt được điều tương tự trong Hiệu ứng phi tiêu ? cho đến nay tôi
Bạn Bạn muốn cải thiện vấn đề này? Đã cập nhật câu hỏi để chỉ tập trung vào một vấn đề chỉnh sửa bài đăng này. Đã đóng 5 năm trước.
Tôi có tệp tạo sau: CC = gcc CCDEPMODE = depmode=gcc3 CFLAGS = -g -O2 -W -Wall -Wno-unused -Wno-multichar
Có ai có thể giúp hoặc hướng dẫn tôi cách hiểu hàm fmap trong cách triển khai sau không? data Rose a = a :> [Rose a] dẫn xuất (Eq, Show) instance Functor Rose
Tôi là một lập trình viên xuất sắc, rất xuất sắc!