首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >用于类型检查和不变性的Python描述符

用于类型检查和不变性的Python描述符
EN

Stack Overflow用户
提问于 2018-08-30 01:50:04
回答 2查看 260关注 0票数 1

阅读Python Cookbook和saw描述符,特别是在使用类属性时强制执行类型的示例。我正在编写一些类,这将是有用的,但我也想强制执行不变性。该怎么做呢?改编自本书的类型检查描述符:

代码语言:javascript
复制
class Descriptor(object):
    def __init__(self, name=None, **kwargs):
        self.name = name

        for key, value in kwargs.items():
            setattr(self, key, value)

    def __set__(self, instance, value):
        instance.__dict__[self.name] = value


# by default allows None
class Typed(Descriptor):
    def __init__(self, expected_types=None, **kwargs):
        self.expected_types = expected_types

        super().__init__(**kwargs)

    def __set__(self, instance, value):
        if value is not None and not isinstance(value, self.expected_types):
            raise TypeError('Expected: {}'.format(str(self.expected_types)))

        super(Typed, self).__set__(instance, value)

class T(object):
    v = Typed(int)

    def __init__(self, v):
        self.v = v

尝试#1:将self.is_set属性添加到类型

代码语言:javascript
复制
# by default allows None
class ImmutableTyped(Descriptor):
    def __init__(self, expected_types=None, **kwargs):
        self.expected_types = expected_types
        self.is_set = False

        super().__init__(**kwargs)

    def __set__(self, instance, value):
        if self.is_set:
            raise ImmutableException(...)
        if value is not None and not isinstance(value, self.expected_types):
            raise TypeError('Expected: {}'.format(str(self.expected_types)))

        self.is_set = True

        super(Typed, self).__set__(instance, value)

错了,因为在执行以下操作时,ImmutableTyped是“全局的”,因为它在类的所有实例中都是一个单例。实例化t2时,前一个对象中的is_set已为True。

代码语言:javascript
复制
class T(object):
    v = ImmutableTyped(int)

    def __init__(self, v):
        self.v = v

t1 = T()
t2 = T()  # fail when instantiating

尝试#2:__set__中的check实例引用包含属性的类,因此尝试检查instance.__dict__[self.name]是否仍然是类型化的。这也是错误的。

想法#3:通过接受返回T个实例的__dict__的'fget‘方法,使类型的使用更类似于@property。这需要在T中定义一个函数,类似于:

代码语言:javascript
复制
@Typed
def v(self):
    return self.__dict__

这似乎是错的。

如何实现不变性和类型检查作为描述符?

EN

回答 2

Stack Overflow用户

发布于 2018-08-30 03:31:20

下面是我解决这个问题的方法:

代码语言:javascript
复制
class ImmutableTyped:
    def __set_name__(self, owner, name):
        self.name = name

    def __init__(self, *, immutable=False, types=None)
        self.immutable == immutable is True
        self.types = types if types else []

    def __get__(self, instance, owner):
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        if self.immutable is True:
            raise TypeError('read-only attribute')
        elif not any(isinstance(value, cls)
                     for cls in self.types):
            raise TypeError('invalid argument type')
        else:
           instance.__dict__[self.name] = value

附注:可以使用__set_name__来允许您在初始化时不指定属性名称。这意味着您可以直接执行以下操作:

代码语言:javascript
复制
class Foo:
    bar = ImmutableTyped()

ImmutableTyped的实例将自动拥有name属性bar,因为我在__set_name__方法中输入了该属性。

票数 0
EN

Stack Overflow用户

发布于 2018-09-07 15:51:10

无法成功创建这样的描述符。也许这也是不必要的复杂。下面的方法+ property使用就足够了。

代码语言:javascript
复制
# this also allows None to go through
def check_type(data, expected_types):
    if data is not None and not isinstance(data, expected_types):
        raise TypeError('Expected: {}'.format(str(expected_types)))

    return data

class A():
    def __init__(self, value=None):
        self._value = check_type(value, (str, bytes))

    @property
    def value(self):
        return self._value


foo = A()
print(foo.value)    # None
foo.value = 'bla'   # AttributeError
bar = A('goosfraba')
print(bar.value)    # goosfraba
bar.value = 'bla'   # AttributeError
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52083467

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档