2016-05-25 2 views
2

В настоящее время я пытаюсь выяснить внутренние свойства 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. Это оставляет мне активный, полезный объект, который не имеет явно определенного дескриптора в моем пространстве имен. Я думаю, что это эксклюзивно для объектов класса из-за их двойственности класса-объекта.

Я работаю над некоторым инструментом, который динамически создает классы и выполняет последовательности команд на экземплярах из них, все на основе какого-то странного ввода. Это связано с большим динамическим импортом. Не зная об этом поведении, я мог бы закончить отладку классов и их процесс сборки, когда я действительно должен изучать некоторые проблемы с потоками.

+0

Мои 2 цента: Я думаю, что альтернатива, связанная с обработкой экземпляра «мертвого» класса, висящего вокруг, вызовет гораздо больше проблем, чем просто сохранение класса «живым». – polku

+1

Я не понимаю, почему вы думаете, что это не должно работать, или что это неожиданное поведение. Это, похоже, полностью согласуется с принципом, что классы - это просто объекты, «А» - это просто имя, и объект может иметь несколько имен или вообще ничего. –

ответ

1

Является ли это предназначено поведение?

Да.

Какова причина этого?

Как Даниэль Роземан в комментариях выше, это конкретный случай общего правила, что все в Python является объектом.

Рассмотрим следующий фрагмент кода:

some_string_a = 'white' 
some_string_b = 'black' 

a = some_string_a 
print(a) 

    >>> white 

a = some_string_b 
print(a) 

    >>> black 

print(some_string_a) 

    >>> white 

Я уверен, что вы не удивлены, что вы можете взаимодействовать с some_string_a, даже если имя переменной, которая используется для обозначения к нему был переназначен, и теперь относится к чему-то другому.

Но, поскольку в вашем вопросе два класса: также объектов, это аналогичный случай. Почему вы не должны иметь возможность взаимодействовать с объектом (первый класс, который вы определили), просто потому, что вы переназначили имя переменной (A), так что теперь оно относится к другому объекту?

Как вы упомянули в своем редактировании, это может привести к некоторой странности пространства имен ... но это цена, которую Python платит за достижения, которые она получает в согласованности, рассматривая все как объект.

+0

В вашем примере ни один из ваших двух строковых объектов никогда не присваивается менее чем одному явно определенному имени. Но это именно то, что происходит с объектами класса. Я бы предпочел, чтобы мое время выполнения дало мне правильную информацию о его состоянии. a1, утверждающий, что является экземпляром '__main __. A', является явно и просто неправильной информацией в случае моего примера. Тем не менее, я принимаю этот ответ в некотором смысле, что он объясняет поведение в результате дизайнерских решений, принятых для python. Благодаря! – shmee

-4

В Python есть нечто, называемое мультиметодами, и основная идея состоит в том, что несколько функций могут иметь одно и то же имя, но являются разными функциями.

Я не уверен, что он имеет какое-либо отношение к нескольким классам с одним и тем же именем.

Короткий блог о нем: https://alexgaynor.net/2010/jun/26/multimethods-python/

+1

Это не имеет никакого отношения к вопросу. Это даже не то, что поставляется с Python или регулярно используется с Python. – user2357112

Смежные вопросы