Default argument to __init__

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • netvaibhav@gmail.com

    #1

    Default argument to __init__

    Hi All:

    Here's a piece of Python code and it's output. The output that Python
    shows is not as per my expectation. Hope someone can explain to me this
    behaviour:

    Code:
    class MyClass:
    def __init__(self, myarr=[]):
    self.myarr = myarr
    
    myobj1 = MyClass()
    myobj2 = MyClass()
    
    myobj1.myarr += [1,2,3]
    
    myobj2.myarr += [4,5,6]
    
    print myobj1.myarr
    print myobj2.myarr
    The output is:
    [1, 2, 3, 4, 5, 6]
    [1, 2, 3, 4, 5, 6]

    Why do myobj1.myarr and myobj2.myarr point to the same list? The
    default value to __init__ for the myarr argument is [], so I expect
    that every time an object of MyClass is created, a new empty list is
    created and assigned to myarr, but it seems that the same empty list
    object is assigned to myarr on every invocation of MyClass.__init_ _

    It this behaviour by design? If so, what is the reason, as the
    behaviour I expect seems pretty logical.

    Thanks.

    Vaibhav

  • skip@pobox.com

    #2
    Re: Default argument to __init__

    vaibhav> Here's a piece of Python code and it's output. The output that
    vaibhav> Python shows is not as per my expectation. Hope someone can
    vaibhav> explain to me this behaviour:
    ...


    Yes, your default arg is evaluated once, at method definition time and
    shared betwee all instances of MyClass. See the thread last week on the
    same thing for more detail.

    Skip

    Comment

    • Larry Bates

      #3
      Re: Default argument to __init__

      This comes up on the list about once a week on this list.

      See:


      -Larry Bates

      netvaibhav@gmai l.com wrote:[color=blue]
      > Hi All:
      >
      > Here's a piece of Python code and it's output. The output that Python
      > shows is not as per my expectation. Hope someone can explain to me this
      > behaviour:
      >
      >
      Code:
      > class MyClass:
      >         def __init__(self, myarr=[]):
      >                 self.myarr = myarr
      >
      > myobj1 = MyClass()
      > myobj2 = MyClass()
      >
      > myobj1.myarr += [1,2,3]
      >
      > myobj2.myarr += [4,5,6]
      >
      > print myobj1.myarr
      > print myobj2.myarr
      >
      >
      > The output is:
      > [1, 2, 3, 4, 5, 6]
      > [1, 2, 3, 4, 5, 6]
      >
      > Why do myobj1.myarr and myobj2.myarr point to the same list? The
      > default value to __init__ for the myarr argument is [], so I expect
      > that every time an object of MyClass is created, a new empty list is
      > created and assigned to myarr, but it seems that the same empty list
      > object is assigned to myarr on every invocation of MyClass.__init_ _
      >
      > It this behaviour by design? If so, what is the reason, as the
      > behaviour I expect seems pretty logical.
      >
      > Thanks.
      >
      > Vaibhav
      >[/color]

      Comment

      • Steve Holden

        #4
        Re: Default argument to __init__

        netvaibhav@gmai l.com wrote:[color=blue]
        > Hi All:
        >
        > Here's a piece of Python code and it's output. The output that Python
        > shows is not as per my expectation. Hope someone can explain to me this
        > behaviour:
        >
        >
        Code:
        > class MyClass:
        >         def __init__(self, myarr=[]):
        >                 self.myarr = myarr
        >
        > myobj1 = MyClass()
        > myobj2 = MyClass()
        >
        > myobj1.myarr += [1,2,3]
        >
        > myobj2.myarr += [4,5,6]
        >
        > print myobj1.myarr
        > print myobj2.myarr
        >
        >
        > The output is:
        > [1, 2, 3, 4, 5, 6]
        > [1, 2, 3, 4, 5, 6]
        >
        > Why do myobj1.myarr and myobj2.myarr point to the same list? The
        > default value to __init__ for the myarr argument is [], so I expect
        > that every time an object of MyClass is created, a new empty list is
        > created and assigned to myarr, but it seems that the same empty list
        > object is assigned to myarr on every invocation of MyClass.__init_ _
        >
        > It this behaviour by design? If so, what is the reason, as the
        > behaviour I expect seems pretty logical.
        >[/color]
        The default value of the keyword argument is evaluated once, at function
        declaration time. The idiom usually used to avoid this gotcha is:

        def __init__(self, myarr=None):
        if myarr is None:
        myarr = []

        This ensures each call with the default myarr gets its own list.

        regards
        Steve
        --
        Steve Holden +44 150 684 7255 +1 800 494 3119
        Holden Web LLC www.holdenweb.com
        PyCon TX 2006 www.python.org/pycon/

        Comment

        • Fredrik Lundh

          #5
          Re: Default argument to __init__

          "netvaibhav@gma il.com" wrote:
          [color=blue]
          > Here's a piece of Python code and it's output. The output that Python
          > shows is not as per my expectation. Hope someone can explain to me this
          > behaviour:[/color]

          /snip/
          [color=blue]
          > Why do myobj1.myarr and myobj2.myarr point to the same list? The
          > default value to __init__ for the myarr argument is [], so I expect
          > that every time an object of MyClass is created, a new empty list is
          > created and assigned to myarr, but it seems that the same empty list
          > object is assigned to myarr on every invocation of MyClass.__init_ _
          >
          > It this behaviour by design?[/color]

          it's explained in the FAQ:



          it's also mentioned in chapter 4 of the tutorial:



          "*Important warning*: The default value is evaluated only once. This
          makes a difference when the default is a mutable object such as a list,
          dictionary, or instances of most classes. "

          (the text then illustrates this with examples, and shows how to do things
          instead)

          and in the description of "def" in the language reference:



          "*Default parameter values are evaluated when the function definition
          is executed*. This means that the expression is evaluated once, when the
          function is defined, and that that same "pre-computed" value is used for
          each call. This is especially important to understand when a default para-
          meter is a mutable object, such as a list or a dictionary: if the function
          modifies the object (e.g. by appending an item to a list), the default
          value is in effect modified."

          (the text then shows how to do things instead)
          [color=blue]
          > If so, what is the reason, as the behaviour I expect seems pretty logical.[/color]

          that only means that you don't fully understand what "def" does (hint: it's
          a statement, not a compiler directive).

          </F>



          Comment

          • Dennis Lee Bieber

            #6
            Re: Default argument to __init__

            On 10 Oct 2005 07:50:12 -0700, netvaibhav@gmai l.com declaimed the
            following in comp.lang.pytho n:
            [color=blue]
            > Hi All:
            >
            > Here's a piece of Python code and it's output. The output that Python
            > shows is not as per my expectation. Hope someone can explain to me this
            > behaviour:
            >
            > [code]
            > class MyClass:
            > def __init__(self, myarr=[]):
            > self.myarr = myarr[/color]

            Python Reference Manual section 7.5 (on my install at least)

            """
            Default parameter values are evaluated when the function definition is
            executed. This means that the expression is evaluated once, when the
            function is defined, and that that same ``pre-computed'' value is used
            for each call. This is especially important to understand when a default
            parameter is a mutable object, such as a list or a dictionary: if the
            function modifies the object (e.g. by appending an item to a list), the
            default value is in effect modified. This is generally not what was
            intended. A way around this is to use None as the default, and
            explicitly test for it in the body of the function, e.g.:

            def whats_on_the_te lly(penguin=Non e):
            if penguin is None:
            penguin = []
            penguin.append( "property of the zoo")
            return penguin
            """
            --[color=blue]
            > =============== =============== =============== =============== == <
            > wlfraed@ix.netc om.com | Wulfraed Dennis Lee Bieber KD6MOG <
            > wulfraed@dm.net | Bestiaria Support Staff <
            > =============== =============== =============== =============== == <
            > Home Page: <http://www.dm.net/~wulfraed/> <
            > Overflow Page: <http://wlfraed.home.ne tcom.com/> <[/color]

            Comment

            Working...