วิธีสร้างคุณสมบัตินามธรรมในคลาสนามธรรมของ python


119

Baseในรหัสต่อไปนี้ฉันจะสร้างฐานระดับนามธรรม ฉันต้องการให้คลาสทั้งหมดที่สืบทอดมาBaseเพื่อจัดหาnameคุณสมบัติดังนั้นฉันจึงสร้างคุณสมบัตินี้เป็น@abstractmethod.

จากนั้นฉันก็สร้างคลาสย่อยที่Baseเรียกว่าBase_1ซึ่งมีไว้เพื่อจัดหาฟังก์ชันการทำงานบางอย่าง แต่ยังคงเป็นนามธรรม ไม่มีnameคุณสมบัติในBase_1แต่อย่างไรก็ตาม python จะติดตั้งอ็อบเจ็กต์ของคลาสนั้นโดยไม่มีข้อผิดพลาด หนึ่งสร้างคุณสมบัติที่เป็นนามธรรมได้อย่างไร?

from abc import ABCMeta, abstractmethod
class Base(object):
    __metaclass__ = ABCMeta
    def __init__(self, strDirConfig):
        self.strDirConfig = strDirConfig

    @abstractmethod
    def _doStuff(self, signals):
        pass

    @property    
    @abstractmethod
    def name(self):
        #this property will be supplied by the inheriting classes
        #individually
        pass


class Base_1(Base):
    __metaclass__ = ABCMeta
    # this class does not provide the name property, should raise an error
    def __init__(self, strDirConfig):
        super(Base_1, self).__init__(strDirConfig)

    def _doStuff(self, signals):
        print 'Base_1 does stuff'


class C(Base_1):
    @property
    def name(self):
        return 'class C'


if __name__ == '__main__':
    b1 = Base_1('abc')  

Gotcha: หากคุณลืมที่จะใช้มัณฑนากร@propertyในclass C, nameจะกลับไปใช้วิธีการ
kevinarpe

คำตอบ:


118

เนื่องจากPython 3.3มีการแก้ไขข้อบกพร่องซึ่งหมายความว่าproperty()มัณฑนากรได้รับการระบุอย่างถูกต้องว่าเป็นนามธรรมเมื่อนำไปใช้กับวิธีนามธรรม

หมายเหตุ: เรื่องการสั่งซื้อคุณต้องใช้@propertyก่อน@abstractmethod

Python 3.3+: ( เอกสาร python ):

class C(ABC):
    @property
    @abstractmethod
    def my_abstract_property(self):
        ...

Python 2: ( เอกสาร python )

class C(ABC):
    @abstractproperty
    def my_abstract_property(self):
        ...

1
@ เจมส์จะทำให้มันเข้ากันได้กับ python 2 และเช่นกันได้อย่างไร?
himanshu219

@ เจมส์จริง ๆ แล้วฉันหมายถึงทั้งคู่ แต่ไม่เป็นไรฉันโพสต์คำตอบตามวิธีแก้ปัญหาของคุณ
himanshu219

45

จนถึงPython 3.3คุณไม่สามารถทำรัง@abstractmethodและ@property.

ใช้@abstractpropertyเพื่อสร้างคุณสมบัตินามธรรม ( เอกสาร )

from abc import ABCMeta, abstractmethod, abstractproperty

class Base(object):
    # ...
    @abstractproperty
    def name(self):
        pass

ตอนนี้รหัสเพิ่มข้อยกเว้นที่ถูกต้อง:

Traceback (โทรล่าสุดล่าสุด):
  ไฟล์ "foo.py" บรรทัด 36 นิ้ว 
    b1 = Base_1 ('abc')  
TypeError: ไม่สามารถสร้างอินสแตนซ์คลาสนามธรรม Base_1 ด้วยชื่อเมธอดนามธรรม

42
จริงๆแล้วคำตอบนี้ไม่ถูกต้องสำหรับงูเหลือมที่อายุน้อยกว่า: ตั้งแต่ 3.3 @abstractpropertyถูกเลิกใช้เนื่องจากการรวมกันเช่น OP
แกะบิน



จนถึง 3.3 เพียงraise NotImplementedError
Sławomir Lenart

เราสามารถสืบทอดจากวัตถุและยังคงใช้คำอธิบายประกอบ ABC ได้หรือไม่ จะได้ผลตามที่แสดงในตัวอย่างหรือไม่?
santhosh kumar

3

ตามคำตอบของเจมส์ข้างต้น

def compatibleabstractproperty(func):

    if sys.version_info > (3, 3):             
        return property(abstractmethod(func))
    else:
        return abstractproperty(func)

และใช้เป็นมัณฑนากร

@compatibleabstractproperty
def env(self):
    raise NotImplementedError()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.