Для Python есть два способа проверить класс объекта - один вызывает type
, а другой проверяет слот __class__
. В большинстве случаев оба возвращают одно и то же, но можно изменить класс (например, путем настройки доступа к атрибутам в метаклассе), чтобы __class__
получило "l ie", а Python код с использованием myobject.__class__
получит " ложная информация.
Однако под слотом "true" __class__
в объекте type
всегда будет содержаться ссылка на реальный тип - и это не может быть подделано. Любое расширение C и, возможно, даже несколько расширений Python, а возврат к type(myobject)
сам увидит реальный класс.
Изменение содержимого этого слота фактически изменяет класс вашего экземпляра. Это возможно из чистого Python с простой атрибуцией =
- но в этом назначении предусмотрены средства защиты, чтобы гарантировать, что оно выполняется только для типов, имеющих совместимый макет памяти. Принудительное изменение его на несовместимый тип (через расширение или ctypes) приведет к тому, что ваша Python среда выполнения перейдет в segfault.
Все это говорит о том, что у пользователя * ie нет никаких оснований относиться к вашему классу. вашего класса - они должны быть в состоянии «увидеть», что объект, который они содержат, является xlist
, а не list
, и что xlist
s также являются list
объектами из-за наследования. Фальсификация этой информации была бы довольно плохой практикой. С другой стороны, в самом Python stdlib есть несколько вызовов, которые требуют, чтобы базовый объект действительно был list
и не принимал подтипы (как известно, сериализация Python json.dumps
). Этот вызов имеет собственный путь к коду и не будет обманут, настроив доступ к __class__
. Однако тот же вызов также имеет только кодовый путь Python, который запускается установкой некоторых необязательных аргументов (например, передачей идент = 4 в вызове). Если это то, чего вы пытаетесь достичь (обмануть какой-то код, требующий строгого списка), вам придется это проверить, и если это код Python, это выполнимо. В указанном c случае json.dump
вам лучше установить кодировщик, чтобы использовать менее строгую проверку, чем фальсифицировать ваш объект - потому что я думаю, что код использует type
для проверки.
Итак, с учетом всего вышесказанного, «трюк метакласса» для фальсификации возврата .__class__
может быть таким простым:
class xlist(list, metaclass=Meta):
def __init__(self, original_list: list):
self._olist = original_list
def sumall(self) -> int:
sum = 0
for e in self._olist:
sum += e
return sum
@property
def __class__(self):
return list