3

The Atom api is a library used by Enaml to implement MVC. Change an atom var, and the UI is updated. Change it in the UI and your model gets updated.

I would like to put an Atom var (Bool() in this case) into a dictionary and later update that var

 from atom.api import Atom,Bool
 class MyModel(Atom):
     myBool = Bool()

     def getDict(self):
         return {'mybool':self.myBool}

     def setAllBoolsTrue(self):
         self.myBool = True #example to show that just setting mybool will update UI components that use it

         #now to show how I'd like to generalize to many components

         for k,v in self.getDict().iteritems():
             v = True  # this fails, even though the id(v) is the same as id(self.mybool)

The last statement fails to update mybool, it just makes a simple assignment.

So is there a way to update the Bool() retrieved from a dictionary in the same way that simply setting it does?

edit: code updated so no syntax errors.

edit: As per suggestions in the comments, I tried without success:

    tempDict = self.getDict();
    #self.myBool = True  # this works
    tempDict['mybool'] = True  #this does not work
Chuck Carlson
  • 977
  • 8
  • 26
  • 2
    I could be crazy, but this looks like you're trying to reassign a local variable (a copy). You probably need to modify the dictionary with a `set` operation. – Carcigenicate Dec 21 '16 at 01:31
  • 1
    Your code has at least one syntax error, make sure that what you post is a [MCVE]. How familiar are you with python OOP? Multiple things are a bit off... and your specific problem is that the name `v` is being rebound; instead you need to store the dict and mutate it in the loop. So all other problems aside; `tmpdict = getDict(); for k in tmpdict: tmpdict[k] = True`. – Andras Deak -- Слава Україні Dec 21 '16 at 01:31
  • You are right @Carcigenicate, a simple variable assignment is happening. The id() of the local var and myBool is the same. Is there a function that I can call to update the original variable? I will look at set. – Chuck Carlson Dec 21 '16 at 01:34
  • @ChuckCarlson Do you know how to mutate a dictionary? You must if you've populated one. Iirc in Python, to associate a key with a value (or overwrite an old association) `dict[key] = newValue`. – Carcigenicate Dec 21 '16 at 01:37
  • @Andras Deak, your code will simply update the value in the dictionary, but will not cause any Atom magic to happen – Chuck Carlson Dec 21 '16 at 01:37
  • @Carcigenicate, that will just update the dictionary, with no changes to the UI. Look at the statement above: mybool = True. This causes the UI that is using this variable to be updated. – Chuck Carlson Dec 21 '16 at 01:39
  • Let me reiterate: `How familiar are you with python OOP?` Magic is overrated, all you need is to understand mutable types. And it's hard to say anything definite with glaring errors in your above code. – Andras Deak -- Слава Україні Dec 21 '16 at 01:39
  • @ChuckCarlson That's an entirely separate issue. Your question mentions the library, but your main issue is the incorrect method of updating the dictionary. – Carcigenicate Dec 21 '16 at 01:40
  • I'll give it a try now, but I believe I have tried this a few days ago. – Chuck Carlson Dec 21 '16 at 01:41
  • Please, first make sure that your code you post here is runnable, and that you run exactly that. This is the zeroth step of [asking an answerable debugging question](http://stackoverflow.com/help/mcve), see also [ask]. Now you have a `self.getVars` from nowhere. It's a complete mess! – Andras Deak -- Слава Україні Dec 21 '16 at 01:51
  • I've updated the original question to show that simply setting the dictionary as suggested does not work. I'll work on adding a better running example. – Chuck Carlson Dec 21 '16 at 01:52
  • I've updated the code in the op so it runs. – Chuck Carlson Dec 21 '16 at 02:03
  • So how is it that you have `self.myBool` and `self.mybool` both in there? – Andras Deak -- Слава Україні Dec 21 '16 at 02:04
  • You are right, it should be self.myBool. I updated the op. – Chuck Carlson Dec 21 '16 at 02:07
  • So here's the thing: what you call `self.myBool` is actually a *class* attribute rather than an instance attribute. You could just call it `MyAtom.myBool` for the same effect. So when you're saying `self.myBool = True`, you're rebinding this attribute *of the given instance*. It shouldn't even be working, but we can't see the magical part that turns your Atom into a UI. So, what you'd need to do, is to *mutate* the `myBool` attribute, preferably after turning it into an instance attribute (depending on how you plan to use it). – Andras Deak -- Слава Україні Dec 21 '16 at 02:15
  • That would be true for 'normal' python. Atom does some extraordinary things under the hood. An instance variable self.myBool is created by Atom when the class is instantiated. Other than the problem I'm asking about, the code works very well and updates the UI. – Chuck Carlson Dec 21 '16 at 02:17
  • Are you then looking for something like [`setattr`](http://stackoverflow.com/questions/285061/how-do-you-programmatically-set-an-attribute-in-python)? Either something like that, or figure out how to mutate a `Bool` (which I couldn't, with five minutes of googling). – Andras Deak -- Слава Україні Dec 21 '16 at 02:21
  • Yes, something like that. I have tried one of the object instance methods a few days ago with no look. I believe it was something like setattr. Will verify again. – Chuck Carlson Dec 21 '16 at 02:24

2 Answers2

0

for k, v in getDict(): won't work unless your getDict() function returns a dict of two keys, i.e. k, v would more aptly be named key1, key2 in this case, where key2 doesn't even exist.


If you really want to implement classes, you can do something like...

class MyModel(Atom):

    def __init__(self):
        self.myBool = True


>>> model = MyModel()
>>> model.myBool
True
>>> model.myBool = False
>>> model.myBool
False
moogle
  • 110
  • 9
  • @Carcigenicate but it doesn't: it returns a dict, as you see. And iterating over a dict gives you the keys. And iterating over key,value pairs is not python 2/3 polyglot, I think. – Andras Deak -- Слава Україні Dec 21 '16 at 01:38
  • I like the instant downvote right after I posted. Anyone want to explain why I'm wrong? – moogle Dec 21 '16 at 01:42
  • The main reason is that this is a badly formed question that is not answerable because the code inside it is inconsistent and erroneous; no way OP is using that. Until it's cleaned up, it's no use trying to debug it. *But*, the actual question of OP is about mutating the dict, which your answer doesn't help with. You selected one error in the code (from among a handful) and solved it *wrong*: there's no way `for k,v in ` will work. *And* I've seen you post low-effort questions to blatantly off-topic questions. Give me a reason why I *shouldn't* downvote. – Andras Deak -- Слава Україні Dec 21 '16 at 01:47
  • For k,v in getDict() will return the key in k and the value in v. – Chuck Carlson Dec 21 '16 at 04:37
0

After hearing from one of the Atom developers, the answer is to use setattr correctly. I had tried to use setattr on the Bool() itself, but one needs to use it on the Atom subclass, as follows:

 from atom.api import Atom,Bool
 class MyModel(Atom):
     myBool = Bool()

     def getDict(self):
         return {'myBool':self.myBool}

     def setAllBoolsTrue(self):
         self.myBool = True #example to show that just setting mybool will update UI components that use it

         #now to show how to generalize to many components

         for key,value in self.getDict().iteritems():
             setattr(self,key,True) #this updates the UI
Chuck Carlson
  • 977
  • 8
  • 26