Apakah untuk mengingatkan diri sendiri dan tim Anda untuk menerapkan kelas dengan benar? Saya tidak sepenuhnya mendapatkan penggunaan kelas abstrak seperti ini:
class RectangularRoom(object):
def __init__(self, width, height):
raise NotImplementedError
def cleanTileAtPosition(self, pos):
raise NotImplementedError
def isTileCleaned(self, m, n):
raise NotImplementedError
Jawaban:
Seperti yang dinyatakan dalam dokumentasi [dokumen] ,
Perhatikan bahwa meskipun kasus penggunaan utama yang dinyatakan kesalahan ini adalah indikasi metode abstrak yang harus diimplementasikan pada kelas yang diwariskan, Anda dapat menggunakannya sesuka Anda, seperti untuk indikasi
TODO
marker.sumber
abc
(lihat jawaban saya ).abstractmethod
dan biarkan terangkatNotImplementedError
. Ini melarangsuper().method()
dalam implementasimethod
di kelas turunan.Seperti yang dikatakan Uriel , ini dimaksudkan untuk metode di kelas abstrak yang harus diimplementasikan di kelas anak, tetapi dapat digunakan untuk menunjukkan TODO juga.
Ada alternatif untuk kasus penggunaan pertama: Kelas Dasar Abstrak . Itu membantu membuat kelas abstrak.
Berikut contoh Python 3:
class C(abc.ABC): @abc.abstractmethod def my_abstract_method(self, ...): ...
Saat membuat instance
C
, Anda akan mendapatkan error karenamy_abstract_method
abstrak. Anda perlu menerapkannya di kelas anak.TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method
Subclass
C
dan implementasinyamy_abstract_method
.class D(C): def my_abstract_method(self, ...): ...
Sekarang Anda dapat membuat contoh
D
.C.my_abstract_method
tidak harus kosong. Itu bisa dipanggil dariD
penggunaansuper()
.Keuntungan dari ini
NotImplementedError
adalah Anda mendapatkan yang eksplisitException
pada waktu pembuatan instance, bukan pada waktu panggilan metode.sumber
from abc import ABCMeta, abstractmethod
dan tentukan ABC Anda dengan__metaclass__ = ABCMeta
. Docs: docs.python.org/2/library/abc.htmlPertimbangkan jika sebaliknya:
class RectangularRoom(object): def __init__(self, width, height): pass def cleanTileAtPosition(self, pos): pass def isTileCleaned(self, m, n): pass
dan Anda membuat subkelas dan lupa memberitahukannya bagaimana
isTileCleaned()
atau, mungkin lebih mungkin, salah ketik sebagaiisTileCLeaned()
. Kemudian dalam kode Anda, Anda akan mendapatkanNone
ketika Anda memanggilnya.None
keluarannya valid? Siapa tahu.raise NotImplmentedError
memaksa Anda untuk menerapkannya, karena ini akan memunculkan pengecualian saat Anda mencoba menjalankannya sampai Anda melakukannya. Ini menghilangkan banyak kesalahan diam. Ini mirip dengan mengapa telanjang kecuali hampir tidak pernah merupakan ide yang baik : karena orang membuat kesalahan dan ini memastikan mereka tidak tersapu ke bawah permadani.Catatan: Menggunakan kelas dasar abstrak, seperti yang disebutkan oleh jawaban lain, lebih baik lagi, karena kesalahan tersebut dimuat di depan dan program tidak akan berjalan sampai Anda mengimplementasikannya (dengan NotImplementedError, ini hanya akan memunculkan pengecualian jika benar-benar dipanggil).
sumber
Seseorang juga bisa melakukan
raise NotImplementedError()
di dalam metode anak dari@abstractmethod
metode kelas dasar berdekorasi.Bayangkan menulis skrip kontrol untuk keluarga modul pengukuran (perangkat fisik). Fungsionalitas setiap modul didefinisikan secara sempit, hanya menerapkan satu fungsi khusus: satu dapat berupa array relai, yang lain DAC atau ADC multi-saluran, yang lain ammeter, dll.
Banyak dari perintah tingkat rendah yang digunakan akan dibagikan antar modul misalnya untuk membaca nomor ID mereka atau untuk mengirim perintah kepada mereka. Mari kita lihat apa yang kita miliki saat ini:
Kelas Dasar
from abc import ABC, abstractmethod #< we'll make use of these later class Generic(ABC): ''' Base class for all measurement modules. ''' # Shared functions def __init__(self): # do what you must... def _read_ID(self): # same for all the modules def _send_command(self, value): # same for all the modules
Kata Kerja Bersama
Kami kemudian menyadari bahwa banyak dari kata kerja perintah khusus modul dan, oleh karena itu, logika antarmukanya juga digunakan bersama. Berikut adalah 3 kata kerja berbeda yang artinya sudah cukup jelas mengingat sejumlah modul target.
get(channel)
relai: nyalakan / matikan status relai
channel
DAC: mendapatkan output yang tegangan pada
channel
ADC: mendapatkan masukan tegangan pada
channel
enable(channel)
relai: aktifkan penggunaan relai
channel
DAC: aktifkan penggunaan saluran keluaran
channel
ADC: aktifkan penggunaan saluran input
channel
set(channel)
relai: nyalakan
channel
/ matikan relaiDAC: setel tegangan keluaran
channel
ADC: hmm ... tidak logis datang ke pikiran.
Kata Kerja Bersama Menjadi Kata Kerja yang Dipaksakan
Saya berpendapat bahwa ada alasan kuat untuk kata kerja di atas untuk dibagikan di seluruh modul karena kita melihat bahwa maknanya terbukti untuk masing-masing modul. Saya akan terus menulis kelas dasar saya
Generic
seperti ini:class Generic(ABC): # ...continued @abstractmethod def get(self, channel): pass @abstractmethod def enable(self, channel): pass @abstractmethod def set(self, channel): pass
Subkelas
Kita sekarang tahu bahwa semua subclass kita harus mendefinisikan metode ini. Mari kita lihat seperti apa modul ADC:
class ADC(Generic): def __init__(self): super().__init__() #< applies to all modules # more init code specific to the ADC module def get(self, channel): # returns the input voltage measured on the given 'channel' def enable(self, channel): # enables accessing the given 'channel'
Anda sekarang mungkin bertanya-tanya:
Anda benar: tidak mengimplementasikan
set
bukanlah pilihan karena Python kemudian akan mengaktifkan kesalahan di bawah ini ketika Anda mencoba membuat instance objek ADC Anda.TypeError: Can't instantiate abstract class 'ADC' with abstract methods 'set'
Jadi, Anda harus menerapkan sesuatu, karena kami membuat
set
sebuah ditegakkan kata kerja (alias '@abstractmethod'), yang dibagi oleh dua modul lain tetapi, pada saat yang sama, Anda juga harus tidak melaksanakan apa-apa karenaset
tidak masuk akal untuk modul tertentu.NotImplementedError to the Rescue
Dengan menyelesaikan kelas ADC seperti ini:
class ADC(Generic): # ...continued def set(self, channel): raise NotImplementedError("Can't use 'set' on an ADC!")
Anda melakukan tiga hal yang sangat baik sekaligus:
sumber
Anda mungkin ingin menggunakan
@property
dekorator,>>> class Foo(): ... @property ... def todo(self): ... raise NotImplementedError("To be implemented") ... >>> f = Foo() >>> f.todo Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in todo NotImplementedError: To be implemented
sumber