Bir de yapabileceğini raise NotImplementedError()
içindeki bir çocuk yöntemiyle @abstractmethod
-dekore temel sınıf yöntemiyle.
Bir ölçüm modülleri ailesi (fiziksel cihazlar) için bir kontrol komut dosyası yazdığınızı hayal edin. Her modülün işlevselliği dar bir şekilde tanımlanmıştır ve yalnızca bir özel işlevi yerine getirir: biri bir dizi röle, diğeri çok kanallı bir DAC veya ADC, diğeri bir ampermetre olabilir.
Kullanılmakta olan düşük seviyeli komutların çoğu, örneğin ID numaralarını okumak veya onlara bir komut göndermek için modüller arasında paylaşılacaktır. Bakalım bu noktada elimizde ne var:
Temel Sınıf
from abc import ABC, abstractmethod
class Generic(ABC):
''' Base class for all measurement modules. '''
def __init__(self):
def _read_ID(self):
def _send_command(self, value):
Paylaşılan Fiiller
Ardından, modüle özgü komut fiillerinin çoğunun ve dolayısıyla arayüzlerinin mantığının da paylaşıldığını fark ederiz. Burada, bir dizi hedef modül düşünüldüğünde anlamı kendi kendini açıklayan 3 farklı fiil var.
get(channel)
röle: rölenin açık / kapalı durumunu alchannel
DAC: get çıkış voltajı üzerindechannel
ADC: get giriş voltajını üzerindechannel
enable(channel)
röle: rölenin açık olarak kullanılmasını etkinleştirchannel
DAC: çıkış kanalının kullanımını etkinleştirinchannel
ADC: giriş kanalının kullanımını etkinleştirinchannel
set(channel)
röle: röleyi channel
açık / kapalı olarak ayarlayın
DAC: çıkış voltajını ayarlayınchannel
ADC: hmm ... akla mantıklı bir şey gelmiyor.
Paylaşılan Fiiller Zorunlu Fiiller Oluyor
Yukarıdaki fiillerin, anlamlarının her biri için açık olduğunu gördüğümüzde modüller arasında paylaşılması için güçlü bir durum olduğunu iddia ediyorum. Temel sınıfımı şöyle yazmaya devam edeceğim Generic
:
class Generic(ABC):
@abstractmethod
def get(self, channel):
pass
@abstractmethod
def enable(self, channel):
pass
@abstractmethod
def set(self, channel):
pass
Alt sınıflar
Artık alt sınıflarımızın hepsinin bu yöntemleri tanımlaması gerektiğini biliyoruz. ADC modülü için neye benzeyebileceğini görelim:
class ADC(Generic):
def __init__(self):
super().__init__()
def get(self, channel):
def enable(self, channel):
Şimdi merak ediyor olabilirsiniz:
Ancak bu, ADC modülü için işe yaramayacak, çünkü set
yukarıda gördüğümüz gibi orada hiçbir anlam ifade etmiyor!
Haklısın: set
Python, ADC nesnenizi başlatmaya çalıştığınızda aşağıdaki hatayı tetikleyeceği için uygulama yapmamak bir seçenek değildir.
TypeError: Can't instantiate abstract class 'ADC' with abstract methods 'set'
Bir şey uygulamalıdır Yani yaptığımız çünkü set
bir fiil zorunlu olarak değil, aynı zamanda, aynı zamanda herhangi bir şey uygulayamaz gereken iki diğer modüller tarafından paylaşıldığı, (aka '@abstractmethod')
set
bu özel modül için bir anlam ifade etmiyor.
NotImplementedError to the Rescue
ADC sınıfını şu şekilde tamamlayarak:
class ADC(Generic):
def set(self, channel):
raise NotImplementedError("Can't use 'set' on an ADC!")
Aynı anda çok iyi üç şey yapıyorsunuz:
- Bir kullanıcıyı yanlışlıkla bu modül için uygulanmayan (ve uygulanmaması gereken!) Bir komut ('set') vermekten koruyorsunuz.
- Onlara sorunun ne olduğunu açıkça söylüyorsunuz (bunun neden önemli olduğunu öğrenmek için TemporalWolf'un 'Çıplak istisnalar' bağlantısına bakın)
- Zorunlu fiillerin
anlamlı olduğu diğer tüm modüllerin uygulanmasını koruyorsunuz . Yani bu fiiller kendisi için bu modüllerin sağlamak yapmak mantıklı bu yöntemleri uygulayacak ve bu tam olarak bu fiilleri kullanarak bunu yapacağız değil diğer bazı geçici isimler.