More __init__ methods

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

    More __init__ methods

    Hi,
    I know there can be only one __init__ method (at least, I think).

    Often I need an object to be created in different ways, for example
    passing a string as argument, or an integer, or another object. To
    achieve this I put the default value of the arguments to None and then
    I some if...elif inside the __init__.

    Is this a good practice? It actually works, but sometimes I think that
    in this way the __init__ method can become too complicated, for
    example when an object can be created using more than one argument and
    in different combinations.

    Hope my doubt is clear.
  • Marc 'BlackJack' Rintsch

    #2
    Re: More __init__ methods

    On Thu, 06 Nov 2008 16:49:08 +0100, Mr.SpOOn wrote:
    I know there can be only one __init__ method (at least, I think).
    >
    Often I need an object to be created in different ways, for example
    passing a string as argument, or an integer, or another object. To
    achieve this I put the default value of the arguments to None and then I
    some if...elif inside the __init__.
    >
    Is this a good practice? It actually works, but sometimes I think that
    in this way the __init__ method can become too complicated, for example
    when an object can be created using more than one argument and in
    different combinations.
    I'm usually using `classmethod()` \s as alternative "constructo rs" then.
    For example:

    class A(object):
    def __init__(self, a, b, c):
    self.a = a
    # ...

    @classmethod
    def from_string(cls , s):
    # ...
    return cls(a, b, c)

    Ciao,
    Marc 'BlackJack' Rintsch

    Comment

    • Mr.SpOOn

      #3
      Re: More __init__ methods

      On Thu, Nov 6, 2008 at 4:59 PM, Marc 'BlackJack' Rintsch <bj_666@gmx.net wrote:
      class A(object):
      def __init__(self, a, b, c):
      self.a = a
      # ...
      >
      @classmethod
      def from_string(cls , s):
      # ...
      return cls(a, b, c)
      Thanks.
      I think it's time to study decorators.

      Comment

      • Tim Golden

        #4
        Re: More __init__ methods

        Mr.SpOOn wrote:
        On Thu, Nov 6, 2008 at 4:59 PM, Marc 'BlackJack' Rintsch <bj_666@gmx.net wrote:
        >class A(object):
        > def __init__(self, a, b, c):
        > self.a = a
        > # ...
        >>
        > @classmethod
        > def from_string(cls , s):
        > # ...
        > return cls(a, b, c)
        >
        Thanks.
        I think it's time to study decorators.

        While that's no bad thing, you don't really need to do
        that simply to understand these examples: they're just
        saying "do whatever you need to to make these method
        class methods, not instance methods".

        TJG

        Comment

        • Mr.SpOOn

          #5
          Re: More __init__ methods

          On Thu, Nov 6, 2008 at 7:44 PM, Tim Golden <mail@timgolden .me.ukwrote:
          While that's no bad thing, you don't really need to do
          that simply to understand these examples: they're just
          saying "do whatever you need to to make these method
          class methods, not instance methods".
          Yes.

          I think this changes the design of my class.

          I mean, till now I had something like:

          class foo:
          def __init__(self, string=None, integer=None, someinstance=No ne):
          self.a = 0
          self.b = 0

          if string:
          # do something to calculate "a and b"
          elif integer:
          # do something else to calculate "a and b"
          ...
          ...

          So I used different methods to calculate the same variables.

          Now I must pass a and b to the main constructor and calculate them in
          the classmethods.

          class foo:
          def __init__(self, a, b):
          self.a = a
          self.b = b

          @classmethod
          def from_string(sel f, ..):
          ...
          ...

          What I mean is: I can't use anymore __init__ as the default
          constructor, but I always have to specify the way I'm creating my
          object. Am I right? I'm asking just to be sure I have understood.

          Comment

          • Larry Bates

            #6
            Re: More __init__ methods

            Mr.SpOOn wrote:
            On Thu, Nov 6, 2008 at 7:44 PM, Tim Golden <mail@timgolden .me.ukwrote:
            >While that's no bad thing, you don't really need to do
            >that simply to understand these examples: they're just
            >saying "do whatever you need to to make these method
            >class methods, not instance methods".
            >
            Yes.
            >
            I think this changes the design of my class.
            >
            I mean, till now I had something like:
            >
            class foo:
            def __init__(self, string=None, integer=None, someinstance=No ne):
            self.a = 0
            self.b = 0
            >
            if string:
            # do something to calculate "a and b"
            elif integer:
            # do something else to calculate "a and b"
            ...
            ...
            >
            So I used different methods to calculate the same variables.
            >
            Now I must pass a and b to the main constructor and calculate them in
            the classmethods.
            >
            class foo:
            def __init__(self, a, b):
            self.a = a
            self.b = b
            >
            @classmethod
            def from_string(sel f, ..):
            ...
            ...
            >
            What I mean is: I can't use anymore __init__ as the default
            constructor, but I always have to specify the way I'm creating my
            object. Am I right? I'm asking just to be sure I have understood.
            Is there some reason not to use something like the following?

            class foo:
            def __init__(self, val):
            self.a = 0
            self.b = 0

            if isinstance(val, basestring):
            #
            # do something to calculate "a and b"
            #

            elif isintance(val, int):
            #
            # do something else to calculate "a and b"
            #

            elif isinstance(val, someinstance)
            #
            # do something else to calculate "a and b"
            #

            else:
            #
            # Don't know what to do with unknown type
            #
            raise ValueError()



            -Larry

            Comment

            • Ben Finney

              #7
              Re: More __init__ methods

              Mr.SpOOn <mr.spoon21@gma il.comwrites:
              On Thu, Nov 6, 2008 at 4:59 PM, Marc 'BlackJack' Rintsch <bj_666@gmx.net wrote:
              class A(object):
              def __init__(self, a, b, c):
              self.a = a
              # ...

              @classmethod
              def from_string(cls , s):
              # ...
              return cls(a, b, c)
              >
              Thanks.
              I think it's time to study decorators.
              Studying decorators is a good idea, but in this instance it's not
              necessary. The above is merely using decorator syntax to apply the
              ‘classmethodâ €™ type to a function.

              All you need to know to understand the above is that it will have
              essentially the same result as:

              class A(object):
              # ...

              def _from_string(cl s, s):
              # ...
              return cls(a, b, c)
              from_string = classmethod(_fr om_string)
              del _from_string

              without the intermediate binding of the ‘_from_string ’ name.

              --
              \ “The best way to get information on Usenet is not to ask a |
              `\ question, but to post the wrong information.” —Aahz |
              _o__) |
              Ben Finney

              Comment

              • Arnaud Delobelle

                #8
                Re: More __init__ methods

                Ben Finney <bignose+hate s-spam@benfinney. id.auwrites:
                [...]
                All you need to know to understand the above is that it will have
                essentially the same result as:
                >
                class A(object):
                # ...
                >
                def _from_string(cl s, s):
                # ...
                return cls(a, b, c)
                from_string = classmethod(_fr om_string)
                del _from_string
                >
                without the intermediate binding of the ‘_from_string ’ name.
                So you mean it is the same as:

                class A(object):
                # ...

                def from_string(cls , s):
                # ...
                from_string = classmethod(fro m_string)

                :)

                --
                Arnaud

                Comment

                • Ben Finney

                  #9
                  Re: More __init__ methods

                  Mr.SpOOn <mr.spoon21@gma il.comwrites:
                  class foo:
                  def __init__(self, a, b):
                  self.a = a
                  self.b = b
                  >
                  @classmethod
                  def from_string(sel f, ..):
                  ...
                  ...
                  >
                  What I mean is: I can't use anymore __init__ as the default
                  constructor, but I always have to specify the way I'm creating my
                  object. Am I right? I'm asking just to be sure I have understood.
                  Yes, that's what the above design requires. You code ‘foo.__init__ ’
                  for the common use case, and create ‘foo.from_bar ’ classmethod factory
                  functions for other cases. The caller then needs to specify which case
                  is being requested.

                  --
                  \ “I was in the first submarine. Instead of a periscope, they had |
                  `\ a kaleidoscope. ‘We're surrounded.’⠀ —Steven Wright |
                  _o__) |
                  Ben Finney

                  Comment

                  • Ben Finney

                    #10
                    Re: More __init__ methods

                    Larry Bates <larry.bates@vi talEsafe.comwri tes:
                    Is there some reason not to use something like the following?
                    >
                    class foo:
                    def __init__(self, val):
                    self.a = 0
                    self.b = 0
                    >
                    if isinstance(val, basestring):
                    #
                    # do something to calculate "a and b"
                    #
                    >
                    elif isintance(val, int):
                    #
                    # do something else to calculate "a and b"
                    #
                    >
                    elif isinstance(val, someinstance)
                    #
                    # do something else to calculate "a and b"
                    #
                    >
                    else:
                    #
                    # Don't know what to do with unknown type
                    #
                    raise ValueError()
                    Yes, the main reason is that it kills duck typing. The initialiser
                    should *use* the parameters passed, and allow exceptions to propagate
                    back to the caller if the parameters don't behave as expected.

                    Another good reason to avoid the above style is that it's far too
                    complex. Different behaviours should be in different functions.

                    --
                    \ “Friendship is born at that moment when one person says to |
                    `\ another, ‘What! You too? I thought I was the only one!’” —C.S. |
                    _o__) Lewis |
                    Ben Finney

                    Comment

                    • Ben Finney

                      #11
                      Re: More __init__ methods

                      Arnaud Delobelle <arnodel@google mail.comwrites:
                      Ben Finney <bignose+hate s-spam@benfinney. id.auwrites:
                      [...]
                      All you need to know to understand the above is that it will have
                      essentially the same result as:

                      class A(object):
                      # ...

                      def _from_string(cl s, s):
                      # ...
                      return cls(a, b, c)
                      from_string = classmethod(_fr om_string)
                      del _from_string

                      without the intermediate binding of the ‘_from_string ’ name.
                      >
                      So you mean it is the same as:
                      >
                      class A(object):
                      # ...
                      >
                      def from_string(cls , s):
                      # ...
                      from_string = classmethod(fro m_string)
                      Sure, but I figured I would make the steps more explicit.

                      --
                      \ “Writing a book is like washing an elephant: there no good |
                      `\ place to begin or end, and it's hard to keep track of what |
                      _o__) you've already covered.” —anonymous |
                      Ben Finney

                      Comment

                      • Mr.SpOOn

                        #12
                        Re: More __init__ methods

                        On Thu, Nov 6, 2008 at 11:00 PM, Ben Finney
                        <bignose+hate s-spam@benfinney. id.auwrote:
                        Yes, the main reason is that it kills duck typing. The initialiser
                        should *use* the parameters passed, and allow exceptions to propagate
                        back to the caller if the parameters don't behave as expected.
                        >
                        Another good reason to avoid the above style is that it's far too
                        complex. Different behaviours should be in different functions.
                        Ok, thanks.
                        Is there a good book or source where I can read about such topics?
                        Core Python Programming doesn't seem to talk about decorators. Maybe
                        it's too old?

                        Comment

                        • Mr.SpOOn

                          #13
                          Re: More __init__ methods

                          On Thu, Nov 6, 2008 at 11:00 PM, Ben Finney
                          <bignose+hate s-spam@benfinney. id.auwrote:
                          Yes, the main reason is that it kills duck typing. The initialiser
                          should *use* the parameters passed, and allow exceptions to propagate
                          back to the caller if the parameters don't behave as expected.
                          >
                          Another good reason to avoid the above style is that it's far too
                          complex. Different behaviours should be in different functions.
                          Sorry for double posting, but in this way it seems I can't use
                          instance method inside the classmethod. Probably it is the right
                          behavior, but if I use this @classmethod style to simplify the
                          __init__ method, now I should move code from instance method inside
                          the classmethods.

                          In this way I'm kinda mixing things. I mean, if to construct an object
                          I have to use different methods, what can I do? Or am I missing
                          something, as usual?

                          Comment

                          • Duncan Booth

                            #14
                            Re: More __init__ methods

                            Mr.SpOOn <mr.spoon21@gma il.comwrote:
                            Now I must pass a and b to the main constructor and calculate them in
                            the classmethods.
                            >
                            class foo:
                            def __init__(self, a, b):
                            self.a = a
                            self.b = b
                            >
                            @classmethod
                            def from_string(sel f, ..):
                            ...
                            ...
                            >
                            What I mean is: I can't use anymore __init__ as the default
                            constructor, but I always have to specify the way I'm creating my
                            object. Am I right? I'm asking just to be sure I have understood.
                            There is a really big advantage to being explicit in this situation: you no
                            longer have to make sure that all your constructors use a unique set of
                            types. Consider:

                            class Location(object ):
                            def __init__(self, lat, long): ...

                            @classmethod
                            def from_city(name) : ...

                            @classmethod
                            def from_postcode(n ame): ...

                            'from_string' is a bad name here for your factory method: you should try to
                            make it clear what sort of string is expected.

                            --
                            Duncan Booth http://kupuguy.blogspot.com

                            Comment

                            • Marc 'BlackJack' Rintsch

                              #15
                              Re: More __init__ methods

                              On Fri, 07 Nov 2008 15:16:29 +0000, Duncan Booth wrote:
                              'from_string' is a bad name here for your factory method: you should try
                              to make it clear what sort of string is expected.
                              When I use a `from_string()` factory I usually make sure it can parse the
                              `str()` form of that type or that there is a `to_string()` as reverse
                              operation.

                              Ciao,
                              Marc 'BlackJack' Rintsch

                              Comment

                              Working...