2

I keep trying to understand obscure Python OOP, and while abstract parent class TLogElement does have property in1, when I try to overrride the same property in a child class TNot interpreter says that it doesn't have one.

Here's a fragment of TLogElement class:

class TLogElement(ABC):
    def __init__(self, _in1=None,_in2=None):
        self._in1 = _in1
        self._in2 = _in2

    @property
    @abstractmethod
    def in1(self):
        return self._in1

    @in1.setter
    @abstractmethod
    def in1(self, _in1):
        self._in1 = _in1

Here's a TNot class:

class TNot (TLogElement):
    def __init__(self, _in1=None, _in2=None):
        super().__init__(_in1)

    @property
    def in1(self):
        return super().in1

    @in1.setter
    def in1(self, _in1):
        super().in1 = _in1

And that's the code which catched AttributeError: 'super' object has no attribute 'in1':

T = TNot()
T.in1 = 5
LazySlav
  • 21
  • 2
  • I think super is a reference to the parent class itself, not the parent object. There is no separate parent object. – Mark Ransom Nov 09 '22 at 21:40
  • `super` is a type with instances of its own. The instance here wraps `self` (a reference to `T`) and `TNot` for the purpose of overriding the attribute lookup on `self`. It's not clear what it is about `in1` being a *property* affects the attribute lookup. – chepner Nov 09 '22 at 21:47
  • @MarkRansom I understood that, but then why doesn't `super().in1 = _in1` work when direct call for a parent class such as `TLogElement.in1 = _in1` works just fine? – LazySlav Nov 09 '22 at 21:52
  • (Specifically, it's the *setter* that's breaking; `print(T.in1)` works fine.) – chepner Nov 09 '22 at 21:54
  • @chepner If i got it correctly, `super()` is essentially a link to parent object, but again, why then `super().in1 = _in1` != `TLogElement.in1 = _in1`? – LazySlav Nov 09 '22 at 22:01
  • @LazySlav, "parent object"? There's no such thing; there's just one object used for both the current class's methods and the parent class's methods. `super` just routes to other methods as per MRE order. – Charles Duffy Nov 09 '22 at 22:04
  • Alright, I guess i'll just stick to not overriding the methods if it works just fine as is... – LazySlav Nov 09 '22 at 22:09
  • Be sure to read the linked duplicate. In short, `super().in1 = _in1` is equivalent to `setattr(super(), 'in1', _in1)`, not something like `getattr(super(), 'in1').fset(self, _in1)` which you expect. – chepner Nov 09 '22 at 22:26
  • 1
    (Having read the linked duplicate, I feel a little silly. Attribute assignments don't involve attribute *lookup*, which is the only reason for `super` instances to exist. Attribute assignments *only* create/update attributes. The error message isn't actually saying that `in1` doesn't exist, because Python isn't looking for it. Rather, it's saying it can't *create* the attribute. It's the same error you get when, working with a class that uses `__slots__`, you try to create an attribute not listed in `__slots__`.) – chepner Nov 09 '22 at 22:32
  • (Although unlike a class with `__slots__`, `super()` instances actually do have `__dict__` attributes, so it's not clear what magic prevents `super().in1` from being defined.) – chepner Nov 09 '22 at 22:35

0 Answers0