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