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

Reply via email to