1

Consider the following code:

class A(object):
    __slots__ = "a", "b"

    def __init__(self, a, b):
        self.a = a
        self.b = b

class B(A):
    __slots__ = "c",

    def __init__(self, a, b, c):
        super(B, self).__init__(a, b)
        self.c = c

b = B(1, 2, 3)
print(b.__slots__) # Prints just "('c',)", but I want to get ("a", "b", "c")

For a B class instance, I want to have access to all the slots declared in all its parents. Is it possible at all?

ivaigult
  • 6,198
  • 5
  • 38
  • 66
  • 1
    You have overridden them in `B` – Yugandhar Chaudhari Feb 25 '20 at 16:44
  • No, I didn't :-) `b` has three attributes: `b.a`, `b.b` and `b.c`. – ivaigult Feb 25 '20 at 16:46
  • As a special field, I would expect it to behave differently. For example, `__dict__` would contain attributes of the parent. – ivaigult Feb 25 '20 at 16:48
  • It won't if you override it... – Tomerikoo Feb 25 '20 at 16:51
  • 3
    @ivaigult Classes don't really have anything to do with instance attributes, beyond "hosting" the method that creates them. `b.__dict__` belongs solely to `b`, in the sense that you can't look *just* at the keys in `b.__dict__` and then say "that key came from `A`" or "that key come from `B`". – chepner Feb 25 '20 at 16:54
  • 1
    `__dict__` also won't exist if you define `__slots__`. If you remove the `__slots__` definition from `B` (but not `A`), then `b.__dict__` gives `{'c': 3}`. However, if you remove the `__slots__` definition from _both_, then `b.__dict__` gives what you would expect, `{'a': 1, 'b': 2, 'c': 3}`. – b_c Feb 25 '20 at 16:55
  • Since `b` doesn't have an instance attribute named `__slots__`, `b.__slots__` resolves to `B.__slots__`, which contains just `c`. – chepner Feb 25 '20 at 16:55
  • 2
    Might be helpful: https://stackoverflow.com/a/28059785/6045800 – Tomerikoo Feb 25 '20 at 16:58
  • Yeah, I understand the magic behind the `__dict__`, and I don't want to remove `__slots__`. The question is more like: "Can I use `__slots__` and iterate over attributes still?". – ivaigult Feb 25 '20 at 16:59

1 Answers1

3
class A(object):
    __slots__ = "a", "b"

    def __init__(self, a, b):
        self.a = a
        self.b = b


class B(A):
    __slots__ = "c",

    def __init__(self, a, b, c):
        super(B, self).__init__(a, b)
        self.c = c


b = B(1, 2, 3)


def all_slots(obj):
    slots = set()
    for cls in obj.__class__.__mro__:
        slots.update(getattr(cls, '__slots__', []))
    return slots


print(all_slots(b))
Miki Tebeka
  • 13,428
  • 4
  • 37
  • 49