In [2]:
# in languages like C, each variable has a type.
# in Python, each value has a type, and a variable can have any value
# the "type" builtin function returns the type of an object
str(3)
Out[2]:
In [3]:
v = 'fish'
type(v)
Out[3]:
In [4]:
v = 3
type(v)
Out[4]:
In [5]:
# suppose you want a function that behaves differently depending on what
# type of object it receives as an argument. You can do it this way:
def count(thing):
if type(thing) == str:
return range(len(thing))
elif type(thing) == int:
return range(thing)
count('fish')
Out[5]:
In [6]:
count(4)
Out[6]:
In [7]:
# this is not the recommended way to do it, for a variety of complex reasons having to
# do with how types are defined and referred to. the more idiomatic approach is "duck typing"
# duck typing is based on the idea that if it walks like a duck and quacks like a duck, it's a duck.
# to duck type, take an action that assumes that a value is a given type, and if it raises an exception,
# then drop that assumption and move on to trying other actions.
# first, let's reimplement count assuming that "thing" has a length:
def count(thing):
return range(thing)
count('fish')
In [8]:
# now let's handle the case where thing has a length
def count(thing):
try:
return range(thing)
except TypeError:
pass
return range(len(thing))
count('fish')
Out[8]:
In [16]:
count(4)
Out[16]:
In [9]:
# this still does not work.
count(3.7)
In [10]:
# let's extend the duck typing to include floats
import math
def count(thing):
try:
return range(thing)
except TypeError:
pass
try:
return range(len(thing))
except TypeError:
pass
try:
return range(int(math.ceil(thing)))
except TypeError:
pass
raise TypeError
count(4.3)
Out[10]:
In [ ]:
# duck typing is based on the idea that types in Python are best thought of
# not as categorical definitions of allowable values, but rather sets of allowable
# actions that are associated with some type.