Jawaban:
Apa yang akan Anda lihat kadang-kadang adalah sebagai berikut:
class Abstract1( object ):
"""Some description that tells you it's abstract,
often listing the methods you're expected to supply."""
def aMethod( self ):
raise NotImplementedError( "Should have implemented this" )
Karena Python tidak memiliki (dan tidak perlu) kontrak Antarmuka formal, perbedaan gaya Java antara abstraksi dan antarmuka tidak ada. Jika seseorang melalui upaya untuk mendefinisikan antarmuka formal, itu juga akan menjadi kelas abstrak. Satu-satunya perbedaan adalah dalam maksud yang dinyatakan dalam dokumen.
Dan perbedaan antara abstrak dan antarmuka adalah hal yang menarik ketika Anda mengetik bebek.
Java menggunakan antarmuka karena tidak memiliki banyak warisan.
Karena Python memiliki banyak pewarisan, Anda juga dapat melihat sesuatu seperti ini
class SomeAbstraction( object ):
pass # lots of stuff - but missing something
class Mixin1( object ):
def something( self ):
pass # one implementation
class Mixin2( object ):
def something( self ):
pass # another
class Concrete1( SomeAbstraction, Mixin1 ):
pass
class Concrete2( SomeAbstraction, Mixin2 ):
pass
Ini menggunakan semacam superclass abstrak dengan mixin untuk membuat subkelas beton yang terpisah.
NotImplementedError("Class %s doesn't implement aMethod()" % (self.__class__.__name__))
adalah pesan kesalahan yang lebih informatif :)
Apa perbedaan antara kelas abstrak dan antarmuka dalam Python?
Antarmuka, untuk suatu objek, adalah seperangkat metode dan atribut pada objek itu.
Dengan Python, kita bisa menggunakan kelas dasar abstrak untuk mendefinisikan dan menjalankan antarmuka.
Sebagai contoh, katakanlah kita ingin menggunakan salah satu kelas dasar abstrak dari collections
modul:
import collections
class MySet(collections.Set):
pass
Jika kita mencoba menggunakannya, kita mendapatkan TypeError
karena kelas yang kita buat tidak mendukung perilaku set yang diharapkan:
>>> MySet()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__
Jadi kita dituntut untuk menerapkan di setidaknya __contains__
, __iter__
, dan __len__
. Mari kita gunakan contoh implementasi ini dari dokumentasi :
class ListBasedSet(collections.Set):
"""Alternate set implementation favoring space over speed
and not requiring the set elements to be hashable.
"""
def __init__(self, iterable):
self.elements = lst = []
for value in iterable:
if value not in lst:
lst.append(value)
def __iter__(self):
return iter(self.elements)
def __contains__(self, value):
return value in self.elements
def __len__(self):
return len(self.elements)
s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2
Kita dapat membuat Kelas Dasar Abstrak kita sendiri dengan mengatur metaclass ke abc.ABCMeta
dan menggunakan abc.abstractmethod
dekorator pada metode yang relevan. Metaclass akan menambahkan fungsi-fungsi yang didekorasi ke __abstractmethods__
atribut, mencegah instantiation hingga didefinisikan.
import abc
Sebagai contoh, "effable" didefinisikan sebagai sesuatu yang dapat diekspresikan dalam kata-kata. Katakanlah kita ingin mendefinisikan kelas dasar abstrak yang efektif, dengan Python 2:
class Effable(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def __str__(self):
raise NotImplementedError('users must define __str__ to use this base class')
Atau dengan Python 3, dengan sedikit perubahan dalam deklarasi metaclass:
class Effable(object, metaclass=abc.ABCMeta):
@abc.abstractmethod
def __str__(self):
raise NotImplementedError('users must define __str__ to use this base class')
Sekarang jika kita mencoba membuat objek yang efektif tanpa mengimplementasikan antarmuka:
class MyEffable(Effable):
pass
dan berusaha untuk instantiate:
>>> MyEffable()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__
Kami diberitahu bahwa kami belum menyelesaikan pekerjaan.
Sekarang jika kami mematuhi dengan menyediakan antarmuka yang diharapkan:
class MyEffable(Effable):
def __str__(self):
return 'expressable!'
kita kemudian dapat menggunakan versi konkret dari kelas yang berasal dari abstrak:
>>> me = MyEffable()
>>> print(me)
expressable!
Ada hal-hal lain yang bisa kita lakukan dengan ini, seperti mendaftar subkelas virtual yang sudah mengimplementasikan antarmuka ini, tapi saya pikir itu di luar cakupan pertanyaan ini. Namun, metode lain yang diperlihatkan di sini harus mengadaptasi metode ini menggunakan abc
modul untuk melakukannya.
Kami telah menunjukkan bahwa pembuatan Kelas Basis Abstrak mendefinisikan antarmuka untuk objek khusus dalam Python.
Python> = 2.6 memiliki Kelas Basis Abstrak .
Abstrak Base Classes (disingkat ABC) melengkapi bebek-mengetik dengan menyediakan cara untuk mendefinisikan antarmuka ketika teknik lain seperti hasattr () akan kikuk. Python hadir dengan banyak ABC bawaan untuk struktur data (dalam modul koleksi), angka (dalam modul angka), dan stream (dalam modul io). Anda dapat membuat ABC Anda sendiri dengan modul abc.
Ada juga modul Zope Interface , yang digunakan oleh proyek di luar zope, seperti twisted. Saya tidak terlalu mengenalnya, tetapi ada halaman wiki di sini yang mungkin membantu.
Secara umum, Anda tidak memerlukan konsep kelas abstrak, atau antarmuka dalam python (diedit - lihat jawaban S.Lott untuk detailnya).
Python tidak benar-benar memiliki konsep apa pun.
Ini menggunakan mengetik bebek, yang menghilangkan kebutuhan untuk antarmuka (setidaknya untuk komputer :-))
Python <= 2.5: Kelas dasar jelas ada, tetapi tidak ada cara eksplisit untuk menandai metode sebagai 'virtual murni', sehingga kelas tidak benar-benar abstrak.
Python> = 2.6: Kelas dasar abstrak memang ada ( http://docs.python.org/library/abc.html ). Dan memungkinkan Anda untuk menentukan metode yang harus diimplementasikan dalam subkelas. Saya tidak terlalu suka dengan sintaks, tetapi fitur itu ada. Sebagian besar waktu mungkin lebih baik menggunakan itik mengetik dari sisi klien 'menggunakan'.
Dengan cara yang lebih mendasar untuk menjelaskan: Antarmuka adalah semacam panci muffin kosong. Ini adalah file kelas dengan sekumpulan definisi metode yang tidak memiliki kode.
Kelas abstrak adalah hal yang sama, tetapi tidak semua fungsi harus kosong. Beberapa dapat memiliki kode. Ini tidak sepenuhnya kosong.
Mengapa membedakan: Tidak ada banyak perbedaan praktis dalam Python, tetapi pada tingkat perencanaan untuk proyek besar, bisa lebih umum untuk berbicara tentang antarmuka, karena tidak ada kode. Terutama jika Anda bekerja dengan programmer Java yang terbiasa dengan istilah tersebut.
Secara umum, antarmuka hanya digunakan dalam bahasa yang menggunakan model kelas pewarisan tunggal. Dalam bahasa pewarisan tunggal ini, antarmuka biasanya digunakan jika kelas mana pun dapat menggunakan metode atau serangkaian metode tertentu. Juga dalam bahasa pewarisan-tunggal ini, kelas-kelas abstrak digunakan untuk menentukan variabel kelas selain dari tidak ada atau lebih metode, atau untuk mengeksploitasi model pewarisan tunggal untuk membatasi rentang kelas yang dapat menggunakan serangkaian metode.
Bahasa yang mendukung model multiple-inheritance cenderung hanya menggunakan kelas atau kelas dasar abstrak dan bukan antarmuka. Karena Python mendukung multiple inheritance, ia tidak menggunakan antarmuka dan Anda ingin menggunakan kelas dasar atau kelas dasar abstrak.
Kelas abstrak adalah kelas yang berisi satu atau lebih metode abstrak. Seiring dengan metode abstrak, kelas abstrak dapat memiliki metode statis, kelas dan contoh. Tetapi dalam hal antarmuka, itu hanya akan memiliki metode abstrak bukan yang lain. Oleh karena itu tidak diwajibkan untuk mewarisi kelas abstrak tetapi wajib untuk mewarisi antarmuka.
Untuk kelengkapan, kita harus menyebutkan PEP3119 di mana ABC diperkenalkan dan dibandingkan dengan antarmuka, dan Talin asli komentar .
Kelas abstrak bukanlah antarmuka yang sempurna:
Tetapi jika Anda mempertimbangkan untuk menuliskannya dengan cara Anda sendiri:
def some_function(self):
raise NotImplementedError()
interface = type(
'your_interface', (object,),
{'extra_func': some_function,
'__slots__': ['extra_func', ...]
...
'__instancecheck__': your_instance_checker,
'__subclasscheck__': your_subclass_checker
...
}
)
ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...
Anda akan dengan cepat menyadari bahwa Anda sedang menciptakan roda untuk akhirnya mencapainya
abc.ABCMeta
abc.ABCMeta
diusulkan sebagai tambahan yang berguna dari fungsi antarmuka yang hilang, dan itu cukup adil dalam bahasa seperti python.
Tentu saja, itu dapat ditingkatkan lebih baik saat menulis versi 3, dan menambahkan sintaks baru dan konsep antarmuka yang tidak dapat diubah ...
Kesimpulan:
The abc.ABCMeta IS "pythonic" interface in python