Unpythonic? Impossible??

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • BrJohan

    #1

    Unpythonic? Impossible??

    Assume having this class hierarchy: (in principle and without details)
    class A(object):
    class B1(A):
    class B2(A):
    class C1(A1):
    class C2(A1):
    class C3(B1):
    class C4(B2):

    each of those classes have an initializer __init__(self, data): and an
    overloaded __new__(cls, data):

    is it then possible to have this call:
    obj = A(data)
    return an instance of that particular class (e.g. class C3) in the
    hierarchy that - as decided by the __new__ functions - is the 'correct' one?

    A.__new__ could select between A, B1 and B2, while B1.__new__ could choose
    from B1, C3 and C4.

    I know how to use a class factory - and could work around using such a
    mechanism. However I am interested to know if I could let the classes do the
    work by themselves.

    /BJ


  • Scott David Daniels

    #2
    Re: Unpythonic? Impossible??

    BrJohan wrote:[color=blue]
    > Assume having this class hierarchy: (in principle and without details)
    > class A(object):
    > class B1(A):
    > class B2(A):
    > ...
    > each of those classes have an initializer __init__(self, data): and an
    > overloaded __new__(cls, data):
    >
    > is it then possible to have this call:
    > obj = A(data)
    > return an instance of that particular class (e.g. class C3) in the
    > hierarchy that - as decided by the __new__ functions - is the 'correct' one?
    >
    > A.__new__ could select between A, B1 and B2, while B1.__new__ could choose
    > from B1, C3 and C4.
    >
    > I know how to use a class factory - and could work around using such a
    > mechanism. However I am interested to know if I could let the classes do the
    > work by themselves.[/color]

    Yes, it can be done. Yes, it is unclear (and hence UnPythonic).
    The class factory _is_ the straightforward way to do this. The
    following is the workaround (if you have to maintain A(...)):


    class A(object):
    def __new__(class_, *args, **kwargs):
    if class_ is A:
    if want_a_B1(*args , **kwargs):
    return B1(*args, **kwargs)
    elif want_a_B2(*args , **kwargs):
    return B2(*args, **kwargs)
    return object.__new__( class_) # Use *a,... except for object

    class B1(A):
    def __new__(class_, *args, **kwargs):
    if class_ is B1:
    if want_a_B1(*args , **kwargs):
    return B1(*args, **kwargs)
    elif want_a_B2(*args , **kwargs):
    return B2(*args, **kwargs)
    return super(B1, class_).__new__ (class_, *args, **kwargs)


    --Scott David Daniels
    scott.daniels@a cm.org

    Comment

    • Felipe Almeida Lessa

      #3
      Re: Unpythonic? Impossible??

      Em Dom, 2006-03-19 às 08:54 -0800, Scott David Daniels escreveu:[color=blue]
      > class A(object):
      > def __new__(class_, *args, **kwargs):
      > if class_ is A:
      > if want_a_B1(*args , **kwargs):
      > return B1(*args, **kwargs)
      > elif want_a_B2(*args , **kwargs):
      > return B2(*args, **kwargs)
      > return object.__new__( class_) # Use *a,... except for object
      >
      > class B1(A):
      > def __new__(class_, *args, **kwargs):
      > if class_ is B1:
      > if want_a_B1(*args , **kwargs):
      > return B1(*args, **kwargs)
      > elif want_a_B2(*args , **kwargs):
      > return B2(*args, **kwargs)
      > return super(B1, class_).__new__ (class_, *args, **kwargs)[/color]

      Why you have that if on B1.__new__? B1 will be created only by
      A.__new__, which already did a check.

      --
      Felipe.

      Comment

      • BrJohan

        #4
        Re: Unpythonic? Impossible??


        "Scott David Daniels" <scott.daniels@ acm.org> skrev i meddelandet
        news:441d8a74$1 @nntp0.pdx.net. ..[color=blue]
        > BrJohan wrote:[/color]
        ....[color=blue][color=green]
        >> is it then possible to have this call:
        >> obj = A(data)
        >> return an instance of that particular class (e.g. class C3) in the
        >> hierarchy that - as decided by the __new__ functions - is the 'correct'
        >> one?
        >>
        >> A.__new__ could select between A, B1 and B2, while B1.__new__ could
        >> choose from B1, C3 and C4.
        >>
        >> I know how to use a class factory - and could work around using such a
        >> mechanism. However I am interested to know if I could let the classes do
        >> the work by themselves.[/color]
        >
        > Yes, it can be done. Yes, it is unclear (and hence UnPythonic).
        > The class factory _is_ the straightforward way to do this. The
        > following is the workaround (if you have to maintain A(...)):
        >
        >
        > class A(object):
        > def __new__(class_, *args, **kwargs):
        > if class_ is A:
        > if want_a_B1(*args , **kwargs):
        > return B1(*args, **kwargs)
        > elif want_a_B2(*args , **kwargs):
        > return B2(*args, **kwargs)
        > return object.__new__( class_) # Use *a,... except for object
        >
        > class B1(A):
        > def __new__(class_, *args, **kwargs):
        > if class_ is B1:
        > if want_a_B1(*args , **kwargs):
        > return B1(*args, **kwargs)
        > elif want_a_B2(*args , **kwargs):
        > return B2(*args, **kwargs)
        > return super(B1, class_).__new__ (class_, *args, **kwargs)
        >
        >
        > --Scott David Daniels
        > scott.daniels@a cm.org[/color]

        Agreed that the class factory method most often (maybe always) is the best
        one. For certain reasons, and in this particular case, I prefer the
        UnPythonic way. Sometimes it's good to have "more than one way to do it".

        It was the "return object.__new__( class_) " that I did not came to think of
        myself, that did it. Thank you for yor helpfulness.

        BrJohan


        Comment

        • Scott David Daniels

          #5
          Re: Unpythonic? Impossible??

          Felipe Almeida Lessa wrote:[color=blue]
          > Em Dom, 2006-03-19 às 08:54 -0800, Scott David Daniels escreveu:[color=green]
          >> class A(object):
          >> def __new__(class_, *args, **kwargs):
          >> if class_ is A:
          >> if want_a_B1(*args , **kwargs):
          >> return B1(*args, **kwargs)
          >> elif want_a_B2(*args , **kwargs):
          >> return B2(*args, **kwargs)
          >> return object.__new__( class_) # Use *a,... except for object
          >>
          >> class B1(A):
          >> def __new__(class_, *args, **kwargs):
          >> if class_ is B1:
          >> if want_a_B1(*args , **kwargs):
          >> return B1(*args, **kwargs)
          >> elif want_a_B2(*args , **kwargs):
          >> return B2(*args, **kwargs)
          >> return super(B1, class_).__new__ (class_, *args, **kwargs)[/color]
          >
          > Why you have that if on B1.__new__? B1 will be created only by
          > A.__new__, which already did a check.[/color]

          Of course your are right. It needs to be more like:
          class B1(A):
          def __new__(class_, *args, **kwargs):
          if class_ is B1:
          if want_a_C1(*args , **kwargs):
          return C1(*args, **kwargs)
          elif want_a_C2(*args , **kwargs):
          return C1(*args, **kwargs)
          return super(B1, class_).__new__ (class_, *args, **kwargs)


          --Scott David Daniels
          scott.daniels@a cm.org

          Comment

          • Erik Max Francis

            #6
            Re: Unpythonic? Impossible??

            BrJohan wrote:
            [color=blue]
            > I know how to use a class factory - and could work around using such a
            > mechanism. However I am interested to know if I could let the classes do the
            > work by themselves.[/color]

            You can, but a class factory is going to be much clearer and probably
            more maintainable. From the user's perspective, there's no difference
            from calling a class A to instantiate it, and calling a factory function
            called A that selects the appropriate class and returns an instance of it.

            --
            Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
            San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
            Never had very much to say / Laugh last, laugh longest
            -- Des'ree

            Comment

            • Paul Rubin

              #7
              Re: Unpythonic? Impossible??

              Erik Max Francis <max@alcyone.co m> writes:[color=blue]
              > You can, but a class factory is going to be much clearer and probably
              > more maintainable. From the user's perspective, there's no difference
              > from calling a class A to instantiate it, and calling a factory
              > function called A that selects the appropriate class and returns an
              > instance of it.[/color]

              I remember having a similar problem involving multiple base classes
              and deciding that factory functions couldn't do quite what I wanted.
              Here's a thread about it, with a recipe using metaclasses by Roeland
              Rengelink:

              http://tinyurl.com/rz6ne

              Unfortunately, the subtleties of what I was trying to do now escape
              me.

              Comment

              • Erik Max Francis

                #8
                Re: Unpythonic? Impossible??

                Paul Rubin wrote:
                [color=blue]
                > I remember having a similar problem involving multiple base classes
                > and deciding that factory functions couldn't do quite what I wanted.
                > Here's a thread about it, with a recipe using metaclasses by Roeland
                > Rengelink:
                >
                > http://tinyurl.com/rz6ne
                >
                > Unfortunately, the subtleties of what I was trying to do now escape
                > me.[/color]

                Your objection seemed to be that you'd prefer that you not have to have
                an explicit if/elif... (or lookup table) since that didn't seem very OO.
                Any solution that accomplishes this, whether it's a factory function,
                metaclasses, or a more traditional type of "virtual constructor" (your
                proposal at the end of your post, which is likely how you'd do it in
                C++) all need this.

                The short version of all this is all these approaches will work, are
                Functionally equivalent from the user's perspective, and all require
                upkeep, but some require more upkeep than others. In a dynamic language
                like Python, the best solution is the most straightforward one that
                requires the least upkeep. And that's a factory pattern.

                --
                Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
                San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
                Man is a hating rather than a loving animal.
                -- Rebecca West

                Comment

                Working...