Автоматическое оформление класса (или проверка) при деривации - PullRequest
4 голосов
/ 20 декабря 2010


У меня есть базовый класс, из которого я получаю несколько подклассов.
Каждый подкласс определяет константы класса, и я хочу применить к ним определенные ограничения. Например:

class Base(object):
    # define these in your sub-class, and make sure (NOM % DENOM == 0)
    NOMINATOR = None
    DENOMINATOR = None

class Subclass_good(Base):
    NOMINATOR = 6
    DENOMINATOR = 3

class Subclass_bad(Base):
    NOMINATOR = 7
    DENOMINATOR = 5

Я хочу иметь возможность применять правило (NOM% DENOM == 0).
В настоящее время я делаю это с декоратором класса:

def nom_denom_validator(cls):
    assert(cls.NOMINATOR % cls.DENOMINATOR == 0)
    return cls

# and decorate each subclass, e.g.:
@nom_denom_validator
class Subclass_another(Base):
    NOMINATOR = 9
    DENOMINATOR = 12

Но мне не нравится тот факт, что мне нужно украшать каждый подкласс (у меня их много). Мне интересно, может ли это быть сделано с помощью некоторых манипуляций с базовым классом напрямую.

Любой совет?

Ответы [ 2 ]

8 голосов
/ 20 декабря 2010

Хорошо, смешно.Я думал об этом некоторое время, но только после публикации вопроса - особенно при выборе тегов и добавлении туда «метакласса» - понял ли я, что могу сам получить ответ.здесь идет:

class Base_Metaclass(type):
    def __new__(meta, classname, bases, class_dict):
        new_type = type.__new__(meta, classname, bases, class_dict)
        if not (new_type.NOMINATOR % new_type.DENOMINATOR) == 0:
            raise Exception("Invalid subclass created - validation failed")
        return new_type

# have Base and all its descendants be enforced:
class Base(object):
    __metaclass__ = Base_Metaclass
    # I must pass the validation myself, no None's anymore...
    NOMINATOR = 1
    DENOMINATOR = 1

И теперь все дети должны быть принудительно применены.

1 голос
/ 20 декабря 2010

Вы можете сделать проверку в конструкторе базовых классов

class Base(object):
    # define these in your sub-class, and make sure (NOM % DENOM == 0)
    NOMINATOR = None
    DENOMINATOR = None
    def __init__(self):
        assert(self.NOMINATOR % self.DENOMINATOR == 0)

Когда вы создаете экземпляр Subclass_bad(), вы получите AssertionError.

...