views:

85

answers:

4

I'm writing an "envirorment" where each variable is composed by a value and a description:

class my_var:
   def __init__(self, value, description):
      self.value = value
      self.description = description

Variables are created and put inside a dictionary:

my_dict["foo"] = my_var(0.5, "A foo var")

This is cool but 99% of operations with variable are with the "value" member. So I have to write like this:

print my_dict["foo"].value + 15  # Prints 15.5

or

my_dict["foo"].value = 17

I'd like that all operation on the object my_dict["foo"] could default to the "value" member. In other words I'd like to write:

print my_dict["foo"] + 15     # Prints 5.5

and stuff like that.

The only way I found is to reimplement all underscore-members (eq, add, str, etc) but I feel like this is the wrong way somehow. Is there a magic method I could use?

A workaround would be to have more dictionaries, like this:

my_dict_value["foo"] = 0.5
my_dict_description["foo"] = "A foo var"

but I don't like this solution. Do you have any suggestions?

+1  A: 

I think the fact that you have to do so much work to make a fancy shortcut is an indication that you're going against the grain. What you're doing violates LSP; it's counter-intuitive.

my_dict[k] = v;
print my_dict[k] == v # should be True

Even two separate dicts would be preferable to changing the meaning of dict.

Patrick McElhaney
+3  A: 

Two general notes.

  1. Please use Upper Case for Class Names.

  2. Please (unless using Python 3.0) subclass object. class My_Var(object):, for example.

Now to your question.

Let's say you do

x= My_Var(0.5, "A foo var")

How does python distinguish between x, the composite object and x's value (x.value)?

Do you want the following behavior?

  • Sometimes x means the whole composite object.

  • Sometimes x means x.value.

How do you distinguish between the two? How will you tell Python which you mean?

S.Lott
+2  A: 

You could create an object that mostly acts like "value" but has an additional attribute "description, by implementing the operators in section "Emulating numeric types" of http://docs.python.org/reference/datamodel.html

class Fooness(object):
    def __init__(self,val, description):
        self._val = val
        self.description = description

    def __add__(self,other):
        return self._val + other

    def __sub__(self,other):
        return self._val - other

    def __mul__(self,other):
        return self._val * other

    # etc

    def __str__(self):
        return str(self._val)


f = Fooness(10,"my f'd up fooness")
b = f + 10
print 'b=',b
d = f - 7
print 'd=',d

print 'f.description=',f.description

Produces:

b= 20
d= 3
f.description= my f'd up fooness
Ross Rogers
+2  A: 

I would personally just use two dictionaries, one for values and one for descriptions. Your desire for magic behavior is not very Pythonic.

With that being said, you could implement your own dict class:

class DescDict(dict):
    def __init__(self, *args, **kwargs):
        self.descs = {}
        dict.__init__(self)

    def __getitem__(self, name):
        return dict.__getitem__(self, name)

    def __setitem__(self, name, tup):
        value, description = tup
        self.descs[name] = description
        dict.__setitem__(self, name, value)

    def get_desc(self, name):
        return self.descs[name]

You'd use this class as follows:

my_dict = DescDict()
my_dict["foo"] = (0.5, "A foo var")  # just use a tuple if you only have 2 vals
print my_dict["foo"] + 15            # prints 15.5
print my_dict.get_desc("foo")        # prints 'A foo var'

If you decide to go the magic behavior route, then this should be a good starting point.

Eli Courtwright