I think your problem comes from a misunderstanding of how variable typing works in Python. In the line
type(do_plus(a))
The reason it complains about a
not being defined is because it's not looking at the parameter a
, it's looking for a variable called a
that it's trying to pass to the function.
In python, method parameters aren't strongly typed. You cannot know what types a method expects just by looking at the signature! I assume you come from a static-typed language where you can use reflection or a similar trick to inspect the parameters declared for the method, but no such functionality exists in python because it doesn't make sense. For example, I can do this:
do_plus(1, 2) # parameters are both `int`
>>> 3
do_plus(1.1, 2.2) # parameters are both `float`
>>> 3.3
do_plus("string1", "string2") # parameters are both `str`
>>> "string1string2"
do_plus("string", 3) # one parameter is `str`, one is `int`
>>> "string3"
do_plus(3, "string")
>>> TypeError: unsupported operand type(s) for +: 'int' and 'str'
Notice that in the last line, the complaint isn't "You can't call this method with these parameters", the complaint is "I don't know how to calculate 3 + "string"
". If you look at the stack trace, it will complain about the line inside do_plus
, which indicates that execution entered the function successfully.
So, since you can't type check from outside the function, you have to type check inside. You can do this with the isinstance
built in function:
def do_plus(a, b):
if not isinstance(a, int) or not isinstance(b, int):
raise TypeError("do_plus only accepts ints")
return a + b
This is because of one of the core Python guidelines: "It is better to ask forgiveness than permission." Instead of checking to see if you can do something, you should try to do it and handle failure.
Other notes
The way you write type (doplus(a))
suggests to me that you think type
is a keyword of some kind. This isn't the case, type
is a function. Actually, it's a little more than just a function, but it is a function nonetheless. You can write
type(type)
>>> <type 'type'>
Which would lead you to conclude that type
is actually a type! Of type type
! This all gets very confusing very quickly, but the point is, very few words are actually reserved as keywords in Python. Most functionality you would see as keywords in other languages is done through built-in functions.
Additionally, I see you already understand this a bit, but generally instead of checking types you want to just try to do something and if it worked, then hurray! This is the beauty of duck typing, which is the idea that "if it looks like a duck and quacks like a duck, it's a duck". You should assume that any parameters people pass into your functions are going to be able to support the operations you try to perform on them; that way people can pass in other objects which support the same operations and in theory, they'll get a reasonable result just the same. It's a way of reasoning about the logic of a method instead of the implementation; the question should be "Am I doing the right thing?" not "Does this do the right thing?"
Hope this helps you. Python is a great, incredibly flexible language but it requires you to think much differently than you do in other languages.