Cara menentukan kelas pengecualian Anda sendiri dengan Python

Halo, Habr!



Ketertarikan Anda pada buku baru " Python Pro Secrets " telah meyakinkan kami bahwa kisah kebiasaan Python layak untuk dilanjutkan. Hari ini kami menawarkan untuk membaca tutorial kecil tentang membuat kelas pengecualian kustom (dalam teks - Anda sendiri). Penulis menariknya, sulit untuk tidak setuju dengannya bahwa keuntungan terpenting dari pengecualian adalah kelengkapan dan kejelasan pesan kesalahan. Sebagian kode dari aslinya berupa gambar.



Selamat datang di cat.



Membuat kelas kesalahan Anda sendiri



Python menyediakan kemampuan untuk membuat kelas pengecualian Anda sendiri. Dengan membuat kelas semacam itu, Anda dapat mendiversifikasi desain kelas dalam aplikasi Anda. Kelas kesalahan khusus bisa mencatat kesalahan, memeriksa objek. Kitalah yang mendefinisikan apa yang dilakukan kelas pengecualian, meskipun biasanya kelas khusus hampir tidak dapat melakukan lebih dari sekadar menampilkan pesan.



Secara alami, jenis kesalahan itu sendiri penting, dan kami sering membuat jenis kesalahan sendiri untuk menunjukkan situasi tertentu yang biasanya tidak tercakup pada level Python. Dengan cara ini, pengguna kelas akan tahu persis apa yang terjadi ketika mereka menemukan kesalahan ini.



Artikel ini dibagi menjadi dua bagian. Pertama, kita akan mendefinisikan kelas pengecualian dengan sendirinya. Kami kemudian mendemonstrasikan bagaimana kami dapat mengintegrasikan kelas pengecualian kami sendiri ke dalam program Python kami dan menunjukkan bagaimana kami dapat meningkatkan kegunaan kelas yang kami desain.



Kelas pengecualian khusus MyCustomError



Melempar pengecualian membutuhkan metode __init__()



dan __str__()



.




Saat melontarkan pengecualian, kami telah membuat sebuah instance dari pengecualian tersebut dan pada saat yang sama menampilkannya di layar. Mari kita lihat lebih dekat kelas pengecualian khusus kami yang ditunjukkan di bawah ini.







Kelas MyCustomError di atas memiliki dua metode ajaib, __init__



dan __str__



, yang secara otomatis dipanggil selama penanganan pengecualian. Metode Init



dipanggil saat instance dibuat, dan metode dipanggil saat instance str



ditampilkan. Oleh karena itu, ketika pengecualian dilemparkan, kedua metode ini biasanya dipanggil segera setelah satu sama lain. Pernyataan pengecualian lemparan Python menempatkan program ke dalam status kesalahan.



Dalam daftar argumen metode __init__



adalah *args



. Komponen *args



adalah mode pencocokan pola khusus yang digunakan dalam fungsi dan metode. Ini memungkinkan Anda untuk melewatkan beberapa argumen, dan menyimpan argumen yang diteruskan sebagai tupel, tetapi pada saat yang sama memungkinkan Anda untuk tidak memberikan argumen sama sekali.



Dalam kasus kami, kami dapat mengatakan bahwa jika MyCustomError



ada argumen yang diteruskan ke konstruktor , maka kami mengambil argumen yang diberikan pertama dan menetapkannya ke atribut message



dalam objek. Jika tidak ada argumen yang diberikan, maka atribut message



akan diberi nilai None



.



Dalam contoh pertama, pengecualian dilempar MyCustomError



tanpa argumen apa pun, jadi atributnya message



objek ini diberi nilai None



. Sebuah metode akan dipanggil str



dan akan menampilkan pesan 'Pesan MyCustomError telah dimunculkan'.







Pengecualian MyCustomError



dilempar tanpa argumen apa pun (tanda kurung kosong). Dengan kata lain, desain objek seperti itu terlihat tidak standar. Tapi ini hanyalah dukungan sintaksis yang disediakan dengan Python saat membuat pengecualian.



Dalam contoh kedua, MyCustomError



ini dilewatkan dengan argumen string 'Kami punya masalah'. Ini ditetapkan sebagai atribut message



objek dan ditampilkan sebagai pesan kesalahan ketika pengecualian dilemparkan.







Kode untuk kelas pengecualian MyCustomError ada di sini...



class MyCustomError(Exception):
    def __init__(self, *args):
        if args:
            self.message = args[0]
        else:
            self.message = None

    def __str__(self):
        print('calling str')
        if self.message:
            return 'MyCustomError, {0} '.format(self.message)
        else:
            return 'MyCustomError has been raised'


#  MyCustomError

raise MyCustomError('We have a problem')
      
      





Kelas CustomIntFloatDic



Kami membuat kamus kami sendiri, yang nilainya hanya dapat berupa bilangan bulat dan angka floating-point.



Mari kita lanjutkan dan tunjukkan cara menyuntikkan kelas kesalahan dengan mudah dan berguna ke dalam program kita sendiri. Untuk memulainya, saya akan menawarkan contoh yang sedikit dibuat-buat. Dalam contoh fiksi ini, saya akan membuat kamus saya sendiri yang hanya dapat menerima bilangan bulat atau bilangan floating point.



Jika pengguna mencoba menentukan tipe data lain sebagai nilai dalam kamus ini, pengecualian akan dilemparkan. Pengecualian ini akan memberikan informasi yang berguna bagi pengguna tentang cara menggunakan kamus ini. Dalam kasus kami, pesan ini langsung memberi tahu pengguna bahwa hanya bilangan bulat atau angka floating point yang dapat ditentukan sebagai nilai dalam kamus ini.



Saat membuat kamus Anda sendiri, perlu diingat bahwa ada dua tempat di mana nilai dapat ditambahkan ke kamus. Pertama, ini bisa terjadi dalam metode init saat membuat objek (pada tahap ini, objek sudah dapat diberi kunci dan nilai), dan kedua, saat menyetel kunci dan nilai secara langsung di kamus. Di kedua tempat ini, Anda perlu menulis kode untuk memastikan bahwa nilainya hanya dapat berupa tipe int



atau float



.



Pertama, saya akan mendefinisikan kelas CustomIntFloatDict yang mewarisi dari kelas bawaan dict



. dict



dilewatkan dalam daftar argumen, yang diapit tanda kurung dan mengikuti nama kelas CustomIntFloatDict



.



Jika kelas dibuat instance-nya CustomIntFloatDict



, selain itu, tidak ada argumen yang diteruskan ke parameter kunci dan nilai, mereka akan disetel ke None



. Ekspresi tersebut if



diinterpretasikan sebagai berikut: jika salah satu kuncinya sama None



, atau nilainya sama None



, maka metode akan dipanggil dengan objek get_dict()



, yang akan mengembalikan atribut empty_dict



; atribut seperti itu pada suatu objek menunjuk ke daftar kosong. Ingatlah bahwa atribut kelas tersedia di semua contoh kelas.







Tujuan dari kelas ini adalah untuk memungkinkan pengguna melewatkan daftar atau tuple dengan kunci dan nilai di dalamnya. Jika pengguna memasukkan daftar atau tuple mencari kunci dan nilai, maka dua set iterable ini akan digabungkan menggunakan fungsi zip



bahasa Python. Variabel terkait yang menunjuk ke suatu objek zip



dapat diulangi, dan tupel dapat dibongkar. Dengan mengulangi tupel, saya memeriksa apakah val adalah turunan dari kelas int



atau float



. Jika itu val



bukan milik salah satu kelas ini, saya membuang pengecualian IntFloatValueError



saya sendiri dan memberikan val sebagai argumen untuk itu.



IntFloatValueError Exception Class



Ketika pengecualian dilemparkan, IntFloatValueError



kami membuat instance kelas IntFloatValueError



dan secara bersamaan menampilkannya di layar. Ini berarti metode ajaib init



dan akan dipanggil str



.



Nilai yang menyebabkan pengecualian yang dilempar ditetapkan sebagai atribut yang value



menyertai kelas IntFloatValueError



. Saat memanggil metode magic str, pengguna menerima pesan kesalahan yang menginformasikan bahwa nilai init



in CustomIntFloatDict



tidak valid. Pengguna tahu apa yang harus dilakukan untuk memperbaiki kesalahan ini.







Kelas pengecualian IntFloatValueError



dan KeyValueConstructError











Jika tidak ada pengecualian dilempar, itu saja val



dari objek yang dirantai ada tipe int



atau float



, kemudian mereka akan disetel menggunakan __setitem__()



, dan metode dari kelas induk akan melakukan segalanya untuk kita dict



, seperti yang ditunjukkan di bawah ini.







Kelas KeyValueConstructError



Apa yang terjadi jika pengguna memasukkan jenis yang bukan daftar atau tuple kunci dan nilai?



Sekali lagi, contoh ini sedikit artifisial, tetapi berguna untuk menunjukkan kepada Anda bagaimana Anda dapat menggunakan kelas pengecualian Anda sendiri.



Jika pengguna tidak menentukan kunci dan nilai sebagai daftar atau tuple, pengecualian akan dilempar KeyValueConstructError



. Tujuan dari pengecualian ini adalah untuk memberi tahu pengguna bahwa untuk menulis kunci dan nilai ke suatu objek CustomIntFloatDict



, daftar atau tuple harus ditentukan dalam konstruktor init



kelas CustomIntFloatDict



.



Dalam contoh di atas, sebagai argumen kedua untuk konstruktor init



banyak hal telah berlalu dan pengecualian dilemparkan karena ini KeyValueConstructError



. Manfaat dari pesan kesalahan yang ditampilkan adalah bahwa pesan kesalahan yang ditampilkan memberi tahu pengguna bahwa kunci dan nilai yang akan dimasukkan harus dilaporkan sebagai daftar atau tupel.



Sekali lagi, saat pengecualian dilemparkan, instance KeyValueConstructError dibuat, dan kunci serta nilai diteruskan sebagai argumen ke konstruktor KeyValueConstructError. Mereka ditetapkan sebagai nilai atribut kunci dan nilai KeyValueConstructError dan digunakan dalam metode __str__ untuk menghasilkan pesan kesalahan yang berarti saat pesan ditampilkan di layar.



Lebih lanjut, saya bahkan menyertakan tipe data yang melekat dalam objek yang ditambahkan ke konstruktor init



- Saya melakukan ini untuk kejelasan.







Menyetel kunci dan nilai di CustomIntFloatDict



CustomIntFloatDict



mewarisi dari dict



. Artinya, ia akan berfungsi persis seperti kamus, kecuali di tempat yang kita pilih untuk mengubah perilakunya secara selektif.



__setitem__



Adalah metode ajaib yang dipanggil saat mengatur kunci dan nilai dalam kamus. Dalam implementasi kami, setitem



kami memeriksa bahwa nilainya bertipe int



atau float



, dan hanya setelah pemeriksaan berhasil, nilai tersebut dapat disetel dalam kamus. Jika pemeriksaan gagal, Anda dapat menggunakan kelas pengecualian lagi IntFloatValueError



. Di sini Anda dapat memastikan bahwa jika kami mencoba menetapkan string โ€˜bad_valueโ€™



sebagai nilai dalam kamus test_4



, kami akan mendapatkan pengecualian.







Semua kode untuk tutorial ini ditampilkan di bawah ini dan diposting di Github .



#  ,        int  float  

class IntFloatValueError(Exception):
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return '{} is invalid input, CustomIntFloatDict can only accept ' \
               'integers and floats as its values'.format(self.value)


class KeyValueContructError(Exception):
    def __init__(self, key, value):
        self.key = key
        self.value = value

    def __str__(self):
        return 'keys and values need to be passed as either list or tuple' + '\n' + \
                ' {} is of type: '.format(self.key) + str(type(self.key)) + '\n' + \
                ' {} is of type: '.format(self.value) + str(type(self.value))


class CustomIntFloatDict(dict):

    empty_dict = {}

    def __init__(self, key=None, value=None):

        if key is None or value is None:
            self.get_dict()

        elif not isinstance(key, (tuple, list,)) or not isinstance(value, (tuple, list)):
            raise KeyValueContructError(key, value)
        else:
            zipped = zip(key, value)
            for k, val in zipped:
                if not isinstance(val, (int, float)):
                    raise IntFloatValueError(val)
                dict.__setitem__(self, k, val)

    def get_dict(self):
        return self.empty_dict

    def __setitem__(self, key, value):
        if not isinstance(value, (int, float)):
            raise IntFloatValueError(value)
        return dict.__setitem__(self, key, value)


#  

# test_1 = CustomIntFloatDict()
# print(test_1)
# test_2 = CustomIntFloatDict({'a', 'b'}, [1, 2])
# print(test_2)
# test_3 = CustomIntFloatDict(('x', 'y', 'z'), (10, 'twenty', 30))
# print(test_3)
# test_4 = CustomIntFloatDict(('x', 'y', 'z'), (10, 20, 30))
# print(test_4)
# test_4['r'] = 1.3
# print(test_4)
# test_4['key'] = 'bad_value'
      
      





Kesimpulan



Jika Anda membuat pengecualian sendiri, bekerja dengan kelas menjadi jauh lebih nyaman. Kelas pengecualian harus memiliki metode ajaib init



dan str



yang secara otomatis dipanggil selama penanganan pengecualian. Terserah Anda apa yang akan dilakukan kelas pengecualian Anda sendiri. Di antara metode yang ditampilkan adalah metode yang bertanggung jawab untuk memeriksa objek dan menampilkan pesan kesalahan informatif di layar.



Bagaimanapun, kelas pengecualian membuatnya lebih mudah untuk menangani kesalahan yang muncul!



All Articles