1

For example take a simple class representing a person. The only class attribute is a string representing the persons name. I want to make sure that nobody tries to pass the constructor some other type of object like an int, or list...etc. This was my first attempt below I thought that this would return an obj of type None if the argument was not a str but it still seems to return a Person obj. I come from a "more" strongly typed language background and I am a little confused as how to handle my self in python. What does pythonic style say about this situation and type safety more generally? Should I raise an exception? Or find a way to return None? Or something else entirely.

class Person: 

    name = None

    def __init__(self, name):
        if not isinstance(name, str):
            return None
        self.name = name
Alexander Van Atta
  • 870
  • 11
  • 34
  • 1
    I essentially made a similar question the other day, and you can find it [here](http://stackoverflow.com/questions/13919772/in-python-is-there-a-way-to-know-if-an-object-implements-an-interface-before-i). **I urge you to read Martijn Pieter's answer** as it is very related to what you ask. – NlightNFotis Dec 18 '12 at 16:36
  • Why not use `self.name = str(name)`? That would accept everything that has a string representation. – Roland Smith Dec 18 '12 at 17:03

3 Answers3

6

You'd want to raise an error within the __init__ method:

if not isinstance(name,basestring):
    raise TypeError("I don't think that is a name ...")

*Note that basestring also includes unicode for python2.x, but isn't available in python3.x.

Careful though, there is nothing here to prevent a user from re-setting the person's name to a list after the person has been constructed.

jack = Person("Jack")
jack.name = ["cheese","steak"]  #???

If you want to have this safety built in, you'll need to start learning about property.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 1
    @JonClements -- Yeah, I suppose so. Good call. :) – mgilson Dec 18 '12 at 16:24
  • OMG - that's scary - we both just added that at the same time :) (the str/basestring thing that is) - Good point about properties though + 1:) – Jon Clements Dec 18 '12 at 16:27
  • @JonClements -- We seem to have hive mind for this question. We posted simultaneously as well... – mgilson Dec 18 '12 at 16:28
  • @RocketDonkey -- I forgot to add the line : `isintance = isinstance` at the top ;-) – mgilson Dec 18 '12 at 16:30
  • @mgilson Haha, should have figured :) – RocketDonkey Dec 18 '12 at 16:30
  • @mgilson -- +1 Thanks for the answers. I have seen duck-typing referenced in a couple of the links provided but I was not sure exactly what that means. Is that just a way of type checking where you use try: except: instead of isinstance()? – Alexander Van Atta Dec 18 '12 at 16:39
  • 1
    @vanattab -- Basically, yes. The idea is that if the variable acts like a duck, and smells like a duck, and looks like a duck, then it must be a duck. – mgilson Dec 18 '12 at 17:45
5

That's about it - short of using some form of decorator, but generally, type checking isn't very Pythonic, although valid in some cases, your code should be:

def __init__(self, name):
    if not isinstance(name, basestring):
        raise TypeError('name must be str/unicode')
    # ...

Note that basestring is the parent of str and unicode in Python 2.x, so this would allow both - either use str (as you are now in 2.x) to not allow unicode (or vice versa - for any particular reason). In 3.x, basestring doesn't exist, you've just got str.

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
0

I would not return None here but rather raise and exception to signify the incorrect object type.

sean
  • 3,955
  • 21
  • 28