Ada dua masalah dasar yang Anda hadapi di sini:
__xxx__
metode hanya dicari di kelas
TypeError: can't set attributes of built-in/extension type 'module'
(1) berarti solusi apa pun juga harus melacak modul mana yang sedang diperiksa, jika tidak, setiap modul akan memiliki perilaku substitusi-instance; dan (2) berarti bahwa (1) bahkan tidak mungkin ... setidaknya tidak secara langsung.
Untungnya, sys.modules tidak pilih-pilih tentang apa yang ada di sana sehingga pembungkus akan berfungsi, tetapi hanya untuk akses modul (yaitu import somemodule; somemodule.salutation('world')
; untuk akses modul yang sama Anda harus mencabut metode dari kelas substitusi dan menambahkannya ke globals()
eiher dengan metode kustom di kelas (saya suka menggunakan .export()
) atau dengan fungsi umum (seperti yang sudah terdaftar sebagai jawaban). Satu hal yang perlu diingat: jika pembungkus selalu membuat instance baru, dan solusi global tidak, Anda berakhir dengan perilaku yang agak berbeda. Oh, dan Anda tidak dapat menggunakan keduanya pada saat yang sama - itu salah satu.
Memperbarui
Dari Guido van Rossum :
Sebenarnya ada peretasan yang kadang-kadang digunakan dan direkomendasikan: modul dapat mendefinisikan kelas dengan fungsionalitas yang diinginkan, dan kemudian pada akhirnya, mengganti dirinya sendiri di sys.modules dengan instance kelas itu (atau dengan kelas, jika Anda bersikeras , tapi itu umumnya kurang berguna). Misalnya:
# module foo.py
import sys
class Foo:
def funct1(self, <args>): <code>
def funct2(self, <args>): <code>
sys.modules[__name__] = Foo()
Ini berfungsi karena mesin impor secara aktif mengaktifkan peretasan ini, dan sebagai langkah terakhirnya menarik modul aktual dari sys.modules, setelah memuatnya. (Ini bukan kebetulan. Peretasan sudah lama diusulkan dan kami memutuskan bahwa kami cukup menyukainya untuk mendukungnya di mesin impor.)
Jadi cara yang mapan untuk mencapai apa yang Anda inginkan adalah dengan membuat satu kelas dalam modul Anda, dan sebagai tindakan terakhir modul ganti sys.modules[__name__]
dengan instance kelas Anda - dan sekarang Anda dapat bermain dengan __getattr__
/ __setattr__
/ __getattribute__
sesuai kebutuhan.
Catatan 1 : Jika Anda menggunakan fungsionalitas ini, apa pun yang ada di modul, seperti global, fungsi lain, dll., Akan hilang saat sys.modules
tugas dibuat - jadi pastikan semua yang diperlukan ada di dalam kelas pengganti.
Catatan 2 : Untuk mendukung from module import *
Anda harus __all__
didefinisikan di kelas; sebagai contoh:
class Foo:
def funct1(self, <args>): <code>
def funct2(self, <args>): <code>
__all__ = list(set(vars().keys()) - {'__module__', '__qualname__'})
Bergantung pada versi Python Anda, mungkin ada nama lain untuk dihilangkan __all__
. The set()
dapat dihilangkan jika Python 2 kompatibilitas tidak diperlukan.