From: Luke Paireepinart Date: 08/17/06 02:29:01 To: Kermit Rose Cc: tutor@python.org Subject: Re: [Tutor] All of Kermit's E-Mails [was: Global Variables] >>> I really dislike the way you reply. Follow the standard format! Leave all the greater-than signs before the previous person's reply so that it will be structured correctly and easy to read. All of this star business is bad. ************* Suggest an alternative, because my email program does not insert the > sign like the standard email program does. I also prefer the standard format, and the first few times I replied in email I typed in all the > in front of each line. After a while I decided that I should find some alternative equivalent that took less time. >>> Okay. >From this it appears that you have no academic training in programming. The term 'side-effect' means that something outside the scope of the called function is modified by the called function. Here is a very basic example. #--- test.py a = ['a','b','c'] def modify_list(alist): del(alist[0]) modify_list(a) modify_list(a) print a #--- #--- output of test.py ['c'] #--- ******************** >From your example: You haven't declared any variable global. does a = [a',b'c'] implicitly declare the variable "a" to be global because it is not inside a function definition? I did not know Python syntax would permit statements to not be inside some function definition. I see that modify_list deletes the zero'th element. The structure of my factor functions are such that this type of mistake could not happen. If I knew how, I would follow up Alan's suggestion of making the module into a class. >>> Now remember that in Python, when you pass a variable to a function, only the reference is passed to the function. Imagine that variables are themselves references (which they are.) a = ['a','b','c'] creates the following picture: a ------> ['a','b','c'] modify_list(a) doesn't do modify_list(['a','b','c']) it does modify_list(ptr) where ptr ------> ['a','b','c'] <----- a they both refer to the same object ( a python list containing three characters.) now when in the body of modify_list we say del(alist[0]), what takes place is the index operator, [0], says 'what object is the variable 'alist' pointing to? and python says 'alist ----> ['a','b','c'] <---- a' so when we delete the element out of alist we're also deleting the element out of the calling function's list. This is probably NOT desired behavior. As such it's an unwanted side-effect. ******************* This confuses me. Isn't the calling functions list [a',b',c'} ? Therefore, wouldn't the resultt of modify_list(a) be [b',c']? That's what I would expect it to be and what I would want it to do. >>> A function printing to the screen is also considered a side-effect. Anything a function does that affects anything outside of its own scope is considered a side-effect. ***************** Ok. Why is this bad. If I'm using global variables, this would be exactly what I would want. But I don't insist on using global variables. The idea of making a factor class appeals to me. I haven't yet learned how. .>>> To refresh your memory, here's the next part of the e-mail I'm going to address: >The names have very little to do with it, the danger of global >variable >use is the reliance on side-effects and the tight coupling that you >introduce between the calling module and the called module. >Changes to the state of the calling module in an unpredictable >manner lead to subtle bugs which are extremely hard to see and fix. >***** >What do you mean by tight coupling? >The only change I can see that would lead to a bug would be if I changed the >name of the global variable in >the calling routine and not in the function it called. >I would know not to do that. 'tight coupling' is an English phrase meaning roughly (for our purposes) 'close interaction' or 'dependence on each other.' you say, I quote: 'The only change ... that would lead to a bug would be if I changed the name of the global variable in the calling routine.' I think you're misunderstanding Alan. consider this following example (it was hard to come up with something this convoluted) #--- start code def b(): global has_been_greeted has_been_greeted = False print "function B is doing lots of stuff" return "whatever we did in function B that's so important" def greet(): global has_been_greeted if has_been_greeted: print 'we already greeted you.' else: print 'hello!' has_been_greeted = True def c(): print "function C is doing lots of stuff." a = b() print "function C is using value a here." b() greet() greet() c() greet() # --- end code. Now we know we're going to call b() every time on startup, so we set has_been_greeted to false inside of it. Then we call greet, once b() is done calculating its stuff, so it will greet the customer. Then we call greet again to make sure that we already greeted them. (say we're debugging our program and we want to make sure greet's working correctly.) Now we call function C, which relies on function b to get a value that it needs for one of its calculations. Oops, we forgot that b() resets has_been_greeted back to false every time it's called. Now when we call greet after function c again, it greets them again! But it's already greeted them so it shouldn't have greeted them. Now imagine this is much more complicated and there are multiple global variables that you're setting all over the place to store your values, and then imagine trying to find something this obscure. A much more straightforward way to do this would be: #--- start code def b(): print "function B is doing lots of stuff" return "whatever we did in function B that's so important" def greet(): print 'hello!' def c(): print "function C is doing lots of stuff." a = b() print "function C is using value a here." b() greet() has_been_greeted = True if has_been_greeted == False: greet() c() if has_been_greeted == False: greet() #--- I know this was a stupid example but it's all I could come up with. does it help you see how global variables could give you trouble? Maybe Alan can fix my example so it makes more sense. ************************* I believe I understand your example. Basically you are saying that if my module becomes sufficiently complicated, I may lose track of how I use the global variables and violate my preset rules for how to use them. >>> I see here you started using Greater-than signs to separate the Original Post from your replies. WTF. RTFM. This is almost as bad as before. **************** Please suggest an alternative that is relatively quick to compensate for my email program, Incredimail, which does not have an option to insert the > in from of each line of the original post. >>> Now I don't have the additional stress of trying to sort out who is speaking at any given time, you or the person you're replying to, but I have these big columns of multi-colored lines to deal with. In my e-mail client, Thunderbird, it converts every > sign to a vertical line of a different color, so I can tell the different levels of replies in any given e-mail. This is super-helpful, unless something like this comes along, and all it does is space out all the messages a tremendous amount and look ugly. Why can't you just use the convention and leave the >> things there? They're there for a reason. Don't fix somethin' that ain't broke, please. *********** Unfortunately, in my email client, Incredimail, it is broken. Thanks for telling me the effect of the > sign in your email client, Thunderbird. I changed all my long lines of > signs to exactly three > signs on a line. >>> No, it's not that global variables are not implemented correctly. You must understand that there are thousands of people using Python every day, and phrases like 'not implemented correctly' or 'there's a bug in python' are converted in my ears to '*i'm complaining because i can't get my program to work*' It's identical, to me, as when I'm playing Counter-Strike and someone starts
yelling 'HACKER!' every time they get killed. ******* :) Yes. I understand your response. >>> It's ____much____ more likely that the person is just good at Counter-Strike than they're cheating, especially since there are a lot of anti-cheat measures. It's ____much____ more likely that your program has a bug than Python itself because there is a lot of quality-control when a programming language is used frequently by many very skilled coders. **************** Well, I would not have claimed a possible bug in Python if I could see how my code could possibly have been responsible for a variable to have one value in the called function, and have a different value when it's returned to the calling function. >>> Alan is being diplomatic here. I would not call what you sent 'documentation.' The tangled mess of your functions doesn't prove there's a bug in python, it just makes me think you messed up the value somewhere along the way. ****************** Suggest a way for me to make more clear what is happening. >>> What Alan means is that your program incorrectly handles certain data values because your functions aren't written correctly. Your first thought when your program doesn't do what you expect it to should not be to blame the return statement of being buggy, but to first blame yourself. It's much more likely that you're at fault. I'm not saying this directly at you. If I wrote a function that returned incorrect values, I would assume it's my fault too. ******** Indeed. I first seek to find the error in my code. Only after I proved that the variable changed in value between just before the return statement in the called routine and after its reception in the calling routine did I suggest that there may be a bug in Python. >>> You have to understand that Python has been used for years and if there was such a fundamental bug, no matter how obscure (only occuring on certain return values), it would have been found by now. ***** I would have expected so also. That is why this strange behavior surprised me. >>> Because it's impractical to search for a certain type of error it must not be that error? Just dwell on that statement a bit and tell me if you still believe it. >The error is occuring between the return statement in the called function >and the picking up of that value >in the calling function. so show us. This is the way I would prove this, if it were my program that uncovered this 'bug.' #--- def func_that_causes_bug(a): print "function is doing a bunch of complex calculations and such." v = 2322**a c = 55/float(v) d = v - a + 543 value = d / 45 print "this is where the problem arises." print "Before I return the value, it is :%s" % value return value tmp = func_that_causes_bug(564) print "And after I return the value, it is :%s" % tmp #--- ***** That is exactly what I did!!!! >>> Do you understand why this would evidence the bug you mentioned? You say it's a problem with the returning of the value. So print the value immediately before the return and immediately after. We'll see if it changes in transit as you claim. ***** Yes. That is exactly what I did!!! >>> >Can you post actual code to illustrate the problem? Don't post your >entire module; just show us the functions involved, the input that >causes the problem, and what output you expect to get. >-- >John. > >******* > >Here is the output that illustratrates the problem. After the output I'll >list the code for the called function, >strongfac, > >and the calling function, fermat. [snip a ton of debug output.] This doesn't help us at all. What the heck was all that? You must understand that I have no idea what your function is supposed to do. Treat me like a child. Explain everything to me. What part of this output isn't what you wanted? *********** Huh? That "ton of debug output" is exactly what you said you wanted. So perhaps we should take a closer look at it. Perhaps we should talk in private email a few times to get the output that is generated more readable to you and the others. >>> ># def strongfac(z,w): ># x = gcd(z,w-1) ># if x > 1: ># if x < z: >[snip the rest of strongfac] ># def fermat(z,maxdiff,pmap,plist,sqlist,sqresidue,torials,limitsteps): ># for j in range(2,3): ># print " " ># print " Try to find factors by using power of ",j," mod z as a >[snip the rest of fermat] Why the CRAP did you put # signs before every line? I spent about 10 minutes pressing delete, down-arrow, delete, down-arrow. Going through all that trouble just so I could run the code was a pain in the rear. ****** Either my email program or your email program removes leading blanks. Putting a # in column 1 is one way to transmit the code in a way that preserves the indentation. Suggest an alternative way of transmitting code. >>> Remember when we were talking about UI usability earlier? Your code usability would be greatly improved if I didn't have to remove a comment from every line to test it. ****** What does UI mean? Could you construct a program to delete column 1 from each line? Perhaps such a program already exist in the editor. >>> Also, in your example call: >IDLE 1.1.2 > >>> import factor34 > >>> from factor34 import testrange > >>> testrange(10**14+37,10**14+37) You called testrange. Now John originally said 'show us which functions are involved.' Well, after I had gone through the trouble of un-commenting all your code, it turned out that I didn't even have all the pieces there. So I went back in e-mail history and downloaded the attached 'factor34.py' file. Now I wish I didn't have to do this, because you could've made improvements in it since then. But it's the only way I can get a functional test file. Turns out testrange depends on x depends on y depends on z depends on ..... basically all of the functions in the module depend on each other. This is obviously a case for ... .dun-dun-dun!.... object-oriented programming. When you have a collection of functions that all operate together to create something, you make a Class to contain them. I think just in the process of doing this you might learn what's wrong with your program. *** I am quite willing to make a Class to contain them, after I learn how. And perhaps, after we rewrite my module as a class, the strange behavior will change, perhaps it won't. If the strange behavior does not change, then it should be easier tracing what is happening. >>> Link me to all the Wikipedia articles I need in order to understand what you're trying to do. I'll help you rewrite this program from scratch if you want. We'll make it object-oriented the whole way. But there is no hope I will understand factor34. I will not even try. ***** Thanks very much. I will be glad to get your help making my module into a class. I don't know what information you might need to understand what I'm trying to do. So, if we get started converting to object oriented format, then we may figure out what Wikipedia articles might be useful. >>> Sorry if I was too harsh anywhere along the way. Feel free to point any of this out and I'll apologize. But this is my honest opinion of the e-mails I've received from you so far. ****** No problem. I value honesty. >>> I don't think this is a good programming project for you to be learning a new language with. Perhaps you should do something simpler. If you'd like some recommendations I'd be happy to give some. *** This project is important to me, independently of my need to learn Python well. >>> Have a good day. -Luke **** Thank you very much. Kermit Rose < [EMAIL PROTECTED] > _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor