Question

I've seen lots of times something like:

def parse(text):
    if hasattr(text, 'read'):
        text = text.read()

    # Parse the text here...

but if I pass an instance of the following class, it will surely fail:

class X(object):
    def __init__(self):
        self.read = 10

My question is: What is the most pythonic way of handling it?

I've been thinking about two main ways:

if hasattr(text, 'read') and callable(text.read):
    text = text.read()

and

try:
    text = text.read()
except ...
Was it helpful?

Solution 2

The pythonic way is not checking the type of the object at all. For one the language is complicated enough that you'll have a hard time making sure to not include any objects that will fail later anyhow (obvious example from your post: You don't check whether the function takes 0 arguments, don't even think about the return type), and - even worse - you can easily exclude valid code by mistake.

It is much better to just assume the input values will be ok and fail later if it turns out they're not.

There is really only one exception: Say you have different code paths for different types (say strings/lists), in this case you have to check the type to decide which path to take. But again: Try the most general check that will work for you (i.e. don't check isinstance(l, list) if isinstance(l, collections.Iterable) would also do the job). If it later turns out the "string" wasn't really stringy enough you can always fail then.

OTHER TIPS

The pythonic way is to assume text is of whatever type is suitable. Only use try-except/hasattr if you know that text will be entirely different things at different times

In other words, don't validate. Only use if if you're going to else, and try if you really want special handling in except.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top