Python "implements <interface>" equivalent?

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Wed Oct 3 14:05:52 CEST 2007


Grant Edwards a écrit :
> On 2007-10-04, Bruno Desthuilliers <bruno.42.desthuilliers at wtf.websiteburo.oops.com> wrote:
> 
> 
>>Yes, and it's even simpler : just pass your object. If it effectively 
>>implements the desired interface, everything will work fine !-)
> 
> [...]
> 
> 
>>>What I'd like to do is create a feature detection system for
>>>my work -- specifically, a general class / interface called
>>>"Feature" and then subclasses that implement functions like
>>>isFeaturePresent() in all of their different and unique ways.
>>>I'd love to hear how I can do this in Python.
>>
>>I'm not sure about what you exactly want to do, but FWIW, checking if an 
>>object has a given attribute is quite simple:
>>
>>if has_attr(obj, 'attribute_name'):
>>   print "Hurray"
>>else:
>>   print "D'oh"
>>
>>Note that in Python, methods are attributes too - only they
>>are callable.
> 
> 
> On a slight tangent....
> 
> The "Pythonic" way to handle things like that is often just
> to call the method you want to call.  If the object doesn't
> have that method, then you catch the exception and do whatever
> it is you do in the case where the object doesn't have the
> feature in question.  

Depends... If you expect the object to have this attribute most of the 
time, then the try/except solution is fine, but else it might be better 
to look-before-you-leap - try/except blocks are costly when there's 
effectively an exception.

As a side note, you may not necessarily want to actually call the 
method, only know if it's there. As a side-side note, if you want to 
call it but choose the look-before-you-leap approach, using getattr() 
and storing a local reference to the method might be better, since it 
avoids a second lookup.

> 
> The tricky bit is only catching the AttributeError exception
> generated by the attempt to access the non-existant method, and
> not catching AttributeError exceptions generated by bugs in the
> method when it does exist.
> 
> Once you've added code to make sure you only catch exceptions
> you care about, it's simpler to just call has_attr
> 
> the obvious method
> 
>    try:
>        myobj.feature1()
>    except AttributeError:
>        print "object doesn't implement feature1"
>     
> isn't correct, since an unhandled AttributeError generated by
> the feature1 method will print "object doesn't implement
> feature1".

Indeed. In this case, it would be better to *not* catch the exception. 
At least, the traceback will make clear where the AttributeError comes from.

>  Attempting to isolate the attributeError we care
> about looks like this:
> 
>    try:
>        m = myobj.feature1
>    except AttributeError:
>        print "object doesn't implement feature1"
>    else:
>        m()

Which might raise a TypeError if myobj.feature1 is not callable !-)

> That's just too messy compared with the has_attr method that
> goes like this:
>        
>    if has_attr(myobj,'feature1'):
>        myobj.feature1()
>    else:
>        print "object doesn't implement feature1"   
> 
> However, I don't like that alot because you've got to supply
> the method name twice: once as a string and once as the method
> name.
> 
> What's the cleanest way to call a method that might not be
> there?

m = getattr(myobj, 'feature1', None)
if callable(m):
   m()
else:
   print "%s doesn't implement feature1()" % myobj





More information about the Python-list mailing list