Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle "duck typing" in Python?

I usually want to keep my code as generic as possible. I'm currently writing a simple library and being able to use different types with my library feels extra important this time.

One way to go is to force people to subclass an "interface" class. To me, this feels more like Java than Python and using issubclass in each method doesn't sound very tempting either.

My preferred way is to use the object in good faith, but this will raise some AttributeErrors. I could wrap each dangerous call in a try/except block. This, too, seems kind of cumbersome:

def foo(obj):     ...     # it should be able to sleep     try:         obj.sleep()     except AttributeError:         # handle error     ...     # it should be able to wag it's tail     try:         obj.wag_tail()     except AttributeError:         # handle this error as well 

Should I just skip the error handling and expect people to only use objects with the required methods? If I do something stupid like [x**2 for x in 1234] I actually get a TypeError and not a AttributeError (ints are not iterable) so there must be some type checking going on somewhere -- what if I want to do the same?

This question will be kind of open ended, but what is the best way to handle the above problem in a clean way? Are there any established best practices? How is the iterable "type checking" above, for example, implemented?

Edit

While AttributeErrors are fine, the TypeErrors raised by native functions usually give more information about how to solve the errors. Take this for example:

>>> ['a', 1].sort() Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: unorderable types: int() < str() 

I'd like my library to be as helpful as possible.

like image 266
André Laszlo Avatar asked Jul 05 '11 23:07

André Laszlo


1 Answers

I'm not a python pro but I believe that unless you can try an alternative for when the parameter doesn't implement a given method, you shoudn't prevent exceptions from being thrown. Let the caller handle these exceptions. This way, you would be hidding problems from the developers.

As I have read in Clean Code, if you want to search for an item in a collection, don't test your parameters with ìssubclass (of a list) but prefer to call getattr(l, "__contains__"). This will give someone who is using your code a chance to pass a parameter that isn't a list but which has a __contains__ method defined and things should work equally well.

So, I think that you should code in an abstract, generic way, imposing as few restrictions as you can. For that, you'll have to make the fewest assumptions possible. However, when you face something that you can't handle, raise an exception and let the programmer know what mistake he made!

like image 119
Pedro Loureiro Avatar answered Sep 24 '22 16:09

Pedro Loureiro