Có hai vấn đề cơ bản mà bạn đang gặp phải ở đây:
__xxx__
phương thức chỉ được tra cứu trên lớp
TypeError: can't set attributes of built-in/extension type 'module'
(1) có nghĩa là bất kỳ giải pháp nào cũng sẽ phải theo dõi mô-đun nào đang được kiểm tra, nếu không thì mọi mô-đun sau đó sẽ có hành vi thay thế cá thể; và (2) có nghĩa là (1) thậm chí không thể ... ít nhất là không trực tiếp.
May mắn thay, sys.modules không kén chọn những gì ở đó nên trình bao bọc sẽ hoạt động, nhưng chỉ để truy cập mô-đun (nghĩa là import somemodule; somemodule.salutation('world')
đối với truy cập cùng mô-đun, bạn phải sử dụng các phương thức từ lớp thay thế và thêm chúng vào globals()
một cách xa hơn phương thức tùy chỉnh trên lớp (tôi thích sử dụng .export()
) hoặc với một hàm chung (chẳng hạn như các hàm đã được liệt kê dưới dạng câu trả lời). Một điều cần lưu ý: nếu trình bao bọc tạo ra một thể hiện mới mỗi lần, và giải pháp toàn cầu thì không, bạn kết thúc với hành vi khác nhau một cách tinh tế. Ồ, và bạn không được sử dụng cả hai cùng một lúc - đó là một hoặc khác.
Cập nhật
Từ Guido van Rossum :
Thực sự có một hack đôi khi được sử dụng và khuyến nghị: một mô-đun có thể định nghĩa một lớp có chức năng mong muốn, và cuối cùng, thay thế nó trong sys.modules bằng một thể hiện của lớp đó (hoặc với lớp, nếu bạn nhấn mạnh , nhưng nói chung là ít hữu ích hơn). Ví dụ:
# module foo.py
import sys
class Foo:
def funct1(self, <args>): <code>
def funct2(self, <args>): <code>
sys.modules[__name__] = Foo()
Điều này hoạt động vì máy móc nhập khẩu đang tích cực kích hoạt hack này và khi bước cuối cùng của nó kéo mô-đun thực tế ra khỏi sys.modules, sau khi tải nó. (Đây không phải là tình cờ. Vụ hack đã được đề xuất từ lâu và chúng tôi quyết định chúng tôi thích đủ để hỗ trợ nó trong máy móc nhập khẩu.)
Vì vậy, cách được thiết lập để thực hiện những gì bạn muốn là tạo một lớp duy nhất trong mô-đun của bạn và là hành động cuối cùng của mô-đun thay thế sys.modules[__name__]
bằng một thể hiện của lớp của bạn - và bây giờ bạn có thể chơi với __getattr__
/ __setattr__
/ __getattribute__
khi cần.
Lưu ý 1 : Nếu bạn sử dụng chức năng này thì mọi thứ khác trong mô-đun, chẳng hạn như toàn cầu, các chức năng khác, v.v., sẽ bị mất khi sys.modules
thực hiện chuyển nhượng - vì vậy hãy đảm bảo mọi thứ cần thiết đều nằm trong lớp thay thế.
Lưu ý 2 : Để hỗ trợ from module import *
bạn phải __all__
xác định trong lớp; ví dụ:
class Foo:
def funct1(self, <args>): <code>
def funct2(self, <args>): <code>
__all__ = list(set(vars().keys()) - {'__module__', '__qualname__'})
Tùy thuộc vào phiên bản Python của bạn, có thể có các tên khác để bỏ qua __all__
. Có set()
thể bỏ qua nếu không cần khả năng tương thích Python 2.