looking for explanations... globals dynamic dict

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

looking for explanations... globals dynamic dict

kirby urner-4

One of my Python students alerted me to this state of affairs.

I understand that what globals( ) returns will fluctuate as new names come and go.

What I less understand is why g isn't just a *snap shot* of what was global at the time globals( ) ran.

Now it's just a dictionary like any other (and yes, it contains itself, as another global).

So when I go to print its items, why should it care that the names k and v have been added.

Why isn't g just a static dictionary?

I guess because it's tied to a callable that gets re-executed whenever g is used.  g.items( ) is like globals( ).items( ) -- another call.


>>> g = globals()
>>> g
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, 'g': {...}, '__package__': None}
>>> len(g)
5
>>> for k, v in g.items():  print(k, v)

__builtins__ <module 'builtins' (built-in)>
Traceback (most recent call last):
  File "<pyshell#156>", line 1, in <module>
    for k, v in g.items():  print(k, v)
RuntimeError: dictionary changed size during iteration
>>> g
{'g': {...}, '__builtins__': <module 'builtins' (built-in)>, 'k': '__builtins__', '__package__': None, 'v': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None}
>>> len(g)
7
>>>


Oh no, not again....

>>> for t,v in g.items():  print(t,v)

g {'g': {...}, '__builtins__': <module 'builtins' (built-in)>, 'k': '__builtins__', '__package__': None, 't': 'g', 'v': {...}, '__name__': '__main__', '__doc__': None}
Traceback (most recent call last):
  File "<pyshell#160>", line 1, in <module>
    for t,v in g.items():  print(t,v)
RuntimeError: dictionary changed size during iteration

This seems to solve the problem:

>>> ================================ RESTART ================================
>>> g = dict(globals())
>>> g
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
>>> for t,v in g.items():  print(t,v)

__builtins__ <module 'builtins' (built-in)>
__name__ __main__
__doc__ None
__package__ None


This behavior still seems a little peculiar.

>>> help(globals)
Help on built-in function globals in module builtins:

globals(...)
    globals() -> dictionary
   
    Return the dictionary containing the current scope's global variables.



_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

John Zelle
Hello,

Isn't the issue here simply that globals does not return a copy of the globals dictionary, it returns THE actual globals dictionary. It's not some sort of callable, it is the globals dictionary, period. There is no such thing as a static dictionary, they are mutable, and this one changes every time you define a new variable. For example, try:

>>> g = globals()
>>> g['k'] = 3
>>> k
3

So when you assign to new variables, this globals dictionary is changing, and that leads to the iteration error. As long as you iterate using existing variables, there is no problem.

>>> g = globals()
>>> k = None
>>> v = None
>>> for k,v in g.items():
...     print k,v
...
g {'g': {...}, '__builtins__': <module '__builtin__' (built-in)>, 'k': 'g', '__package__': None, 'v': {...}, '__name__': '__main__', '__doc__': None}
__builtins__ <module '__builtin__' (built-in)>
k None
__package__ None
v None
__name__ __main__
__doc__ None


--John

 

From: edu-sig-bounces+john.zelle=[hidden email] [edu-sig-bounces+john.zelle=[hidden email]] on behalf of kirby urner [[hidden email]]
Sent: Monday, March 28, 2011 1:19 PM
To: [hidden email]
Subject: [Edu-sig] looking for explanations... globals dynamic dict


One of my Python students alerted me to this state of affairs.

I understand that what globals( ) returns will fluctuate as new names come and go.

What I less understand is why g isn't just a *snap shot* of what was global at the time globals( ) ran.

Now it's just a dictionary like any other (and yes, it contains itself, as another global).

So when I go to print its items, why should it care that the names k and v have been added.

Why isn't g just a static dictionary?

I guess because it's tied to a callable that gets re-executed whenever g is used.  g.items( ) is like globals( ).items( ) -- another call.


>>> g = globals()
>>> g
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, 'g': {...}, '__package__': None}
>>> len(g)
5
>>> for k, v in g.items():  print(k, v)

__builtins__ <module 'builtins' (built-in)>
Traceback (most recent call last):
  File "<pyshell#156>", line 1, in <module>
    for k, v in g.items():  print(k, v)
RuntimeError: dictionary changed size during iteration
>>> g
{'g': {...}, '__builtins__': <module 'builtins' (built-in)>, 'k': '__builtins__', '__package__': None, 'v': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None}
>>> len(g)
7
>>>


Oh no, not again....

>>> for t,v in g.items():  print(t,v)

g {'g': {...}, '__builtins__': <module 'builtins' (built-in)>, 'k': '__builtins__', '__package__': None, 't': 'g', 'v': {...}, '__name__': '__main__', '__doc__': None}
Traceback (most recent call last):
  File "<pyshell#160>", line 1, in <module>
    for t,v in g.items():  print(t,v)
RuntimeError: dictionary changed size during iteration

This seems to solve the problem:

>>> ================================ RESTART ================================
>>> g = dict(globals())
>>> g
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
>>> for t,v in g.items():  print(t,v)

__builtins__ <module 'builtins' (built-in)>
__name__ __main__
__doc__ None
__package__ None


This behavior still seems a little peculiar.

>>> help(globals)
Help on built-in function globals in module builtins:

globals(...)
    globals() -> dictionary
   
    Return the dictionary containing the current scope's global variables.



_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

mdipierro
In python variables assigned to dict and list are always references.

>>> a = {}
>>> b = a  # b and a point to the same dictionary
>>> b['key'] = 'value'
>>> print a['key']
value

primitive types like integers behave differently

>>> a = 1
>>> b = a  # b and a are two different 1s
>>> b+=2
>>> print a
1

You can copy the objects copied by a reference

>>> a = {}
>>> import copy
>>> b = copy.deepcopy(a)  # b is a complete copy of a (also objects in keys and values are copied recursively)
>>> b['key'] = 'value'
>>> print a['key']
KeyError





On Mar 28, 2011, at 2:15 PM, John Zelle wrote:

Hello,

Isn't the issue here simply that globals does not return a copy of the globals dictionary, it returns THE actual globals dictionary. It's not some sort of callable, it is the globals dictionary, period. There is no such thing as a static dictionary, they are mutable, and this one changes every time you define a new variable. For example, try:

>>> g = globals()
>>> g['k'] = 3
>>> k
3

So when you assign to new variables, this globals dictionary is changing, and that leads to the iteration error. As long as you iterate using existing variables, there is no problem.

>>> g = globals()
>>> k = None
>>> v = None
>>> for k,v in g.items():
...     print k,v
... 
g {'g': {...}, '__builtins__': <module '__builtin__' (built-in)>, 'k': 'g', '__package__': None, 'v': {...}, '__name__': '__main__', '__doc__': None}
__builtins__ <module '__builtin__' (built-in)>
k None
__package__ None
v None
__name__ __main__
__doc__ None


--John

 

From: [hidden email] [[hidden email]] on behalf of kirby urner [[hidden email]]
Sent: Monday, March 28, 2011 1:19 PM
To: [hidden email]
Subject: [Edu-sig] looking for explanations... globals dynamic dict


One of my Python students alerted me to this state of affairs.

I understand that what globals( ) returns will fluctuate as new names come and go.

What I less understand is why g isn't just a *snap shot* of what was global at the time globals( ) ran.

Now it's just a dictionary like any other (and yes, it contains itself, as another global).

So when I go to print its items, why should it care that the names k and v have been added.

Why isn't g just a static dictionary?

I guess because it's tied to a callable that gets re-executed whenever g is used.  g.items( ) is like globals( ).items( ) -- another call.


>>> g = globals()
>>> g
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, 'g': {...}, '__package__': None}
>>> len(g)
5
>>> for k, v in g.items():  print(k, v)

__builtins__ <module 'builtins' (built-in)>
Traceback (most recent call last):
  File "<pyshell#156>", line 1, in <module>
    for k, v in g.items():  print(k, v)
RuntimeError: dictionary changed size during iteration
>>> g
{'g': {...}, '__builtins__': <module 'builtins' (built-in)>, 'k': '__builtins__', '__package__': None, 'v': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None}
>>> len(g)
7
>>> 


Oh no, not again....

>>> for t,v in g.items():  print(t,v)

g {'g': {...}, '__builtins__': <module 'builtins' (built-in)>, 'k': '__builtins__', '__package__': None, 't': 'g', 'v': {...}, '__name__': '__main__', '__doc__': None}
Traceback (most recent call last):
  File "<pyshell#160>", line 1, in <module>
    for t,v in g.items():  print(t,v)
RuntimeError: dictionary changed size during iteration

This seems to solve the problem:

>>> ================================ RESTART ================================
>>> g = dict(globals())
>>> g
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
>>> for t,v in g.items():  print(t,v)

__builtins__ <module 'builtins' (built-in)>
__name__ __main__
__doc__ None
__package__ None


This behavior still seems a little peculiar.

>>> help(globals)
Help on built-in function globals in module builtins:

globals(...)
    globals() -> dictionary
    
    Return the dictionary containing the current scope's global variables.


_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig


_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

kirby urner-4
In reply to this post by John Zelle
Good hearing from you John.

It's interesting to compare globals( ) with dir( ).  That latter is affected by
the new names in a for loop but doesn't reflect these changes until
later, whereas globals( ) raises an exception.

The globals dict seems an unusual beast.  Interesting recursivity too.

>>> g = globals()
>>> g['g']['g']['g']['g']['g']['g']['g']['g']['g']
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, 'g': {...}, '__package__': None}

I call it "flat recursivity" in that we're not looking at successive frames on some stack.

Hmmm, just stumbled upon (is "recursivity" a word?):  http://recursed.blogspot.com/

Kirby


>>> ================================ RESTART ================================
>>> g = dict(globals())
>>> g
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
>>> for t,v in g.items():  print(t,v)

__builtins__ <module 'builtins' (built-in)>
__name__ __main__
__doc__ None
__package__ None
>>> help(globals)
Help on built-in function globals in module builtins:

globals(...)
    globals() -> dictionary
   
    Return the dictionary containing the current scope's global variables.

>>> d = dir()
>>> for v in d:  print(v)

__builtins__
__doc__
__name__
__package__
g
t
v
>>> ================================ RESTART ================================
>>> d = dir()
>>> for v in d:  print(v)

__builtins__
__doc__
__name__
__package__
>>> g = globals()
>>> for v in g:  print(v)

d
g
__builtins__
__package__
v
__name__
__doc__
>>> ================================ RESTART ================================
>>> g = globals()
>>> for v in g:  print(v)

__builtins__
Traceback (most recent call last):
  File "<pyshell#178>", line 1, in <module>
    for v in g:  print(v)
RuntimeError: dictionary changed size during iteration
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'g', 'v']
>>> ================================ RESTART ================================
>>> d = dir()
>>> for v in d:  print(v)

__builtins__
__doc__
__name__
__package__
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'd', 'v']
>>>


_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

Laura Creighton-2
In reply to this post by kirby urner-4
In a message of Mon, 28 Mar 2011 11:19:45 PDT, kirby urner writes:
>--===============0915739999==
>Content-Type: multipart/alternative; boundary=20cf303b3f9bfa4ea5049f8efcd

>What I less understand is why g isn't just a *snap shot* of what was global
>at the time globals( ) ran.

Because you didn't bind g to a copy of the global dictionary at time t.
You bound it to the global dictionary itself.

Laura
_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

kirby urner-4
On Mon, Mar 28, 2011 at 1:29 PM, Laura Creighton <[hidden email]> wrote:
In a message of Mon, 28 Mar 2011 11:19:45 PDT, kirby urner writes:
>--===============0915739999==
>Content-Type: multipart/alternative; boundary=20cf303b3f9bfa4ea5049f8efcd

>What I less understand is why g isn't just a *snap shot* of what was global
>at the time globals( ) ran.

Because you didn't bind g to a copy of the global dictionary at time t.
You bound it to the global dictionary itself.

Laura


Yes, and the contents of that dict change as a side effect of assignment in the global namespace.

When I bind to dir( ) at time t, there's no mutating dict on the other end of the line, just a snap shot.

>>> ================================ RESTART ================================
>>> d = dir()
>>> d
['__builtins__', '__doc__', '__name__', '__package__']
>>> v = 14
>>> d
['__builtins__', '__doc__', '__name__', '__package__']
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'd', 'v']

Kirby


_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

Carl Cerecke-4
In reply to this post by mdipierro
On 29 March 2011 08:28, Massimo Di Pierro <[hidden email]> wrote:

primitive types like integers behave differently

>>> a = 1
>>> b = a  # b and a are two different 1s
>>> b+=2
>>> print a
1



Well, not really. Although I see what you are trying to say.

numbers (like strings) are immutable. There can ever be only one number 1. You can't change a number to something else. If add 5 to 3, the number 3 doesn't change, I get a new number, 8.

with "a = 1", python is still using a reference to an object. You can see this because ints have methods:
>>> a = 1
>>> a.__add__
<method-wrapper '__add__' of int object at 0x009ADD38>
>>> a.__add__(5)
6
>>> a
1


After a 'b = a' statement, b and a point to the same object (in this case, the one at 0x009ADD38):

>>> b = a
>>> b.__add__
<method-wrapper '__add__' of int object at 0x009ADD38>
>>>

Remember,  the object that both b and a reference is immutable. It's the number 1. You can't change the number one to be some other number. If you then do 'b += 2', python calculates the result of the expression 'b + 2', which is 3, and then changes b's reference to point to the object representing the int 3.

Cheers,
Carl.


_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

Laura Creighton-2
In a message of Tue, 29 Mar 2011 09:59:40 +1300, Carl Cerecke writes:
>Well, not really. Although I see what you are trying to say.

>numbers (like strings) are immutable. There can ever be only one number 1
>You can't change a number to something else. If add 5 to 3, the number 3
>doesn't change, I get a new number, 8.

This is merely an implementation detail.

Python 2.6.6
Type "help", "copyright", "credits" or "license" for more information.
>>> w = 1
>>> y = 1      
>>> w is y  # this might surprise you
True

[PyPy 1.4.1]
Type "help", "copyright", "credits" or "license" for more information.

>>>> w = 1
>>>> y = 1
>>>> w is y # or are you so used to CPython that this surprises you?
False

You can have as many number ones as you like.  In CPython they are
cached to be the same object, but you shouldn't rely on that behaviour.
It's actually pretty dodgy to test the object identity on immutable
objects -- unless you want to surprise people like I tried to.

Incidentally

Python 2.6.6
Type "help", "copyright", "credits" or "license" for more information.
>>> w = 5234
>>> y = 5324    
>>> w is y  
False

so after a certain point, the CPython developers have decided that the
performance gains of cacheing all number xs as the same x isn't worth
it.

Laura


_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

Michael H. Goldwasser


On Monday March 28, 2011, Laura Creighton wrote:

>    In a message of Tue, 29 Mar 2011 09:59:40 +1300, Carl Cerecke writes:
>    >Well, not really. Although I see what you are trying to say.
>    
>    >numbers (like strings) are immutable. There can ever be only one number 1
>    >You can't change a number to something else. If add 5 to 3, the number 3
>    >doesn't change, I get a new number, 8.
>    
>    This is merely an implementation detail.

Note well that the issue has changed since the original post.  The
question at the time concerned the following code

>>> a = 1
>>> b = a  # b and a are two different 1s

Carl correctly points out that b and a are not two different 1s in
this case. The assignment statment of a = b has the same semantics for
integers as it does for any other data type.  a and b become aliases
for the same underlying instance.  On any platform, it will be the
case that

>>> a is b
True

folowing that assignment.  The original misunderstanding involved the
semantics of b += 2; that command does not mutate the underlying
instance, but re-associates the identifier b to a new value (while a
remains associated with the value 1).

In your reply, the code fragment (below) shows a different issue
regarding the re-use of integer literals in source code (as you
assigned b=1 rather than b=a).  In that case, it is system-dependent
whether the interpretter uses different instances or the same
instance, and you are right that there is no guarantee that equivalent
instances will be identical instances.

With regard,
Michael

>    
>    Python 2.6.6
>    Type "help", "copyright", "credits" or "license" for more information.
>    >>> w = 1
>    >>> y = 1      
>    >>> w is y  # this might surprise you
>    True
>    
>    [PyPy 1.4.1]
>    Type "help", "copyright", "credits" or "license" for more information.
>    
>    >>>> w = 1
>    >>>> y = 1
>    >>>> w is y # or are you so used to CPython that this surprises you?
>    False
>    
>    You can have as many number ones as you like.  In CPython they are
>    cached to be the same object, but you shouldn't rely on that behaviour.
>    It's actually pretty dodgy to test the object identity on immutable
>    objects -- unless you want to surprise people like I tried to.
>    
>    Incidentally
>    
>    Python 2.6.6
>    Type "help", "copyright", "credits" or "license" for more information.
>    >>> w = 5234
>    >>> y = 5324    
>    >>> w is y  
>    False
>    
>    so after a certain point, the CPython developers have decided that the
>    performance gains of cacheing all number xs as the same x isn't worth
>    it.
>    
>    Laura

+-----------------------------------------------
| Michael H. Goldwasser, Ph.D.
| Associate Professor
| Director of Computer Science
| Dept. Mathematics and Computer Science
| Saint Louis University
| 220 North Grand Blvd.
| St. Louis, MO 63103-2007
|
| Office: Ritter Hall 108
| Email:  [hidden email]
| URL:    http://cs.slu.edu/~goldwasser
| Phone:  (314) 977-7039
| Fax:    (314) 977-1452

_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

Carl Cerecke-4
In reply to this post by Laura Creighton-2
Yes. Laura, you're correct. I'll try again:

Massimo was trying to say that after:
a = 1
b = a

b and a refer to *different* 'one's because changing one of them (b += 2) doesn't change the other.

This isn't true. They refer to the same 'one' object (regardless of python implementation). b += 2 doesn't change the 'one' object, but simply points b to a 'three' object.

There. How's that?

Carl.

On 29 March 2011 10:25, Laura Creighton <[hidden email]> wrote:
In a message of Tue, 29 Mar 2011 09:59:40 +1300, Carl Cerecke writes:
>Well, not really. Although I see what you are trying to say.

>numbers (like strings) are immutable. There can ever be only one number 1
>You can't change a number to something else. If add 5 to 3, the number 3
>doesn't change, I get a new number, 8.

This is merely an implementation detail.

Python 2.6.6
Type "help", "copyright", "credits" or "license" for more information.
>>> w = 1
>>> y = 1
>>> w is y  # this might surprise you
True

[PyPy 1.4.1]
Type "help", "copyright", "credits" or "license" for more information.

>>>> w = 1
>>>> y = 1
>>>> w is y # or are you so used to CPython that this surprises you?
False

You can have as many number ones as you like.  In CPython they are
cached to be the same object, but you shouldn't rely on that behaviour.
It's actually pretty dodgy to test the object identity on immutable
objects -- unless you want to surprise people like I tried to.

Incidentally

Python 2.6.6
Type "help", "copyright", "credits" or "license" for more information.
>>> w = 5234
>>> y = 5324
>>> w is y
False

so after a certain point, the CPython developers have decided that the
performance gains of cacheing all number xs as the same x isn't worth
it.

Laura




_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

Laura Creighton-2
In a message of Tue, 29 Mar 2011 11:49:08 +1300, Carl Cerecke writes:

>--20cf307abcff67e7bc049f92c049
>Content-Type: text/plain; charset=ISO-8859-1
>
>Yes. Laura, you're correct. I'll try again:
>
>Massimo was trying to say that after:
>a = 1
>b = a
>
>b and a refer to *different* 'one's because changing one of them (b += 2)
>doesn't change the other.
>
>This isn't true. They refer to the same 'one' object (regardless of pytho
>n
>implementation). b += 2 doesn't change the 'one' object, but simply point
>s b
>to a 'three' object.
>
>There. How's that?
>
>Carl.

Incorrect, I think.  When I am talking about 'the same 'one' object',
what I mean is not some sort of philosophical one-ness, some Platonic
ideal of one, which like all the numbers, is a singleton, wherever it
occurs in the universe.  I mean something much more concrete than
that.  Somewhere in my computer are addressable pieces of memory, and
in those locations are values.  When I say that two variables are
bound to the same object I mean they refer to that exact same piece of
memory right there.  (We will ignore, for the purpose of this
discussion, issues related to garbage collectors that move objects
around.  Because its the job of the gc writer to make sure that after
the collection happens, all of those references to the old memory
location all point to the new memory location.  So the location is
different, but the property that all variables bound to the same object
get the same location in memory remains true.)

Consider what happens when your memory goes bad.  Stray alpha particle, or
(more likely) just a bad bit of memory.

I've typed:

>>> w = 1
>>> y = 1  
>>> z = 1

suddenly, a bit of memory goes bad, the chunk that w is bound to. Instead
of containing 1, it contains 2.

What happens?
Well, in CPython, w is now bound to the value 2.  So is y and z.  And
I will bet that CPython will fall over and die a horrible death.  All
the places where it internally uses the value '1' will get the wrong
value.  But this is an implementation detail.

But in PyPy, when the chunk that w is bound to goes bad, y and z, which
were bound to entirely different pieces of memory, still have good values
in them.  Assuming that w is not something that PyPy uses internally, it
is entirely possible that things could go on seemingly fine.  Should w
be in the code you typed at an interactive PyPy interpreter, you may be
amazed and perplexed when you type:

>>>> w = 1  # that memory location goes bad right now!
>>>> w + w
4

Not the result you expected.  You'd complain pypy was broken, and if
it kept happening (i.e. it was a bug, not bad memory) you'd be correct.

---------------
What I think you are trying to say is that you cannot change the values of
immutable objects.  Which is very true. (Barring disasters with bad memory
and alpha particles and the like.)  But this has nothing to do with how
many immutable objects share the same value.  It has to do with the fact
that you cannot mutate immutable objects.  

>>>> a = 1
>>>> a = 2
>>>> a = "horseradish"

All I have done is changed a's bindings.  No walking out to memory, making a
chunk of it mean '1', and binding a to it, then walking about again, finding
the same bit of memory, and scribbling on it so it means '2', and then
walking out and scribbling on it to mean 'horseradish'.  That doesn't
happen.  

as opposed to:

>>>> a = [1]
>>>> b = a
>>>> a.append(2)
>>>> b
[1, 2]

a.append(2) really did walk out into memory, find the bit that a was bound
to, and scribbled on it so that where it once said [1] it now says [1, 2]
Since b is bound to the same bit of memory, it changes too.

Laura






_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

kirby urner-4
On Mon, Mar 28, 2011 at 5:02 PM, Laura Creighton <[hidden email]> wrote:

 
Incorrect, I think.  When I am talking about 'the same 'one' object',
what I mean is not some sort of philosophical one-ness, some Platonic
ideal of one, which like all the numbers, is a singleton, wherever it
occurs in the universe.  I mean something much more concrete than
that. 

 
Loved your really explicit and detailed reply there Laura. 

On a student quiz I'd write "Good and complete answer!".

Kirby

Footnote to Plato:

Not being a Platonist in the sense of nominalist (the two schools are
usually counter-posed, but not here), I don't see a need for some
"essential meaning" of "oneness". 

Lots of partially overlapping use cases bearing a family resemblance
to one another is sufficient to anchor one's meaning.


_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

Carl Cerecke-4
In reply to this post by Laura Creighton-2
At the risk of boring the other readers....

Yes. You are right. But so was I (on the second time around):

a=1
b=1

a and b could refer to the same object or different objects with the same value. It depends on implementation details. I agree here.

a=1
b=a

a and b refer to the *same* object here regardless of implementation. Massimo said they were different, because b+= 2 doesn't change a. That statement is incorrect.

That's really all I was trying to say. I wasn't trying to be philsophical about Platonic singleness in the universe or whatever.

Cheers,
Carl.

On 29 March 2011 13:02, Laura Creighton <[hidden email]> wrote:
In a message of Tue, 29 Mar 2011 11:49:08 +1300, Carl Cerecke writes:
>--20cf307abcff67e7bc049f92c049
>Content-Type: text/plain; charset=ISO-8859-1
>
>Yes. Laura, you're correct. I'll try again:
>
>Massimo was trying to say that after:
>a = 1
>b = a
>
>b and a refer to *different* 'one's because changing one of them (b += 2)
>doesn't change the other.
>
>This isn't true. They refer to the same 'one' object (regardless of pytho
>n
>implementation). b += 2 doesn't change the 'one' object, but simply point
>s b
>to a 'three' object.
>
>There. How's that?
>
>Carl.

Incorrect, I think.  When I am talking about 'the same 'one' object',
what I mean is not some sort of philosophical one-ness, some Platonic
ideal of one, which like all the numbers, is a singleton, wherever it
occurs in the universe.  I mean something much more concrete than
that.  Somewhere in my computer are addressable pieces of memory, and
in those locations are values.  When I say that two variables are
bound to the same object I mean they refer to that exact same piece of
memory right there.  (We will ignore, for the purpose of this
discussion, issues related to garbage collectors that move objects
around.  Because its the job of the gc writer to make sure that after
the collection happens, all of those references to the old memory
location all point to the new memory location.  So the location is
different, but the property that all variables bound to the same object
get the same location in memory remains true.)

Consider what happens when your memory goes bad.  Stray alpha particle, or
(more likely) just a bad bit of memory.

I've typed:

>>> w = 1
>>> y = 1
>>> z = 1

suddenly, a bit of memory goes bad, the chunk that w is bound to. Instead
of containing 1, it contains 2.

What happens?
Well, in CPython, w is now bound to the value 2.  So is y and z.  And
I will bet that CPython will fall over and die a horrible death.  All
the places where it internally uses the value '1' will get the wrong
value.  But this is an implementation detail.

But in PyPy, when the chunk that w is bound to goes bad, y and z, which
were bound to entirely different pieces of memory, still have good values
in them.  Assuming that w is not something that PyPy uses internally, it
is entirely possible that things could go on seemingly fine.  Should w
be in the code you typed at an interactive PyPy interpreter, you may be
amazed and perplexed when you type:

>>>> w = 1  # that memory location goes bad right now!
>>>> w + w
4

Not the result you expected.  You'd complain pypy was broken, and if
it kept happening (i.e. it was a bug, not bad memory) you'd be correct.

---------------
What I think you are trying to say is that you cannot change the values of
immutable objects.  Which is very true. (Barring disasters with bad memory
and alpha particles and the like.)  But this has nothing to do with how
many immutable objects share the same value.  It has to do with the fact
that you cannot mutate immutable objects.

>>>> a = 1
>>>> a = 2
>>>> a = "horseradish"

All I have done is changed a's bindings.  No walking out to memory, making a
chunk of it mean '1', and binding a to it, then walking about again, finding
the same bit of memory, and scribbling on it so it means '2', and then
walking out and scribbling on it to mean 'horseradish'.  That doesn't
happen.

as opposed to:

>>>> a = [1]
>>>> b = a
>>>> a.append(2)
>>>> b
[1, 2]

a.append(2) really did walk out into memory, find the bit that a was bound
to, and scribbled on it so that where it once said [1] it now says [1, 2]
Since b is bound to the same bit of memory, it changes too.

Laura








_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

Re: looking for explanations... globals dynamic dict

Laura Creighton-2
In a message of Tue, 29 Mar 2011 13:27:20 +1300, Carl Cerecke writes:

>Yes. You are right. But so was I (on the second time around):
>
>a=1
>b=1
>
>a and b could refer to the same object or different objects with the same
>value. It depends on implementation details. I agree here.
>
>a=1
>b=a
>
>a and b refer to the *same* object here regardless of implementation.
>Massimo said they were different, because b+= 2 doesn't change a. That
>statement is incorrect.
>
>That's really all I was trying to say. I wasn't trying to be philsophical
>about Platonic singleness in the universe or whatever.
>
>Cheers,
>Carl.

Ok.  I still found the way you said that confusing. Sorry about that.

Laura
_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig
Reply | Threaded
Open this post in threaded view
|

looking for explanations... globals dynamic dict

kirby urner-4
In reply to this post by Michael H. Goldwasser
On Mon, Mar 28, 2011 at 3:23 PM, Michael H. Goldwasser <[hidden email]> wrote:


Note well that the issue has changed since the original post.  The
question at the time concerned the following code


Not to quibble, but the issue of the *original* post had to do with 
assignments (such as those below) dynamically mutating an 
"environment dict" named globals().

What this function returns varies moment to moment as a side 
effect of new assignment operations top level, or deletions.

dir(), on the other hand, returns a snapshot, a "static" list
(not that lists are static in the sense of immutable -- not 
what I meant).

One could imagine a globals() that *did* return a snapshot, 
as dict(globals()) does.

>>> g = dict(globals())
>>> for k,v in g.items(): print(k,v, sep=":")  # no problemo

__builtins__:<module 'builtins' (built-in)>
__name__:__main__
__doc__:None
__package__:None



>>> a = 1
>>> b = a  # b and a are two different 1s

Carl correctly points out that b and a are not two different 1s in
this case. The assignment statment of a = b has the same semantics for
integers as it does for any other data type.  a and b become aliases
for the same underlying instance.  On any platform, it will be the
case that

>>> a is b
True

folowing that assignment.  

Very true and related to Python's bias against unnecessary 
copying, making copy (as a verb) live inside its own module
(like in a dog house) not even present as a built-in.

This is because names are light and airy whereas the objects
they name on the heap may be gargantuan, in terms of 
resources used.  

green = Giant( ); red = green should not inadvertently 
cause two instances of Giant, with copying a side effect 
of assignment.  

As a language, Python is refreshingly consistent about 
not doing that.
 
The original misunderstanding involved the
semantics of b += 2; that command does not mutate the underlying
instance, but re-associates the identifier b to a new value (while a
remains associated with the value 1).

Likewise I get students talking about how "hello world".upper( )
is "transforming" a string, whereas more accurately its 
returning a new string instance that's based on "hello world"
-- like transcribing DNA, building a protein.

So is "transcribing" to go back to inadvertent copying?  

No, because a = "hello world"; b = a.upper( ) is about 
creating two different strings, each with its own name.

No copies here.
 

In your reply, the code fragment (below) shows a different issue
regarding the re-use of integer literals in source code (as you
assigned b=1 rather than b=a).  In that case, it is system-dependent
whether the interpretter uses different instances or the same
instance, and you are right that there is no guarantee that equivalent
instances will be identical instances.

>>> (17 + 1) is 18
True

>>> 8243985209384708709180298734 is (8243985209384708709180298733 + 1)
False

Implementation details...

Kirby
 

With regard,
Michael

>
>    Python 2.6.6
>    Type "help", "copyright", "credits" or "license" for more information.
>    >>> w = 1
>    >>> y = 1
>    >>> w is y  # this might surprise you
>    True
>
>    [PyPy 1.4.1]
>    Type "help", "copyright", "credits" or "license" for more information.
>
>    >>>> w = 1
>    >>>> y = 1
>    >>>> w is y # or are you so used to CPython that this surprises you?
>    False

 



_______________________________________________
Edu-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/edu-sig