Question

I have a function which needs to behave differently depending on the type of the parameter taken in. My first impulse was to include some calls to isinstance, but I keep seeing answers on stackoverflow saying that this is bad form and unpythonic but without much reason why its bad form and unpythonic. For the latter, I suppose it has something to do with duck-typing, but whats the big deal to check if your arguments are of a specific type? Isn't it better to play it safe?

Was it helpful?

Solution 2

Using isinstance limits the objects which you can pass to your function. For example:

def add(a,b):
    if isinstance(a,int) and isinstance(b,int):
        return a + b
    else:
        raise ValueError

Now you might try to call it:

add(1.0,2)

expecting to get 3 but instead you get an error because 1.0 isn't an integer. Clearly, using isinstance here prevented our function from being as useful as it could be. Ultimately, if our objects taste like a duck when we roast them, we don't care what type they were to begin with just as long as they work.

However, there are situations where the opposite is true:

def read(f):
    if isinstance(f,basestring):
        with open(f) as fin
            return fin.read()
    else:
        return f.read()

The point is, you need to decide the API that you want your function to have. Cases where your function should behave differently based on the type exist, but are rare (checking for strings to open files is one of the more common uses that I know of).

OTHER TIPS

Consult this great post


My opinion on the matter is this:

  • If you are restricting your code, don't do it.
  • If you are using it to direct your code, then limit it to very specific cases.

Good Example: (this is okay)

def write_to_file(var, content, close=True):
    if isinstance(var, str):
        var = open(var, 'w')
    var.write(content)
    if close:
        var.close()

Bad Example: (this is bad)

def write_to_file(var, content, close=True):
    if not isinstance(var, file):
        raise Exception('expected a file')
    var.write(content)
    if close:
        var.close()

Because doing so explicitly prevents duck-typing.

Here's an example. The csv module allows me to write data to a file in CSV format. For that reason, the function accepts a file as a parameter. But what if I didn't want to write to an actual file, but to something like a StringIO object? That's a perfectly good use of it, since StringIO implements the necessary read and write methods. But if csv was explicitly checking for an actual object of type file, that would be forbidden.

Generally, Python takes the view that we should allow things as much as possible - it's the same reasoning behind the lack of real private variables in classes.

sometimes usage of isinstance just reimplements the polymorphic dispatch. Look at str(...), it calls object.__str__(..) which is implemented with each type individually. By implementing __str__ you can reuse code that depends on str by extending that one object instead of having to manipulate the built in method str(...).

Basically this is the culminating point of OOP. You want polymorphic behaviour, you do not want do spell out types.

There are valid reasons to use it though.

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