basic language question

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

    basic language question

    Once in a while, I get bitten by the fact, that mutating list methods such
    as 'append' or 'extend' return None instead of the (mutated) list itself.
    Is there a compelling reason for that? I googled around, but didn't find
    anything about this.
    Thanks

    Stephan
  • Daniel Dittmar

    #2
    Re: basic language question

    Stephan Diehl wrote:[color=blue]
    > Once in a while, I get bitten by the fact, that mutating list methods
    > such as 'append' or 'extend' return None instead of the (mutated)
    > list itself. Is there a compelling reason for that? I googled around,
    > but didn't find anything about this.
    > Thanks
    >
    > Stephan[/color]

    The reasons described for sort ()
    <http://www.python.org/doc/faq/genera...ort-return-the
    -sorted-list> also apply to append and extend.

    Daniel



    Comment

    • Stephan Diehl

      #3
      Re: basic language question

      Daniel Dittmar wrote:
      [color=blue]
      > Stephan Diehl wrote:[color=green]
      >> Once in a while, I get bitten by the fact, that mutating list methods
      >> such as 'append' or 'extend' return None instead of the (mutated)
      >> list itself. Is there a compelling reason for that? I googled around,
      >> but didn't find anything about this.
      >> Thanks
      >>
      >> Stephan[/color]
      >
      > The reasons described for sort ()
      >[/color]
      <http://www.python.org/doc/faq/genera...ort-return-the[color=blue]
      > -sorted-list> also apply to append and extend.[/color]

      Thanks for the link. I don't find the given reason really compelling,
      though. (but that's mine, not your problem)
      [color=blue]
      >
      > Daniel[/color]

      Stephan

      Comment

      • Terry Reedy

        #4
        Re: basic language question


        "Stephan Diehl" <stephan.diehl@ gmx.net> wrote in message
        news:bj7ots$48j $06$1@news.t-online.com...[color=blue]
        > Once in a while, I get bitten by the fact, that mutating list[/color]
        methods such[color=blue]
        > as 'append' or 'extend' return None instead of the (mutated) list[/color]
        itself.[color=blue]
        > Is there a compelling reason for that? I googled around, but didn't[/color]
        find[color=blue]
        > anything about this.[/color]

        Some people, including GvR, think in-place mutators should not return
        anything to distinguish them from methods which return a new object
        and leave original untouched. One argument, I presume based on some
        experience, is that if both types of method look the same, people will
        forget difference, leading to obscure bugs. Others, confident in
        their ability to remember and not make mistakes, want mutated object
        returned so they chain methods togethers. While Python is generally a
        consenting-adults language, this is one place where Guido opted for
        the supposedly 'safer' choice.

        'Returners' could wrap no-return mutators with functions or
        derived-class methods that do return the object, but I have never seen
        anyone post a complete module that does so for, say, all list
        mutators.

        Terry J. Reedy


        Comment

        • Stephan Diehl

          #5
          Re: basic language question

          Terry Reedy wrote:
          [color=blue]
          >
          > "Stephan Diehl" <stephan.diehl@ gmx.net> wrote in message
          > news:bj7ots$48j $06$1@news.t-online.com...[color=green]
          >> Once in a while, I get bitten by the fact, that mutating list[/color]
          > methods such[color=green]
          >> as 'append' or 'extend' return None instead of the (mutated) list[/color]
          > itself.[/color]

          [...]
          [color=blue]
          >
          > 'Returners' could wrap no-return mutators with functions or
          > derived-class methods that do return the object, but I have never seen
          > anyone post a complete module that does so for, say, all list
          > mutators.[/color]

          That's actually a nice idea. I might just do that.[color=blue]
          >
          > Terry J. Reedy[/color]

          Stephan

          Comment

          • Michael Peuser

            #6
            Re: basic language question


            "Stephan Diehl" <stephan.diehl@ gmx.net> schrieb im Newsbeitrag
            news:bj7ots$48j $06$1@news.t-online.com...[color=blue]
            > Once in a while, I get bitten by the fact, that mutating list methods such
            > as 'append' or 'extend' return None instead of the (mutated) list itself.
            > Is there a compelling reason for that? I googled around, but didn't find
            > anything about this.[/color]

            There is a very old religious law saying: Thou shalt not cause side effects
            by a function.
            There is some wisdom in it but it is easily forgotten with languages which
            do not differ between functions and routines.

            Kindly
            Michael P


            Comment

            • John Roth

              #7
              Re: basic language question


              "Michael Peuser" <mpeuser@web.de > wrote in message
              news:bj820r$8up $05$1@news.t-online.com...[color=blue]
              >
              > "Stephan Diehl" <stephan.diehl@ gmx.net> schrieb im Newsbeitrag
              > news:bj7ots$48j $06$1@news.t-online.com...[color=green]
              > > Once in a while, I get bitten by the fact, that mutating list methods[/color][/color]
              such[color=blue][color=green]
              > > as 'append' or 'extend' return None instead of the (mutated) list[/color][/color]
              itself.[color=blue][color=green]
              > > Is there a compelling reason for that? I googled around, but didn't find
              > > anything about this.[/color]
              >
              > There is a very old religious law saying: Thou shalt not cause side[/color]
              effects[color=blue]
              > by a function.
              > There is some wisdom in it but it is easily forgotten with languages which
              > do not differ between functions and routines.[/color]

              Like most "religious laws," it's a rule that has a multitude of exceptions.
              You can't do I/O without having side effects, something that the designers
              of functional languages have learned, sometimes the hard way.

              As far as I'm concerned, this is one of those things that Ruby did
              right. By convention, methods that modify the object as a side effect
              have names that end with an "!" (exclamation point.) Ruby usually supplies
              two methods in such cases, one that modifies the object, and one that
              creates a copy and then modifies the copy. Both methods return the
              modified or new object.

              It obeys the Principle of Least Surprise because if you forget the
              "!", you get the slow version that does a copy and leaves the original
              intact.

              Nice as the solution is, it's impossible to import it into Python
              cleanly without introducing catastrophic backward incomaptibiliti es.

              John Roth[color=blue]
              >
              > Kindly
              > Michael P
              >
              >[/color]


              Comment

              • Michael Peuser

                #8
                Re: basic language question


                "John Roth" <newsgroups@jhr othjr.com>[color=blue]
                > "Michael Peuser" <mpeuser@web.de >[/color]
                [color=blue][color=green]
                > > There is a very old religious law saying: Thou shalt not cause side
                >> effects by a function.
                > > There is some wisdom in it but it is easily forgotten with languages[/color][/color]
                which[color=blue][color=green]
                > > do not differ between functions and routines.[/color]
                >
                > Like most "religious laws," it's a rule that has a multitude of[/color]
                exceptions.[color=blue]
                > You can't do I/O without having side effects, something that the designers
                > of functional languages have learned, sometimes the hard way.[/color]

                Stream I/O can never be done right in functional languages. The only
                solution is to use something like memory mapped files (which I do more and
                more ...)

                But look at this mess:
                twolines=f.read line()+f.readli ne()
                There are solutions in some languages with _routines_ and
                _call-by-reference_ but it it is generally very clumpy.

                On the other there is a growing popularity of generators and iterators which
                by concept are *heretic*

                Kindly
                Michael P





                Comment

                • Stephan Diehl

                  #9
                  Re: basic language question

                  Stephan Diehl wrote:
                  [color=blue]
                  > Terry Reedy wrote:
                  >[color=green]
                  >>
                  >> "Stephan Diehl" <stephan.diehl@ gmx.net> wrote in message
                  >> news:bj7ots$48j $06$1@news.t-online.com...[color=darkred]
                  >>> Once in a while, I get bitten by the fact, that mutating list[/color]
                  >> methods such[color=darkred]
                  >>> as 'append' or 'extend' return None instead of the (mutated) list[/color]
                  >> itself.[/color]
                  >
                  > [...]
                  >[color=green]
                  >>
                  >> 'Returners' could wrap no-return mutators with functions or
                  >> derived-class methods that do return the object, but I have never seen
                  >> anyone post a complete module that does so for, say, all list
                  >> mutators.[/color]
                  >
                  > That's actually a nice idea. I might just do that.[/color]

                  o.k., the following short code would give you a list class, that returns
                  'self' when invoking any of the mutating methods.
                  The solution involves a metaclass and I wouldn't consider this code more as
                  an example than an industrial strength solution (for example, at the
                  moment, you couldn't overload any of these methods)
                  ------------------------------------------------------------------
                  def wrapedmeth(clas sname,meth):
                  def _meth(self,*arg l,**argd):
                  getattr(super(g lobals()[classname],self),meth)(*a rgl,**argd)
                  return self

                  return _meth

                  class ReturnMeta(type ):
                  def __new__(cls,cla ssname,bases,cl assdict):
                  wrap = classdict.get(' return_self_sup er_methods')
                  if wrap is not None:
                  for method in wrap:
                  classdict[method] = wrapedmeth(clas sname,meth)
                  return super(ReturnMet a,cls).__new__( cls,classname,b ases,classdict)

                  class mylist(list):
                  __metaclass__ = ReturnMeta
                  return_self_sup er_methods = ['append',
                  'extend',
                  'insert',
                  'remove',
                  'reverse',
                  'sort']


                  if __name__ == '__main__':
                  print 'l = [1,2]'
                  print 'mylist: print l.append(3)'
                  l = mylist([1,2])
                  print l.append(3)
                  print 'list: print l.append(3)'
                  l = [1,2]
                  print l.append(3)
                  ------------------------------------------------------------------------------

                  have fun

                  Stephan

                  Comment

                  • Jacek Generowicz

                    #10
                    Re: basic language question

                    Stephan Diehl <stephan.diehl@ gmx.net> writes:
                    [color=blue]
                    > Stephan Diehl wrote:
                    >[color=green]
                    > > Terry Reedy wrote:
                    > >[color=darkred]
                    > >> 'Returners' could wrap no-return mutators with functions or
                    > >> derived-class methods that do return the object, but I have never seen
                    > >> anyone post a complete module that does so for, say, all list
                    > >> mutators.[/color]
                    > >
                    > > That's actually a nice idea. I might just do that.[/color]
                    >
                    > o.k., the following short code would give you a list class, that returns
                    > 'self' when invoking any of the mutating methods.[/color]

                    OK, here's a variaton on the theme, just wraps the object in-place in
                    a way which makes it return self. This way you can get the desired
                    effect on any object you get, without pre-meditation, so you can still
                    fit the call chain on one line (wasn't that the point?)
                    [color=blue]
                    > The solution involves a metaclass[/color]

                    Mine avoids them altogether.
                    [color=blue]
                    > and I wouldn't consider this code more as an example than an
                    > industrial strength solution[/color]

                    Ditto.


                    class returner:

                    def __init__(self, object):
                    self.object = object

                    def __getattr__(sel f, name):
                    def proxy(*args, **kwds):
                    getattr(self.ob ject, name)(*args, **kwds)
                    return self.object
                    return proxy

                    lst = [1,2,3]
                    print lst.append(4) # Here you get None
                    print returner(lst).a ppend(5) # Here you get the modified list.

                    Comment

                    • Jacek Generowicz

                      #11
                      Re: basic language question

                      Jacek Generowicz <jacek.generowi cz@cern.ch> writes:
                      [color=blue]
                      > OK, here's a variaton on the theme, just wraps the object in-place in
                      > a way which makes it return self.[/color]

                      I meant "makes any calls to methods return the original object in its
                      new state."
                      [color=blue]
                      > This way you can get the desired effect on any object you get,
                      > without pre-meditation, so you can still fit the call chain on one
                      > line (wasn't that the point?)[/color]

                      Of course, the chaining should work in Stephan's example too.

                      Comment

                      • Alex Martelli

                        #12
                        Re: basic language question

                        Terry Reedy wrote:
                        ...[color=blue]
                        > 'Returners' could wrap no-return mutators with functions or
                        > derived-class methods that do return the object, but I have never seen
                        > anyone post a complete module that does so for, say, all list
                        > mutators.[/color]

                        What about...:

                        def wrapReturning(f unc):
                        def returningWrappe r(*args, **kwds):
                        func(*args, **kwds)
                        return args[0]
                        return returningWrappe r


                        class metaReturner(ty pe):
                        ''' simplified metaReturner: deal with single inheritance only '''

                        def __new__(mcl, className, classBases, classDict):

                        # get the "real" base class, then wrap its mutators
                        for base in classBases:
                        if not isinstance(base , metaReturner):
                        for mutator in classDict['__mutators__']:
                        classDict[mutator] = wrapReturning(g etattr(base,
                        mutator))
                        break

                        # delegate the rest to built-in 'type'
                        return type.__new__(mc l, className, classBases, classDict)

                        class Returner: __metaclass__ = metaReturner


                        # example usage

                        class returnerlist(Re turner, list):
                        __mutators__ = 'sort reverse append extend insert'.split()

                        print returnerlist('h ello').extend(' ciao').sort().r everse()


                        Alex

                        Comment

                        Working...