В настоящее время я пытаюсь выяснить внутренние свойства mappingproxies и namespaces в python. При тестировании немного, я пришел к некоторому поведению, которого я не ожидал.Назначение имен и повторное использование в пространстве имен python
Я определяю класс, создаю экземпляр, определяю другой под тем же именем и создаю экземпляр этого.
class A:
color = 'white'
def __init__(self, val):
self.val = val
a1 = A(1)
class A:
color = 'black'
def __init__(self, val):
self.val = val
a2 = A(2)
Теперь, a1 и a2 являются экземплярами разных объектов класса, которые все еще существуют. В пространстве имен вторая измененная версия класса теперь назначается имени A. Первая, начальная версия объекта класса может быть адресована только через атрибут своего экземпляра __class__
. Тем не менее, вы можете полностью взаимодействовать со старым объектом класса.
print(a1.__class__ is a2.__class__) # False
print(a1.__class__ is A) # False
print(a2.__class__ is A) # True
a3 = a1.__class__(3)
print(a3.__class__ is a1.__class__) # True
print(a3.color) # white
a3.__class__.color = 'red'
print(a1.color) # red
Я предполагаю, что питоны Референс объекта счетчик несет ответственность за то, что старый объект класса по-прежнему существует, так как счетчик не был равен нулем, как a1 все еще держали реф, когда новый объект класса был назначен имя A.
Что касается моего вопроса: Является ли это предполагаемым поведением? Если да, то в чем причина этого? Для меня это выглядит слишком неявным. Я бы ожидал, что это не сработает, и бросит какое-то исключение, tbh.
EDIT
Чтобы объяснить, почему это поражает меня, и в ответ на Daniel Роземан в комментариях ниже:
И, a1 и a2 считают себя экземпляры __main__.A
, когда на самом деле один из них является примером того, что раньше было __main__.A
. Это оставляет мне активный, полезный объект, который не имеет явно определенного дескриптора в моем пространстве имен. Я думаю, что это эксклюзивно для объектов класса из-за их двойственности класса-объекта.
Я работаю над некоторым инструментом, который динамически создает классы и выполняет последовательности команд на экземплярах из них, все на основе какого-то странного ввода. Это связано с большим динамическим импортом. Не зная об этом поведении, я мог бы закончить отладку классов и их процесс сборки, когда я действительно должен изучать некоторые проблемы с потоками.
Мои 2 цента: Я думаю, что альтернатива, связанная с обработкой экземпляра «мертвого» класса, висящего вокруг, вызовет гораздо больше проблем, чем просто сохранение класса «живым». – polku
Я не понимаю, почему вы думаете, что это не должно работать, или что это неожиданное поведение. Это, похоже, полностью согласуется с принципом, что классы - это просто объекты, «А» - это просто имя, и объект может иметь несколько имен или вообще ничего. –