-2

I'm trying to implement special behavior, so that values in self and self.aux_gate are always the same. I tried doing this by implementing __setattr__(), but in doing this, I've ran in many problems regarding __dict__.

From what I could gather, it seems like whenever self.__setattr__() is called normally, it adds a key-value pair to self.__dict__, corresponding to the arguments self.__setattr__() is given.

However, the self.__setattr__() I've written seems to create extra self.__dict__ entries, I've seen self.__dict__["conditional"],self.__dict__["current_Position"], and self.__dict__["current_Track"]. I don't see how those values have made their way into self.__dict__.

Here is the class, I've copied and pasted it's superclass below

class SWAP_Gate(Quantum_Gate):
    
    def __init__(self, cost, conditional, current_Track, current_Position, rectangle = None, aux_gate = None):
        if aux_gate is None:
            self.aux_gate = SWAP_Gate(cost,conditional,current_Track,current_Position, aux_gate = self)
        else:
            self.aux_gate = aux_gate
        self.cost = cost
        self.__SWAPconditional = conditional
        self.__SWAPcurrent_Track = current_Track
        self.__SWAPcurrent_Position = current_Position
        if rectangle is None:
            self.rectangle = pg.Rect(430, 0, 1480, 150)
        else:
            self.rectangle = rectangle
    
    def __setattr__(self, name, value):
        super(SWAP_Gate, self).__setattr__(name, value)
        if name == "conditional":
            self.aux_gate.conditional = value
        #I've deleted some code on this line that jsut made the whole post a lot harder to read, it's not relevant to my problem
        elif name == "current_Position":
            self.current_Position = value
            self.aux_gate.current_Position = value
        elif name == "aux_gate":
            self.__dict__["aux_gate"] == value
        else:
            self.__dict__[name] == value
    
    def __getattr__(self, name):
        if name == "conditional":
            return self.__SWAPconditional
        elif name == "current_Track":
            return self.__SWAPcurrent_Track
        elif name == "current_Position":
            return self.__SWAPcurrent_Position
class Quantum_Gate():
        
    def __init__(self, cost, conditional, current_Track, current_Position, rectangle = None):
        self.cost = cost
        self.conditional = conditional
        self.current_Track = current_Track
        self.current_Position = current_Position
        if rectangle is None:
            self.rectangle = pg.Rect(0, 0, 100, 100)
        else:
            self.rectangle = rectangle```
Therk
  • 15
  • 4
  • I don't think you want to fall back to the `super` class handlers until you're sure you can't handle it yourself. – Tim Roberts May 10 '21 at 18:46
  • It totally isn't clear what you asking. What do you mean "whatever code generates `__dict__`??" What, *exactly* is the issue? – juanpa.arrivillaga May 10 '21 at 18:53
  • @juanpa.arrivillaga sorry about that, I've rewrote what I mean, hopefully it's clearer? – Therk May 10 '21 at 19:15
  • @Tim Roberts I've written the superclass myself, I know how it works, there just seems to be some weird interaction going on here – Therk May 10 '21 at 19:19
  • "However, the `self.__setattr__()` I've written seems to create extra `self.__dict__` entries, I've seen `self.__dict__["conditional"]`,`self.__dict__["current_Position"]`, and `self.__dict__["current_Track"]`. I don't see how those values have made their way into `self.__dict__`." This is *incredibly* vague. Please **provide actual code** that does the behavior you described, and tell us *exactly* what you expect and don't expect. – juanpa.arrivillaga May 10 '21 at 19:39
  • You say that you don't understand how `self.__dict__["current_Position"]` could be assigned... but you clearly assign to it here: `self.current_Position = value` in your `__setattr__`, although, I'm not sure how that isn't causing recursion. To be frank, your entire approach is confusing and this is highly disorganized, your class does a lot of "magical" unobvious things which is generally not how you want to design your programs. – juanpa.arrivillaga May 10 '21 at 19:46
  • @juanpa.arrivillaga I'm very sorry for the confusion, I'm still quite new with python, I'll try to clear up best I can. However, I can't provide actual code that does exactly what I want. If I had that code, integrating it in my code would be trivial. Now, for the behaviour I'm expecting: I want everything to act like it does if I hadn't written any ```__setattr__``` or ```__getattr__()``` methods, except for two parts: I want any value given to ```self.argument``` to be attributed to ```self.__SWAPargument``` for self.conditional, self.current_Position and self.current_Track – Therk May 10 '21 at 20:04
  • @juanpa.arrivillaga Second, for all the values I just talked about, I also want ```self.aux_gate.argument``` to be given the same value, in a way where ```self.argument``` and ```self.aux_gate.argument``` can't be different – Therk May 10 '21 at 20:10
  • @Therk no, you don't understand, you need to *provide some code to reproduce the behavior you are seeing*. Currently, you have a class definition, which doesn't do *anything*. In any case, please edit your question and describe the behavior you are looking for, and provide a [mcve] for the behavior you are seeing – juanpa.arrivillaga May 10 '21 at 20:11

1 Answers1

0

The main thing I see is that the first statement in your __setattr__ function is

super(SWAP_Gate, self).__setattr__(name, value)

This statement will cause the default setattr behavior to occur in addition to any other code you have in __setattr__, so seeing "current_Track" in __dict__ is expected anytime current_Track is set (unless a super class to SWAP_Gate prevents the default behavior of setattr) .

If you don't want that default behavior to occur, then remove the super() statement at the top of __setattr__ and replace the self.__dict__ statement with it in the final else statement:

def __setattr__(self, name, value):
        # Removed super() statement from here
        if name == "conditional":
            self.aux_gate.conditional = value
        elif name == "current_Track":
            if self.current_Track:
        #...
        elif name == "aux_gate":
            self.__dict__["aux_gate"] == value
        else:
            #replaced self.__dict__[name]=value with super() statement:
            super(SWAP_Gate, self).__setattr__(name, value)
davdforg
  • 41
  • 2
  • I think a better solution would be to get rid of the `__setattr__` and `__getattr__` code and make properties using the `@property` and `@x.setter` decorator for each of the attributes that need to be redirected. That would alleviate the need for both magic methods. – davdforg May 10 '21 at 21:16
  • Also, the last `elif name == "aux_gate": self.__dict__["aux_gate"] == value` is redundant because the final else statement would do the same thing. Also, it has an equivalency operator, `==`, instead of assignment operator, `=`, which will cause you problems if that line of code is ever reached. – davdforg May 10 '21 at 21:20