Bagaimana saya bisa membuat kelas atau metode abstrak dengan Python?
Saya mencoba mendefinisikan ulang __new__()
seperti:
class F:
def __new__(cls):
raise Exception("Unable to create an instance of abstract class %s" %cls)
tetapi sekarang jika saya membuat kelas G
yang mewarisi dari F
seperti:
class G(F):
pass
maka saya tidak bisa instantiate G
juga, karena ia memanggil __new__
metode super class-nya .
Apakah ada cara yang lebih baik untuk mendefinisikan kelas abstrak?
python
class
inheritance
abstract-class
abstract
Martin Thoma
sumber
sumber
Jawaban:
Gunakan
abc
modul untuk membuat kelas abstrak. Gunakanabstractmethod
dekorator untuk mendeklarasikan abstrak metode, dan mendeklarasikan abstrak kelas menggunakan salah satu dari tiga cara, tergantung pada versi Python Anda.Di Python 3.4 dan di atasnya, Anda bisa mewarisi dari
ABC
. Di versi Python sebelumnya, Anda perlu menentukan metaclass kelas Anda sebagaiABCMeta
. Menentukan metaclass memiliki sintaks yang berbeda dalam Python 3 dan Python 2. Tiga kemungkinan ditunjukkan di bawah ini:Dengan cara apa pun yang Anda gunakan, Anda tidak akan dapat membuat instance kelas abstrak yang memiliki metode abstrak, tetapi akan dapat membuat instance subkelas yang memberikan definisi konkret dari metode tersebut:
sumber
@abstractmethod
sehingga fungsi yang didekorasi harus ditimpa sebelum kelas dapat dipakai. Dari dokumen:A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden.
@abstractmethod
untuk__init__
metode juga, lihat stackoverflow.com/q/44800659/547270Cara sekolah lama (pra- PEP 3119 ) untuk melakukan ini adalah hanya untuk
raise NotImplementedError
di kelas abstrak ketika metode abstrak dipanggil.Ini tidak memiliki properti bagus yang sama seperti menggunakan
abc
modul. Anda masih dapat membuat instance kelas dasar abstrak itu sendiri, dan Anda tidak akan menemukan kesalahan Anda sampai Anda memanggil metode abstrak saat runtime.Tetapi jika Anda berurusan dengan satu set kecil kelas sederhana, mungkin hanya dengan beberapa metode abstrak, pendekatan ini sedikit lebih mudah daripada mencoba mengarungi
abc
dokumentasi.sumber
Inilah cara yang sangat mudah tanpa harus berurusan dengan modul ABC.
Dalam
__init__
metode kelas yang Anda inginkan menjadi kelas abstrak, Anda dapat memeriksa "tipe" diri. Jika tipe diri adalah kelas dasar, maka penelepon mencoba untuk membuat instance kelas dasar, jadi ajukan pengecualian. Berikut ini contoh sederhana:Saat dijalankan, ini menghasilkan:
Ini menunjukkan bahwa Anda bisa instantiate subclass yang mewarisi dari kelas dasar, tetapi Anda tidak bisa membuat instance kelas dasar secara langsung.
sumber
Sebagian besar jawaban Sebelumnya benar tetapi berikut adalah jawaban dan contoh untuk Python 3.7. Ya, Anda bisa membuat kelas dan metode abstrak. Sama seperti pengingat, kadang-kadang sebuah kelas harus mendefinisikan metode yang secara logis milik kelas, tetapi kelas itu tidak bisa menentukan cara mengimplementasikan metode tersebut. Sebagai contoh, di kelas Orangtua dan Bayi di bawah ini mereka berdua makan tetapi implementasinya akan berbeda untuk masing-masing karena bayi dan orang tua makan jenis makanan yang berbeda dan berapa kali mereka makan berbeda. Jadi, makan metode subclass menimpa AbstractClass.eat.
KELUARAN:
sumber
import abc
tidak berguna.Yang ini akan bekerja di python 3
sumber
Seperti yang dijelaskan dalam jawaban lain, ya Anda bisa menggunakan kelas abstrak di Python menggunakan
abc
modul . Di bawah ini saya memberikan contoh aktual menggunakan abstrak@classmethod
,@property
dan@abstractmethod
(menggunakan Python 3.6+). Bagi saya biasanya lebih mudah untuk memulai dengan contoh-contoh yang saya dapat dengan mudah menyalin & menempel; Saya harap jawaban ini juga bermanfaat bagi orang lain.Pertama mari kita membuat kelas dasar yang disebut
Base
:Base
Kelas kami akan selalu memiliki afrom_dict
classmethod
, aproperty
prop1
(yang hanya baca) dan aproperty
prop2
(yang juga dapat diatur) serta fungsi yang disebutdo_stuff
. Apa pun kelas yang sekarang dibangun berdasarkanBase
harus menerapkan semua ini untuk metode / properti. Harap dicatat bahwa untuk metode menjadi abstrak, diperlukan dua dekorator -classmethod
dan abstrakproperty
.Sekarang kita bisa membuat kelas
A
seperti ini:Semua metode / properti yang diperlukan diimplementasikan dan kami - tentu saja - juga dapat menambahkan fungsi tambahan yang bukan bagian dari
Base
(di sinii_am_not_abstract
:).Sekarang kita bisa melakukan:
Seperti yang diinginkan, kami tidak dapat mengatur
prop1
:akan kembali
from_dict
Metode kami juga berfungsi dengan baik:Jika sekarang kita mendefinisikan kelas kedua
B
seperti ini:dan mencoba untuk instantiate objek seperti ini:
kami akan mendapatkan kesalahan
daftar semua hal yang didefinisikan di
Base
mana kami tidak menerapkannyaB
.sumber
ini juga berfungsi dan sederhana:
sumber
Anda juga dapat memanfaatkan metode __new__ untuk keuntungan Anda. Anda baru saja melupakan sesuatu. Metode __new__ selalu mengembalikan objek baru sehingga Anda harus mengembalikan metode baru superclassnya. Lakukan sebagai berikut.
Saat menggunakan metode baru, Anda harus mengembalikan objek, bukan kata kunci None. Itu semua yang Anda lewatkan.
sumber
Saya menemukan jawaban yang diterima, dan semua yang lain aneh, karena mereka lolos
self
ke kelas abstrak. Kelas abstrak tidak dipakai jadi tidak bisa memilikiself
.Jadi coba ini, ini berhasil.
sumber
sumber
Dalam cuplikan kode Anda, Anda juga bisa menyelesaikan ini dengan memberikan implementasi untuk
__new__
metode di subkelas, juga:Tetapi ini adalah retasan dan saya menyarankan Anda untuk tidak melakukannya, kecuali jika Anda tahu apa yang Anda lakukan. Untuk hampir semua kasus, saya menyarankan Anda untuk menggunakan
abc
modul, yang disarankan orang lain sebelum saya.Juga ketika Anda membuat (base) kelas baru, membuat subclass
object
, seperti ini:class MyBaseClass(object):
. Saya tidak tahu apakah itu jauh lebih penting lagi, tetapi ini membantu mempertahankan konsistensi gaya pada kode Andasumber
Hanya tambahan cepat ke jawaban old-school @ TimGilbert ... Anda dapat membuat init () metode abstrak kelas dasar Anda membuat pengecualian dan itu akan mencegahnya dari dipakai, bukan?
sumber