【问题标题】:Overridden attribute access does not work (as expected)覆盖的属性访问不起作用(如预期的那样)
【发布时间】:2009-12-09 13:52:35
【问题描述】:

以下模块的主要目标是为某些名称提供一种“恒定”语义。

class ConstantError(Exception):

    def __init__(self, msg):
            self._msg = msg


class Constant(object):

    def __init__(self, name):
            self._name = name

    def __get__(self, instance, owner):
            return instance._content[self._name]

    def __set__(self, instance, value):
            raise ConstantError, 'Illegal use of constant'


class Constants(object):

    def __init__(self, content):
            self._content = content
            for k in self._content:
                    setattr(self, k, Constant(k))

num_const = Constants({
    'one': 1,
    'two': 2
})

使用时:

>>> from const import *
>>> dir(num_const)
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', '_content', 'one', 'two']

所以onetwo 在那里,但属性访问令人失望:

>>> num_const.one
<const.Constant object at 0x7faef4871710>
>>> 

在这种情况下,我希望1。我哪里错了?

【问题讨论】:

    标签: python attributes setattr


    【解决方案1】:

    描述符协议仅适用于类的属性,不适用于类实例的属性。见How-To Guide for Descriptors

    【讨论】:

    • 这就是重点。您能否解释一下这种行为的基本原理?我的意思是,如果描述符协议也适用于类的实例,还会出现什么问题?
    • 我不知道为什么。属性访问的性能问题?或者如果不调用它就很难访问属性本身(描述符)。
    【解决方案2】:

    您在常量中缺少 str() 或 unicode() 方法。

    添加:

    def __unicode__(self):
        return self._name
    

    【讨论】:

    • 感谢您的评论。不幸的是,这无助于实现预期的行为,即:num_cons.one 应在num_const._content 中查找'one',并返回其值。
    【解决方案3】:

    我认为 python 会阻止类访问描述符机制,以便对其进行操作。否则,如果没有某种“神奇”功能,操纵描述符可能会变得非常棘手,而且如果你注意到 python 试图让许多语言机器保持可访问性。为了解决这个问题,我经常即时生成课程。例如,你的 Constants 类可以这样声明:

    class Constants(object):
        def __new__(cls, content):
           class _Constants(object):
               pass
           constants = _Constants
           constants._content = content
           for k in constants._content:
                setattr(_Constants, k, Constant(k))
           return constants
    

    但实际上,出于您的目的,您可能会更好:

    class Constants(object):
        def __init__(self, content):
           self._content = content
        def __getattr__(self,key):
           return self._content[key]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-22
      • 2013-05-15
      • 1970-01-01
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      • 2021-09-15
      • 2014-05-16
      相关资源
      最近更新 更多