5

Consider this example of a function (and its use) that receives one parameter which is only meaningful as int:

def fun(index):
    index = int(index)
    # do something with index

def main():
    print fun(1e6)

I find that I keep repeating this pattern on several functions that deal with integers since it ensures that I really receive some integer number (note that 1e6 is a floating point instance).

This is a bit cumbersome and if forgotten once it could produce problems (there is code that reacts differently to floating-point/integer/string/... values). So could this be somehow encoded in the function signature?

E.g. something along the lines of this pseudo-code:

def fun(int index):
    # do something with index
bitmask
  • 32,434
  • 14
  • 99
  • 159
  • This is a bit of a non-answer (as I have never actually worked with them) but there are some frame works (zope is one I think) that will do this for you – tacaswell Apr 07 '13 at 03:10
  • Type enforcement isn't very Pythonic. Is there any reason that you are avoiding the duck-typing paradigm? – Joel Cornett Apr 07 '13 at 04:03
  • @JoelCornett: The rounding errors (stemming from the exponent notation of floating point numbers) cause problems when comparing to `0` and I had some loops overshoot. (But I'm right in the middle of learning Python, coming from C++ and Haskell --- so I'm not surprised that I have trouble accepting duck-typing.) – bitmask Apr 07 '13 at 04:19
  • If you are going to use `index` for a loop, use it as `range(index)`. That will raise an exception if you feed it an object that cannot be represented as an integer. – Roland Smith Apr 07 '13 at 08:58

2 Answers2

9

First of all, you shouldn't really be doing this (even though some days I kind of want to as well…). Python is not statically-typed, so you shouldn't really be introducing cludgy static-typing.

Buuut, to answer you question. Decorators:

def ensure_int(fn):
    def wrapper(num):
        return fn(int(num))
    return wrapper

def test(num):
    return num + 2

@ensure_int
def test2(num):
    return num + 2

Works like:

> test("2") 
ERROR!!!

>test2("2")
4
Isaac
  • 15,783
  • 9
  • 53
  • 76
  • 1
    this will behave badly with `1e65` as an arguement – tacaswell Apr 07 '13 at 03:07
  • Thanks for pointing it out! There are edge-cases to handle, but I'll leave that as an exercise to the user. (hint, convert to int then str) ;) – Isaac Apr 07 '13 at 03:08
  • Hmmm, I would have to implement a decorator for each function signature (you usually have additional parameters that don't necessarily have that restriction), which is really more cumbersome than useful. I was more thinking about a specification that is *close to the individual formal parameters*. – bitmask Apr 07 '13 at 03:13
  • 2
    +1 "Python is not statically-typed". If you don't know what you're passing to a function, does it matter what the return is? – msw Apr 07 '13 at 03:13
  • @bitmask If you're using Python 3, you could do something with function annotation, as BrenBarn described. Really, you should've be doing this in any sort of ad hoc manner (i.e. unless you're writing a Type System for Python, which would be more academic than practical). You should be writing functions which compose neatly, not type-casting all over the place (very un-Pythonic). – Isaac Apr 07 '13 at 05:08
  • *"shouldn't", not "should've". – Isaac Apr 09 '13 at 13:35
2

In Python 3 you could use function annotations and then write a decorator that converts (or tries to convert) arguments to the types you specify.

In Python 2 you can't do this in the way you seem to want. Python 2's syntax doesn't support putting anything in the function definition except the arguments themselves, and you can't alter Python's syntax to let you put types in there as well.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • Some sample code would be really helpful! – ToJo Sep 23 '21 at 15:11
  • 1
    hey @ToJo I shared sample code for you :) https://stackoverflow.com/questions/15299878/how-to-use-python-decorators-to-check-function-arguments/69647529#69647529 – ati ince Oct 20 '21 at 14:07