Как правило, экземпляр, назначенный в качестве атрибута какого-либо другого экземпляра, не может получить ссылку на содержащий экземпляр.С одной стороны, может быть ноль или более одной такой ссылки!Например, если вы создали второй экземпляр OuterClass
с тем же экземпляром InnerClass
, то будет два потенциально разных атрибута variable
, которые вы, возможно, захотите прочитать.
В общем, если вы хотитечтобы получить доступ к атрибутам объекта, вам сначала нужна ссылка на объект.Одной ссылки на вас недостаточно, если только вы не устроите какой-нибудь альтернативный API.
Например, возможно, InnerClass
ожидает получить ссылку на OuterClass
в своем методе test
и OuterClass
получает метод для передачи себя:
class InnerClass:
def test(self, outer):
return outer.variable
class OuterClass:
def __init__(self, inner, variable):
self.inner = inner
self.variable = variable
def run_test(self):
return self.inner.test(self)
out = OuterClass(InnerClass(), "foo")
print(out.run_test())
Вы также можете настроить классы на циклические ссылки, где каждый из них ссылается друг на друга.Тогда любой из них может делать что-то с другим:
class InnerClass:
def __init__(self):
self.outer = None
def test(self):
if self.outer is None:
raise ValueError("Not in an OuterClass instance!")
return self.outer.variable
class OuterClass:
def __init__(self, inner, variable):
self.inner = inner
inner.outer = self # set reference back to us!
self.variable = variable
out = OuterClass(InnerClass(), "foo")
print(out.inner.test())
Это очень грубая версия такого подхода, вы можете убедиться, что ваши ссылки остаются согласованными (не позволяя использовать тот же экземпляр InnerClass
).например, двумя различными экземплярами OuterClass
.
Обратите внимание, что подобные циклические ссылки усложняют работу сборщика мусора.Обычно объекты Python очищаются сразу после исчезновения их последней ссылки.Но объекты с циклами ссылок всегда имеют ссылки, идущие между собой, и поэтому GC должен проверить, не мертв ли весь набор объектов вместе.Вероятно, он справится с этим довольно хорошо для цикла, который содержит всего два объекта, как в этом примере, но в более крупной структуре данных это может быть сложнее.