我知道这听起来像是一个愚蠢的问题,尤其是对于了解 python 本质的人来说,但我只是想知道,有没有办法知道一个对象是否“实现了一个接口(interface)”以便说?强>
举个例子说明我想说的:
假设我有这个功能:
def get_counts(sequence):
counts = {}
for x in sequence:
if x in counts:
counts[x] += 1
else:
counts[x] = 1
return counts
我的问题是:有没有办法确保传递给函数的对象是可迭代
?我知道在 Java 或 C# 中我可以通过让方法接受实现特定接口(interface)的任何对象,让我们说(例如)iIterable
像这样:void get_counts(iIterable sequence)
我的猜测是,在 Python 中,我必须采用先发制人的自省(introspection)检查(也许在 decorator
中?)并抛出自定义的 exception
如果对象没有 __iter__
属性)。但是有没有更pythonic的方法来做到这一点?
最佳答案
在isinstance()
或接口(interface)之前使用多态和鸭子类型
您通常定义要对对象做什么,然后使用多态性来调整每个对象如何响应您想要做的事情,或者使用鸭子类型;首先测试手头的对象是否可以做您想做的事情。这是调用与内省(introspection)的权衡,传统观点认为调用优于内省(introspection),但在 Python 中,duck-typing 优于 isinstance
测试。
所以你首先需要弄清楚为什么你需要过滤某些东西是否是可迭代的;你为什么需要知道这个?只需使用一个try: iter(object)
, except TypeError: # not iterable
来测试。
或者,如果传递的内容不是可迭代对象,您可能只需要抛出异常,因为这会发出错误信号。
基础知识
使用 duck-typing,您可能会发现必须测试多种方法,因此 isinstance()
测试可能看起来是更好的选择。在这种情况下,使用 Abstract Base Class (ABC)也可以是一种选择;例如,使用 ABC 让您“绘制”几个不同的类作为给定操作的正确类型。使用 ABC 让您专注于需要执行的任务,而不是使用的具体实现;你可以有一个Paintable
ABC,一个Printable
ABC,等等
Zope 接口(interface)和组件架构
如果您发现您的应用程序使用了很多糟糕的 ABC,或者您一直不得不向您的类中添加多态方法来处理各种不同的情况,那么下一步就是考虑使用一个完整的-组件架构失效,例如 Zope Component Architecture (ZCA) .
zope.interface
接口(interface)是类固醇的基础知识,尤其是与 ZCA 适配器结合使用时。接口(interface)记录类的预期行为:
if IFrobnarIterable.providedBy(yourobject):
# it'll support iteration and yield Frobnars.
但它也让您查找适配器;您无需将每次使用形状的所有行为都放在类中,而是实现适配器以为特定用例提供多态行为。您可以将您的对象调整为可打印、可迭代或可导出为 XML:
class FrobnarsXMLExport(object):
adapts(IFrobnarIterable)
provides(IXMLExport)
def __init__(self, frobnariterator):
self.frobnars = frobnariterator
def export(self):
entries = []
for frobnar in self.frobnars:
entries.append(
u'<frobnar><width>{0}</width><height>{0}</height></frobnar>'.format(
frobnar.width, frobnar.height)
return u''.join(entries)
并且您的代码只需为每个形状查找适配器:
for obj in setofobjects:
self.result.append(IXMLExport(obj).export())
关于python - 在 python 中,有没有办法在将对象传递给函数之前知道它是否为 "implements an interface"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13919772/