Подтвердить что ты не робот

Получение контейнера/родительского объекта изнутри 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()

Возможно ли это? Спасибо!

4b9b3361

Ответ 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