Python'daki soyut sınıf ve arayüz arasındaki fark nedir?
Python'daki soyut sınıf ve arayüz arasındaki fark nedir?
Yanıtlar:
Bazen göreceğiniz şey şudur:
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" )
Python'un resmi bir Arayüz sözleşmesi olmadığı (ve gerekmediği) için, soyutlama ve arayüz arasındaki Java tarzı ayrım mevcut değildir. Birisi resmi bir arayüz tanımlama çabasından geçerse, aynı zamanda soyut bir sınıf olacaktır. Tek fark doktrinlerde belirtilen niyette olacaktır.
Ve soyut ve arayüz arasındaki fark, ördek yazarken saç dökücü bir şeydir.
Java, çoklu mirasa sahip olmadığı için arabirimler kullanır.
Python'un birden fazla mirası olduğundan, bunun gibi bir şey de görebilirsiniz.
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
Bu, ayrık beton alt sınıflar oluşturmak için bir tür soyut süper sınıf karışımı kullanır.
NotImplementedError("Class %s doesn't implement aMethod()" % (self.__class__.__name__))
daha bilgilendirici bir hata mesajıdır :)
Python'daki soyut sınıf ve arayüz arasındaki fark nedir?
Bir nesne için bir arabirim, o nesne üzerindeki bir dizi yöntem ve özniteliktir.
Python'da, bir arabirimi tanımlamak ve uygulamak için soyut bir temel sınıf kullanabiliriz.
Örneğin, collections
modüldeki soyut temel sınıflardan birini kullanmak istediğimizi düşünelim:
import collections
class MySet(collections.Set):
pass
Kullanmaya çalışırsak, TypeError
oluşturduğumuz sınıf kümelerin beklenen davranışını desteklemediği için şunu alırız:
>>> 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__
Biz uygulamak zorundadır Yani az __contains__
, __iter__
ve __len__
. Bu uygulama örneğini belgelerden kullanalım :
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
Metaclass'ı ayarlayarak abc.ABCMeta
ve abc.abstractmethod
dekoratörü ilgili yöntemlerde kullanarak kendi Soyut Temel Sınıfımızı oluşturabiliriz . Metaclass, dekore edilmiş fonksiyonları __abstractmethods__
özniteliğe ekleyerek tanımlanana kadar somutlaşmayı önleyecektir.
import abc
Örneğin, "etkili" sözcüklerle ifade edilebilecek bir şey olarak tanımlanır. Diyelim ki Python 2'de etkili bir soyut temel sınıf tanımlamak istedik:
class Effable(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def __str__(self):
raise NotImplementedError('users must define __str__ to use this base class')
Veya Python 3'te, metasınıf bildirimindeki küçük bir değişiklikle:
class Effable(object, metaclass=abc.ABCMeta):
@abc.abstractmethod
def __str__(self):
raise NotImplementedError('users must define __str__ to use this base class')
Şimdi arabirimi uygulamadan etkili bir nesne oluşturmaya çalışırsak:
class MyEffable(Effable):
pass
ve somutlaştırmaya çalışın:
>>> MyEffable()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__
Bize işi bitirmediğimiz söylendi.
Şimdi beklenen arayüzü sağlayarak uyursak:
class MyEffable(Effable):
def __str__(self):
return 'expressable!'
daha sonra soyut olandan türetilen sınıfın somut versiyonunu kullanabiliriz:
>>> me = MyEffable()
>>> print(me)
expressable!
Bununla ilgili yapabileceğimiz başka şeyler de var, bu arayüzleri zaten uygulayan sanal alt sınıfları kaydettirmek gibi, ama bence bu sorunun kapsamı dışında. Ancak burada gösterilen diğer yöntemler abc
, bunu yapmak için modülü kullanarak bu yöntemi uyarlamak zorunda kalacaktır .
Soyut Temel Sınıf oluşturmanın Python'daki özel nesneler için arayüzler tanımladığını gösterdik.
Python> = 2.6, Soyut Temel Sınıflara sahiptir .
Özet Temel Sınıflar (kısaltılmış ABC'ler) hasattr () gibi diğer teknikler beceriksiz olduğunda arayüzleri tanımlamak için bir yol sağlayarak ördek tipini tamamlar. Python, veri yapıları (koleksiyonlar modülünde), sayılar (sayılar modülünde) ve akışlar (io modülünde) için birçok yerleşik ABC ile birlikte gelir. Abc modülü ile kendi ABC'nizi oluşturabilirsiniz.
Ayrıca, bükülmüş gibi zope dışındaki projeler tarafından kullanılan Zope Arayüz modülü de vardır . Gerçekten bilmiyorum, ama burada yardımcı olabilecek bir wiki sayfası var .
Genel olarak, soyut sınıflar kavramına veya python'daki arayüzlere ihtiyacınız yoktur (düzenlenmiştir - ayrıntılar için S.Lott'un cevabına bakın).
Python'un bu iki konsepti de yok.
Arayüz ihtiyacını ortadan kaldıran ördek yazmayı kullanır (en azından bilgisayar için :-))
Python <= 2.5: Temel sınıflar açıkça var, ancak bir yöntemi 'saf sanal' olarak işaretlemenin açık bir yolu yok, bu yüzden sınıf gerçekten soyut değil.
Python> = 2.6: Soyut temel sınıflar vardır ( http://docs.python.org/library/abc.html ). Ve alt sınıflarda uygulanması gereken yöntemleri belirtmenize izin verin. Sözdizimini pek sevmiyorum, ancak özellik orada. Çoğu zaman 'kullanma' istemci tarafında ördek yazarak kullanmak daha iyidir.
Açıklamak için daha temel bir yolla: Arayüz boş bir çörek tepsisi gibidir. Kod içermeyen bir dizi yöntem tanımı içeren bir sınıf dosyasıdır.
Soyut bir sınıf aynı şeydir, ancak tüm işlevlerin boş olması gerekmez. Bazılarının kodu olabilir. Kesinlikle boş değil.
Neden farklılaşmalı: Python'da çok fazla pratik fark yok, ancak büyük bir projenin planlama düzeyinde, kodlar olmadığından arayüzler hakkında konuşmak daha yaygın olabilir. Özellikle terime alışık olan Java programcılarıyla çalışıyorsanız.
Genel olarak, arabirimler yalnızca tek miras sınıf modelini kullanan dillerde kullanılır. Bu tek miras dillerinde, arabirimler genellikle herhangi bir sınıf belirli bir yöntemi veya yöntem kümesini kullanabiliyorsa kullanılır. Ayrıca bu tek miras dillerinde, soyut sınıflar ya hiçbir ya da daha fazla yönteme ek olarak sınıf değişkenlerini tanımlamak ya da bir takım yöntemler kullanabilen sınıfların aralığını sınırlamak için tek kalıtım modelinden yararlanmak için kullanılır.
Çoklu kalıtım modelini destekleyen diller arabirimleri değil, yalnızca sınıfları veya soyut temel sınıfları kullanma eğilimindedir. Python çoklu kalıtımı desteklediğinden, arabirimler kullanmaz ve temel sınıfları veya soyut temel sınıfları kullanmak istersiniz.
Soyut sınıflar, bir veya daha fazla soyut yöntem içeren sınıflardır. Soyut yöntemlerle birlikte, Soyut sınıflar statik, sınıf ve örnek yöntemlere sahip olabilir. Ancak arayüz durumunda, sadece soyut yöntemlere sahip değildir. Bu nedenle soyut sınıfı miras almak zorunlu değildir, ancak arayüzü miras almak zorunludur.
Tamlığı için, bahsetmeliyiz PEP3119 ABC arayüzleri ile tanıtıldı ve karşılaştırılmıştır ve orijinal Talin en yorumunu.
Soyut sınıf mükemmel bir arayüz değildir:
Ama kendi yolunuzla yazmayı düşünüyorsanız:
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
...
sonuçta ulaşmak için tekerleği icat ettiğinizi oldukça hızlı fark edeceksiniz
abc.ABCMeta
abc.ABCMeta
, eksik arayüz işlevselliğinin yararlı bir eki olarak önerildi ve bu, python gibi bir dilde yeterince adil.
Elbette, sürüm 3 yazılırken ve yeni sözdizimi ve değişmez arayüz kavramı eklenirken daha iyi geliştirilebildi ...
Sonuç:
The abc.ABCMeta IS "pythonic" interface in python