When I started Making App Pie, one of my big frustrations was wrapping my head around defining methods. I was used to C++ and Java functions. Objective-C and its Smalltalk roots just threw me. Now going into Python is difficult too — but for another reason. Once again dynamic typing in Python rears up to make things different in defining functions.
Simple functions are not that difficult to define though. Just use the
def my_function(a,b): c=a+b*b return c
This looks simple enough.
def works great in this situation. Dynamic typing means there is no specifying the return type or the types of the parameters. For the same reason it’s simple,
def can cause some big run time errors. If somewhere in your program there was:
There would be a fatal
TypeError exception. Even Python can’t multiply strings together. With a few notable exceptions, in Objective-C as a static typed, compiled language, this generally cannot occur. In an interpreted language with dynamic type like Python this isn’t caught until run time, when it is too late. So when working in Python, ether type checking or good error handling are a good idea.Exception handling uses the
try:...except: clause. For our function above, this would look like:
def my_fun(a,b): try: c=a+b*b return c except TypeError: return 'TypeError' print(my_fun(5,'cute'))
We place the code where the error may occur after the
try:. In the case of an exception, one or more
except: handlers do something other than crash the program.
What I return in the case of a TypeError could be a problem too. In the case above, what I return is a string TypreError. If I always check for type errors wherever this function gets called, this will be okay. If I just use the function in some other mathematical expression, the TypeError will then happen there. I could also return 0 in the case of a type error, though it might mess up the math I was trying to do, or make a bug very difficult to trace.
Besides exception handling, I could type check. Python’s function
isinstance() returns a boolean value of an object given a target type or class.
def my_fun_too(a,b): if isinstance(a,int) and isinstance(b,int): c=a+b*b return c else: return 0
This works, sort of. I can now use the function, but only for two integers. If I want one of the two, or both of the numbers to be float values, I would get zero for a result. Python has a form of NSArray which makes a unmutable ordered collection called a tuple. We can put a tuple in the
isinstance() function of all the types we will accept for calculations.
def my_fun_too(a,b): if isinstance(a,(int,float)) and isinstance(b,(int,float)): c=a+b*b return c else: return 0
An alternative to this code would be this snippet, using a second function to let numbers only into the calculation before we do the calculation in the
def cast_number(a): #returns floats and int, makes everything else 0 if isinstance(a,(int,float)): return a else: return 0 def my_fun_three(a,b): b = cast_number(b) c= cast_number(a) + b*b return c
The big change between Python and any of the compiled languages like C, C++, Java, or Objective-C is that the compiler demanding static typing handles much, if not all of this for us. In Python we need to be very careful about what types end up in a function’s parameter, and for every function deal with the eventuality that something that doesn’t belong there will end up in a place it could break our program. Of course the upside of Python is we do not, as in Objective-C have both an
int and an
float method to write code for — its just one function.