【问题标题】:Python Data Descriptor With Pass-through __set__ command带有传递 __set__ 命令的 Python 数据描述符
【发布时间】:2009-08-16 04:26:11
【问题描述】:

我在解决我正在研究的问题时遇到了一些问题。我有一组专门的函数,它们将在整个程序中使用,它们基本上是可以替换函数和方法的动态可调用函数。由于需要让它们正常工作以模拟方法的功能,这些函数会覆盖 __get__ 以提供一个包装版本,以提供对检索对象的访问权限。

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

有什么方法可以让 python 认为描述符是数据描述符,但让包含的类/实例仍然能够正常使用它的 setattr 命令?

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

或者,如果有任何替代解决方案,我很乐意听到。

这是一个问题示例:

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 = (some value) 的任何命令无法像以前一样工作。由于我不想弄乱此功能,因此没有帮助。任何解决方案都会很棒。

更正:我之前的想法仍然行不通,因为我稍微误解了描述符处理。显然,如果一个描述符根本不在一个类上,它就永远不会被调用——不管 set 是什么。我的条件只有在有一个 dict val 和一个同名的类访问器时才有帮助。实际上,我正在寻找一个更类似于http://blog.brianbeck.com/post/74086029/instance-descriptors 的解决方案,但这并不涉及让阳光下的所有东西都继承一个专门的接口。

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

【问题讨论】:

    标签: python function methods set descriptor


    【解决方案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)
    

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

    当然,只有当你有新式的类时,这一切才能正常工作,但描述符无论如何都不能很好地与旧式的类配合使用;-)。

    【讨论】:

    • 对不起,我最初的误导性描述。不幸的是,这仍然不能解决根本问题,因为在某些情况下,类的实例可能合法地希望在实例上设置函数(通常作为现有函数的覆盖)。
    • ...并通过调用我在回答中给出的 setdesc 函数的实例,这正是获得的结果:它“在实例上设置”一个函数或任何其他描述符,覆盖或不作为情况可能是这样。那么,为什么不呢?
    【解决方案2】:

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

    让这种情况自动发生仍然很好,但强制设置新函数的人使用 x.a = Descriptor().get(x) 在这种情况下并不可怕将给出所需的行为(以及例如,就此而言)。这不是一个通用的解决方案,但它适用于这个有限的问题,其中方法绑定基本上是被模拟的。话虽如此,如果有人有更好的解决方案,我仍然很高兴听到它。

    【讨论】:

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