Executing class variables in a subclass

I'm working on extending the Pappon webapp2 web framework for the App Engine to take advantage of some of the missing features (to make building apps a little faster and easier).

One of the requirements here is that for each subclass it is required to have certain variables of the static class. Is it best to do this just to throw an exception if they are missing, when do I use them or is there a better way?

Example (not real code):

Subclass:

class Bar(Foo):
  page_name = 'New Page'

page_name should be submitted for processing here:

page_names = process_pages(list_of_pages)

def process_pages(list_of_pages)
  page_names = []

  for page in list_of_pages:
    page_names.append(page.page_name)

  return page_names
+7
source share
5 answers

, . , , pythonic.

import abc

class Base(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractproperty
    def value(self):
        return 'Should never get here'


class Implementation1(Base):

    @property
    def value(self):
        return 'concrete property'


class Implementation2(Base):
    pass # doesn't have the required property

:

print Implementation1()
Out[6]: <__main__.Implementation1 at 0x105c41d90>

:

print Implementation2()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-bbaeae6b17a6> in <module>()
----> 1 Implementation2()

TypeError: Can't instantiate abstract class Implementation2 with abstract methods value
+4

Python , , . , , . , . , , , , .

, , . , , , , , .

; , factory, , .

def RequiredAttributes(*required_attrs):

    class RequiredAttributesMeta(type):
        def __init__(cls, name, bases, attrs):
            missing_attrs = ["'%s'" % attr for attr in required_attrs 
                             if not hasattr(cls, attr)]
            if missing_attrs:
                raise AttributeError("class '%s' requires attribute%s %s" %
                                     (name, "s" * (len(missing_attrs) > 1), 
                                      ", ".join(missing_attrs)))
    return RequiredAttributesMeta

, , . , , , , , . , , ( ), .

class Base(object):
    __metaclass__ = RequiredAttributes("a", "b" ,"c")
    a = b = c = 0

del Base.a, Base.b, Base.c

, , :

class Child(Base):
    pass

:

AttributeError: class 'Child' requires attributes 'a', 'b', 'c'

N.B. Google App Engine, , . , RequiredAttributesMeta , type.

+6

, , Python:

Python instance creation

1: Python [1]

, , Python Metaclass. , , __call__, , , __new__ __init__ , __cal__ .

, , __init__, "" .

class ForceRequiredAttributeDefinitionMeta(type):
    def __call__(cls, *args, **kwargs):
        class_object = type.__call__(cls, *args, **kwargs)
        class_object.check_required_attributes()
        return class_object

__call__, , check_required_attributes(), , . , , .

Superclass

Python 2

class ForceRequiredAttributeDefinition(object):
    __metaclass__ = ForceRequiredAttributeDefinitionMeta
    starting_day_of_week = None

    def check_required_attributes(self):
        if self.starting_day_of_week is None:
            raise NotImplementedError('Subclass must define self.starting_day_of_week attribute. \n This attribute should define the first day of the week.')

Python 3

class ForceRequiredAttributeDefinition(metaclass=ForceRequiredAttributeDefinitionMeta):
    starting_day_of_week = None

    def check_required_attributes(self):
        if self.starting_day_of_week is None:
            raise NotImplementedError('Subclass must define self.starting_day_of_week attribute. \n This attribute should define the first day of the week.')

. :

  • .
  • None . starting_day_of_week = None
  • check_required_attributes, , None, NotImplementedError .

class ConcereteValidExample(ForceRequiredAttributeDefinition):
    def __init__(self):
        self.starting_day_of_week = "Monday"


class ConcereteInvalidExample(ForceRequiredAttributeDefinition):
    def __init__(self):
        # This will throw an error because self.starting_day_of_week is not defined.
        pass

Traceback (most recent call last):
  File "test.py", line 50, in <module>
    ConcereteInvalidExample()  # This will throw an NotImplementedError straightaway
  File "test.py", line 18, in __call__
    obj.check_required_attributes()
  File "test.py", line 36, in check_required_attributes
    raise NotImplementedError('Subclass must define self.starting_day_of_week attribute. \n This attribute should define the first day of the week.')
NotImplementedError: Subclass must define self.starting_day_of_week attribute.
 This attribute should define the first day of the week.

, , , , NotImplementedError .

+4
source

Generally speaking, it is widely recognized in Python that the best way to handle such a scenario, as you correctly assumed, is to wrap any operation that requires this class variable with a try-except block.

+1
source

It works. Prevents even defining subclasses, not to mention instantiating.

class Foo:

    page_name = None
    author = None

    def __init_subclass__(cls, **kwargs):
        for required in ('page_name', 'author',):
            if not getattr(cls, required):
                raise TypeError(f"Can't instantiate abstract class {cls.__name__} without {required} attribute defined")
        return super().__init_subclass__(**kwargs)


class Bar(Foo):
    page_name = 'New Page'
    author = 'eric'
0
source

Source: https://habr.com/ru/post/1528999/


All Articles