initializing mutable class attributes

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

    initializing mutable class attributes

    There is something with initializing mutable class attributes that I am
    struggling with. I'll use an example to explain:
    class Father:
    attr1=None # this is OK
    attr2=[ ] # this is wrong
    def foo(self, data):
    self.attr1=data
    self.attr2.appe nd(data)
    The initialization of attr1 is obviously OK, all instances of Father
    redefine it in the method foo. But the initialization of attr2 is wrong
    because all the instances of Father end up sharing the same value. Maybe
    that is desired sometimes, but usually it is just a bug.

    So the only solution I see to this is to initialize attr2 in __init__:
    class Father:
    attr1=None
    def __init__(self):
    self.attr2=[ ]

    This is already awkward because there is such a difference between attr1 and
    attr2. But moreover, I think this forces subclasses of Father to do
    something like this:
    class Child (Father):
    def __init__(self):
    Father.__init__ (self)
    self.attr3=[ ]

    I find this even more awkward because many people will forget to do it.
    Clearly, this is then a more general issue with __init__, but I think it is
    accentuated by the fact that you HAVE TO HAVE __init__ in order to
    initialize attributes that are mutable.

    Is there something I don't know here and there is a better way to do this in
    Python? I would like to get a better solution or otherwise start a
    discussion.


  • Benjamin Niemann

    #2
    Re: initializing mutable class attributes

    That's the way it is supposed to work. Instance attributes have to be
    initialized via self.foo=..., usually in __init__() which in turn is
    *STRONGLY* advised to class its parents __init__() - or you create
    instance attributes 'on-the-fly' when they are used for the first time
    (useful technique for mixin classes without constructor). Class
    attributes are initialized once for the class and are shared between
    instances.
    "self.attr1=dat a" in Father.foo() doesn't "override" the Father.attr1
    attribute you defined before. It creates an instance attribute that
    shadows Father.attr1!
    Both attribute assignments in Father are OK - if you treat them as class
    attributes. They won't become instance attributes by hidden magic.

    Dan Perl wrote:[color=blue]
    > There is something with initializing mutable class attributes that I am
    > struggling with. I'll use an example to explain:
    > class Father:
    > attr1=None # this is OK
    > attr2=[ ] # this is wrong
    > def foo(self, data):
    > self.attr1=data
    > self.attr2.appe nd(data)
    > The initialization of attr1 is obviously OK, all instances of Father
    > redefine it in the method foo. But the initialization of attr2 is wrong
    > because all the instances of Father end up sharing the same value. Maybe
    > that is desired sometimes, but usually it is just a bug.
    >
    > So the only solution I see to this is to initialize attr2 in __init__:
    > class Father:
    > attr1=None
    > def __init__(self):
    > self.attr2=[ ]
    >
    > This is already awkward because there is such a difference between attr1 and
    > attr2. But moreover, I think this forces subclasses of Father to do
    > something like this:
    > class Child (Father):
    > def __init__(self):
    > Father.__init__ (self)
    > self.attr3=[ ]
    >
    > I find this even more awkward because many people will forget to do it.
    > Clearly, this is then a more general issue with __init__, but I think it is
    > accentuated by the fact that you HAVE TO HAVE __init__ in order to
    > initialize attributes that are mutable.
    >
    > Is there something I don't know here and there is a better way to do this in
    > Python? I would like to get a better solution or otherwise start a
    > discussion.[/color]

    Comment

    • Alex Martelli

      #3
      Re: initializing mutable class attributes

      Dan Perl <dperl@rogers.c om> wrote:
      [color=blue]
      > There is something with initializing mutable class attributes that I am
      > struggling with. I'll use an example to explain:
      > class Father:
      > attr1=None # this is OK
      > attr2=[ ] # this is wrong
      > def foo(self, data):
      > self.attr1=data
      > self.attr2.appe nd(data)
      > The initialization of attr1 is obviously OK, all instances of Father
      > redefine it in the method foo. But the initialization of attr2 is wrong
      > because all the instances of Father end up sharing the same value. Maybe
      > that is desired sometimes, but usually it is just a bug.[/color]

      I disagree: good Python programmers often use mutable class attributes,
      and use them to good effect. I've done my share of Python teaching,
      consulting and mentoring, and I definitely do *not* think this usage "is
      desired sometimes but usually it is just a bug".

      [color=blue]
      > So the only solution I see to this is to initialize attr2 in __init__:
      > class Father:
      > attr1=None
      > def __init__(self):
      > self.attr2=[ ][/color]

      This is the canonical way, sure.

      [color=blue]
      > This is already awkward because there is such a difference between attr1 and
      > attr2.[/color]

      One is a class attribute (which nobody forced you to have), the other is
      an instance attribute. If you want both to be instance attributes,
      initialize both in __init__ -- that's all there is to it. Don't use
      class attributes unless there's a reason for them to be class
      attributes, that seems like a good and sensible rule of thumb to me.
      [color=blue]
      > But moreover, I think this forces subclasses of Father to do
      > something like this:
      > class Child (Father):
      > def __init__(self):
      > Father.__init__ (self)
      > self.attr3=[ ][/color]

      Assuming an instance of Child needs to have both attributes attr2 and
      attr3, yes.
      [color=blue]
      >
      > I find this even more awkward because many people will forget to do it.[/color]

      Forget to do what -- call the parent class's __init__? Again, this is
      rare -- not as rare as the other "usually just a bug" you opined about,
      but not common. A class normally needs __init__ for a large number of
      purposes, of course, not just to assign mutable attributes to each
      instance, therefore people who learn subclassing do learn to call the
      parent class __init__ very early on, to avoid everything breaking.
      [color=blue]
      > Clearly, this is then a more general issue with __init__, but I think it is
      > accentuated by the fact that you HAVE TO HAVE __init__ in order to
      > initialize attributes that are mutable.[/color]

      Making __init__ more common means people are more likely to get used to
      it, and thus makes the bug of not calling a parent class's __init__
      rarer, not "accentuate d".
      [color=blue]
      >
      > Is there something I don't know here and there is a better way to do this in
      > Python? I would like to get a better solution or otherwise start a
      > discussion.[/color]

      There is no BETTER way, IMHO, than normal Python coding, which I believe
      is quite good -- but you appear to disagree, therefore it's hard for me
      to gauge what you may consider "better". There is definitely a
      DIFFERENT way -- coding a custom metaclass which will tweak the
      instantiation of all classes belonging to it, in order to insert some
      funky initialization of mutable attributes, and perhaps automate calls
      to superclasses' __init__ methods, and so on. Such automation is a
      ticklish issue, in the general case, so let's assume initializing
      mutable attributes is all we ever want to do. Then, for example...:

      import copy
      class metaImu(type):
      def __call__(cls, *a, **k):
      instance = type.__call__(c ls, *a, **k)
      for sup in cls.mro():
      muts = gerattr(sup, '__mutables__', ())
      for mutname in muts:
      if hasattr(instanc e, mutname): continue
      mutvalue = muts[mutname]
      setattr(instanc e, mutname, copy.copy(mutva lue))
      return instance

      class Father:
      __metaclass__ = metaImu
      __mutables__ = dict(attr1=None , attr2={})

      class Child(Father):
      __mutables__ = dict(attr3=[])

      I haven't tested this, but I believe it should behave as you appear to
      desire (assuming you want shallow rather than deep copying of the
      values, of course: I can't read your mind!). I specifically showed that
      you can use __mutables__ also for attributes which are in fact not
      mutable, since copy.copy should be innocuous (identity) on those, just
      in case you insist on having the same form for all such attributes. I
      have also assumed that an instance's __init__ may be allowed to set its
      own value for an attribute in __mutables__ and if it does so then that
      should be left alone. But of course you can play with all of these
      aspects at will. You could even have that __call__ method examine all
      attributes defined in the class (or any superclass) and force copies of
      them into instance attributes for all whose types are [[whatever
      criteria you like...]].


      Alex

      Comment

      • Dan Perl

        #4
        Re: initializing mutable class attributes

        I will clarify something that was probably not clear enough in my initial
        posting. I am interested in instance attributes, but I am using the class
        attributes to provide a default, "null", value for the instance attributes.
        Yes, the instance attributes only mask the class ones, but a class attribute
        and an instance attribute can be used like this:
        class WorksForMe:
        attr=None # used just as a default value for the instance
        attribute self.attr
        def foo(self):
        self.attr=Somet hingUseful( )
        def bar(self):
        if self.attr:
        useIt(self.attr )
        else:
        ignoreIt(self.a ttr)
        This makes it safe for an instance of WorksForMe to invoke bar( ) even if it
        never invoked foo( ).

        "Benjamin Niemann" <b.niemann@bett ernet.de> wrote in message
        news:cgul4v$h1d $1@online.de...[color=blue]
        > That's the way it is supposed to work. Instance attributes have to be
        > initialized via self.foo=..., usually in __init__() which in turn is
        > *STRONGLY* advised to class its parents __init__() - or you create
        > instance attributes 'on-the-fly' when they are used for the first time
        > (useful technique for mixin classes without constructor). Class
        > attributes are initialized once for the class and are shared between
        > instances.[/color]

        You are confirming the code I suggested but you don't share my view that
        such code is awkward. I think I I was actually conservative calling it
        awkward, I would rather call it unsafe. If I were a third-party library
        vendor, I would not be comfortable providing a mixin class that forces users
        to either invoke the parent's __init__ in their constructors or to
        initialize the instance attributes on-the-fly. The latter would even be
        against the principles of encapsulation, users should not need to know about
        the parent's attributes, especially because they may change in future
        releases. Both ways of restricting the use of the mixin class are unsafe
        because they are easy to be ignored by users. And it is not only the users'
        fault if they do not follow the restrictions, it is also my fault to put
        such restrictions in the first place.

        I think this points to a weakness in Python as an OO language. I'm not
        trying to bash it, but my understanding is that Python is still evolving in
        that respect and I think that this should be improved in the future. Then,
        on the other hand, maybe I'm the only one feeling this way and there's not
        going to be a change.
        [color=blue]
        > "self.attr1=dat a" in Father.foo() doesn't "override" the Father.attr1
        > attribute you defined before. It creates an instance attribute that
        > shadows Father.attr1!
        > Both attribute assignments in Father are OK - if you treat them as class
        > attributes. They won't become instance attributes by hidden magic.
        >
        > Dan Perl wrote:[color=green]
        > > There is something with initializing mutable class attributes that I am
        > > struggling with. I'll use an example to explain:
        > > class Father:
        > > attr1=None # this is OK
        > > attr2=[ ] # this is wrong
        > > def foo(self, data):
        > > self.attr1=data
        > > self.attr2.appe nd(data)
        > > The initialization of attr1 is obviously OK, all instances of Father
        > > redefine it in the method foo. But the initialization of attr2 is wrong
        > > because all the instances of Father end up sharing the same value.[/color][/color]
        Maybe[color=blue][color=green]
        > > that is desired sometimes, but usually it is just a bug.
        > >
        > > So the only solution I see to this is to initialize attr2 in __init__:
        > > class Father:
        > > attr1=None
        > > def __init__(self):
        > > self.attr2=[ ]
        > >
        > > This is already awkward because there is such a difference between attr1[/color][/color]
        and[color=blue][color=green]
        > > attr2. But moreover, I think this forces subclasses of Father to do
        > > something like this:
        > > class Child (Father):
        > > def __init__(self):
        > > Father.__init__ (self)
        > > self.attr3=[ ]
        > >
        > > I find this even more awkward because many people will forget to do it.
        > > Clearly, this is then a more general issue with __init__, but I think it[/color][/color]
        is[color=blue][color=green]
        > > accentuated by the fact that you HAVE TO HAVE __init__ in order to
        > > initialize attributes that are mutable.
        > >
        > > Is there something I don't know here and there is a better way to do[/color][/color]
        this in[color=blue][color=green]
        > > Python? I would like to get a better solution or otherwise start a
        > > discussion.[/color]
        >[/color]


        Comment

        • Peter Otten

          #5
          Re: initializing mutable class attributes

          Dan Perl wrote:
          [color=blue]
          > something like this:
          > class Child (Father):
          > def __init__(self):
          > Father.__init__ (self)
          > self.attr3=[ ]
          >
          > I find this even more awkward because many people will forget to do it.[/color]

          You have to call base-class-__init__() in every non-trivial inheritance
          scheme. Should you forget it, pychecker is always there to remind you

          <sloppy-code>
          class X:
          def __init__(self):
          self.x = 2

          class Y(X):
          pass

          class Z(Y):
          def __init__(self):
          pass
          </sloppy-code>

          And here's what pychecker says:

          $ pychecker t1.py
          Processing t1...

          Warnings...

          t1.py:9: Base class (t1.Y) __init__() not called

          Clear enough.

          Peter

          Comment

          • Larry Bates

            #6
            Re: initializing mutable class attributes

            Dan,

            I too use class attributes to assign defaults, but do
            it like following:

            import copy

            class Father:
            _attr1default=N one
            _attr2default=[]

            def __init__(self):
            self.attr1=self ._attr1default
            # Get copy of attr2default
            self.attr2=list (self._attr2def ault)

            def foo(self, data):
            self.attr1=data
            self.attr2.appe nd(data)


            class Child (Father):
            def __init__(self):
            Father.__init__ (self)
            #
            # At this point self.attr1 (instance)
            # and self.attr2 (instance) hold their defaults
            # while _attr1/_attr2default (class) still hold
            # their default values for initialization of more
            # class instances.
            #

            HTH,
            Larry Bates
            Syscon, Inc.


            "Dan Perl" <dperl@rogers.c om> wrote in message
            news:sHGYc.9330 6$pTn.42032@new s01.bloor.is.ne t.cable.rogers. com...[color=blue]
            > I will clarify something that was probably not clear enough in my initial
            > posting. I am interested in instance attributes, but I am using the class
            > attributes to provide a default, "null", value for the instance[/color]
            attributes.[color=blue]
            > Yes, the instance attributes only mask the class ones, but a class[/color]
            attribute[color=blue]
            > and an instance attribute can be used like this:
            > class WorksForMe:
            > attr=None # used just as a default value for the instance
            > attribute self.attr
            > def foo(self):
            > self.attr=Somet hingUseful( )
            > def bar(self):
            > if self.attr:
            > useIt(self.attr )
            > else:
            > ignoreIt(self.a ttr)
            > This makes it safe for an instance of WorksForMe to invoke bar( ) even if[/color]
            it[color=blue]
            > never invoked foo( ).
            >
            > "Benjamin Niemann" <b.niemann@bett ernet.de> wrote in message
            > news:cgul4v$h1d $1@online.de...[color=green]
            > > That's the way it is supposed to work. Instance attributes have to be
            > > initialized via self.foo=..., usually in __init__() which in turn is
            > > *STRONGLY* advised to class its parents __init__() - or you create
            > > instance attributes 'on-the-fly' when they are used for the first time
            > > (useful technique for mixin classes without constructor). Class
            > > attributes are initialized once for the class and are shared between
            > > instances.[/color]
            >
            > You are confirming the code I suggested but you don't share my view that
            > such code is awkward. I think I I was actually conservative calling it
            > awkward, I would rather call it unsafe. If I were a third-party library
            > vendor, I would not be comfortable providing a mixin class that forces[/color]
            users[color=blue]
            > to either invoke the parent's __init__ in their constructors or to
            > initialize the instance attributes on-the-fly. The latter would even be
            > against the principles of encapsulation, users should not need to know[/color]
            about[color=blue]
            > the parent's attributes, especially because they may change in future
            > releases. Both ways of restricting the use of the mixin class are unsafe
            > because they are easy to be ignored by users. And it is not only the[/color]
            users'[color=blue]
            > fault if they do not follow the restrictions, it is also my fault to put
            > such restrictions in the first place.
            >
            > I think this points to a weakness in Python as an OO language. I'm not
            > trying to bash it, but my understanding is that Python is still evolving[/color]
            in[color=blue]
            > that respect and I think that this should be improved in the future.[/color]
            Then,[color=blue]
            > on the other hand, maybe I'm the only one feeling this way and there's not
            > going to be a change.
            >[color=green]
            > > "self.attr1=dat a" in Father.foo() doesn't "override" the Father.attr1
            > > attribute you defined before. It creates an instance attribute that
            > > shadows Father.attr1!
            > > Both attribute assignments in Father are OK - if you treat them as class
            > > attributes. They won't become instance attributes by hidden magic.
            > >
            > > Dan Perl wrote:[color=darkred]
            > > > There is something with initializing mutable class attributes that I[/color][/color][/color]
            am[color=blue][color=green][color=darkred]
            > > > struggling with. I'll use an example to explain:
            > > > class Father:
            > > > attr1=None # this is OK
            > > > attr2=[ ] # this is wrong
            > > > def foo(self, data):
            > > > self.attr1=data
            > > > self.attr2.appe nd(data)
            > > > The initialization of attr1 is obviously OK, all instances of Father
            > > > redefine it in the method foo. But the initialization of attr2 is[/color][/color][/color]
            wrong[color=blue][color=green][color=darkred]
            > > > because all the instances of Father end up sharing the same value.[/color][/color]
            > Maybe[color=green][color=darkred]
            > > > that is desired sometimes, but usually it is just a bug.
            > > >
            > > > So the only solution I see to this is to initialize attr2 in __init__:
            > > > class Father:
            > > > attr1=None
            > > > def __init__(self):
            > > > self.attr2=[ ]
            > > >
            > > > This is already awkward because there is such a difference between[/color][/color][/color]
            attr1[color=blue]
            > and[color=green][color=darkred]
            > > > attr2. But moreover, I think this forces subclasses of Father to do
            > > > something like this:
            > > > class Child (Father):
            > > > def __init__(self):
            > > > Father.__init__ (self)
            > > > self.attr3=[ ]
            > > >
            > > > I find this even more awkward because many people will forget to do[/color][/color][/color]
            it.[color=blue][color=green][color=darkred]
            > > > Clearly, this is then a more general issue with __init__, but I think[/color][/color][/color]
            it[color=blue]
            > is[color=green][color=darkred]
            > > > accentuated by the fact that you HAVE TO HAVE __init__ in order to
            > > > initialize attributes that are mutable.
            > > >
            > > > Is there something I don't know here and there is a better way to do[/color][/color]
            > this in[color=green][color=darkred]
            > > > Python? I would like to get a better solution or otherwise start a
            > > > discussion.[/color]
            > >[/color]
            >
            >[/color]


            Comment

            • Dan Perl

              #7
              Re: initializing mutable class attributes


              "Alex Martelli" <aleaxit@yahoo. com> wrote in message
              news:1gjc8cs.sq vo1v1fhabdjN%al eaxit@yahoo.com ...[color=blue]
              > Dan Perl <dperl@rogers.c om> wrote:
              >[color=green]
              > > There is something with initializing mutable class attributes that I am
              > > struggling with. I'll use an example to explain:
              > > class Father:
              > > attr1=None # this is OK
              > > attr2=[ ] # this is wrong
              > > def foo(self, data):
              > > self.attr1=data
              > > self.attr2.appe nd(data)
              > > The initialization of attr1 is obviously OK, all instances of Father
              > > redefine it in the method foo. But the initialization of attr2 is wrong
              > > because all the instances of Father end up sharing the same value.[/color][/color]
              Maybe[color=blue][color=green]
              > > that is desired sometimes, but usually it is just a bug.[/color]
              >
              > I disagree: good Python programmers often use mutable class attributes,
              > and use them to good effect. I've done my share of Python teaching,
              > consulting and mentoring, and I definitely do *not* think this usage "is
              > desired sometimes but usually it is just a bug".[/color]

              My mistake. I shouldn't have made that statement. I don't really know
              which case happens more often. Having said that, that is probably a mistake
              that many beginners make. Okay, I have no real way of knowing that either,
              but I think it's a good assumption.
              [color=blue][color=green]
              > > So the only solution I see to this is to initialize attr2 in __init__:
              > > class Father:
              > > attr1=None
              > > def __init__(self):
              > > self.attr2=[ ][/color]
              >
              > This is the canonical way, sure.
              >
              >[color=green]
              > > This is already awkward because there is such a difference between attr1[/color][/color]
              and[color=blue][color=green]
              > > attr2.[/color]
              >
              > One is a class attribute (which nobody forced you to have), the other is
              > an instance attribute. If you want both to be instance attributes,
              > initialize both in __init__ -- that's all there is to it. Don't use
              > class attributes unless there's a reason for them to be class
              > attributes, that seems like a good and sensible rule of thumb to me.[/color]

              I was using the class attribute as a default, "null", value for the instance
              attributes. That works just fine for immutable attributes and it allows me
              not to implement an __init__.
              [color=blue][color=green]
              > > But moreover, I think this forces subclasses of Father to do
              > > something like this:
              > > class Child (Father):
              > > def __init__(self):
              > > Father.__init__ (self)
              > > self.attr3=[ ][/color]
              >
              > Assuming an instance of Child needs to have both attributes attr2 and
              > attr3, yes.
              >[color=green]
              > >
              > > I find this even more awkward because many people will forget to do it.[/color]
              >
              > Forget to do what -- call the parent class's __init__? Again, this is
              > rare -- not as rare as the other "usually just a bug" you opined about,
              > but not common. A class normally needs __init__ for a large number of
              > purposes, of course, not just to assign mutable attributes to each
              > instance, therefore people who learn subclassing do learn to call the
              > parent class __init__ very early on, to avoid everything breaking.
              >[color=green]
              > > Clearly, this is then a more general issue with __init__, but I think it[/color][/color]
              is[color=blue][color=green]
              > > accentuated by the fact that you HAVE TO HAVE __init__ in order to
              > > initialize attributes that are mutable.[/color]
              >
              > Making __init__ more common means people are more likely to get used to
              > it, and thus makes the bug of not calling a parent class's __init__
              > rarer, not "accentuate d".[/color]

              I'm leaving the rest of your reply out, but thanks for the suggestion of a
              metaclass, I'll look into it.

              After seeing a few replies (yours, Benjamin Niemann's and Peter Otten's) to
              my initial posting, I think I am getting the picture that there is a
              conscious decision to keep the use of __init__ the way it is and just make
              people learn it and learn it early enough. That's a valid approach and I'll
              accept it.

              I can also understand your frustration with people who are new to Python,
              like me, coming from a background in other OO languages, who are not yet
              comfortable with "the Python way" and feel that there is a "better way" and
              who suggest changing Python. But you also have to be reallistic and accept
              that there will always be people coming to Python from other languages and
              that the adjustment is rather difficult in some areas. You may just say
              'Tough!', or you may help them to make that adjustment (I think you are
              doing that), or you may even accommodate them (you should at least consider
              that).

              No one, including you, has given me a reason WHY __init__ is implemented
              this way. I am not bashing you for that, I would just still like to hear
              that 'WHY'. I'm sure that this implementation has some advantages. But,
              coming from a C++ and Java background, where parent default constructors are
              automatically invoked (well, not always, and that is something that users
              have to learn too), I find that that approach has some clear advantages.

              Those are my 2 cents.

              Dan
              PS: Does my last name attract the wrong kind of attention from people in
              this newsgroup? It's really my name, it's not fake, BTW.


              Comment

              • Dan Perl

                #8
                Re: initializing mutable class attributes

                Larry,

                I don't think it is very different from what I suggested. You still
                implement an __init__ and you initialize the instance attributes there.

                Thanks, though. It's a nice trick and it's useful because you have a
                default value that can be used also in other places in the code (like
                restoring the default). And it's probably a good use of pseudo-private
                class attributes.

                Dan

                "Larry Bates" <lbates@swamiso ft.com> wrote in message
                news:29SdnfncSK 8R3K7cRVn-sA@comcast.com. ..[color=blue]
                > Dan,
                >
                > I too use class attributes to assign defaults, but do
                > it like following:
                >
                > import copy
                >
                > class Father:
                > _attr1default=N one
                > _attr2default=[]
                >
                > def __init__(self):
                > self.attr1=self ._attr1default
                > # Get copy of attr2default
                > self.attr2=list (self._attr2def ault)
                >
                > def foo(self, data):
                > self.attr1=data
                > self.attr2.appe nd(data)
                >
                >
                > class Child (Father):
                > def __init__(self):
                > Father.__init__ (self)
                > #
                > # At this point self.attr1 (instance)
                > # and self.attr2 (instance) hold their defaults
                > # while _attr1/_attr2default (class) still hold
                > # their default values for initialization of more
                > # class instances.
                > #
                >
                > HTH,
                > Larry Bates
                > Syscon, Inc.
                >
                >
                > "Dan Perl" <dperl@rogers.c om> wrote in message
                > news:sHGYc.9330 6$pTn.42032@new s01.bloor.is.ne t.cable.rogers. com...[color=green]
                > > I will clarify something that was probably not clear enough in my[/color][/color]
                initial[color=blue][color=green]
                > > posting. I am interested in instance attributes, but I am using the[/color][/color]
                class[color=blue][color=green]
                > > attributes to provide a default, "null", value for the instance[/color]
                > attributes.[color=green]
                > > Yes, the instance attributes only mask the class ones, but a class[/color]
                > attribute[color=green]
                > > and an instance attribute can be used like this:
                > > class WorksForMe:
                > > attr=None # used just as a default value for the instance
                > > attribute self.attr
                > > def foo(self):
                > > self.attr=Somet hingUseful( )
                > > def bar(self):
                > > if self.attr:
                > > useIt(self.attr )
                > > else:
                > > ignoreIt(self.a ttr)
                > > This makes it safe for an instance of WorksForMe to invoke bar( ) even[/color][/color]
                if[color=blue]
                > it[color=green]
                > > never invoked foo( ).
                > >
                > > "Benjamin Niemann" <b.niemann@bett ernet.de> wrote in message
                > > news:cgul4v$h1d $1@online.de...[color=darkred]
                > > > That's the way it is supposed to work. Instance attributes have to be
                > > > initialized via self.foo=..., usually in __init__() which in turn is
                > > > *STRONGLY* advised to class its parents __init__() - or you create
                > > > instance attributes 'on-the-fly' when they are used for the first time
                > > > (useful technique for mixin classes without constructor). Class
                > > > attributes are initialized once for the class and are shared between
                > > > instances.[/color]
                > >
                > > You are confirming the code I suggested but you don't share my view that
                > > such code is awkward. I think I I was actually conservative calling it
                > > awkward, I would rather call it unsafe. If I were a third-party library
                > > vendor, I would not be comfortable providing a mixin class that forces[/color]
                > users[color=green]
                > > to either invoke the parent's __init__ in their constructors or to
                > > initialize the instance attributes on-the-fly. The latter would even be
                > > against the principles of encapsulation, users should not need to know[/color]
                > about[color=green]
                > > the parent's attributes, especially because they may change in future
                > > releases. Both ways of restricting the use of the mixin class are[/color][/color]
                unsafe[color=blue][color=green]
                > > because they are easy to be ignored by users. And it is not only the[/color]
                > users'[color=green]
                > > fault if they do not follow the restrictions, it is also my fault to put
                > > such restrictions in the first place.
                > >
                > > I think this points to a weakness in Python as an OO language. I'm not
                > > trying to bash it, but my understanding is that Python is still evolving[/color]
                > in[color=green]
                > > that respect and I think that this should be improved in the future.[/color]
                > Then,[color=green]
                > > on the other hand, maybe I'm the only one feeling this way and there's[/color][/color]
                not[color=blue][color=green]
                > > going to be a change.
                > >[color=darkred]
                > > > "self.attr1=dat a" in Father.foo() doesn't "override" the Father.attr1
                > > > attribute you defined before. It creates an instance attribute that
                > > > shadows Father.attr1!
                > > > Both attribute assignments in Father are OK - if you treat them as[/color][/color][/color]
                class[color=blue][color=green][color=darkred]
                > > > attributes. They won't become instance attributes by hidden magic.
                > > >
                > > > Dan Perl wrote:
                > > > > There is something with initializing mutable class attributes that I[/color][/color]
                > am[color=green][color=darkred]
                > > > > struggling with. I'll use an example to explain:
                > > > > class Father:
                > > > > attr1=None # this is OK
                > > > > attr2=[ ] # this is wrong
                > > > > def foo(self, data):
                > > > > self.attr1=data
                > > > > self.attr2.appe nd(data)
                > > > > The initialization of attr1 is obviously OK, all instances of Father
                > > > > redefine it in the method foo. But the initialization of attr2 is[/color][/color]
                > wrong[color=green][color=darkred]
                > > > > because all the instances of Father end up sharing the same value.[/color]
                > > Maybe[color=darkred]
                > > > > that is desired sometimes, but usually it is just a bug.
                > > > >
                > > > > So the only solution I see to this is to initialize attr2 in[/color][/color][/color]
                __init__:[color=blue][color=green][color=darkred]
                > > > > class Father:
                > > > > attr1=None
                > > > > def __init__(self):
                > > > > self.attr2=[ ]
                > > > >
                > > > > This is already awkward because there is such a difference between[/color][/color]
                > attr1[color=green]
                > > and[color=darkred]
                > > > > attr2. But moreover, I think this forces subclasses of Father to do
                > > > > something like this:
                > > > > class Child (Father):
                > > > > def __init__(self):
                > > > > Father.__init__ (self)
                > > > > self.attr3=[ ]
                > > > >
                > > > > I find this even more awkward because many people will forget to do[/color][/color]
                > it.[color=green][color=darkred]
                > > > > Clearly, this is then a more general issue with __init__, but I[/color][/color][/color]
                think[color=blue]
                > it[color=green]
                > > is[color=darkred]
                > > > > accentuated by the fact that you HAVE TO HAVE __init__ in order to
                > > > > initialize attributes that are mutable.
                > > > >
                > > > > Is there something I don't know here and there is a better way to do[/color]
                > > this in[color=darkred]
                > > > > Python? I would like to get a better solution or otherwise start a
                > > > > discussion.
                > > >[/color]
                > >
                > >[/color]
                >
                >[/color]


                Comment

                • F. Petitjean

                  #9
                  Re: initializing mutable class attributes

                  On Mon, 30 Aug 2004 15:39:54 GMT, Dan Perl <dperl@rogers.c om> wrote:[color=blue]
                  >
                  > "Alex Martelli" <aleaxit@yahoo. com> wrote in message
                  > news:1gjc8cs.sq vo1v1fhabdjN%al eaxit@yahoo.com ...
                  >[color=green][color=darkred]
                  >> > So the only solution I see to this is to initialize attr2 in __init__:
                  >> > class Father:
                  >> > attr1=None
                  >> > def __init__(self):
                  >> > self.attr2=[ ][/color]
                  >>
                  >> This is the canonical way, sure.
                  >>[/color][/color]
                  Snip[color=blue]
                  >
                  > After seeing a few replies (yours, Benjamin Niemann's and Peter Otten's) to
                  > my initial posting, I think I am getting the picture that there is a
                  > conscious decision to keep the use of __init__ the way it is and just make
                  > people learn it and learn it early enough. That's a valid approach and I'll
                  > accept it.
                  >[/color]
                  Snip[color=blue]
                  >
                  > No one, including you, has given me a reason WHY __init__ is implemented
                  > this way. I am not bashing you for that, I would just still like to hear
                  > that 'WHY'. I'm sure that this implementation has some advantages. But,[/color]
                  Explicit is better than implicit

                  import this[color=blue]
                  >
                  >
                  > Dan
                  > PS: Does my last name attract the wrong kind of attention from people in
                  > this newsgroup? It's really my name, it's not fake, BTW.[/color]
                  My nick littlejohn is the direct translation of my last name and I'm
                  far from big. So what ? :=)

                  Comment

                  • Dan Perl

                    #10
                    Re: initializing mutable class attributes

                    Thanks, Peter. pychecker detecting the wrong use makes the argument that
                    there is no excuse for making the mistake of not calling the parent's
                    __init__ in subclasses. I am regularly using pychecker on my code, but I
                    never saw that warning because I did use __init__ correctly.

                    But I did make the mistake once of using a class attribute with an empty
                    dictionary to initialize an instance attribute just because I was doing the
                    same thing with immutable attributes. Fortunately, I caught it soon enough
                    and I will not make that mistake again. But it was kind of an embarrassing
                    mistake and I learned my lesson only after that.

                    Dan

                    "Peter Otten" <__peter__@web. de> wrote in message
                    news:cgvdun$1mb $01$1@news.t-online.com...[color=blue]
                    > You have to call base-class-__init__() in every non-trivial inheritance
                    > scheme. Should you forget it, pychecker is always there to remind you
                    > [....]
                    > And here's what pychecker says:
                    >
                    > $ pychecker t1.py
                    > Processing t1...
                    >
                    > Warnings...
                    >
                    > t1.py:9: Base class (t1.Y) __init__() not called
                    >
                    > Clear enough.
                    >
                    > Peter
                    >[/color]


                    Comment

                    • Shalabh Chaturvedi

                      #11
                      Re: initializing mutable class attributes

                      Dan Perl wrote:[color=blue]
                      > After seeing a few replies (yours, Benjamin Niemann's and Peter Otten's) to
                      > my initial posting, I think I am getting the picture that there is a
                      > conscious decision to keep the use of __init__ the way it is and just make
                      > people learn it and learn it early enough.[/color]

                      I'd agree.
                      [color=blue]
                      > That's a valid approach and I'll
                      > accept it.[/color]

                      That's nice :)
                      [color=blue]
                      > No one, including you, has given me a reason WHY __init__ is implemented
                      > this way. I am not bashing you for that, I would just still like to hear
                      > that 'WHY'. I'm sure that this implementation has some advantages. But,
                      > coming from a C++ and Java background, where parent default constructors are
                      > automatically invoked (well, not always, and that is something that users
                      > have to learn too), I find that that approach has some clear advantages.[/color]

                      'Why' is a very subjective question. People from different backgrounds
                      may accept very different answers for why since it may always be in a
                      specific context (why this instead of *that*?). The following is my idea
                      of why:

                      In Python you either have an __init__ or you don't. There is no 'default
                      constructor' - or if there is, it does nothing. Since attributes can be
                      dynamically added to an instance (not just in __init__ but in any
                      method), it follows that the standard practice is to initialize instance
                      members in __init__ as it is always called before any other instance
                      method. Now that there is one way to do a thing, Python avoids the
                      introduction of another way (unless it is notably more productive). That
                      would lead to a whole set of questions about 'which way is better?
                      __init__ or the other way?'.

                      Btw, now that there are descriptors, you can create descriptors that
                      initialize instance members with default values when they are accessed.
                      However, unless there is great advantage in your specific case, it might
                      be just better to follow standard practice and make it easier for
                      everyone else reading your code.
                      [color=blue]
                      > Dan
                      > PS: Does my last name attract the wrong kind of attention from people in
                      > this newsgroup?[/color]

                      I don't think so.

                      --
                      Shalabh

                      Comment

                      • Dan Perl

                        #12
                        Re: initializing mutable class attributes


                        "Shalabh Chaturvedi" <shalabh@cafepy .com> wrote in message
                        news:mailman.26 24.1093889688.5 135.python-list@python.org ...[color=blue]
                        > 'Why' is a very subjective question. People from different backgrounds
                        > may accept very different answers for why since it may always be in a
                        > specific context (why this instead of *that*?). The following is my idea
                        > of why:
                        >
                        > In Python you either have an __init__ or you don't. There is no 'default
                        > constructor' - or if there is, it does nothing. Since attributes can be
                        > dynamically added to an instance (not just in __init__ but in any
                        > method), it follows that the standard practice is to initialize instance
                        > members in __init__ as it is always called before any other instance
                        > method. Now that there is one way to do a thing, Python avoids the
                        > introduction of another way (unless it is notably more productive). That
                        > would lead to a whole set of questions about 'which way is better?
                        > __init__ or the other way?'.[/color]

                        It is a subjective issue indeed. But I'll restrict my question to a simpler
                        question. By analogy to C++ and Java, why is __init__ not implemented to
                        automatically invoke the __init__(self) of the parent classes? I'm
                        beginning to see a reason here, which is that C++ and Java allow you to
                        overload the constructor and have a default constructor at the same time as
                        another constructor with arguments. C++ and Java then force you to create a
                        default constructor for a parent class, even if it's empty, if you create a
                        non-default constructor for it and you subclass the parent class.

                        In contrast, Python does not allow method overloading and I'm OK with that.
                        It's a simplification that allows using Python in ways that are not possible
                        with C++ and Java. So Python cannot force you to have a 'default' __init__
                        and allow you to have 'non-default '__init__'s at the same time. I am
                        answering my own question here, but that's OK and it would not have happened
                        without this discussion.
                        [color=blue]
                        > Btw, now that there are descriptors, you can create descriptors that
                        > initialize instance members with default values when they are accessed.
                        > However, unless there is great advantage in your specific case, it might
                        > be just better to follow standard practice and make it easier for
                        > everyone else reading your code.[/color]

                        I'll have to look more into descriptors, I haven't used them yet and I see
                        there are many discussions on the topic in this newsgroup. I found your
                        "Python Attributes and Methods" page on cafepy.com and I'll take a look
                        there. Thanks!

                        Dan


                        Comment

                        • Shalabh Chaturvedi

                          #13
                          Re: initializing mutable class attributes

                          Dan Perl wrote:[color=blue]
                          > "Shalabh Chaturvedi" <shalabh@cafepy .com> wrote[color=green]
                          >>In Python you either have an __init__ or you don't. There is no 'default
                          >>constructor ' - or if there is, it does nothing. Since attributes can be
                          >>dynamically added to an instance (not just in __init__ but in any
                          >>method), it follows that the standard practice is to initialize instance
                          >>members in __init__ as it is always called before any other instance
                          >>method. Now that there is one way to do a thing, Python avoids the
                          >>introductio n of another way (unless it is notably more productive). That
                          >>would lead to a whole set of questions about 'which way is better?
                          >>__init__ or the other way?'.[/color]
                          >
                          >
                          > It is a subjective issue indeed. But I'll restrict my question to a simpler
                          > question. By analogy to C++ and Java, why is __init__ not implemented to
                          > automatically invoke the __init__(self) of the parent classes? I'm
                          > beginning to see a reason here, which is that C++ and Java allow you to
                          > overload the constructor and have a default constructor at the same time as
                          > another constructor with arguments. C++ and Java then force you to create a
                          > default constructor for a parent class, even if it's empty, if you create a
                          > non-default constructor for it and you subclass the parent class.
                          >
                          > In contrast, Python does not allow method overloading and I'm OK with that.
                          > It's a simplification that allows using Python in ways that are not possible
                          > with C++ and Java. So Python cannot force you to have a 'default' __init__
                          > and allow you to have 'non-default '__init__'s at the same time. I am
                          > answering my own question here, but that's OK and it would not have happened
                          > without this discussion.[/color]

                          Yes, if the parent class __init__ accepts parameters, how can Python
                          call it automatically? Should it be automatic in some cases and
                          non-automatic in others? (Answer: no, it's too ambiguous). Also what if
                          there are multiple parent classes? As the Quixote folks put it, in the
                          face of ambiguity, refuse the temptation to guess. (Btw, Python's
                          solution for multiple parent classes completely knocks the socks off C++
                          [1])

                          Cheers,
                          Shalabh

                          [1] http://www.python.org/2.2.3/descrintro.html#cooperation

                          Comment

                          • Aahz

                            #14
                            Re: initializing mutable class attributes

                            In article <mailman.2624.1 093889688.5135. python-list@python.org >,
                            Shalabh Chaturvedi <shalabh@cafepy .com> wrote:[color=blue]
                            >
                            >In Python you either have an __init__ or you don't. There is no 'default
                            >constructor' - or if there is, it does nothing.[/color]

                            Actually, that's not quite true. Python does indeed have a default
                            constructor that returns the object. This isn't particularly visible
                            from classic classes because there's no way to get access to a
                            constructor. New-style classes make the constructor available through
                            __new__(). __init__() is an initializer.
                            --
                            Aahz (aahz@pythoncra ft.com) <*> http://www.pythoncraft.com/

                            "To me vi is Zen. To use vi is to practice zen. Every command is a
                            koan. Profound to the user, unintelligible to the uninitiated. You
                            discover truth everytime you use it." --reddy@lion.aust in.ibm.com

                            Comment

                            • Dan Perl

                              #15
                              Re: initializing mutable class attributes


                              "Alex Martelli" <aleaxit@yahoo. com> wrote in message
                              news:1gje9dn.r6 jpetyroi0N%alea xit@yahoo.com.. .[color=blue]
                              > ............[color=green]
                              > > No one, including you, has given me a reason WHY __init__ is implemented
                              > > this way. I am not bashing you for that, I would just still like to[/color][/color]
                              hear[color=blue][color=green]
                              > > that 'WHY'. I'm sure that this implementation has some advantages.[/color][/color]
                              But,[color=blue][color=green]
                              > > coming from a C++ and Java background, where parent default constructors[/color][/color]
                              are[color=blue][color=green]
                              > > automatically invoked (well, not always, and that is something that[/color][/color]
                              users[color=blue][color=green]
                              > > have to learn too), I find that that approach has some clear advantages.[/color]
                              >
                              > In this like in many other details, Python chooses simplicity and
                              > clarity against automatic, black-magic, "behind the scenes" approaches.
                              > "Explicit is better than implicit" is one part of the Zen of Python that
                              > speaks to this -- at a python interactive prompt do
                              > import this
                              > to read it all. The automatic invocation of default constructors when
                              > they exist, what you have to do instead to get different constructors
                              > for parent classes, etc etc, are all complications. When classes are
                              > designed to execute responsibilitie s it's not unusual that they can't
                              > really have a useful no-arguments constructor -- and when they don't
                              > have such a constructor, C++'s and Java's rules are nothing BUT overhead
                              > and conceptual complication. In C++ one often works around the burden
                              > of contraints on constructor calls via "two-phase constructors" -- a
                              > default constructor that does not really leave the instance in a usable
                              > state, just to bypass the darn rules you find "have some clear
                              > advantages", and then a normal member function that really does the job
                              > of initialization and has the enormous advantage that YOU decide when
                              > and with what arguments to call it, without all the darn rules in the
                              > way, explicitly. Well, in Python the constructor, __init__, is under
                              > you control in exactly this way -- less complication, more simplicity,
                              > more transparency, fewer rules to learn, and far fewer instances of the
                              > "two-phase constructor" pattern (not zero, mind you -- just 99% fewer).[/color]

                              This is the kind of answer I was hoping for. Actually, I was prepared to
                              see a suggestion for solving the problem in a different way and there were a
                              couple of them, even if the people suggesting them were themselves advising
                              to prefer the original solution.

                              When learning something, I need to understand the 'WHY' behind a design
                              decision like that, when clearly there are alternatives. I will not be
                              satisfied with an explanation of "that's the Python way and you just have to
                              learn it". The explanation of choosing "explicit" instead of "implicit"
                              makes sense and helps me in better understanding Python. I have to mention
                              though that I do not accept "explicit is better than implicit" as an
                              absolute truth. [That's like when someone told me once with pride: "I
                              always design bottom-up."] Applying a principle like that CONSISTENTLY in
                              the design of a language can make a very good language. On the other hand,
                              I can imagine there can be very good languages, with their own uses and
                              advantages, if the reverse principle were consistently used.

                              You may see in another message I posted in this thread that I ended up
                              giving an answer to my own question (the 'WHY' question). Here is my reason
                              for that 'WHY'. Python does not have method overloading (and I am ok with
                              that, because it comes with the dynamic typing), so you cannot have a
                              default constructor and a non-default one at the same time. C++ and Java
                              have overloading and then can also mandate a default constructor for a
                              parent class, even if it's empty because you actually use only a non-default
                              constructor for that class. Python cannot request that you also implement a
                              default __init__ when you need a non-default one. There would be the
                              possibility of adding another special method, but there's already __init__
                              and __new__, so that would be too confusing.

                              I don't know whether that was an actual reason for the design even if it is
                              definitely an obstacle. But the principle of "explicit instead of implicit"
                              (I'll think of it that way) will help me to understand also other aspects of
                              Python. And thank you for that.

                              Dan


                              Comment

                              Working...