Как отменить декораторы класса в конструкторе - PullRequest
0 голосов
/ 16 ноября 2018

Давайте рассмотрим следующий пример декораторов классов (origin http://www.informit.com/articles/article.aspx?p=1309289&seqNum=4):

class GenericDescriptor:

    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter

    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        return self.getter(instance)

    def __set__(self, instance, value):
        return self.setter(instance, value)


def valid_string(attr_name, empty_allowed=True, regex=None,
                 acceptable=None):
    def decorator(cls):
        name = "__" + attr_name

        def getter(self):
            return getattr(self, name)

        def setter(self, value):
            assert isinstance(value, str), (attr_name +
                                            " must be a string")
            if not empty_allowed and not value:
                raise ValueError("{0} may not be empty".format(
                    attr_name))
            if ((acceptable is not None and value not in acceptable) or
                    (regex is not None and not regex.match(value))):
                raise ValueError("{attr_name} cannot be set to "
                                 "{value}".format(**locals()))
            setattr(self, name, value)

        setattr(cls, attr_name, GenericDescriptor(getter, setter))
        return cls

    return decorator


@valid_string("name", empty_allowed=False)
class StockItem:
    name = None

    def __init__(self, **kwargs):
        if kwargs.get('second_call'):
            pass
            # proceed normally without calling @valid_string
        self.name = kwargs.get('name', None)
        self.price = kwargs.get('price', None)
        self.quantity = kwargs.get('quantity', None)


if __name__ == "__main__":
    import doctest

    doctest.testmod()

    # valid value for name
    cameras1 = StockItem(name="Camera", price=45.99, quatity=2)
    # invalid value for name according to @valid_string but I need this to be also valid if 'second_call'
    cameras2 = StockItem(name=67, price=45.99, quatity=2, second_call=True)

. Конструктор класса StockItem вызывается дважды, и во второй поворот я хочу, чтобы декоратор @valid_string как-то был отменен (Я не хочу, чтобы значение атрибута name больше менялось).

...