带有Pass-through __set__命令的Python数据描述符

时间:2009-08-16 04:26:12

标签: python function methods set descriptor

我正在解决我正在考虑的问题。我有一套专门的函数,它们将在程序中使用,它们基本上是动态的callables,可以替换函数和方法。由于需要让它们正常工作以模拟方法的功能,因此这些函数会覆盖__get__以提供一个包装版本,以便访问检索对象。

不幸的是,如果函数直接在实例上设置,则__get__不起作用。这是因为当在实例的__get__中找到密钥时,只有“数据描述符”会调用__dict__函数。想到这一点的唯一解决方案是:欺骗python认为这是一个数据描述符。这涉及在描述符上创建__set__函数。理想情况下,我希望此__set__函数作为传递函数(将控制权返回给调用者并继续进行评估,就好像它不存在一样)。

有没有办法欺骗python认为描述符是一个数据描述符,但是让一个包含的类/实例仍能正常使用它的setattr命令?

另外,我知道可以通过覆盖__getattribute__来为调用者执行此操作。但是,这是一个糟糕的解决方案,因为我必须为内置的'object'和覆盖它的任何东西执行此操作。这不是一个很好的解决方案。

或者,如果有任何替代解决方案,我会很高兴听到它。

这是一个问题示例:

class Descriptor(object):  
    def __get__(self, obj, objtype = None):  
        return None  

class Caller(object):  
    a = Descriptor()  

print a  
>>> None  
x = Caller()  
print a
>>> None
x.a = Descriptor()
print x.a
>>> <__main__.Descriptor object at 0x011D7F10>  

最后一个案例应打印'无'以保持一致性。

如果您向描述符添加__set__,则会打印“无”(根据需要)。但是,这会像以前那样混淆x.a =(某些值)的任何命令。由于我不想搞砸这个功能,所以没有用。任何解决方案都会很棒。

更正:我之前的想法仍然不起作用,因为我误解了描述符处理。显然,如果一个描述符根本不在一个类上,它将永远不会被调用 - 无论 set 。如果有一个dict val和一个同名的类访问器,我只有帮助的条件。我实际上正在寻找更多的解决方案:http://blog.brianbeck.com/post/74086029/instance-descriptors但这并不涉及让太阳下的所有东西都继承一个专门的界面。

不幸的是,鉴于这种对描述符接口的新理解,这可能是不可能的?为什么哦为什么python使装饰器基本上是非动态的?

2 个答案:

答案 0 :(得分:1)

我认为最干净的解决方案是单独留下__set__,并在类上设置描述符 - 如果需要包装原始类。即,不是x.a = Descriptor(),而是setdesc(x, 'a', Descriptor()其中:

class Wrapper(object): pass

def setdesc(x, name, desc):
  t = type(x)
  if not issubclass(t, wrapper):
    class awrap(Wrapper, t): pass
    x.__class__ = awrap
  setattr(x.__class__, name, desc)

这是我建议当有人想要“设置实例”时需要在类上设置的任何东西(特殊方法或描述符)工作的一般方法,但不希望影响实例的原始类。

当然,只有你有新式的课程才能很好地运作,但是无论如何,描述符并不能很好地适应旧式的课程; - )。

答案 1 :(得分:0)

我想我可能对我的问题有一个答案,虽然不是那么漂亮 - 它确实回避了这个问题。我目前的攻击计划是做python做的事情 - 手动绑定函数。我已经使用我的未绑定函数的 get 命令来生成绑定类型的函数。一种可能的解决方案是强制任何想要设置新功能的人手动绑定它。这很烦人,但并不疯狂。 Python实际上让你这样做(如果你只是将一个函数设置为一个实例作为一个属性,它就不会被绑定)。

让这种情况自动发生仍然会很好,但强迫设置新功能的人使用xa = Descriptor()并不是很糟糕。获取(x)在这种情况下将给出期望的行为(以及该示例,就此而言)。它不是一般解决方案,但它适用于这个有限的问题,其中方法绑定基本上被模拟。话虽如此,如果有人有更好的解决方案,我仍然会很高兴听到它。