Python 2.6:如何访问被派生类隐藏的基类描述符字段?

3 投票
1 回答
837 浏览
提问于 2025-04-16 13:52

我有一个描述符,它把数据存储在主对象的字典里。这个描述符在类的层次结构中有一些同名的字段:

class ADescriptor(object):
    def __init__(self, keyname='descr'):
        self.keyname = keyname

    def __get__(self, obj, objtype):
        return getattr(obj, self.keyname, 8192 )

    def __set__(self, obj, val):
        setattr(obj, self.keyname, val)

class A(object):
    f = ADescriptor('keyA')

class B(A):
    f = ADescriptor('keyB')

b = B()
b.f = 'b'
print super(B,b).f
super(B,b).f = 'a'

最后一行不工作:
super(B,b).f = 'a'

为什么获取值的操作可以,而设置值的操作不行呢?有没有比用 A.dict['f'].set(b,'a') 更优雅的方法来设置 A 的 f 呢?


更正:

在我最初的帖子中,A.f 的值是 A 的一个名为 keyname 的属性(缺失)或者默认值 8192 - 跟这个没有关系。所以我用了 A.dict['f'] - 这样可以避免调用 get 方法。为了让 A.f 能够正确地评估到需要的 ADescriptor 实例,我做了一些小修改:

def __get__(self, obj, objtype=None):
    if not obj:      #return descriptor itself if no bound object given
        return self
    return getattr(obj, self.keyname, 8192 )

在这种情况下,A.f.__set__(b,'a') 可以正常工作。
但这看起来还是很丑!@BiggAl 提出的属性解决方案不适合我的需求 - 我需要把所有的描述符都包装成属性。

1 个回答

1

当然,如果 A.__dict__['f'].__set__(b,'a') 能够正常工作,那么 A.f.__set__(b,'a') 也应该可以对吧?

而且,即使是 A.f.b = 'a' 也应该能正常工作,虽然如果我没记错的话,你可能需要把它指定为一个属性。


看看历史记录,真是个大失误……

>>> class ADescriptor(object):
    def __init__(self, keyname='descr'):
        self.keyname = keyname
    def __get__(self, obj, objtype):
        return (self.keyname, getattr(obj, self.keyname, 8192 ))
    def __set__(self, obj, val):
        setattr(obj, self.keyname, val)

>>> class A(object):
    f = ADescriptor('keyA')


>>> class B(A):
        f = ADescriptor('keyB')


>>> a, b = A(), B()
>>> print (a.f, b.f, A.f, B.f)
(('keyA', 8192), ('keyB', 8192), ('keyA', 8192), ('keyB', 8192))
>>> b.f = 'b'
>>> print (a.f, b.f, A.f, B.f)
(('keyA', 8192), ('keyB', 'b'), ('keyA', 8192), ('keyB', 8192))
>>> A.f = 'a'
>>> print (a.f, b.f, A.f, B.f)
('a', ('keyB', 'b'), 'a', ('keyB', 8192))
>>> 

这就是你得到的结果,对吧?(我为了调试把 __get__ 改了,应该改回你原来的样子)

你想用 super 做什么呢?

撰写回答