在python中,有没有一种方法可以知道一个对象;实现一个接口";在我把它传递给函数之前?
我知道这听起来可能是一个愚蠢的问题,特别是对于了解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] =
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())