Accessing parent objects

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sun Mar 25 07:42:41 EDT 2018


On Sun, 25 Mar 2018 21:17:59 +1100, Chris Angelico wrote:

> On Sun, Mar 25, 2018 at 8:37 PM, Jugurtha Hadjar
> <jugurtha.hadjar at gmail.com> wrote:
[...]
>> I prefer to *feed* the child to the parent or vice versa.
> 
> Congrats, this ranks on my list of "creative people who sound like
> psycho murderers". Digital artists and cooks tend to rank fairly highly
> on that list.

:-)

>> class C1(object):
>>     def __init__(self):
>>         self.child = None
>> class C2(object):
>>     def __init__(self, parent=None):
>>         self.parent = parent
> 
> The trouble with this is that there's fully-constructed objects with no
> parent-child relationships. Why should you have a two-step construction
> process? 

Such a two-step construction process is normally called "dependency 
injection", and it's really useful.

https://martinfowler.com/articles/injection.html

Instead of class C2 controlling what its parent is:

class C2:
    def __init__(self):
        self.parent = C1()

the caller decides what parent to use. Provided the parent provides the 
same interface as C1, you can use any duck-type you like.

The thing is, we use dependency injection in Python all the time. We just 
don't call it that! We normally write things like:

class Spam:
    def __init__(self, queue=None):
        if queue is None:
            queue = Queue()
        self.queue = queue

and so we get the best of both worlds: the ability to inject the queue we 
want when we need to, and the freedom to not bother when we don't. This 
is such second nature that we don't even think that what we're doing has 
a fancy OOP design pattern name that Java programmers stress over.

And because we duck-type, we don't care if queue is a real queue, or just 
something that has all the queue methods we require.


> It makes a LOT more sense to simply require a parent on
> construction, rather than feeding one to the other in a
> post-construction assignment.

I tend to agree... but not everyone in the OOP world does. Quoting from 
Wikipedia:

    There are at least three ways an object can receive a reference
    to an external module:

    - constructor injection: the dependencies are provided through
      a class constructor.
    - setter injection: the client exposes a setter method that the
      injector uses to inject the dependency.
    - interface injection: the dependency provides an injector method
      that will inject the dependency into any client passed to it.

https://en.wikipedia.org/wiki/Dependency_injection



-- 
Steve




More information about the Python-list mailing list