Вы не можете получить «полный путь к классу, заданному экземпляром класса», потому что в Python такого нет.Например, основываясь на вашем примере:
>>> class B(object):
... class C(object):
... pass
...
>>> D = B.C
>>> x = D()
>>> isinstance(x, B.C)
True
Каким должен быть "путь к классу" x
?D
или B.C
?Оба одинаково действительны, и поэтому Python не дает никаких средств отличить одно от другого.
Действительно, даже у модуля Python pickle
есть проблемы с выбором объекта x
:
>>> import pickle
>>> t = open('/tmp/x.pickle', 'w+b')
>>> pickle.dump(x, t)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.6/pickle.py", line 1362, in dump
Pickler(file, protocol).dump(obj)
...
File "/usr/lib/python2.6/pickle.py", line 748, in save_global
(obj, module, name))
pickle.PicklingError: Can't pickle <class '__main__.C'>: it's not found as __main__.C
Итак, в общем, я не вижу другой возможности, кроме добавления атрибута ко всем вашим классам (скажем, _class_path
), и ваш код сериализации будет искать его для записи имени класса в сериализованный формат:
class A(object):
_class_path = 'mymodule.A'
class B(object):
_class_path = 'mymodule.A.B'
...
Вы даже можете сделать это автоматически с некоторой магией метакласса (но также прочитайте другие комментарии в той же публикации SO для предупреждений, которые могут применяться, если вы выполните D=B.C
выше).
Тем не менее, если вы можете ограничить свой код сериализации до (1) экземпляров классов нового стиля и (2) эти классы определены на верхнем уровне модуля, товы можете просто скопировать то, что делает pickle
(функция save_global
в строках 730--768 в pickle.py из Python 2.6).
Идея состоит в том, что каждый класс нового стиля определяет атрибуты __name__
и__module__
, которые являются строкамиэто расширение до имени класса (как в источниках) и имени модуля (как в sys.modules
);сохранив их, вы можете позже импортировать модуль и получить экземпляр класса:
__import__(module_name)
class_obj = getattr(sys.modules[module_name], class_name)