【问题标题】:Why is property.fget a read-only attribute?为什么 property.fget 是只读属性?
【发布时间】:2011-08-11 13:20:00
【问题描述】:

我目前正在修补库中的一个类的属性,以使其更加通用。

我正在使用以下代码执行此操作,效果很好:

_orig_is_xhr = BaseRequest.is_xhr.fget
_orig_is_xhr_doc = BaseRequest.is_xhr.__doc__
BaseRequest.is_xhr = property(lambda self: _orig_is_xhr(self) or
    '_iframe-xhr' in request.form, doc=_orig_is_xhr_doc)

但是,如果我可以简单地覆盖 getter 函数以便保留文档字符串,那就更好了:

_orig_is_xhr = BaseRequest.is_xhr.fget
BaseRequest.is_xhr.fget = lambda self: (_orig_is_xhr(self) or
    '_iframe-xhr' in request.form)

这不起作用,因为property.fget 是一个只读属性(TypeError: readonly attribute 尝试分配给它时)。 我很好奇这是否有特殊原因,或者 python 开发人员只是认为在创建属性后修改属性而不用新属性替换它是没有意义的。

【问题讨论】:

    标签: python properties


    【解决方案1】:

    您可能是对的,将这些属性设置为只读只是一种约定,选择使属性“全有或全无”。允许在事后分配这些似乎更“Pythonic”,但在Python 2.2 release notes(引入属性时)中找不到理由。

    在Objects/descrobject.c 中属性的成员属性被定义为只读:

        static PyMemberDef property_members[] = {
            {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY},
            {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY},
            {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY},
            {"__doc__",  T_OBJECT, offsetof(propertyobject, prop_doc), READONLY},
            {0}
        };
    

    除此之外:如果您将 READONLY 替换为 0 并进行编译,这就是允许分配 fget, fset, .. 所需的全部内容:

    class Test(object):
        def __init__(self):
            self.flag = True
        prop = property(lambda self: self.flag)
    
    obj = Test()
    print obj.prop
    Test.prop.fget = lambda self: not self.flag
    print obj.prop
    

    输出:

    True
    False
    

    【讨论】:

    • 嘿,很好 - 我不会破解 python 源代码:p
    • 当然 :-) 我只是指出,在只读性背后没有什么比这更奇特的了。
    • 可变属性会为无意的副作用创造一些可怕的机会。 Thread.ident.fget = Thread.daemon.fget 有人吗?
    【解决方案2】:

    在 IDLE shell 中使用 Anaconda 2.3.0 (Python 3.4.3) 进行测试

    >>> p = property()
    >>> p.fget
    >>> p.__init__( lambda obj: None )
    >>> p.fget
    <function <lambda> at 0x0121FF18>
    >>> p.fget = lambda obj: None
    Tracebabk (most recent call last):
      File "<pyshell#19>", line 1, in <module>
        p.fget = lambda obj: None
    AttributeError: readonly attribute
    >>>
    

    在我看来并不那么只读;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-05
      • 2015-07-10
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-15
      相关资源
      最近更新 更多