问题描述
假设我要为一组对象创建一个函数,这些对象来自不同的库,但具有相同的流程属性:
def get_foo(fooable,fooer):
return fooer.foo(fooable)
这在任何OOP语言中都是一项有用的功能,它允许您定义对象必须支持的特定接口...
在python的类型提示系统中,如果fooer
没有属性foo
,我是否可以声明该函数将失败?
# in psuedo code
def get_foo(fooable,fooer: Type.has_attr('foo')):
return fooer.foo(fooable)
解决方法
Python在collections.abc
中原生定义了类似于接口的功能。这是在by using ABC metaclasses,specifically defining the __instancecheck__()
and/or __subclasscheck__()
methods on a metaclass中实现的。您可以执行类似的操作:定义一个类似于接口的抽象基元类:
>>> class FooableMeta(abc.ABCMeta):
... def __instancecheck__(self,instance):
... return (
... hasattr(instance,'foo') # has a .foo
... and callable(instance.foo) # .foo is callable
... and not isinstance(instance,type) # is an instance,not a class
... )
...
>>> class Fooer(metaclass=FooableMeta):
... def __init__():
... raise NotImplementedError()
... def foo():
... raise NotImplementedError()
...
>>> class Foo:
... def foo():
... print("foo")
...
>>> isinstance(Foo(),Fooable)
True
>>> class Bar:
... def bar():
... print("bar")
...
>>> isinstance(Bar(),Fooable)
False
根据相同的原理,您现在可以使用Fooable
进行类型提示。