Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

function call questions

142 views
Skip to first unread message

chenyo...@gmail.com

unread,
Oct 18, 2016, 3:36:26 AM10/18/16
to
Hi,
I got a function call as this:

>>>def add_to_tree(root,value_string):
... print "root is %s, value_string is %s" % (root, value_string)
... for ch in value_string:
... print "ch is %s" % ch
... root = root.setdefault(ch,{})
... print "root is", root
... print "tree is", tree
...
>>> tree={}
>>> txt='abc'
>>> add_to_tree(tree,txt)
root is {}, value_string is abc
ch is a
root is {}
tree is {'a': {}}
ch is b
root is {}
tree is {'a': {'b': {}}}
ch is c
root is {}
tree is {'a': {'b': {'c': {}}}}

My question is:
(1) why root is always {}?
(2) why tree is {'a': {'b': {'c': {}}}}?
(3) why root isn't the same as tree? shouldn't they be the same because tree is argument passed as root?


regards
skyworld

Peter Otten

unread,
Oct 18, 2016, 4:16:34 AM10/18/16
to
Because that's what you bind it to in the line

> ... root = root.setdefault(ch,{})

See <https://docs.python.org/dev/library/stdtypes.html#dict.setdefault>
for a description of the the setdefault() method.

> (2) why tree is {'a': {'b': {'c': {}}}}?

Basically the same answer -- you bind root to the innermost dict and that's
where you insert the ch key on the next iteration of the for loop
.
> (3) why root isn't the same as tree? shouldn't they be the same because
> tree is argument passed as root?

You should know the answer by now ;)

Anssi Saari

unread,
Oct 18, 2016, 5:13:57 AM10/18/16
to
chenyo...@gmail.com writes:

> My question is:
> (1) why root is always {}?

Because that's what you wrote. root.setdefault(ch, {}) returns {} and
you assign that to root. You probably want to do just
root.setdefault(ch, {}) instead of root = root.setdefault(ch, {}).

> (2) why tree is {'a': {'b': {'c': {}}}}?

That I don't know. Seems odd to me. From some debugging it seems that
after root = root.setdefault(ch,{}) tree['a'] and root are the same
object. So on the second round your code calls
tree['a'].setdefault('b',{}) and on the third round
tree['a'].setdefault('c',{}) which results in {'a': {'b': {'c': {}}}} as
the value of tree.

> (3) why root isn't the same as tree? shouldn't they be the same because tree is argument passed as root?

They are the same until you bind root to a new object with root =
root.setdefault(ch,{}).

chenyo...@gmail.com

unread,
Oct 18, 2016, 5:28:42 AM10/18/16
to
> > My question is:
> > (1) why root is always {}?
>
> Because that's what you bind it to in the line
>
> > ... root = root.setdefault(ch,{})
>
> See <https://docs.python.org/dev/library/stdtypes.html#dict.setdefault>
> for a description of the the setdefault() method.

I'm still confused here. root.setdefault(ch,{}) should return {'a':{}}, right? then this dictionary is referenced by root by "root = root.setdefault(ch,{})". why root is an empty dictionary now?


>
> > (2) why tree is {'a': {'b': {'c': {}}}}?
>
> Basically the same answer -- you bind root to the innermost dict and that's
> where you insert the ch key on the next iteration of the for loop
> .
> > (3) why root isn't the same as tree? shouldn't they be the same because
> > tree is argument passed as root?
>
> You should know the answer by now ;)

In fact i'm still confused by these answers. Could you please described more? thanks

Peter Otten

unread,
Oct 18, 2016, 5:52:28 AM10/18/16
to
chenyo...@gmail.com wrote:

>> > My question is:
>> > (1) why root is always {}?
>>
>> Because that's what you bind it to in the line
>>
>> > ... root = root.setdefault(ch,{})
>>
>> See <https://docs.python.org/dev/library/stdtypes.html#dict.setdefault>
>> for a description of the the setdefault() method.
>
> I'm still confused here. root.setdefault(ch,{}) should return {'a':{}},
> right?

No. Try with something you can recognize (all empty dicts look the same; you
have to use id() to tell them apart):

>>> d = {1.0: "one"}
>>> d.setdefault(1, "ONE")
'one'
>>> d
{1.0: 'one'}
>>> d.setdefault(2, "TWO")
'TWO'
>>> d
{1.0: 'one', 2: 'TWO'}

setdefault() always returns the value, not the whole dict; if the first
argument doesn't already exist as a key in the dict the second argument
becomes the value of the new entry.

chenyo...@gmail.com

unread,
Oct 18, 2016, 10:15:23 PM10/18/16
to
Thanks Peter and Anssi for your kind help. Now I'm ok with the first question. But the second question still confused me. Why "it seems that
after root = root.setdefault(ch,{}) tree['a'] and root are the same
object" and follows tree['a']['b']? Thanks.

MRAB

unread,
Oct 18, 2016, 11:46:28 PM10/18/16
to
You call the .setdefault method with a key and a default value.

The .setdefault method does this: if the key is in the dict, it returns
the associated value, else it puts the key and the default into the dict
and then returns the default.

chenyo...@gmail.com

unread,
Oct 19, 2016, 2:30:18 AM10/19/16
to
在 2016年10月19日星期三 UTC+8上午11:46:28,MRAB写道:
thanks for the reply. I understand this. I'm now confused on why tree got its magic result.

Peter Otten

unread,
Oct 19, 2016, 3:17:18 AM10/19/16
to
Perhaps it is easier to understand if you rewrite the function without
setdefault()?

def add_to_tree(root, value_string):
print "root is %s, value_string is %s" % (root, value_string)
for ch in value_string:
print "ch is %s" % ch
if ch not in root: # always true if the root arg is an empty dict
root[ch] = {}
root = root[ch] # inside the function the inner dict becomes the new
# root
print "root is", root

chenyo...@gmail.com

unread,
Oct 19, 2016, 10:37:03 PM10/19/16
to
在 2016年10月19日星期三 UTC+8下午3:17:18,Peter Otten写道:
please forgive my stupid. I still can't follow this.

Frank Millman

unread,
Oct 20, 2016, 1:32:18 AM10/20/16
to
wrote in message
news:5506e4d8-bd1d-4e56...@googlegroups.com...

在 2016年10月19日星期三 UTC+8下午3:17:18,Peter Otten写道:
> chenyo...@gmail.com wrote:
>
> > 在 2016年10月19日星期三 UTC+8上午11:46:28,MRAB写道:
> >> On 2016-10-19 03:15, chenyo...@gmail.com wrote:
> >> > Thanks Peter and Anssi for your kind help. Now I'm ok with the first
> >> > question. But the second question still confused me. Why "it seems
> >> > that
> >> > after root = root.setdefault(ch,{}) tree['a'] and root are the same
> >> > object" and follows tree['a']['b']? Thanks.
> >> >

> please forgive my stupid. I still can't follow this.

Let's see if I can explain. I am using 't' and 'r' instead of 'tree' and
'root', but otherwise it is the same as your original example.

>>> t = {}
>>> r = t
>>> id(t)
2542235910088
>>> id(r)
2542235910088

At this point, t and r are both references to the same empty dictionary.

>>> r = r.setdefault('a', {})

This has done two things.

It has inserted the key 'a' into the dictionary, and set its value to {}.

>>> t
{'a': {}}
>>> id(t)
2542235910088

It has also rebound 'r' so that it now references the new empty dictionary
that has been inserted.

>>> r
{}
>>> id(r)
2542234429896
>>>t['a']
{}
>>> id(t['a'])
2542234429896

Now continue this process with r = r.setdefault('b', {}), and watch what
happens.

Hopefully this will help you to understand. Feel free to ask further if not
sure.

Frank Millman


chenyo...@gmail.com

unread,
Oct 20, 2016, 9:39:02 AM10/20/16
to
在 2016年10月20日星期四 UTC+8下午1:32:18,Frank Millman写道:
Hi Frank,

thanks very much for your kind help. Your reply is clear. But I'm hindered by those you've not explained.

I'm always confused by "r = r.setdefault('a', {})". when the first loop finished, as what you have pointed out,
> >>> t
> {'a': {}}
> >>> r
> {}

Then next "r = r.setdefault('b', {})" will run again. Here what is "r" in "r.setdefault('b',{})"? According to final result, it should be "t['a']", which I can't understand. I thought the command is r.setdefault, so it should still be last "r", i.e., empty {}. Could you please let me know what I missed? thanks.

Frank Millman

unread,
Oct 20, 2016, 11:04:38 AM10/20/16
to
wrote in message
news:01cfd810-0561-40b1...@googlegroups.com...

在 2016年10月20日星期四 UTC+8下午1:32:18,Frank Millman写道:
> wrote in message
> news:5506e4d8-bd1d-4e56...@googlegroups.com...
>
> thanks very much for your kind help. Your reply is clear. But I'm hindered
> by those you've not explained.
>
> I'm always confused by "r = r.setdefault('a', {})". when the first loop
> finished, as what you have pointed out,
> > >>> t
> > {'a': {}}
> > >>> r
> > {}
>
> Then next "r = r.setdefault('b', {})" will run again. Here what is "r" in
> "r.setdefault('b',{})"? According to final result, it should be "t['a']",
> which I can't understand. I thought the command is r.setdefault, so it
> should still be last "r", i.e., empty {}. Could you please let me know
> what I missed? thanks.

Firstly, I want to explain more clearly what I am doing here.

Instead of running your loop 3 times, I am running your command three times
one step at a time (though I only showed the first one).

>>> t = {}
>>> r = t
>>> r = r.setdefault('a', {})
>>> r = r.setdefault('b', {})
>>> r = r.setdefault('c', {})

This should give exactly the same result as your loop. The benefit of
running it this way is that you can check the values after each step.

May I suggest that you do this, and try to understand the contents of 't'
and 'r' at each point. If you are still unsure, let us know at which point
the values are not what you expect, and I will try to explain further.

It is important that you understand that you are rebinding 'r' at each step,
so after each command, 'r' is no longer referencing the same object that it
was referencing in the previous step.

To see the difference, try running it it this way -

>>> t = {}
>>> r = t
>>> r.setdefault('a', {})
>>> r.setdefault('b', {})
>>> r.setdefault('c', {})

Hope this helps.

Frank


Anssi Saari

unread,
Oct 21, 2016, 3:10:35 AM10/21/16
to
"Frank Millman" <fr...@chagford.com> writes:

> Let's see if I can explain. I am using 't' and 'r' instead of 'tree'
> and 'root', but otherwise it is the same as your original example.
>
>>>> t = {}
>>>> r = t
>>>> id(t)
> 2542235910088
>>>> id(r)
> 2542235910088
>
> At this point, t and r are both references to the same empty dictionary.
>
>>>> r = r.setdefault('a', {})
>
> This has done two things.
>
> It has inserted the key 'a' into the dictionary, and set its value to {}.
>
>>>> t
> {'a': {}}
>>>> id(t)
> 2542235910088
>
> It has also rebound 'r' so that it now references the new empty
> dictionary that has been inserted.

I guess this is where I fell of the wagon previously. I got it now.

>>>> r
> {}
>>>> id(r)
> 2542234429896
>>>>t['a']
> {}
>>>> id(t['a'])
> 2542234429896
>
> Now continue this process with r = r.setdefault('b', {}), and watch
> what happens.

OK, so what happens is that now t references the dictionary with
{'a': {}} and r references the empty dict inside that. So when we assign to r
again, it's the empty dict inside t (the one accessed by key 'a') that
changes to {'b': {}} and t becomes {'a': {'b': {}}}.

Frank Millman

unread,
Oct 21, 2016, 3:44:20 AM10/21/16
to
"Anssi Saari" wrote in message news:vg3wph2...@coffee.modeemi.fi...

> OK, so what happens is that now t references the dictionary with
{'a': {}} and r references the empty dict inside that. So when we assign to
r
again, it's the empty dict inside t (the one accessed by key 'a') that
changes to {'b': {}} and t becomes {'a': {'b': {}}}.

Yup, you have got it :-)

Frank


chenyo...@gmail.com

unread,
Oct 22, 2016, 4:39:16 AM10/22/16
to
在 2016年10月20日星期四 UTC+8下午11:04:38,Frank Millman写道:
Hi Frank,

thanks for your kind help. What confused me is at this line:

> >>> r = r.setdefault('b', {})

and its previous one

> >>> r = r.setdefault('a', {})

When r.setdefault('a',{}) is run, I understand it will return an empty {}. At this time both r & t reference to {'a':{}}, right? So when "r = r.setdefault('a',{})" is run, r reference to {} while t keeps the same as {'a':{}}.

then comes r.setdefault('b',{}). What hinder me is here. since r has changed its reference to {}, r.setdefault('b',{}) will return {} again. So what does this done to t? why at this time t changes to {'a':'b':{}}? Sorry for my silly here. Thanks


Frank Millman

unread,
Oct 22, 2016, 5:06:22 AM10/22/16
to
wrote in message
news:2853d778-857e-46fc...@googlegroups.com...

在 2016年10月20日星期四 UTC+8下午11:04:38,Frank Millman写道:
> wrote in message
> news:01cfd810-0561-40b1...@googlegroups.com...
>
> Hi Frank,
>
> thanks for your kind help. What confused me is at this line:
>
> >>> r = r.setdefault('b', {})
>
> and its previous one
>
> >>> r = r.setdefault('a', {})
>
> When r.setdefault('a',{}) is run, I understand it will return an empty {}.
> At this time both r & t reference to {'a':{}}, right? So when "r =
> r.setdefault('a',{})" is run, r reference to {} while t keeps the same as
> {'a':{}}.
>
> then comes r.setdefault('b',{}). What hinder me is here. since r has
> changed its reference to {}, r.setdefault('b',{}) will return {} again. So
> what does this done to t? why at this time t changes to {'a':'b':{}}?
> Sorry for my silly here. Thanks
>

I don't know if you have been following the other posts in this thread.

There were some posts from Anssi Saari who was also confused by this, but
then yesterday he sent a post saying that he has now 'got it'.

I don't think I can do better than quote his explanation of what is
happening -

"""
OK, so what happens is that now t references the dictionary with {'a': {}}
and r references the empty dict inside that.

So when we assign to r again, it's the empty dict inside t (the one accessed
by key 'a') that changes to {'b': {}} and t becomes {'a': {'b': {}}}.
"""

That is exactly right.

Does that help?

Frank


chenyo...@gmail.com

unread,
Oct 22, 2016, 8:26:17 AM10/22/16
to
在 2016年10月22日星期六 UTC+8下午5:06:22,Frank Millman写道:
Hi Frank,

I have read Anssi's post already before I sent the post. To be frankly, I can't understand why he got the right answer. I'm sorry for my silly. "So when we assign to r again, it's the empty dict inside t (the one accessed
by key 'a')". I do can't understand why this happens. that is the reason why I have asked for this once again and again. There must be some import point I missed but I don't what is it.

Frank Millman

unread,
Oct 22, 2016, 9:15:06 AM10/22/16
to
wrote in message
news:9c91a4cf-1f3e-43b3...@googlegroups.com...

> I have read Anssi's post already before I sent the post. To be frankly, I
can't understand why he got the right answer. I'm sorry for my silly. "So
when we assign to r again, it's the empty dict inside t (the one accessed
by key 'a')". I do can't understand why this happens. that is the reason why
I have asked for this once again and again. There must be some import point
I missed but I don't what is it.

Let's try this -

>>> t = {}
>>> r = t
>>> r = r.setdefault('a', {})
>>> t
{'a': {}}

I think you are happy up to this point.

We now have three objects -

"t" is a dictionary
'a' is a key in the dictionary
{} is the value associated with the key 'a' in "t"

I think you are happy up to this point.

The question is, what is "r"?

Before the assignment, "r" was a reference to the dictionary referenced by
"t".

After the assignment, "r" no longer refers to "t". It is now a reference to
the
third object listed above, the {} that is the value associated with the key
'a'.

>>> t
{'a': {}}
>>> t['a']
{}
>>> r
{}
>>> t['a] is r
True

Keep looking at this until it sinks in. "r" and "t['a']" are *the same
object*. We just have two ways of accessing it.

Try adding some key/values to the empty dictionary -

>>> r['x'] = 99
>>> r
{'x': 99}
>>> t['a']
{'x': 99}
>>> t
{'a': {'x': 99}}

I will pause at this point, and give you a moment to absorb that.

Hopefully, the penny will drop and everything will become clear.

If not, let us know which of the above steps you do not understand.

Good luck - keep plugging away, and you will get there :-)

Frank

P.S. I assume you understand that the lines prefixed with '>>>' are to be
entered while in the python interpreter. It is really important that you
type these lines in yourself and examine the results.


chenyo...@gmail.com

unread,
Oct 23, 2016, 9:29:50 AM10/23/16
to
在 2016年10月22日星期六 UTC+8下午9:15:06,Frank Millman写道:
Hi Frank,

I got it this time. Thanks very much for your help. I thought r is an empty dictionary without any connection to t before. Now I know that happened. Thanks.


regards
skyworld
0 new messages