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 |
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 |
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:
_______________________________________________ Edu-sig mailing list [hidden email] http://mail.python.org/mailman/listinfo/edu-sig |
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 |
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 |
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: 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 |
In reply to this post by mdipierro
On 29 March 2011 08:28, Massimo Di Pierro <[hidden email]> wrote:
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 |
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 |
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 |
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:
_______________________________________________ Edu-sig mailing list [hidden email] http://mail.python.org/mailman/listinfo/edu-sig |
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 |
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', 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 |
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: _______________________________________________ Edu-sig mailing list [hidden email] http://mail.python.org/mailman/listinfo/edu-sig |
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 |
In reply to this post by Michael H. Goldwasser
On Mon, Mar 28, 2011 at 3:23 PM, Michael H. Goldwasser <[hidden email]> wrote:
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
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 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.
>>> (17 + 1) is 18 True >>> 8243985209384708709180298734 is (8243985209384708709180298733 + 1)
False Implementation details... Kirby
_______________________________________________ Edu-sig mailing list [hidden email] http://mail.python.org/mailman/listinfo/edu-sig |
Free forum by Nabble | Edit this page |