Предположим, у нас есть следующий класс:
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
. Для любого атрибута d
класса, имеющего метод __get__
, было бы неплохо определить, является ли некоторая ссылка ref
ссылкой на d
или значением, возвращаемым d.__get__()
(при условии, что d.__get__()
не возвращает d
)
Общего решения нет. Любой возможный дескриптор также является возможным возвращаемым значением __get__
. Для определения этого вам потребуется больше информации, чем просто объект.