default value for __init__ doesn't work

  • Thread starter 人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶
  • Start date
Ä

人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶

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?
 
B

Benjamin Kaplan

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 ==
...
 
Ä

人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶

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.
 
Ä

人言è½æ—¥æ˜¯å¤©æ¶¯ï¼Œæœ›æžå¤©æ¶¯ä¸è§å®¶

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!
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top