default value for __init__ doesn't work

Discussion in 'Python' started by 人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶, Sep 11, 2010.

  1. Please look at below code snippet:
    class test():
    def __init__(self, a, dic={}):
    self.a = a
    self.dic = dic
    print('__init__ params:',a, dic)

    def get(self):
    self.dic[1] = 2
    self.dic[4] = 5

    def foo():
    print('in foo function')
    bar = test(1)
    bar.get()

    if __name__ == '__main__':
    foo()
    foo()
    -----------------------
    Result:
    in foo function
    __init__ params: 1 {}
    in foo function
    __init__ params: 1 {1: 2, 4: 5}

    But my expect result is :
    in foo function
    __init__ params: 1 {}
    in foo function
    __init__ params: 1 {}

    it seems that the default value for dic doesn't work on the second
    call for the class test.
    It's wired. Who can give a explaination for this scenario?
     
    人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶, Sep 11, 2010
    #1
    1. Advertising

  2. On Sat, Sep 11, 2010 at 12:38 AM, 人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶ <> wrote:
    > Please look at below code snippet:
    > class test():
    >    def __init__(self, a, dic={}):
    >        self.a = a
    >        self.dic = dic
    >        print('__init__ params:',a, dic)
    >



    This is a pretty popular mistake to make. Default arguments aren't
    evaluated when you call the method. They're created when the method is
    created (meaning when you first run the file and the class itself is
    defined), and that's it. Because you do self.dic = dic, this means
    that every instance of the object will receive the same dict object.
    Change it for one object, and the change will show up in all of them.
    The solution to this is to use a sentinel value, like None

    def __init__(self, a, dic=None) :
    if dic is None :
    self.dic = {}
    else :
    self.dic = dic

    If None is a valid value for the parameter, make a sentinel object and use that

    sentinel = object()
    def __init__(self, a, dic=sentinel) :
    if dic is sentinel : #you want to use is here, not ==
    ...
     
    Benjamin Kaplan, Sep 11, 2010
    #2
    1. Advertising

  3. On Sep 11, 1:14 pm, Benjamin Kaplan <> wrote:
    > On Sat, Sep 11, 2010 at 12:38 AM, 人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶ <> wrote:
    > > Please look at below code snippet:
    > > class test():
    > >    def __init__(self, a, dic={}):
    > >        self.a = a
    > >        self.dic = dic
    > >        print('__init__ params:',a, dic)

    >
    > This is a pretty popular mistake to make. Default arguments aren't
    > evaluated when you call the method. They're created when the method is
    > created (meaning when you first run the file and the class itself is
    > defined), and that's it. Because you do self.dic = dic, this means
    > that every instance of the object will receive the same dict object.
    > Change it for one object, and the change will show up in all of them.
    > The solution to this is to use a sentinel value, like None
    >
    > def __init__(self, a, dic=None) :
    >     if dic is None :
    >         self.dic = {}
    >     else :
    >         self.dic = dic
    >
    > If None is a valid value for the parameter, make a sentinel object and use that
    >
    > sentinel = object()
    > def __init__(self, a, dic=sentinel) :
    >     if dic is sentinel : #you want to use is here, not ==
    >       ...


    Got it. Thanks for point out my mistake. You are very nice.
     
    人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶, Sep 11, 2010
    #3
  4. On Sep 11, 1:55 pm, 人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶ <> wrote:
    > On Sep 11, 1:14 pm, Benjamin Kaplan <> wrote:
    >
    >
    >
    > > On Sat, Sep 11, 2010 at 12:38 AM, 人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶ <> wrote:
    > > > Please look at below code snippet:
    > > > class test():
    > > >    def __init__(self, a, dic={}):
    > > >        self.a = a
    > > >        self.dic = dic
    > > >        print('__init__ params:',a, dic)

    >
    > > This is a pretty popular mistake to make. Default arguments aren't
    > > evaluated when you call the method. They're created when the method is
    > > created (meaning when you first run the file and the class itself is
    > > defined), and that's it. Because you do self.dic = dic, this means
    > > that every instance of the object will receive the same dict object.
    > > Change it for one object, and the change will show up in all of them.
    > > The solution to this is to use a sentinel value, like None

    >
    > > def __init__(self, a, dic=None) :
    > >     if dic is None :
    > >         self.dic = {}
    > >     else :
    > >         self.dic = dic

    >
    > > If None is a valid value for the parameter, make a sentinel object and use that

    >
    > > sentinel = object()
    > > def __init__(self, a, dic=sentinel) :
    > >     if dic is sentinel : #you want to use is here, not ==
    > >       ...

    >
    > Got it. Thanks for point out my mistake. You are very nice.


    I remember the same issue was occurred in my C++ program. There I have
    a function with a parameter referenced a default object . May be C++
    also constructs the the default arguments before the function is
    called.
    Thank you again to help me so much!
     
    人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶, Sep 11, 2010
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Steven Bethard
    Replies:
    2
    Views:
    472
    Steven Bethard
    Feb 16, 2005
  2. Replies:
    5
    Views:
    365
    Dennis Lee Bieber
    Oct 10, 2005
  3. Kent Johnson
    Replies:
    7
    Views:
    933
    Jan Niklas Fingerle
    Feb 12, 2006
  4. kenneth

    default value in __init__

    kenneth, Oct 9, 2008, in forum: Python
    Replies:
    38
    Views:
    879
    Bruno Desthuilliers
    Oct 20, 2008
  5. Ramchandra Apte
    Replies:
    17
    Views:
    357
    Manuel Pégourié-Gonnard
    Sep 30, 2012
Loading...

Share This Page