These exceptions are caused when the type of some object should be different
A function or method was called with more (or less) arguments than the ones it can accept.
If more arguments are given:
def foo(a): return a
foo(a,b,c,d) #And a,b,c,d are defined
If less arguments are given:
def foo(a,b,c,d): return a += b + c + d
foo(a) #And a is defined
Note: if you want use an unknown number of arguments, you can use *args or **kwargs. See *args and **kwargs
Some types cannot be operated together, depending on the operand.
For example: + is used to concatenate and add, but you can't use any of them for both types. For instance, trying to make a set by concatenating (+ing) 'set1' and 'tuple1' gives the error. Code:
set1, tuple1 = {1,2}, (3,4)
a = set1 + tuple1
Some types (eg: int and string) use both + but for different things:
b = 400 + 'foo'
Or they may not be even used for anything:
c = ["a","b"] - [1,2]
But you can for example add a float to an int:
d = 1 + 1.0
For an object to be iterable it can take sequential indexes starting from zero until the indexes are no longer valid and a IndexError is raised (More technically: it has to have an __iter__ method which returns an __iterator__, or which defines a __getitem__ method that does what was previously mentioned).
Here we are saying that bar is the zeroth item of 1. Nonsense:
foo = 1
bar = foo[0]
This is a more discrete version: In this example for tries to set x to amount[0], the first item in an iterable but it can't because amount is an int:
amount = 10
for x in amount: print(x)
You are defining a variable and calling it later (like what you do with a function or method)
foo = "notAFunction"
foo()