Is there a reliable way to list all of a class's __slots__?

Viewed 37

I'm looking for a way to reliably get a list of all slot names for a class with __slots__. Example:

class A:
    __slots__ = ('a',)

print(list_slots(A))  # should output ['a']

Of course, this can be done with list(A.__slots__), but unfortunately there are a couple of things that make this more difficult:

  • Inherited slots:

    class B(A):
        __slots__ = ('b',)
    
    print(list_slots(B))  # should output ['a', 'b']
    
  • Strings:

    class C:
        __slots__ = 'xyz'
    
    print(list_slots(C))  # should output ['xyz']
    
  • Iterators:

    class D:
        __slots__ = iter(['d'])
    
    print(list_slots(D))  # should output ['d']
    

As you can see, there are plenty of pitfalls here... is there an implementation of list_slots that handles all of these cases correctly?

1 Answers

I would use inspect.ismemberdescriptor in this case (doc):

import inspect

class A:
    __slots__ = ('a',)

class B(A):
    __slots__ = ('b',)

class X(B):
    __slots__ = ('c',)

class C:
    __slots__ = 'xyz'

class D:
    __slots__ = iter(['d'])

def get_slots(cls):
    for k, v in cls.__dict__.items():
        if inspect.ismemberdescriptor(v):
            yield k
    for b in cls.__bases__:
        yield from get_slots(b)

print(list(get_slots(A)))
print(list(get_slots(B)))
print(list(get_slots(C)))
print(list(get_slots(D)))
print(list(get_slots(X)))

Prints:

['a']
['b', 'a']
['xyz']
['d']
['c', 'b', 'a']

EDIT 1: Updated my answer to recursive version of get_slots()

EDIT 2: As Aran-Fey pointed out in the comments, this solution works only in CPython.

Related