<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p><br>
    </p>
    <br>
    <div class="moz-cite-prefix">On 2017-10-29 02:28 AM, Nick Coghlan
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CADiSq7eNnMG+oFeVmxUKZTaKRcvcLd4u8rrb-meYKWG+2X6Bpw@mail.gmail.com">
      <div dir="ltr">
        <div class="gmail_extra">
          <div class="gmail_quote">On 29 October 2017 at 12:25, Brendan
            Barnwell <span dir="ltr"><<a
                href="mailto:brenbarn@brenbarn.net" target="_blank"
                moz-do-not-send="true">brenbarn@brenbarn.net</a>></span>
            wrote:<br>
            <blockquote class="gmail_quote" style="margin:0px 0px 0px
              0.8ex;border-left:1px solid
              rgb(204,204,204);padding-left:1ex"><span class="gmail-">On
                2017-10-28 19:13, Soni L. wrote:<br>
                <blockquote class="gmail_quote" style="margin:0px 0px
                  0px 0.8ex;border-left:1px solid
                  rgb(204,204,204);padding-left:1ex">
                  And to have all cars have engines, you'd do:<br>
                  <br>
                  class Car:<br>
                      def __init__(self, ???):<br>
                        self[Engine] = GasEngine()<br>
                  <br>
                  car = Car()<br>
                  car[Engine].kickstart() # kickstart gets the car as
                  second argument.<br>
                  <br>
                  And if you can't do that, then you can't yet do what
                  I'm proposing, and<br>
                  thus the proposal makes sense, even if it still needs
                  some refining...<br>
                </blockquote>
                <br>
              </span>
                      As near as I can tell you can indeed do that,
              although it's still not clear to me why you'd want to. 
              You can give Car a __getitem__ that on-the-fly generates
              an Engine object that knows which Car it is attached to,
              and then you can make Engine.kickstart a descriptor that
              knows which Engine it is attached to, and from that can
              figure out which Car it is attached to.<br>
            </blockquote>
            <div><br>
            </div>
            Right, I think a few different things are getting confused
            here related to how different folks use composition.</div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">For most data modeling use cases, the
            composition model you want is either a tree or an acyclic
            graph, where the subcomponents don't know anything about the
            whole that they're a part of. This gives you good component
            isolation, and avoids circular dependencies.</div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">However, for other cases, you *do*
            want the child object to be aware of the parent - XML etrees
            are a classic example of this, where we want to allow
            navigation back up the tree, so each node gains a reference
            to its parent node. This often takes the form of a
            combination of delegation (parent->child references) and
            dependency inversion (child->parent reference).</div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">For the car/engine example, this
            relates to explicitly modeling the relationship whereby a
            car can have one or more engines (but the engine may not
            currently be installed), while an engine can be installed in
            at most one car at any given point in time.<br>
          </div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">You don't even need the descriptor
            protocol for that though, you just need the subcomponent to
            accept the parent reference as a constructor parameter:<br>
          </div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">
            <div class="gmail_quote">    class Car:<br>
                    def __init__(self, engine_type):<br>
                      self.engine = engine_type(self)</div>
            <br>
            <div class="gmail_quote">However, this form of explicit
              dependency inversion wouldn't work as well if you want to
              be able to explicitly create an "uninstalled engine"
              instance, and then pass the engine in as a parameter to
              the class constructor:</div>
            <div class="gmail_quote"><br>
            </div>
            <div class="gmail_quote">
              <div class="gmail_quote">    class Car:<br>
                      def __init__(self, engine):<br>
                        self.engine = engine # How would we ensure the
                engine is marked as installed here?<br>
              </div>
            </div>
          </div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">As it turns out, Python doesn't need
            new syntax for this either, as it's all already baked into
            the regular attribute access syntax, whereby descriptor
            methods get passed a reference not only to the descriptor,
            but *also* to the object being accessed: <a
href="https://docs.python.org/3/howto/descriptor.html#descriptor-protocol"
              moz-do-not-send="true">https://docs.python.org/3/howto/descriptor.html#descriptor-protocol</a></div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">And then the property builtin lets
            you ignore the existence of the descriptor object entirely,
            and only care about the original object, allowing the above
            example to be written as:</div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">
            <div class="gmail_quote">
              <div class="gmail_quote">    class Car:<br>
                      def __init__(self, engine):<br>
                        self.engine = engine # This implicitly marks the
                engine as installed<br>
              </div>
            </div>
            <div class="gmail_quote"><br>
            </div>
          </div>
                @property</div>
        <div class="gmail_extra">      def engine(self):</div>
        <div class="gmail_extra">          return self._engine</div>
        <div class="gmail_extra"><br>
        </div>
        <div class="gmail_extra">      @engine.setter</div>
        <div class="gmail_extra">      def engine(self, engine):</div>
        <div class="gmail_extra">         if engine is not None:<br>
        </div>
        <div class="gmail_extra">             if self._engine is not
          None:</div>
        <div class="gmail_extra">                 raise
          RuntimeError("Car already has an engine installed")<br>
        </div>
        <div class="gmail_extra">
          <div class="gmail_extra">             if engine._car is not
            None:</div>
          <div class="gmail_extra">                 raise
            RuntimeError("Engine is already installed in another car")</div>
          <div class="gmail_extra">
            <div class="gmail_extra">             engine._car = self<br>
                       self._engine = engine<br>
            </div>
          </div>
        </div>
        <div class="gmail_extra">
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">    
            car = Car(GasEngine())</div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote">ORMs use this kind of descriptor
            based composition management extensively in order to
            reliably model database foreign key relationships in a way
            that's mostly transparent to users of the ORM classes.<br>
          </div>
        </div>
      </div>
    </blockquote>
    <br>
    And this is how you miss the whole point of being able to
    dynamically add/remove arbitrary components on objects you didn't
    create, at runtime.<br>
    <br>
    Someone gave me this code and told me it explains what I'm trying to
    do: <a class="moz-txt-link-freetext" href="https://repl.it/NYCF/3">https://repl.it/NYCF/3</a><br>
    <br>
    class T:<br>
        pass<br>
    <br>
    class C:<br>
        pass<br>
    <br>
    c = C()<br>
    <br>
    #c.[T] = 1<br>
    c.__dict__[T] = 1<br>
    <br>
    I'd also like to add:<br>
    <br>
    def someone_elses_lib_function(arbitrary_object):<br>
      #arbitrary_object.[T] = object()<br>
      arbitrary_object.__dict__[T] = object()<br>
    <br>
    and<br>
    <br>
    def another_ones_lib_function(arbitrary_object):<br>
      #if arbitrary_object.[T]:<br>
      if arbitrary_object.__dict__[T]:<br>
        #arbitrary_object.[T].thing()<br>
        arbitrary_object.__dict__[T].thing(arbitrary_object)<br>
    <br>
    <blockquote type="cite"
cite="mid:CADiSq7eNnMG+oFeVmxUKZTaKRcvcLd4u8rrb-meYKWG+2X6Bpw@mail.gmail.com">
      <div dir="ltr">
        <div class="gmail_extra"><br>
          <div class="gmail_quote">Cheers,</div>
          <div class="gmail_quote">Nick.<br>
          </div>
          <br>
          -- <br>
          <div class="gmail_signature">Nick Coghlan   |   <a
              href="mailto:ncoghlan@gmail.com" target="_blank"
              moz-do-not-send="true">ncoghlan@gmail.com</a>   |  
            Brisbane, Australia</div>
        </div>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      <pre wrap="">_______________________________________________
Python-ideas mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Python-ideas@python.org">Python-ideas@python.org</a>
<a class="moz-txt-link-freetext" href="https://mail.python.org/mailman/listinfo/python-ideas">https://mail.python.org/mailman/listinfo/python-ideas</a>
Code of Conduct: <a class="moz-txt-link-freetext" href="http://python.org/psf/codeofconduct/">http://python.org/psf/codeofconduct/</a>
</pre>
    </blockquote>
    <br>
  </body>
</html>