在python中,有没有一种方法可以知道一个对象;实现一个接口";在我把它传递给函数之前?

在python中,有没有一种方法可以知道一个对象;实现一个接口";在我把它传递给函数之前?,python,exception,object,introspection,Python,Exception,Object,Introspection,我知道这听起来可能是一个愚蠢的问题,特别是对于了解python本质的人来说,但我只是想知道,有没有办法知道对象是否“实现了接口”,比如说? 举一个我想说的例子: 假设我有这个函数: def get_counts(sequence): counts = {} for x in sequence: if x in counts: counts[x] += 1 else: counts[x] =

我知道这听起来可能是一个愚蠢的问题,特别是对于了解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\u计数(iIterable序列)

我的猜测是,在Python中,我必须使用先发制人的内省检查(在
装饰程序中,可能是吧?)并在对象没有
\iter\uuuu
属性的情况下抛出一个自定义
异常。但是有没有一种更符合Python的方法来实现这一点呢?

Python(自2.6版起)有(又称虚拟接口),它比Java或C接口更具吸引力。要检查对象是否可编辑,请使用:


但是,如果您的
else
块只会引发一个异常,那么最常见的Python回答是:不要检查!由您的调用者传入适当的类型;你只需要记录下你期待的是一个iterable对象。

python的方法是使用duck输入和“请求原谅,而不是许可”。这通常意味着在
try
块中执行一个操作,假设它的行为符合您的预期,然后在
块中处理除
之外的其他情况。

我认为社区会建议您这样做:

import sys

def do_something(foo):
    try:
        for i in foo:
            process(i)
    except:
        t, ex, tb = sys.exc_info()
        if "is not iterable" in ex.message:
            print "Is not iterable"

do_something(True)
或者,您可以使用类似于
zope.interface

的方法在
isinstance()或interfaces之前使用多态性和duck类型
您通常定义要对对象执行的操作,然后使用多态性来调整每个对象如何响应您要执行的操作,或者使用duck类型;测试手边的对象是否可以做您首先想要做的事情。这是调用与内省之间的权衡,传统观点认为调用优于内省,但在Python中,duck类型优于
isinstance
测试

所以你首先需要弄清楚为什么你需要过滤某些东西是否合适;你为什么要知道这些?只需使用
try:iter(object)
除了TypeError:#notiterable
来测试

或者,如果传递的内容不是iterable,您可能只需要抛出一个异常,因为这将发出错误信号

ABCs 使用duck类型,您可能会发现必须测试多个方法,因此
isinstance()
test可能是更好的选择。在这种情况下,使用a也可能是一种选择;例如,使用ABC,您可以“绘制”几个不同的类,作为给定操作的正确类型。使用ABC,您可以专注于需要执行的任务,而不是使用的具体实现;你可以有一个
Paintable
ABC,一个
Printable
ABC,等等

Zope接口和组件体系结构

如果你发现你的应用程序使用了大量的ABC,或者你必须不断地向你的类中添加多态方法来处理各种不同的情况,下一步就是考虑使用一个完整的组件架构,比如.

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)

是的,但是我应该在同一个方法中还是在另一个
装饰器
方法中进行这种内省检查?我想说的是,使用decorator方法使其更具可读性,但如果在表中大量使用,则会带来性能问题。还有什么比python更具python风格?@nlightn最具python风格的做法是记录您的期望,并允许在调用方传入不合适的类型时引发
TypeError
。请问为什么调用优先于内省?是因为内省代价高昂吗?@NlightNFotis:如果你只需要调用这个方法,那么你就可以把测试保存下来。测试是一个额外的步骤,所以如果可以避免的话,就这样做。@NlightNFotis:但也可以查看DuckType和异常处理之间的性能权衡。我本想问这个问题,但一个电话让我停了下来!你在我心里,兄弟!感谢您的回答。这只有在您已经期望实例符合界面,并且在出现错误之前知道不会发生任何副作用的情况下才有意义。我很确定,“社区”不会使用未指定的
,除非
语句,但至少要写
除了TypeError:
,以便将错误与
进程()内部可能出现的其他错误区分开来。
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())