1

In Python, I would like to check the type of the arguments passed to a function.

I wrote two implementations:

class FooFloat(float):
    pass

# Solution 1
def foo(foo_instance):
   if type(foo_instance) is FooFloat:
      raise TypeError, 'foo only accept FooFloat input'


# Solution 2
def foo(foo_instance):
   assert type(foo_instance) is FooFloat, 'foo only accept FooFloat input'

In my opinion the latter is easier to read and less boilerplate. However it will throw an AssertionError which is not the type of error I would like to raise.

Is there a better third solution in this case more common?

I was thinking about a decorator:

@argtype('foo_instance', FooFloat)
def foo(foo_instance):
   pass
4
  • Possible duplicate of Best practice for Python Assert Commented Dec 3, 2015 at 8:56
  • 1
    There is a type hint feature in Python 3.5: python.org/dev/peps/pep-0484 Commented Dec 3, 2015 at 9:08
  • @eph: But it doesn't do any checking. Commented Dec 3, 2015 at 21:32
  • @user2357112: Python encourages to check attr instead of type. But you can still do type checking with a decorator as in stackoverflow.com/a/32844779/918120 or in mypy mypy-lang.org Commented Dec 4, 2015 at 0:27

2 Answers 2

1

I like this idea and thinking of using it in future. I implement the third solution as following, please have a try.

def argtype(arg_name, arg_type):
    def wrap_func(func):
        def wrap_args(*args, **kwargs):
            if not isinstance(kwargs.get(arg_name), arg_type):
                raise TypeError, '%s\'s argument %s should be %s type' % (func.__name__, arg_name, arg_type.__name__)
            return func(*args, **kwargs)
        return wrap_args
    return wrap_func


@argtype('bar', int)
@argtype('foo', int)
def work(foo, bar):
    print 'hello word'

work(foo='a', bar=1)

Besides, I think use isinstance is more suitable if there is inheritance.

Sign up to request clarification or add additional context in comments.

Comments

0

isinstance() does this. It accepts the type and subtypes.

if not isinstance(arg,<required type>):
    raise TypeError("arg: expected `%s', got `%s'"%(<required type>,type(arg))

After eliminating all duplication (DRY principle), this becomes:

(n,t)=('arg',<required_type>);o=locals()[n]
if not isinstance(o,t):
    raise TypeError("%(n)s: expected `%(t)s', got `%(rt)s'"
            %dict(locals(),rt=type(o)) # fine in this particular case.
                                       # See http://stackoverflow.com/a/26853961/648265
                                       # for other ways and limitations
del n,t,o

Personally, I would use assert instead unless I care about which exceptions it throws (which I typically don't - an invalid argument is a fatal error, so I'm only interested in the fact one was thrown):

assert isinstance(arg,<type>),"expected `%s',got `%s'"%(<type>,type(arg))
        #arg name would be seen in the source in stacktrace

Also consider duck typing instead of explicit type checks (this includes checking for special members, e.g. __iter__ for iterables). Full "duck typing vs type checks" discussion is beyond the scope of the current topic, but it looks like explicit checks are more fit for highly-specialized and/or complex interfaces as opposed to simple and generic ones.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.