Equivalent of NotImplementedError for fields in Python

前端 未结 8 1307
北海茫月
北海茫月 2020-12-07 18:56

In Python 2.x when you want to mark a method as abstract, you can define it like so:

class Base:
    def foo(self):
        raise NotImplementedError(\"Subcl         


        
相关标签:
8条回答
  • 2020-12-07 19:34

    An interesting pattern to handle this is to set attribute to None in the parent class and to access the attribute with a function that ensure it has been set in the child class.

    Here is an example from django-rest-framework:

    class GenericAPIView(views.APIView):
    
        [...]
    
        serializer_class = None
    
        [...]
    
        def get_serializer_class(self):
            assert self.serializer_class is not None, (
                "'%s' should either include a `serializer_class` attribute, "
                "or override the `get_serializer_class()` method."
                % self.__class__.__name__
            )
    
            return self.serializer_class
    
    0 讨论(0)
  • 2020-12-07 19:35

    Yes, you can. Use the @property decorator. For instance, if you have a field called "example" then can't you do something like this:

    class Base(object):
    
        @property
        def example(self):
            raise NotImplementedError("Subclasses should implement this!")
    

    Running the following produces a NotImplementedError just like you want.

    b = Base()
    print b.example
    
    0 讨论(0)
  • 2020-12-07 19:42

    Alternate answer:

    @property
    def NotImplementedField(self):
        raise NotImplementedError
    
    class a(object):
        x = NotImplementedField
    
    class b(a):
        # x = 5
        pass
    
    b().x
    a().x
    

    This is like Evan's, but concise and cheap--you'll only get a single instance of NotImplementedField.

    0 讨论(0)
  • 2020-12-07 19:46

    And here is my solution:

    def not_implemented_method(func):
        from functools import wraps
        from inspect import getargspec, formatargspec
    
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            c = self.__class__.__name__
            m = func.__name__
            a = formatargspec(*getargspec(func))
            raise NotImplementedError('\'%s\' object does not implement the method \'%s%s\'' % (c, m, a))
    
        return wrapper
    
    
    def not_implemented_property(func):
        from functools import wraps
        from inspect import getargspec, formatargspec
    
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            c = self.__class__.__name__
            m = func.__name__
            raise NotImplementedError('\'%s\' object does not implement the property \'%s\'' % (c, m))
    
        return property(wrapper, wrapper, wrapper)
    

    It can be used as

    class AbstractBase(object):
        @not_implemented_method
        def test(self):
            pass
    
        @not_implemented_property
        def value(self):
            pass
    
    class Implementation(AbstractBase):
        value = None
    
        def __init__(self):
            self.value = 42
    
        def test(self):
            return True
    
    0 讨论(0)
  • 2020-12-07 19:48
    def require_abstract_fields(obj, cls):
        abstract_fields = getattr(cls, "abstract_fields", None)
        if abstract_fields is None:
            return
    
        for field in abstract_fields:
            if not hasattr(obj, field):
                raise RuntimeError, "object %s failed to define %s" % (obj, field)
    
    class a(object):
        abstract_fields = ("x", )
        def __init__(self):
            require_abstract_fields(self, a)
    
    class b(a):
        abstract_fields = ("y", )
        x = 5
        def __init__(self):
            require_abstract_fields(self, b)
            super(b, self).__init__()
    
    b()
    a()
    

    Note the passing of the class type into require_abstract_fields, so if multiple inherited classes use this, they don't all validate the most-derived-class's fields. You might be able to automate this with a metaclass, but I didn't dig into that. Defining a field to None is accepted.

    0 讨论(0)
  • 2020-12-07 19:48

    Here is a simple example how to set required properties/methods for sublasses in Python 3.

    class Base:
        requires = ('foo', 'bar')
    
        def __init_subclass__(cls, **kwargs):
            for requirement in cls.requires:
                if not hasattr(cls, requirement):
                    raise NotImplementedError(
                            f'"{cls.__name__}" must have "{requirement}".')
            super().__init_subclass__(**kwargs)
    
    0 讨论(0)
提交回复
热议问题