Cách tạo thuộc tính trừu tượng trong lớp trừu tượng python


118

Trong đoạn mã sau, tôi tạo một lớp trừu tượng cơ sở Base. Tôi muốn tất cả các lớp kế thừa từ đó Basecung cấp thuộc nametính, vì vậy tôi đã tạo thuộc tính này là an @abstractmethod.

Sau đó, tôi tạo một lớp con Base, được gọi là Base_1, có nghĩa là cung cấp một số chức năng, nhưng vẫn còn trừu tượng. Không có namethuộc tính trong Base_1, nhưng tuy nhiên, python cài đặt một đối tượng của lớp đó mà không có lỗi. Làm thế nào để tạo ra các thuộc tính trừu tượng?

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: Nếu bạn quên sử dụng decorator @propertytrong class C, namesẽ hoàn nguyên về một phương thức.
kevinarpe

Câu trả lời:


117

Vì trong Python 3.3, một lỗi đã được sửa có nghĩa là trình property()trang trí hiện được xác định chính xác là trừu tượng khi áp dụng cho một phương thức trừu tượng.

Lưu ý: Vấn đề đặt hàng, bạn phải sử dụng @propertytrước@abstractmethod

Python 3.3+: ( tài liệu python ):

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

Python 2: ( tài liệu về trăn )

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

1
@James Làm thế nào để làm cho nó tương thích với python 2 và cả?
heanshu219

@ James thực sự tôi có nghĩa là cho cả hai nhưng nevermind tôi đã đăng một câu trả lời dựa trên giải pháp của bạn
himanshu219

45

Cho đến Python 3.3 , bạn không thể lồng @abstractmethod@property.

Sử dụng @abstractpropertyđể tạo thuộc tính trừu tượng ( tài liệu ).

from abc import ABCMeta, abstractmethod, abstractproperty

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

Mã bây giờ tăng ngoại lệ chính xác:

Traceback (cuộc gọi gần đây nhất):
  Tệp "foo.py", dòng 36, trong 
    b1 = Base_1 ('abc')  
TypeError: Không thể khởi tạo lớp trừu tượng Base_1 với tên phương thức trừu tượng

42
thực sự câu trả lời này là sai đối với những con trăn trẻ hơn: kể từ 3.3, @abstractpropertynó không được dùng nữa để ủng hộ sự kết hợp như OP.
cừu bay vào



vì vậy cho đến ngày 3.3, chỉraise NotImplementedError
Sławomir Lenart

chúng ta có thể kế thừa từ đối tượng và vẫn sử dụng các chú thích ABC không? Nó sẽ hoạt động như trong ví dụ?
santhosh kumar

3

Dựa trên câu trả lời của James ở trên

def compatibleabstractproperty(func):

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

và sử dụng nó như một người trang trí

@compatibleabstractproperty
def env(self):
    raise NotImplementedError()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.