2

让我们以下面的类装饰器示例(来源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 装饰器以某种方式被取消(我不想再更改名称属性的值)。

4

0 回答 0