在python中,有没有一种方法可以在将对象传递给函数之前知道它是否“实现了接口”?


问题内容

我知道这听起来像是一个愚蠢的问题,特别是对于那些了解python本质的人来说,但是我只是想知道, 有没有办法知道对象是否“实现了接口”这样说?

举一个我想说的例子:

假设我有这个功能:

def get_counts(sequence):
     counts = {}
     for x in sequence:
         if x in counts:
             counts[x] += 1
         else:
             counts[x] = 1
     return counts

我的问题是:有没有办法确保传递给函数的对象是iterable我知道在Java或C#中,我可以通过让方法接受实现特定接口的任何对象来做到这一点,例如(例如)iIterable这样说:void get_counts(iIterable sequence)

我的猜测是,在Python中, 如果对象没有属性, 我将不得不采用先发性自省检查decorator
也许是?)并抛出一个自定义)。但是,有没有更 Python的 方式来做到这一点?exception``__iter__ __


问题答案:

isinstance()or接口之前使用多态和鸭式输入

你通常定义要怎样 你的对象,那么无论使用多态,怎么每个对象响应调整到你想要做什么,或者你用鸭打字;
首先测试对象是否可以做您想做的事情。这是调用与内省之间的权衡,传统观点认为,调用比自省要好,但是在Python中,鸭子类型胜于isinstance测试。

因此,您需要弄清楚 为什么 首先需要过滤或不过滤某些东西。你为什么需要知道这个?只需使用一个try: iter(object)except TypeError: # not iterable来测试。

或者,如果传递的内容不是可迭代的,则可能只需要引发异常,因为这将表明错误。

美国广播公司

使用鸭式输入法,您可能会发现必须测试多种方法,因此isinstance()测试可能是更好的选择。在这种情况下,也可以选择使用抽象基类(ABC)。例如,使用ABC,您可以将几种不同的类“绘制”为给定操作的正确类型。使用ABC,您可以专注于需要执行的任务,而不是所使用的特定实现。您可以拥有PaintableABC,PrintableABC等。

Zope接口和组件架构

如果你发现你的应用程序正在使用的 可怕的
很多基本知识,或者你一直有一个多态的方法来你的类添加应对各种不同的情况,下一步就是如考虑使用全面的组件体系结构,Zope的组件架构(ZCA)

zope.interface接口是类固醇上的ABC,尤其是与ZCA适配器结合使用时。接口记录了类的预期行为:

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())