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

Nli*_*tis 11 python exception introspection object

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

举一个我想说的例子:

假设我有这个功能:

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

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

我的猜测是,在Python中,我必须采用抢占式内省检查(在一个decorator 或许?中)并exception在对象没有__iter__属性的情况下抛出自定义.但有更多的pythonic方式来做到这一点?

eca*_*mur 10

Python(自2.6起)具有抽象基类(也称为虚拟接口),它比Java或C#接口更灵活.要检查对象是否可迭代,请使用collections.Iterable:

if isinstance(obj, collections.Iterable):
    ...
Run Code Online (Sandbox Code Playgroud)

但是,如果您的else块只会引发异常,那么大多数Python的答案是:不要检查!您的来电者可以通过合适的类型传递; 你只需要记录你期望一个可迭代的对象.

  • @NlightNFot是最诡计多端的事情,就是记录你的期望,并且如果调用者传入一个不合适的类型,就会引发`TypeError`. (2认同)

Mar*_*ers 8

在before isinstance()或interfaces 之前使用多态和duck-typing

你通常定义要怎样你的对象,那么无论使用多态来调整每个对象如何回应你想要做什么,或者你用鸭打字; 测试手头的物体是否可以做你想做的事情.这是调用与内省权衡的关系,传统观点认为调用优于内省,但在Python中,鸭子类型优于isinstance测试.

所以你需要弄清楚为什么你需要过滤或不首先可迭代的东西; 为什么你需要知道这个?只需使用a try: iter(object),except TypeError: # not iterable进行测试.

或者,如果传递的任何内容都不是可迭代的,那么您可能只需要抛出异常,因为这会发出错误信号.

基本知识

使用duck-typing,您可能会发现必须测试多种方法,因此isinstance()测试可能看起来更好.在这种情况下,使用抽象基类(ABC)也可以是一种选择; 例如,使用ABC让你"绘制"几个不同的类作为给定操作的正确类型.使用ABC让您专注于需要执行的任务而不是使用的特定实现; 你可以有PaintableABC,PrintableABC等

Zope接口和组件架构

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

zope.interface接口是类固醇的ABCs,特别是当与ZCA适配器结合使用时.接口记录了类的预期行为:

if IFrobnarIterable.providedBy(yourobject):
    # it'll support iteration and yield Frobnars.
Run Code Online (Sandbox Code Playgroud)

但它也让你看起来适配器; 您可以实现适配器以针对特定用例提供多态行为,而不是将所有行为用于表中的每个形状使用.您可以将对象调整为可打印,可迭代或可导出为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)
Run Code Online (Sandbox Code Playgroud)

并且您的代码只需查找每个形状的适配器:

for obj in setofobjects:
    self.result.append(IXMLExport(obj).export())
Run Code Online (Sandbox Code Playgroud)