【问题标题】:understanding a python descriptors example (TypedProperty)了解 Python 描述符示例(TypedProperty)
【发布时间】:2016-01-19 19:03:51
【问题描述】:

以下是 Python 书籍中一些代码的略微修改版本:

class TypedProperty(object):
    def __init__(self,name,type,default=None):
        self.name = "_" + name
        self.type = type
        self.default = default if default else type()
    def __get__(self,instance,cls):
        return getattr(instance,self.name,self.default)
    def __set__(self,instance,value):
        if not isinstance(value,self.type):
            raise TypeError("Must be a %s" % self.type)
        setattr(instance,self.name,value)

class Foo(object):
    name = TypedProperty("name",str)
    num = TypedProperty("num",int,42)

f = Foo()
f.name = 'blah'

我的问题:我们为什么要在 f 中创建属性?在上面的代码中,TypedProperty 被写成 f.name = 'blah' 在实例 f 中创建属性“_name”。

为什么不将值保存为 TypedProperty 类的属性?这是我的想法:

class TypedProperty2(object):
    def __init__(self, val, typ):
        if not isinstance(val, typ):
            raise TypeError()
        self.value = val
        self.typ = typ

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, val):
        if not isinstance(val, self.typ):
            raise TypeError()
        self.value = val

这是一个随意的设计决定吗?

【问题讨论】:

    标签: python class descriptor


    【解决方案1】:

    所有类实例将共享同一个描述符实例(例如TypedProperty)。因此,如果您将值存储在TypedProperty 上,那么Foo 的所有实例对于namenum 值将具有相同的值。这通常对于描述符来说是不可取的(或预期的)。

    例如如果您运行以下脚本:

    class TypedProperty2(object):
        def __init__(self, val, typ):
            if not isinstance(val, typ):
                raise TypeError()
            self.value = val
            self.typ = typ
    
        def __get__(self, instance, owner):
            return self.value
    
        def __set__(self, instance, val):
            if not isinstance(val, self.typ):
                raise TypeError()
            self.value = val
    
    
    class Foo(object):
        name = TypedProperty2("name", str)
    
    f1 = Foo()
    f1.name = 'blah'
    
    f2 = Foo()
    print(f2.name)
    f2.name = 'bar'
    
    print(f1.name)
    

    您将看到以下输出:

    blah
    bar
    

    所以我们可以看到最初f2f1 的名字,然后在更改f2 的名字后,f1 拿起了f2 的名字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-17
      • 1970-01-01
      • 2015-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多