Автоматически сделать вывод, что объект является атрибутом родительского объекта / класса - PullRequest
1 голос
/ 27 мая 2020

При использовании таких классов:

class Parent:
    def __init__(self):
        self.child = Child()
class Child:
    def __init__(self):
        print(self.parent)  # error, I don't have any way to know my parent!
p = Parent()

, конечно, возвращается ошибка, потому что экземпляр Child не имеет атрибута parent, это нормально.

Одно решение просто определить классы следующим образом:

class Parent:
    def __init__(self):
        self.child = Child(self)
class Child:
    def __init__(self, parent):
        self.parent = parent
        print(self.parent)  # now it's ok!

Но в моем коде у меня много классов, и как-то раздражает необходимость передавать self в качестве параметра все время при создании экземпляра дочернего элемента объекты:

self.child = Child(self)  # pass self so that this Child instance will know its parent

и я бы предпочел оставить просто:

self.child = Child()      # can this Child instance know its parent without passing self?

Есть ли способ для Python автоматически сделать вывод, что объект на самом деле является атрибутом родительского объекта, без необходимости явно передавать self? Если да, то как получить родительский объект?


Пример: в GUI программировании при создании экземпляра кнопки, который является член Panel, который сам является членом Window и т. д. c. кажется, что мы должны все время передавать self дочерним конструкторам.

Примечание: я бы не хотел использовать inspect, потому что решения с ним кажутся хуже, чем просто передача self.

Ответы [ 2 ]

1 голос
/ 27 мая 2020

Вместо использования inspect для динамического определения вызывающего, вы можете создать метод установки для создания экземпляров дочерних элементов.

class Parent:
    def __init__(self):
        self.child = self.create_child(Child)

    def create_child(self, cls, *args, **kwargs):
        return cls(*args, parent=self, **kwargs)

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

1 голос
/ 27 мая 2020

Технически вы можете сделать это, пройдя стек с модулем inspect, примерно так:

>>> import inspect
>>>
>>> class Parent:
...     def __init__(self):
...         self.child = Child()
...
>>> class Child:
...     def __init__(self):
...         for frame in inspect.stack():
...             if isinstance(frame[0].f_locals.get('self'), Parent):
...                 self.parent = frame[0].f_locals.get('self')
...                 break
...
>>> p = Parent()
>>>
>>> p.child.parent
<__main__.Parent object at 0x000001ED3901A310>

Это ужасно по многим причинам. В идеале вам следует вообще избегать таких циклических ссылок, не говоря уже о том, чтобы создавать их, копаясь в стеке вызовов.

...