Получение контейнера/родительского объекта изнутри python
В Python можно ли получить объект, скажем Foo, который содержит другой объект, Bar, из самого Bar? Вот пример того, что я имею в виду
class Foo(object):
def __init__(self):
self.bar = Bar()
self.text = "Hello World"
class Bar(object):
def __init__(self):
self.newText = foo.text #This is what I want to do,
#access the properties of the container object
foo = Foo()
Возможно ли это? Спасибо!
Ответы
Ответ 1
Передайте ссылку на объект Bar, например:
class Foo(object):
def __init__(self):
self.text = "Hello World" # has to be created first, so Bar.__init__ can reference it
self.bar = Bar(self)
class Bar(object):
def __init__(self, parent):
self.parent = parent
self.newText = parent.text
foo = Foo()
Изменить:, как указано в @thomleo, это может вызвать проблемы с сборкой мусора. Предлагаемое решение выложено на http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/ и выглядит как
import weakref
class Foo(object):
def __init__(self):
self.text = "Hello World"
self.bar = Bar(self)
class Bar(object):
def __init__(self, parent):
self.parent = weakref.ref(parent) # <= garbage-collector safe!
self.newText = parent.text
foo = Foo()
Ответ 2
Можно ли получить объект, скажем, Foo, который содержит другой объект, Bar, изнутри самой панели?
Не "автоматически", потому что язык не построен таким образом, и, в частности, язык построен таким образом, что нет возможности гарантировать, что Foo существует.
Тем не менее, вы всегда можете сделать это явно. Атрибуты, как и любой другой идентификатор в Python, - это просто имена, а не пространство для хранения данных; поэтому ничто не мешает вам позволить экземпляру Bar присвоить вручную атрибут foo
, который является экземпляром Foo, и наоборот в то же время.
Ответ 3
Да, это возможно. Даже не передавая ссылку на контейнер при создании объекта, т.е. если ваш объект является атрибутом класса. Ваш объект должен реализовать протокол дескриптора (иметь __get__()
):
class ChildName(SimpleNamespace):
def __get__(self, instance, owner):
# instance is our parent
return f'I am {self.name}, my parent is {instance.name}.'
class ChildDiff(SimpleNamespace):
@property
def diff(self):
return self.born - self.parent.born
def age_diff(self):
return f'I am {self.diff} years older than {self.parent.name}.'
def __get__(self, instance, owner):
self.parent = instance # XXX: weakref?
return self # expose object to be able call age_diff() etc.
class Parent(SimpleNamespace):
child_name = ChildName(name='Bar')
child_diff = ChildDiff(born=42)
parent = Parent(name='Foo', born=23)
print(parent.child_name) # ... I am Bar, my parent is Foo.
print(parent.child_diff.age_diff()) # ... I am 19 years older than Foo.
Ответ 4
Как насчет использования наследования:
class Bar(object):
def __init__(self):
self.newText = self.text
class Foo(Bar):
def __init__(self):
self.txt = 'Hello World'
Bar.__init__(self)
foo = Foo()
print foo.newText