Nonaktifkan pernyataan dengan Python

Jawaban:

75

Bagaimana cara menonaktifkan pernyataan dengan Python?

Ada beberapa pendekatan yang memengaruhi satu proses, lingkungan, atau satu baris kode.

Saya mendemonstrasikan masing-masing.

Untuk keseluruhan proses

Menggunakan -Obendera (kapital O) menonaktifkan semua pernyataan assert dalam suatu proses.

Sebagai contoh:

$ python -Oc "assert False"

$ python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Perhatikan bahwa dengan menonaktifkan maksud saya itu juga tidak mengeksekusi ekspresi yang mengikutinya:

$ python -Oc "assert 1/0"

$ python -c "assert 1/0"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

Untuk lingkungan

Anda juga dapat menggunakan variabel lingkungan untuk menyetel tanda ini.

Ini akan mempengaruhi setiap proses yang menggunakan atau mewarisi lingkungan.

Misalnya, di Windows, mengatur dan menghapus variabel lingkungan:

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError
C:\>SET PYTHONOPTIMIZE=TRUE

C:\>python -c "assert False"

C:\>SET PYTHONOPTIMIZE=

C:\>python -c "assert False"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
AssertionError

Sama di Unix (menggunakan set dan unset untuk fungsionalitas masing-masing)

Satu titik dalam kode

Anda melanjutkan pertanyaan Anda:

jika sebuah pernyataan gagal, saya tidak ingin ia menampilkan AssertionError, tetapi untuk melanjutkan.

Jika Anda ingin kode yang gagal dijalankan, Anda dapat memastikan aliran kontrol tidak mencapai pernyataan, misalnya:

if False:
    assert False, "we know this fails, but we don't get here"

atau Anda dapat menangkap kesalahan pernyataan:

try:
    assert False, "this code runs, fails, and the exception is caught"
except AssertionError as e:
    print(repr(e))

yang mencetak:

AssertionError('this code runs, fails, and the exception is caught')

dan Anda akan terus melanjutkan dari titik Anda menangani AssertionError.

Referensi

Dari yang assertdokumentasi :

Pernyataan tegas seperti ini:

assert expression #, optional_message

Setara dengan

if __debug__:
    if not expression: raise AssertionError #(optional_message)

Dan,

variabel built-in __debug__adalah Truedalam keadaan normal, Falseketika optimasi diminta (perintah baris opsi -O).

dan selanjutnya

Tugas ke __debug__ilegal. Nilai untuk variabel built-in ditentukan saat interpreter dimulai.

Dari dokumen penggunaan:

-HAI

Aktifkan pengoptimalan dasar. Ini mengubah ekstensi nama file untuk file yang dikompilasi (bytecode) dari .pyc menjadi .pyo. Lihat juga PITONOPTIMASI.

dan

PITONOPTIMASI

Jika ini disetel ke string tidak kosong, ini setara dengan menentukan -Oopsi. Jika disetel ke bilangan bulat, ini setara dengan menetapkan -Obeberapa kali.

Aaron Hall
sumber
apakah mungkin untuk melewati kode yang gagal dalam kasus 'Satu titik dalam kode'? Saya mencoba menyetel __debug__ke False tetapi itu tidak diizinkan.
Matthijs
1
@Matthijs Anda dapat memastikan aliran kontrol tidak mencapainya (misalnya if False: assert False) atau Anda dapat menangkap kesalahan Penegasan. Itu adalah pilihanmu. Memperbarui jawaban untuk menjawab pertanyaan Anda.
Aaron Hall
Terima kasih atas jawabannya, tetapi belum sepenuhnya apa yang saya pikirkan. Saya ingin menonaktifkan menegaskan dalam fungsi selama runtime, idealnya dengan semacam manajer konteks: pernyataan dievaluasi: foo()dan pernyataan mematikan: with skip_assertion(): foo(). Manfaat dari ini adalah bahwa saya tidak perlu menambahkan bendera lain pada fungsinya
Matthijs
2
Anda dapat menulis ulang bytecode dari fungsi tersebut, menulis ulang AST, atau menulis ulang fungsi itu sendiri. (secara manual atau secara terprogram, untuk keduanya). Menulis ulang AST mungkin akan menjadi pendekatan yang paling dapat diandalkan ("cukup" ganti Assertobjek dengan Passobjek). Manajer konteks tidak akan langsung bekerja untuk itu, tetapi Anda dapat memiliki semacam mekanisme yang menggunakan fungsi dekorasi dengan cara itu. Terlepas dari itu, saya tidak merekomendasikannya. Saya curiga alasan Anda ingin melakukannya adalah karena Anda memanggil kode yang tidak Anda kendalikan dan mendapatkan AssertionErrors. Jika demikian, Anda mungkin perlu mencari perbaikan lain.
Aaron Hall
59

Panggil Python dengan tanda -O:

test.py:

assert(False)
print 'Done'

Keluaran:

C:\temp\py>C:\Python26\python.exe test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    assert(False)
AssertionError

C:\temp\py>C:\Python26\python.exe -O test.py
Done
Mark Rushakoff
sumber
8
Tegaskan bukan fungsi, jadi tanda kurung tidak berguna.
Aaron Hall
15

Kedua jawaban yang sudah diberikan adalah valid (panggil Python dengan salah satu -Oatau -OOpada baris perintah).

Inilah perbedaan di antara keduanya:

  • -OAktifkan pengoptimalan dasar. Ini mengubah ekstensi nama file untuk file yang dikompilasi (bytecode) dari .pyc menjadi .pyo.

  • -OOBuang dokumen selain-O pengoptimalan.

(Dari dokumentasi Python )

Michael Currie
sumber
7

Penggunaan python -O:

$ python -O
>>> assert False
>>> 
John Millikin
sumber
3

Anda TIDAK boleh menonaktifkan (sebagian besar) pernyataan. Mereka menangkap kesalahan yang tidak terduga saat perhatian ada di tempat lain. Lihat Aturan 5 dalam "Kekuatan sepuluh" .

Sebaliknya, lindungi beberapa pemeriksaan pernyataan yang mahal dengan sesuatu seperti:

import logging
logger = logging.getLogger(__name__)

if logger.getEffectiveLevel() < logging.DEBUG:
    ok = check_expensive_property()
    assert ok, 'Run !'

Salah satu cara untuk mempertahankan pernyataan penting, dan memungkinkan assertpernyataan dioptimalkan adalah dengan memunculkan pernyataan pemilihan:

if foo_is_broken():
    raise AssertionError('Foo is broken!')
Ioannis Filippidis
sumber
1
//, Masalahnya adalah, meskipun, pernyataan tersebut masih menambah kompleksitas siklomatik, dan penanganan kesalahan harus menangani sisanya?
Nathan Basanese
1
Pernyataan yang akan dilindungi seperti di atas adalah panggilan mahal yang secara signifikan memperlambat eksekusi. Untuk beberapa algoritme, pemeriksaan semacam ini dapat mengambil urutan besarnya lebih lama daripada keseluruhan program. Pikirkan untuk menjalankan implementasi yang naif tetapi lebih sederhana (sehingga cenderung tidak mengandung kesalahan) dari algoritma yang sama untuk memeriksa kebenaran. Atau pemeriksaan dengan penghitungan lengkap dari sesuatu yang tidak mungkin untuk operasi normal.
Ioannis Filippidis
Saya tidak melihat banyak masalah dengan keterbacaan, karena pernyataan seperti itu tidak menambahkan penumpukan ke kode. Mengekstraknya sebagai pemanggilan fungsi dapat menghilangkannya, jika itu menjadi masalah (dan saya berharap refactoring seperti itu akan mengurangi kompleksitas siklomatik). Bagaimanapun, kompleksitas siklomatik tidak boleh mengatur pemeriksaan keselamatan.
Ioannis Filippidis
2

Berjalan dalam mode yang dioptimalkan harus melakukannya:

python -OO module.py
FogleBird
sumber