0

我有一堆字典,我想用类型信息对其进行注释,以便以后能够为它们获取适配器。在以下示例中,失败的情况是我想要做的,而另一种情况显示的是工作版本。是否有可能在不引入额外对象的情况下让第一个版本工作?创建字典的代码不容易更改,因此我正在寻找最简单且非侵入性的方式来添加一些类型信息。

from zope.interface import Interface, implements, directlyProvides               
from zope.interface.registry import Components                                   

registry = Components()                                                          

class IA(Interface):                                                             
    pass                                                                         

#   this one fails                                                               

data = {}                                                                        
directlyProvides(data, IA)                                                       

#   this way it works                                                            

class X(dict):                                                                   
    pass                                                                         

data = X()                                                                       
directlyProvides(data, IA)
4

2 回答 2

1

zope.interface依赖于在各种对象和类上设置一些魔法属性的能力。这就是发生的事情

>>> class Dict(dict):
...     pass
...
>>> getattr(Dict, '__provides__', None)

没有什么。现在尝试做你所做的。

>>> from zope.interface import Interface, implements, directlyProvides
>>> class IA(Interface):
...     pass
... 
>>> data = Dict()
>>> directlyProvides(data, IA)

尝试__provides__再次抓住它

>>> getattr(Dict, '__provides__', None)
<zope.interface.declarations.ClassProvides object at 0x7f133cab48d0>

内置类型失败的原因是您实际上无法在其中任何一个上设置属性(通过标准方式)。

>>> setattr(dict, '__provides__', None)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'dict'

因此,如果您想在标准类型的某些实例上分配一些标记接口,它将失败。只需按原样对它们进行子类化,或者创建更符合 Zope 组件架构设计用途的真实对象。

于 2014-07-17T10:55:42.680 回答
1

您不能使用接口信息来注释 Python 内置类型;您根本无法添加所需的属性。

可以为该类型注册适配器(因此没有实现接口):

>>> from zope.interface.registry import Components                                   
>>> from zope.interface import Interface
>>> registry = Components()                                                          
>>> class IA(Interface):                                                             
...     pass                                                                         
... 
>>> data = {}
>>> registry.registerAdapter(lambda o: 'adapter from dict to IA', [dict], IA)
>>> registry.queryAdapter(data, IA)
'adapter from dict to IA'

不幸的是,您不能这样做:

>>> registry.registerAdapter(lambda o: 'adapter from data to IA', [data], IA)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/site-packages/zope/interface/registry.py", line 186, in registerAdapter
    required = _getAdapterRequired(factory, required)
  File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/site-packages/zope/interface/registry.py", line 432, in _getAdapterRequired
    raise TypeError("Required specification must be a "
TypeError: Required specification must be a specification or class.

这意味着如果你真的必须改编特定的词典,那么你的选择是有限的。使用的子类dict是一种解决方法。

但是,您必须真正询问改编字典是否是解决您的问题的最佳方法。

于 2014-07-17T10:56:34.970 回答