B
Bruno Desthuilliers
Grant Edwards a écrit :
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.
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.
Which might raise a TypeError if myobj.feature1 is not callable !-)
m = getattr(myobj, 'feature1', None)
if callable(m):
m()
else:
print "%s doesn't implement feature1()" % myobj
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