Python'da soyut sınıf ve arayüz arasındaki fark


Yanıtlar:


618

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.


5
S. Lott, ördek yazarak has-a (arayüz) ve is-a (kalıtım) arasındaki ayrımın önemli olmadığı anlamına mı geliyor?
Lorenzo

3
Soyut ve arayüz arasındaki fark, ördek yazarken saç dökücü bir şeydir. "Önemli" ne demek bilmiyorum. Tasarım açısından "gerçek" - madde var -. Ancak dil açısından bakıldığında destek olmayabilir. Python'da soyut bir sınıf ile arayüz sınıfı tanımını birbirinden ayıracak kurallar benimseyebilirsiniz.
S.Lott

26
@ L.DeLeo - has-a ve is-a kavramınızın doğru olduğundan emin misiniz? Genelde ayırımı has-a = üye değişkeni olarak is-a = kalıtım (üst sınıf veya arabirim) olarak görürüm . Java ile Karşılaştırılabilir veya Listelenebilir; bunlar arayüzler mi, soyut sınıflar olsun, bir ilişkidir.
dimo414

43
NotImplementedError("Class %s doesn't implement aMethod()" % (self.__class__.__name__))daha bilgilendirici bir hata mesajıdır :)
naught101

9
@Lorenzo a has-a ilişkisinin kalıtım, ördek yazma, arayüzler ve soyut sınıflarla hiçbir ilgisi yoktur (dördü de is-a ilişkilerine işaret eder).
Karl Richter

197

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.

Soyut Temel Sınıf Kullanma

Örneğin, collectionsmodüldeki soyut temel sınıflardan birini kullanmak istediğimizi düşünelim:

import collections
class MySet(collections.Set):
    pass

Kullanmaya çalışırsak, TypeErroroluş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

Uygulama: Soyut Temel Sınıf Oluşturma

Metaclass'ı ayarlayarak abc.ABCMetave abc.abstractmethoddekoratö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 .

Sonuç

Soyut Temel Sınıf oluşturmanın Python'daki özel nesneler için arayüzler tanımladığını gösterdik.


101

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).


2
Python'da ABC kullanarak ne kazanıyorsunuz?
CpILL

38

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.


3
Python 3.0 gerçek soyut temel sınıflar ekler. Koleksiyon modülünde ve diğer yerlerde kullanılırlar. docs.python.org/3.0/library/abc.html
Lara Dougan

Ördek yazmanın arayüzlere olan ihtiyacı neden ortadan kaldırdığına dair bir referans yardımcı olacaktır. Herhangi bir nesneyi herhangi bir yöntem veya özniteliği "dürtme" yeteneği olarak anladığım ördek yazmanın, gerekli davranışları belirtmeniz (ve derleyiciyi size hatırlatması gerekmediği) anlamına gelmiyor. onları uygulamak için).
Reb.Cabin

Ördek yazımından daha az, örneğin Java'nın çizdiği arayüz ve soyut sınıf arasındaki yapay çizgiyi kaldıran çoklu kalıtım desteği.
masi

35

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.


ABC'nin kendi uygulamalarına sahip olabileceği ayrım için +1 - bu kendini
aşmanın

17

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.

http://docs.python.org/library/abc.html


2

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.


1

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:

  • kalıtım hiyerarşisine aittir
  • değiştirilebilir

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.