Есть ли надежный способ перечислить все __slots__ класса? - PullRequest
2 голосов
/ 21 июня 2019

Я ищу способ получить список всех имен слотов для класса с __slots__. Пример:

class A:
    __slots__ = ('a',)

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

Конечно, это можно сделать с помощью list(A.__slots__), но, к сожалению, есть несколько вещей, которые усложняют это:

  • Унаследованные слоты:

    class B(A):
        __slots__ = ('b',)
    
    print(list_slots(B))  # should output ['a', 'b']
    
  • Строки:

    class C:
        __slots__ = 'xyz'
    
    print(list_slots(C))  # should output ['xyz']
    
  • итераторы:

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

Как видите, здесь много подводных камней ... есть ли реализация list_slots, которая корректно обрабатывает все эти случаи?

1 Ответ

0 голосов
/ 21 июня 2019

Я бы использовал inspect.ismemberdescriptor в этом случае ( 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)))

Печать:

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

РЕДАКТИРОВАТЬ 1: Обновил мой ответ до рекурсивной версии get_slots()

РЕДАКТИРОВАТЬ 2: Как отметил Аран-Фей в комментариях, это решение работает только в CPython.

...