Saya menggunakan kelas berikut untuk menyimpan data lagu saya dengan mudah.
class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
exec 'self.%s=None'%(att.lower()) in locals()
def setDetail(self, key, val):
if key in self.attsToStore:
exec 'self.%s=val'%(key.lower()) in locals()
Saya merasa ini jauh lebih bisa diperluas daripada menulis satu if/else
blok. Namun, eval
tampaknya dianggap praktik yang buruk dan tidak aman untuk digunakan. Jika demikian, adakah yang bisa menjelaskan kepada saya mengapa dan menunjukkan kepada saya cara yang lebih baik untuk mendefinisikan kelas di atas?
exec/eval
dan masih belum tahusetattr
?Jawaban:
Ya, menggunakan eval adalah praktik yang buruk. Hanya untuk menyebutkan beberapa alasan:
Dalam kasus Anda, Anda dapat menggunakan setattr sebagai gantinya:
EDIT:
Ada beberapa kasus di mana Anda harus menggunakan eval atau exec. Tetapi mereka jarang. Menggunakan eval dalam kasus Anda tentu merupakan praktik yang buruk. Saya menekankan pada praktik buruk karena eval dan eksekutif sering digunakan di tempat yang salah.
EDIT 2:
Sepertinya beberapa orang tidak setuju bahwa eval 'sangat berbahaya dan tidak aman' dalam kasus OP. Itu mungkin benar untuk kasus khusus ini tetapi tidak secara umum. Pertanyaannya adalah umum dan alasan yang saya cantumkan juga benar untuk kasus umum.
EDIT 3: Menyusun ulang poin 1 dan 4
sumber
eval
tidak ada hubungannya satu sama lain. Aplikasi yang secara fundamental salah desain pada dasarnya salah desain.eval
tidak lebih merupakan akar penyebab desain yang buruk daripada pembagian dengan nol atau berusaha mengimpor modul yang diketahui tidak ada.eval
tidak aman. Aplikasi tidak aman.calc
, dan untuk menambahkan angka itu dijalankanprint(eval("{} + {}".format(n1, n2)))
dan keluar. Sekarang Anda mendistribusikan program ini dengan beberapa OS. Kemudian seseorang membuat skrip bash yang mengambil beberapa angka dari situs stok dan menambahkannya menggunakancalc
. ledakan?Menggunakan
eval
itu lemah, bukan praktik yang jelas buruk .Itu melanggar "Prinsip Dasar Perangkat Lunak". Sumber Anda bukan jumlah total dari apa yang dapat dieksekusi. Selain sumber Anda, ada argumen untuk
eval
, yang harus dipahami dengan jelas. Untuk alasan ini, ini adalah alat pilihan terakhir.Ini biasanya merupakan tanda desain yang tidak dipikirkan. Jarang ada alasan bagus untuk kode sumber dinamis, dibuat dengan cepat. Hampir semua hal dapat dilakukan dengan pendelegasian dan teknik desain OO lainnya.
Ini menyebabkan kompilasi on-the-fly yang relatif lambat dari potongan-potongan kecil kode. Overhead yang dapat dihindari dengan menggunakan pola desain yang lebih baik.
Sebagai catatan kaki, di tangan para sosiopat gila, itu mungkin tidak berhasil dengan baik. Namun, ketika berhadapan dengan pengguna atau administrator sosiopat yang kacau, yang terbaik adalah tidak memberi mereka Python yang ditafsirkan. Di tangan orang yang benar-benar jahat, Python dapat menjadi tanggung jawab;
eval
sama sekali tidak meningkatkan risiko.sumber
eval
ada semacam "kerentanan keamanan". Seolah-olah Python - itu sendiri - bukan hanya sekelompok sumber ditafsirkan bahwa siapa pun dapat memodifikasi Ketika dihadapkan dengan "eval is a security hole", Anda hanya bisa berasumsi bahwa itu adalah lubang keamanan di tangan sosiopat. Pemrogram biasa hanya memodifikasi sumber Python yang ada dan menyebabkan masalah mereka secara langsung. Tidak secara tidak langsung melaluieval
sihir.while True: pass
akan sulit untuk dibersihkan dengan semacam pelarian.eval()
, karena itu adalah string. Kode dari "dunia luar" tidak dapat disanitasi. String dari dunia luar hanyalah string. Saya tidak jelas tentang apa yang Anda bicarakan. Mungkin Anda harus memberikan posting blog yang lebih lengkap dan menautkannya di sini.Dalam hal ini, ya. Dari pada
Anda harus menggunakan fungsi builtin
setattr
:sumber
Ya itu:
Retas menggunakan Python:
Kode di bawah ini akan mencantumkan semua tugas yang berjalan pada mesin Windows.
Di Linux:
sumber
Perlu dicatat bahwa untuk masalah spesifik yang dimaksud, ada beberapa alternatif untuk menggunakan
eval
:Yang paling sederhana, seperti disebutkan, menggunakan
setattr
:Pendekatan yang kurang jelas adalah memperbarui objek
__dict__
objek secara langsung. Jika semua yang ingin Anda lakukan adalah menginisialisasi atributNone
, maka ini kurang mudah daripada di atas. Tetapi pertimbangkan ini:Ini memungkinkan Anda meneruskan argumen kata kunci ke konstruktor, misalnya:
Ini juga memungkinkan Anda untuk membuat penggunaan Anda
locals()
lebih eksplisit, misalnya:... dan, jika Anda benar-benar ingin menetapkan
None
atribut yang namanya ditemukan dilocals()
:Pendekatan lain untuk menyediakan objek dengan nilai default untuk daftar atribut adalah dengan mendefinisikan metode kelas
__getattr__
:Metode ini dipanggil ketika atribut bernama tidak ditemukan dengan cara normal. Pendekatan ini agak kurang langsung daripada hanya mengatur atribut dalam konstruktor atau memperbarui
__dict__
, tetapi memiliki manfaat tidak benar-benar membuat atribut kecuali jika ada, yang dapat secara substansial mengurangi penggunaan memori kelas.Inti dari semua ini: Ada banyak alasan, secara umum, untuk dihindari
eval
- masalah keamanan mengeksekusi kode yang tidak Anda kontrol, masalah praktis kode yang tidak dapat Anda debug, dll. Tapi alasan yang lebih penting adalah bahwa secara umum, Anda tidak perlu menggunakannya. Python memaparkan begitu banyak mekanisme internalnya kepada programmer sehingga Anda jarang benar-benar perlu menulis kode yang menulis kode.sumber
__dict__
secara langsung, berikan objek objek kamus yang sebenarnya, baik melalui warisan atau sebagai atribut.__setattr__
menimpa, yang mungkin mengarah pada hasil yang tidak terduga.setattr()
tidak memiliki masalah ini.Pengguna lain menunjukkan bagaimana kode Anda dapat diubah agar tidak bergantung
eval
; Saya akan menawarkan use-case yang sah untuk digunakaneval
, yang bahkan ditemukan di CPython: testing .Inilah satu contoh yang saya temukan di
test_unary.py
mana tes tentang apakah(+|-|~)b'a'
menimbulkanTypeError
:Penggunaannya jelas bukan praktik yang buruk di sini; Anda mendefinisikan input dan hanya mengamati perilaku.
eval
berguna untuk pengujian.Lihatlah pencarian ini untuk
eval
, dilakukan pada CPython git repositori; pengujian dengan eval banyak digunakan.sumber
Saat
eval()
digunakan untuk memproses input yang disediakan pengguna, Anda memungkinkan pengguna untuk Drop-to-REPL memberikan sesuatu seperti ini:Anda mungkin lolos begitu saja, tetapi biasanya Anda tidak ingin vektor untuk eksekusi kode arbitrer dalam aplikasi Anda.
sumber
Selain jawaban @Nadia Alramli, karena saya baru mengenal Python dan sangat ingin memeriksa bagaimana penggunaan
eval
akan memengaruhi timing , saya mencoba sebuah program kecil dan di bawah ini adalah pengamatannya:sumber