1. This is due to the fact that python is treating t1 and t4 as different objects. However, when I implement the comparison operator 'eq', with the following code:
When you do this below operation in python....
class Test(object):
    def __init__(self, test = 0):
        self.test = test
if __name__ == '__main__':
    t1 = Test(1)
    t2 = Test(2)
    t3 = Test(3)
    t4 = Test(1)
    my_dict = {}
    my_dict[t1] = 1
    my_dict[t2] = 2
    my_dict[t3] = 3
This means that you are actually trying to create a dict with keys as Test objects, Python does first checks whether the keys are hashable or not.
Any object in Python is hashable when it returns any integer value for obj.__hash__() method. In python all user defined classes by default gets some hash value that is id(self).
Obviously when you get id value as it's hash value, they are gonna look some thing like this value 8772302607193. SO with these id's if we construct the hash table it might looks like this..
Lets assume id's like this..
id(t1) = 1
id(t2) = 4   # These are just assumptions.
id(t3) = 10  # actual id's are long values.
id(t4) = 20
This is how hash table gets constructed....
    hash     Actual
    value    value  
    ------------------
    | 1    |  t1     |
    ------------------
    | 2    | NULL    |
    ------------------   # Consider that you've respective values are
    | 3    | NULL    |   # here, just for representation I've mentioned
    ------------------   # t1, t2, t3, t4, ..
    | 4    | t2      |
    ------------------
           |
           |
    ------------------
    | 10   |  t3     |
    ------------------
           |
         SO ON
Like this your hash table gets constructed, So here when you try for getting value of t4 just trying my_dict[t4]. First python check for hash value of t4 by calling t4.__hash__(), as per the assumption t4 hash value is 20.
After getting the hash value 20 it checks over the hash table with index as 20, since we didn't insert any value with 20 Python simply raises KeyError exception, this is the reason your were getting KeyError when you try my_dict[t4].
Another Scenario Here:
If you try overriding __hash__ method f Test class and proceed with the same operations you did like below..
class Test(object):
    def __init__(self, test = 0):
        self.test = test
    def __hash__(self):
        self.test       # You are just returning the same value
if __name__ == '__main__':
    t1 = Test(1)
    t2 = Test(2)
    t3 = Test(3)
    t4 = Test(1)
    my_dict = {}
    my_dict[t1] = 1
    my_dict[t2] = 2
    my_dict[t3] = 3
Since we've overloaded hash method to return the same value as initialized, below are the hash values we get
t1 = 1 , t2 = 2, t3 = 3, t4 = 1
This is how hash table looks like when we've multiple values with same hash value.
      hash    Actual
      value   value  
      ------------------
      | 1    | [t1,t4] | # List of values for the same hash value.
      ------------------
      | 2    |  t2     |
      ------------------ # Consider that you've respective values are
      | 3    |  t3     | # here, just for representation I've mentioned
      ------------------ # t1, t2, ...
      | 4    |  NULL   |
      ------------------
           |
         SO ON
In this situation when you try to get my_dict[t4], as said before first checks for the hash value t4.__hash__() returns 1. Now Python dict check at index 1 in the hash table and it gets multiple values [t1, t4].
And this is the situation where __eq__ helps you to identify the object when you've multiple values with same hash value. You can do like below to avoid that situation...
class Test(object):
    def __init__(self, test = 0):
        self.test = test
    def __hash__(self):
        return self.test
    def __eq__(self, other):
        return self is other
In your case you just need to verify the self.test value to get the object...
class Test(object):
    def __init__(self, test = 0):
        self.test = test
    def __hash__(self):
        return self.test
    def __eq__(self, other):
        return other.test == self.test
This is how you can manage your dict values!