Saya memiliki kebutuhan untuk mengambil argumen string dan membuat objek kelas yang dinamai dalam string itu dengan Python. Di Jawa, saya akan menggunakan Class.forName().newInstance()
. Apakah ada yang setara dengan Python?
Terima kasih atas tanggapannya. Untuk menjawab mereka yang ingin tahu apa yang saya lakukan: Saya ingin menggunakan argumen baris perintah sebagai nama kelas, dan membuatnya. Saya sebenarnya memprogram dalam Jython dan membuat instance kelas Java, oleh karena itu pertanyaan Java-an. getattr()
bekerja dengan baik. Terimakasih banyak.
java
python
class
instantiation
Jason
sumber
sumber
importlib.import
, yang di-backport dari python 3 ke 2.7 ( docs.python.org/2/library/importlib.html )Jawaban:
Refleksi dengan python jauh lebih mudah dan jauh lebih fleksibel daripada di Java.
Saya merekomendasikan membaca tutorial ini
Tidak ada fungsi langsung (yang saya ketahui) yang mengambil nama kelas yang memenuhi syarat dan mengembalikan kelas, namun Anda memiliki semua bagian yang diperlukan untuk membangunnya, dan Anda dapat menghubungkannya bersama.
Sedikit saran: jangan mencoba memprogram dengan gaya Java saat Anda menggunakan python.
Jika Anda dapat menjelaskan apa yang Anda coba lakukan, mungkin kami dapat membantu Anda menemukan cara yang lebih pythonic untuk melakukannya.
Inilah fungsi yang melakukan apa yang Anda inginkan:
Anda dapat menggunakan nilai hasil dari fungsi ini seolah-olah itu adalah kelas itu sendiri.
Berikut contoh penggunaan:
Bagaimana cara kerjanya?
Kami menggunakan
__import__
untuk mengimpor modul yang menampung kelas, yang mengharuskan kami mengekstrak nama modul dari nama yang sepenuhnya memenuhi syarat. Kemudian kami mengimpor modul:Pada kasus ini,
m
hanya akan mengacu pada modul tingkat atas,Misalnya, jika kelas Anda tinggal di
foo.baz
modul, makam
akan menjadi modul.foo
Kita dapat dengan mudah mendapatkan referensi untuk
foo.baz
digunakangetattr( m, 'baz' )
Untuk mendapatkan dari modul tingkat atas ke kelas, harus menggunakan secara rekursif
gettatr
nama kelasKatakanlah misalnya, jika nama kelas Anda
foo.baz.bar.Model
maka kami melakukan ini:Inilah yang terjadi di loop ini:
Di akhir loop,
m
akan menjadi referensi ke kelas. Ini berarti itum
sebenarnya adalah kelasnya sendiri, Anda dapat melakukannya misalnya:sumber
__import__
ada. Proyek seperti Django yang melakukan module-loading-magic menggunakannya sepanjang waktu. Jawaban bagus.get_class = lambda name: reduce(getattr, name.split('.')[1:], __import__(name.partition('.')[0]))
. Meskipun 'object.from_name' mungkin nama yang lebih baik. Contoh: get_class ('decimal.Decimal'), get_class (module_name).Dengan asumsi kelas berada dalam lingkup Anda:
Jika tidak:
Edit: Catatan, Anda tidak bisa memberi nama seperti 'foo.bar' ke getattr. Anda harus membaginya. dan panggil getattr () pada setiap bagian kiri-ke-kanan. Ini akan menangani itu:
sumber
attrs = 'foo.bar.baz'.split('.'); fooBar = reduce(getattr, attrs[1:], __import__(attrs[0]))
module, _, attrs = 'foo.bar.baz'.partition('.'); fooBar = reduce(getattr, attrs, __import__(module))
Pemakaian
sumber
Implementasi lain.
sumber
if module_name
LBYL cukup redudant, karena kesalahan yang Anda dapatkan jika Anda hanya menghapus garis adalah:ValueError: Empty module name
.Sepertinya Anda mendekati ini dari tengah, bukan dari awal. Apa yang sebenarnya kamu coba lakukan? Menemukan kelas yang terkait dengan string yang diberikan adalah sarana untuk mencapai tujuan.
Jika Anda memperjelas masalah Anda, yang mungkin memerlukan refactoring mental Anda sendiri, solusi yang lebih baik mungkin muncul dengan sendirinya.
Misalnya: Apakah Anda mencoba memuat objek yang disimpan berdasarkan nama jenisnya dan sekumpulan parameter? Python mengeja kata ini dan Anda harus melihat modul acar . Dan meskipun proses pembongkaran melakukan persis seperti yang Anda gambarkan, Anda tidak perlu khawatir tentang cara kerjanya secara internal:
sumber
Ini ditemukan di pustaka standar python, sebagai unittest.TestLoader.loadTestsFromName. Sayangnya, metode ini terus melakukan aktivitas terkait pengujian tambahan, tetapi ha pertama ini tampaknya dapat digunakan kembali. Saya telah mengeditnya untuk menghapus fungsionalitas terkait pengujian:
sumber
Saya perlu mendapatkan objek untuk semua kelas yang ada di
my_package
. Jadi saya mengimpor semua kelas yang diperlukan kemy_package
dalam__init__.py
.Jadi struktur direktori saya seperti ini:
Dan
__init__.py
penampilanku seperti ini:Kemudian saya membuat fungsi seperti ini:
Dimana
module_name = 'my_package'
periksa dokumen: https://docs.python.org/3/library/inspect.html#inspect.getmembers
sumber