Dengan properti python, saya bisa membuatnya seperti itu
obj.y
memanggil fungsi, bukan hanya mengembalikan nilai.
Apakah ada cara untuk melakukan ini dengan modul? Saya memiliki kasus yang saya inginkan
module.y
untuk memanggil fungsi, bukan hanya mengembalikan nilai yang disimpan di sana.
python
properties
python-module
Josh Gibson
sumber
sumber
__getattr__
modul untuk solusi yang lebih modern.Jawaban:
Hanya instance dari kelas gaya baru yang dapat memiliki properti. Anda dapat membuat Python percaya bahwa instance seperti itu adalah modul dengan menyimpannya
sys.modules[thename] = theinstance
. Jadi, misalnya, file modul m.py Anda bisa jadi:sumber
types.ModuleType
seperti yang ditunjukkan dalam jawaban @ Tidak diketahui yang sebaliknya sangat mirip?builtins.module
dalamnya mereka adalah contoh , yang dengan sendirinya merupakan turunantype
(yang merupakan definisi dari kelas gaya baru). Masalahnya adalah bahwa sifat harus berada di kelas, tidak contoh: jika Anda melakukannyaf = Foo()
,f.some_property = property(...)
itu akan gagal dengan cara yang sama seperti jika Anda naif memasukkannya ke dalam modul. Solusinya adalah dengan meletakkannya di kelas, tetapi karena Anda tidak ingin semua modul memiliki properti, Anda membuat subkelas (lihat jawaban tidak diketahui).globals()
(menjaga kunci tetap utuh tetapi mengatur ulang nilainya keNone
) pada rebinding namasys.modules
adalah masalah Python 2 - Python 3.4 berfungsi sebagaimana mestinya. Jika Anda memerlukan akses ke objek kelas di Py2, tambahkan misalnya_M._cls = _M
tepat setelahclass
pernyataan (atau simpan dengan setara di beberapa namespace lain) dan akses sepertiself._cls
dalam metode yang memerlukannya (type(self)
mungkin OK, tetapi tidak jika Anda juga melakukan subkelas apa pun_M
) .Saya akan melakukan ini untuk mewarisi semua atribut modul dengan benar, dan diidentifikasi dengan benar oleh isinstance ()
Dan kemudian Anda dapat memasukkan ini ke dalam sys.modules:
sumber
__file__
yang harus ditentukan secara manual, (2) impor yang dibuat dalam modul yang berisi kelas tidak akan "terlihat" selama run time, dll ...types.ModuleType
, setiap (gaya baru) kelas yang akan dilakukan. Atribut modul khusus apa yang ingin Anda warisi?__init__
sebuah instance, dan Anda akan mendapatkan perilaku yang benar saat menggunakanisinstance
.Karena PEP 562 telah diimplementasikan dengan Python> = 3.7, sekarang kita bisa melakukan ini
file: module.py
pemakaian:
Perhatikan bahwa jika Anda menghilangkan
raise AttributeError
in the__getattr__
function, itu berarti fungsi diakhiri denganreturn None
, makamodule.nosuch
akan mendapatkan nilaiNone
.sumber
Berdasarkan jawaban John Lin :
Penggunaan (perhatikan garis bawah di depan), di
the_module.py
:Kemudian:
Garis bawah di depan diperlukan untuk membedakan fungsi yang di-properti-kan dari fungsi aslinya. Saya tidak dapat memikirkan cara untuk menetapkan ulang pengenal, karena selama waktu eksekusi dekorator, pengenal tersebut belum ditetapkan.
Perhatikan bahwa IDE tidak akan mengetahui bahwa properti itu ada dan akan menampilkan gelombang merah.
sumber
@property def x(self): return self._x
menurut sayadef thing()
tanpa garis bawah lebih konvensional. Dan dapatkah Anda membuat dekorator "penyetel properti modul" dalam jawaban Anda juga?def thing()
saran Anda . Masalahnya adalah bahwa__getattr__
hanya dipanggil untuk atribut yang hilang . Tapi setelah@module_property def thing(): …
berjalan,the_module.thing
ditentukan, jadi getattr tidak akan pernah dipanggil. Kita perlu mendaftarthing
di dekorator dan kemudian menghapusnya dari namespace modul. Saya mencoba kembaliNone
dari dekorator, tetapi kemudianthing
didefinisikan sebagaiNone
. Seseorang bisa melakukannya@module_property def thing(): … del thing
tetapi saya menemukan itu lebih buruk daripada menggunakanthing()
sebagai fungsi__getattribute__
". Terima kasih.Kasus penggunaan tipikal adalah: memperkaya modul (besar) yang ada dengan beberapa (beberapa) atribut dinamis - tanpa mengubah semua materi modul menjadi tata letak kelas. Sayangnya patch kelas modul yang paling sederhana seperti
sys.modules[__name__].__class__ = MyPropertyModule
gagal denganTypeError: __class__ assignment: only for heap types
. Jadi pembuatan modul perlu kabel.Pendekatan ini melakukannya tanpa kait impor Python, hanya dengan memiliki beberapa prolog di atas kode modul:
Pemakaian:
Catatan: Sesuatu seperti
from propertymodule import dynval
akan menghasilkan salinan beku tentu saja - sesuai dengandynval = someobject.dynval
sumber
Jawaban singkatnya: gunakan
proxy_tools
The
proxy_tools
paket mencoba untuk memberikan@module_property
fungsionalitas.Ini menginstal dengan
Menggunakan sedikit modifikasi dari contoh @ Marein,
the_module.py
kami masukkanSekarang dari skrip lain, saya bisa melakukannya
Perilaku tidak terduga
Solusi ini bukannya tanpa peringatan. Yaitu,
the_module.thing
adalah tidak string ! Ini adalahproxy_tools.Proxy
objek yang metode khususnya telah diganti sehingga meniru string. Berikut adalah beberapa tes dasar yang menggambarkan hal tersebut:Secara internal, fungsi asli disimpan ke
the_module.thing._Proxy__local
:Pikiran lebih lanjut
Sejujurnya, saya bingung tentang mengapa modul tidak memiliki fungsi bawaan ini. Saya pikir inti masalahnya adalah itu
the_module
adalah turunan daritypes.ModuleType
kelas. Menyetel "properti modul" berarti menyetel properti pada instance kelas ini, bukan padatypes.ModuleType
kelas itu sendiri. Untuk lebih jelasnya, lihat jawaban ini .Kami sebenarnya dapat mengimplementasikan properti pada
types.ModuleType
sebagai berikut, meskipun hasilnya tidak bagus. Kami tidak dapat langsung mengubah tipe bawaan, tetapi kami dapat mengutuknya :Ini memberi kita properti yang ada di semua modul. Ini agak sulit, karena kami merusak perilaku pengaturan di semua modul:
sumber
@module_property
dekorator. Secara umum,@property
dekorator built-in digunakan ketika kelas ditentukan, bukan setelah sebuah instance dibuat, jadi saya akan berasumsi hal yang sama akan berlaku untuk properti modul dan dengan jawaban Alex - ingat pertanyaan ini bertanya "Dapatkah modul memiliki properti dengan cara yang sama seperti objek?". Namun adalah mungkin untuk menambahkan mereka setelah itu dan saya sudah dimodifikasi saya sebelumnya potongan untuk menggambarkan cara yang bisa dilakukan.cached_module_property
, fakta yang__getattr__()
tidak akan dipanggil lagi jika atributnya didefinisikan sangat membantu. (mirip dengan apa yangfunctools.cached_property
dicapai).