ely*_*ely 8 python interface subclass abc
这是一个尝试创建装饰器的玩具示例,该装饰器允许声明属性名称,这些属性名称应该是标准__subclasshook__和__instancecheck__模式中"接口检查"的必要部分.
当我装饰这个Foo类时,它似乎按预期工作.我创建了一个Bar与之无关的类,Foo但它具有所需的属性,并且它正确地满足isinstance(instance_of_bar, Foo) == True.
但是作为另一个例子,我创建了一个dict扩充的子类,以便key可以使用getattr语法访问这些值(例如dict,d['a']可以替换d.a为可获得相同结果的where ).在这种情况下,属性只是实例属性,因此__instancecheck__应该工作.
这是代码.请注意,鉴于具有Bar工作实例的示例,将__subclasshook__函数"monkeypatch"选择到Foo类(具有元类)中的选择正常.因此,似乎不必直接在元类的类定义中定义函数.
#Using Python 2.7.3
import abc
def interface(*attributes):
def decorator(Base):
def checker(Other):
return all(hasattr(Other, a) for a in attributes)
def __subclasshook__(cls, Other):
if checker(Other):
return True
return NotImplemented
def __instancecheck__(cls, Other):
return checker(Other)
Base.__subclasshook__ = classmethod(__subclasshook__)
Base.__instancecheck__ = classmethod(__instancecheck__)
return Base
return decorator
@interface("x", "y")
class Foo(object):
__metaclass__ = abc.ABCMeta
def x(self): return 5
def y(self): return 10
class Bar(object):
def x(self): return "blah"
def y(self): return "blah"
class Baz(object):
def __init__(self):
self.x = "blah"
self.y = "blah"
class attrdict(dict):
def __getattr__(self, attr):
return self[attr]
f = Foo()
b = Bar()
z = Baz()
t = attrdict({"x":27.5, "y":37.5})
print isinstance(f, Foo)
print isinstance(b, Foo)
print isinstance(z, Foo)
print isinstance(t, Foo)
Run Code Online (Sandbox Code Playgroud)
打印:
True
True
False
False
Run Code Online (Sandbox Code Playgroud)
这只是一个玩具示例 - 我不是在寻找更好的方法来实现我的attrdict课程.该Bar示例演示了monkeypatched __subclasshook__工作.另外两个示例演示了__instancecheck__仅具有实例属性的实例的检查失败.在那些情况下,__instancecheck__甚至没有被召唤.
我可以手动检查,从我的病情__instancecheck__功能是通过实例满意attrdict(即,hasattr(instance_of_attrdict, "x")是True因为需要)或z.
再次,它似乎适用于实例Bar.这表明__subclasshook__装饰器正在应用,并且修补自定义__metaclass__不是问题.但__instancecheck__似乎并未在此过程中调用.
为什么可以__subclasshook__在元类的类定义之外定义并在以后添加,但不是__instancecheck__?
一切都按应有的方式进行。如果您使用__metaclass__,您将覆盖类创建过程。看起来你的 Monkeypatch 正在工作,__subclasshook__但它只是__subclasshook__从ABCMeta. 你可以用这个来检查:
>>> type(Foo)
<class 'abc.ABCMeta'>
Run Code Online (Sandbox Code Playgroud)
更明确地说:__subclasshook__在这个例子中,这种情况是偶然发生的,因为元类在某些情况下__subclasscheck__碰巧遵循类的__subclasshook__。元类的协议__instancecheck__永远不会遵循类的定义__instancecheck__,这就是为什么最终会调用 Monkeypatched 版本,但不会调用__subclasshook__Monkeypatched 版本。__instancecheck__
更详细地说:如果您使用元类创建类,则该类的类型将是元类。在这种情况下ABCMeta,. 其定义isinstance()如下:'isinstance(object, class-or-type-or-tuple) -> bool',这意味着实例检查将在给定的类、类型或类/类型的元组上执行。ABCMeta在这种情况下, isinstance 检查将在(ABCMeta.__instancecheck__()将被调用 )上完成。因为 Monkeypatch 应用于Foo类而不是ABCMeta,__instancecheck__所以 的方法Foo永远不会运行。但是 的__instancecheck__会ABCMethod调用它自己的方法,而第二个方法将通过执行创建的类的方法__subclasscheck__来尝试验证(在本例中)。__subclasshook__Foo
在这种情况下,如果您像这样覆盖元类的函数,则可以获得所需的行为:
def interface(*attributes):
def decorator(Base):
def checker(Other):
return all(hasattr(Other, a) for a in attributes)
def __subclasshook__(cls, Other):
if checker(Other):
return True
return NotImplemented
def __instancecheck__(cls, Other):
return checker(Other)
Base.__metaclass__.__subclasshook__ = classmethod(__subclasshook__)
Base.__metaclass__.__instancecheck__ = classmethod(__instancecheck__)
return Base
return decorator
Run Code Online (Sandbox Code Playgroud)
以及带有更新代码的输出:
True
True
True
True
Run Code Online (Sandbox Code Playgroud)
另一种方法是定义您自己的类作为元类,并创建__instancecheck__您正在寻找的协议类型,以便当元类的定义达到某些失败标准时,它确实遵循类的定义__instancecheck__。然后,设置__metaclass__为内部的类,Foo并且您现有的装饰器应该按原样工作。
更多信息:关于元类的好文章
| 归档时间: |
|
| 查看次数: |
2084 次 |
| 最近记录: |