Предположим, у нас есть следующий класс:
class K:
# classmethod creates a descriptor
@classmethod
def cm(cls, a, b, c):
pass
Теперь мы получаем атрибут cm
следующим образом:
import random
getters = [
lambda attr_name: object.__getattribute__(K, '__dict__')[attr_name]
lambda attr_name: getattr(cm, attr_name)
]
geht = random.choice(getters)
cm = geht('cm')
Какой эффективный способ проверить, какой cm
мы только что получили?
(у нас нет прямого доступа к классу K, только cm
, возвращаемый geht
)
random.choice
очень надуманный, но есть случаи, когда у нас есть контейнер с псевдоатрибутами, и мы хотим убедиться, что они либо все еще не были развернуты, либо убедиться, что они были развернуты.
Один неудачный подход
Кто-то может подумать, что дескриптор имеет метод __get__()
, а объект, возвращаемый __get__()
, - нет.
Однако метод __get__
функции, украшенной @classmethod
, возвращает объект, который также имеет метод __get__
.
Свойства метода упакованного и развернутого класса
# still wrapped cm
type <class 'classmethod'>
hasattr __get__ True
hasattr __call__ False
# unwrapped cm
type <class 'method'>
hasattr __get__ True
hasattr __call__ True
Мне хочется подумать, что мы можем проверить псевдоатрибут, чтобы узнать, есть ли у него метод __call__
или нет. Однако я хотел бы, чтобы решение работало для дескрипторов в целом, а не только для classmethod
s. Для любого атрибута, d
класса, имеющего метод __get__
, было бы неплохо определить, является ли некоторая ссылка ref
ссылкой на d
или значением, возвращаемым d.__get__()
(при условии, что d.__get__()
не возвращается d
)