0

I'd like to represent an object as a string so that it can be accessed both as a dictionary key and as an object in itself. i.e.

class test(object):
 def __init__(self, name, number_array): 
     self.name = name
     self.number_array = number_array
     self.graph= barChart(number_array) 

sample_obj = test('test_object', [(x1,y1), (x2,y2)etc.])

but so that {sample_obj: another_object} would look like {'test_object': another_object}

while still making something like this possible:

for key, val in sample_dict.items(): print(key.name, key.graph)

as well as:

>>> sample_dict['test_object']
another_object
3
  • There is currently no way to provide such key aliases, so that the dict would treat 'test_object' as an alias for some_object. See PEP-455 for a proposal which would add a new type of dict with this functionality. Commented Sep 25, 2014 at 13:22
  • Is it possible to change the default method for accessing an object in a dictionary? so instead of say, D['foo'] checking if t.__eq__('foo') to checking if t.name.__eq__('foo') ? Could one override getitem ? Commented Sep 25, 2014 at 13:38
  • 1
    Chepner is wrong. It is possible to do what you want. Commented Sep 25, 2014 at 13:54

2 Answers 2

1

You must define eq that returns positive when comparing with the string i.e.:

def __eq__(self, other):
    if self.name == other:
        return True
    ... continue with comparison ...

You must also define hash that returns the same hash as the compared string:

def __hash__(self):
    return hash(self.name)

UPDATE: The following code does exactly what the author wanted:

class test(object):
    def __init__(self, name, number_array): 
        self.name = name
        self.number_array = number_array
        #self.graph= barChart(number_array)

    def __eq__(self, other):
        try:
            return (self.name == other.name) and (self.number_array == other.number_array)
        except AttributeError:
            return self.name == other

    def __hash__(self):
        return hash(self.name)

sample_obj = test('test_object', [(0, 1), (2, 3)])

dict1 = {sample_obj: "Hurray"}
print("dict1[sample_obj]", dict1[sample_obj])
print("dict1['test_object']", dict1['test_object'])

dict2 = {'test_object': "Yippie"}
print("dict2[sample_obj]", dict2[sample_obj])
print("dict2['test_object']", dict2['test_object'])
Sign up to request clarification or add additional context in comments.

2 Comments

This would require str.__eq__, not test.__eq__, to be overridden.
Doesn't matter. Default str.__eq__ will return NotImplemented, then Python will try test.__eq__ with the string as the second argument.
1

To use a class as a dictionary key, implement __hash__ and __eq__. To change how it appears when you print the dictionary, implement __repr__:

class Test(object):

    def __init__(self, name, number_array): 
        self.name = name
        self.number_array = number_array
        self.graph = barChart(number_array) 

    def __eq__(self, other):
        return self.name == other.name and self.number_array == other.number_array

    def __hash__(self):
        return hash(self.name) ^ hash(self.number_array)

    def __repr__(self):
        return "test_object"

In use:

>>> t = Test("foo", (1, 2, 3))
>>> d = {t: [1, 2, 3]}
>>> t
test_object
>>> d
{test_object: [1, 2, 3]}
>>> d[t]
[1, 2, 3]

Note that this means that both the name and number_array attributes must be hashable - I have used a string and a tuple to ensure this. Also, it is better if __repr__ represents the actual object more closely, e.g.

def __repr__(self):
    return "Test({0.name!r}, {0.number_array!r})".format(self)

4 Comments

This doesn't address the second part (using the string 'test_object' as the key to access the element mapped to the object), but I don't think such a thing is possible, at least without using the proposed TransformDict class.
I got it to work with def __repr__(self): return str(self.name) and def __eq__(self, other): return self.name == other - But I'm unsure this is good programming practice because now not only will d['foo'] work but t == 'foo' will now also return true - which seems rather dangerous.
@user3467349 yes, I'm not sure that's a good idea at all. Also, it means all Test instances are functionally identical, even if they contain different data. What's the rationale behind your current approach?
I need a tree like structure that's easily mappable (for a different set of objects), so a single dict() would have a large advantage over multiple nodes with .next() and .previous() methods, but I haven't found a good way to nest objects in a dictionary and still be able to access them by key without doing something pretty hackish.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.