bob.sacamento
bob.sacamento

Reputation: 6651

python reference to a float, int, etc

As I understand it, there are no references in python to ints or floats or similar data. Nevertheless, I am working on a problem where it would be very convenient for me if I could do something like

a=1
b=2
c=3
ref_dict={'field1':ref_to_var_a,'field2':ref_to_var_b,'field3':ref_to_var_c}

and then

def update(field,value):
   ref_dict[field]=value

And so if the user called

update('field2',5)

the value of b would become 5.

Is there any way this can be done? Thanks.

In response to arbanert's helpful comment and answer, what I really want to do is -- surprise, surprise -- more complicated. I am building a GUI with wxPython. I have many TextCtrl controls, each of which will set the value of one variable. Of course, I could write one method for each control, or I could write a single method, which would look something like

def handleTextEvent(self,event):
    if (event.GetEventObject() == widget1):
       a=int(event.GetString)
    elif (event.GetEventObject() == widget2):
       b= ....

I think you can see why I don't like this either. It would be nice if I could just do one short function like:

def handleTextEvent(self,event):
    ref_dict[event.GetEventObject()]=int(event.GetString())

And, yes, I am very new with wxPython.

Thanks!

Upvotes: 0

Views: 2561

Answers (1)

abarnert
abarnert

Reputation: 365767

This is possible, but it's almost always a bad idea.

Assuming a, b, and c are globals:

ref_dict = {'field1': 'a', 'field2': 'b', 'field3': 'c'}
def update(field, value):
    globals()[ref_dict[field]] = value

If you really want to, you can even create "reference wrappers":

class GlobalReference(object):
    def __init__(self, name):
        self.name = name
    def get(self):
        return globals()[self.name]
    def set(self, value):
        globals()[self.name] = value

ref_dict = {'field1': GlobalReference('a'), 'field2': GlobalReference('b')}
def update(field, value):
    ref_dict[field].set(value)

And if you want to wrap things that aren't in globals, like globals from another module, class attributes, instance attributes, etc.? Create more reference wrapper types:

class NamespaceReference(object):
    def __init__(self, namespace, name):
        self.namespace, self.name = namespace, name
    def get(self):
        return getattr(self.namespace, self.name)
    def set(self, value):
        setattr(self.namespace, self.name, value)

ref_dict = {'field1': GlobalReference('a'), 'field2': NamespaceReference('myobj', 'b')}

Or you can forgo the classes and just store setter functions…


So, if this is a bad idea, what's the right answer?

Without knowing what you're trying to do, it's hard to say, but here are some possibilities:

  • Use a single dict variable full of values instead of a bunch of separate variables.
  • Make the variables instance attributes of a class, and pass an instance of that class around.
  • Use a mutable float-holder object instead of a plain float instance.

For your specific case, I think what you want is the second one. This is standard model-view-controller design. Or, if you don't like MVC, model-template-view or some other variant (you don't really need a controller here).

Your model is a bunch of scattered globals, which is why it's hard to hook it up to the view. The simplest answer is to represent the model as an object. Then give the view (or its controller) a reference to this model, which is trivial, and you're done.

Upvotes: 2

Related Questions