Greg Ewing wrote:
> Isidor wrote:
> >
> > ##def date_time_stamp(self):
> > def date_time_stamp():
>
> I think the first version of that line was better.
> If it's a method of a class, it'll need a self
> argument. That would account for the "No arguments
> expected" exception - it's being called with one
> argument (self) but it's not expecting any.
Hello Greg -
Thanks for responding to my query. I also thought that having "self"
in there would help. I didn't think this because I knew what I was
doing, but, because like a good monkey, I see that most funcs in a
class have a "self" argument, so I figured, yup, better try it out.
Unfortunately, it didn't work. In fact, it brought up an "odd" error:
case 1: using: def date_time_stamp(self): ...generates...
>>> Exception in Tkinter callback
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764, in
__call__
return apply(self.func, args)
TypeError: too many arguments; expected 1, got 2
Why do I call it an "odd" error message? Well, because to the
untrained eye (e.g., mine) the previous error message is completely
at odds with the following message:
case 2: using def date_time_stamp(): ...generates...
>>> Exception in Tkinter callback
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764, in
__call__
return apply(self.func, args)
TypeError: no arguments expected
To me it sounds as if in case 1, when I gave an argument, it said I
gave too many while in case 2, when I didn't give an argument, it
said it didn't want any. (Kind of like life?..;)
But of course, what's wrong here is my totally ass-backwards
interpretation of the error messages. I would never have figured this
out if it hadn't been for an email sent to me personally by a kind
gent who shall go unnamed here (he is being bcc'ed (hello and
thanks!) (am i correct in assuming that a private emailer does not
want public acknowledgment?)). He wrote:
::::::::::::::::::::
You seem to have done everything right (I don't use TKInter enough to
help with the real debugging), then ignored the information in the
exception...
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764, in
__call__
return apply(self.func, args)
TypeError: no arguments expected
Which is trying to say: "Tkinter tried to call a function with too
many arguments"
So...
def date_time_stamp( *args, **namedargs)
:::::::::::::::::
Since at the time I understood nothing about the uses of *args,
**namedargs , I did not understand his clue. Thanks to some recent
posts and replies discussing these argument-passing-methods, I have a
better grip on what's happening here. So, with a little time on my
hands (yeah, right ;), I did a simple copy and paste from his
message, and voila, it worked. I was able to pass through the
function definition and into the interior of the function. He wasn't
giving me a *clue*, he was giving me the freakin' *answer*! (Again,
thanks.)
error messages, a newbie's eye-view:
So now that it works, I am looking back, trying to reinterpret the
error messages to fit with reality...not my ass-backwards version of
them.
case 1: def blah(self):
error: too many arguments; expected 1, got 2
case 2: def blah():
error: no arguments expected
It seems to me that the error message is being "spoken" by the
"receiving" function (i.e., the "blah" func). In case 1, it is set up
to handle one argument, but gets more than that and balks. In case 2,
it is set up to handle no arguments, gets some, and balks. You see, I
was thinking that the error was being "spoken" by something *after*
the function had been defined (um, I have mentioned several times
that I'm new at this, right?;)...so that whatever was being invoked
after the def statement was balking in a very strange way...telling
me that no arguments were expected when I didn't *give* it any
arguments. Maybe this would have been clearer to me if the error
message in case 2 were (similar to the error message in case 1): "too
many arguments; expected 0, got 2", then I would have realized that
both errors were variations on a theme rather than opposites. Of
course, this new interpretation could be totally wrong too. If that
is the case, I hope someone will point it out to me.
One thing I don't really understand here is why it is necessary to
raise an exception when an argument is passed to a function that
isn't prepared to handle it. If the argument is needed *inside* the
function, I could understand an exception being raised then (e.g.,
"hey, where's my argument"), but in my case i'm doing nothing (or at
least I *think* I'm doing nothing) with those arguments. Why do I
need to make a "landing strip" for them? To add more metaphors to the
blender, something about this reminds me of the trick of putting a
potato in a car exhaust pipe. If the exhaust has nowhere to go, it
backs up until nothing can move in or out of cylinders and the motor
dies (or at least it did in Beverly Hills Cop...or whatever that
Eddie Murphy movie was). So, maybe by allowing the unused arguments
to pass through my function, everything flows nicely and nothing gets
stopped up. Hmm, strange. Am I on basically the right track here with
this idea?
Understanding the "self" ("the toughest thing of all" - stated in a
philosophy of science seminar on reflexivity i once attended):
So, anyway, what did I have inside that function? Well, basically
just some test code to see if I was getting that far:
print "cheese"
It worked, but poorly. It pushed whatever text was already on the
line (at the command prompt) on to the next line and jumped to the
front of the line. Hmm. I suspected that using "print" was like using
a sledgehammer where a scalpel was needed. Scanning through the other
functions in EditorWindow.py, I saw a lot of things being done to/by
self.text. In the init constructor, I saw that "self.text =
Text(...lots of arguments that would make sense for a text widget
type thing...)", and I realized, aha, "text" must be the arena in
which we are actually playing when using IDLE. So, then I wondered,
what "methods" does "text" provide me to insert text? I looked at the
Tkinter text man page and found a section on insert that looked
reasonably like what I wanted to do, but it didn't look anything like
what I was seeing in EditorWindow.py (to me, at least). So then I id
a "Find in Files..." (oh my, what a wonderful feature!) for
text.insert in the idle files and found a nice example in line 51 of
Autoexpand.py. Something like:
self.text.insert("insert", newwords)
My guess is that insert is a method of text, and "insert" (first
argument) is the location of the insertion point and will be the
location where the second argument gets injected into "text". So,
just for kicks, I copied that line into my newly-functioning def,
changed "newwords" to "timestr" (which contained the date-time string
I wanted), and tried it out. (I suspected it wasn't going to work,
but I wanted to try anyway.)
case 3:
def date_time_stamp( *args, **namedargs):
timestr = ...stuff...
self.text.insert("insert", timestr)
>>> Exception in Tkinter callback
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764,
in __call__
return apply(self.func, args)
File "C:\PROGRA~1\PYTHON15\TOOLS\IDLE\EditorWindow.py", line 586,
in date_time_stamp
self.text.insert("insert", timestr)
NameError: self
I was curious: I wanted to know whether a function inside a class
could automatically see the methods and attributes of that class.
Well, this error message makes me think that the answer is no. Self
has to be "created" in the arguments of the function. Ok, so now I'm
starting to understand *why* everyone always says you have to have
"self" as the first argument. But, I wondered, maybe "self" doesn't
work here because I haven't created it within the context of this
func, but "text" would be recognized because it is created in the
class that houses the func. So I tried the following (hey, give me a
break, I'm a newbie! ;) :
case 4:
def date_time_stamp( *args, **namedargs):
timestr = ...stuff...
text.insert("insert", timestr)
>>> Exception in Tkinter callback
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764,
in __call__
return apply(self.func, args)
File "C:\PROGRA~1\PYTHON15\TOOLS\IDLE\EditorWindow.py", line 587,
in date_time_stamp
text.insert("insert", timestr)
NameError: text
Nope, as I suspected, that didn't work either. If I am correct, then,
these results point to the interesting fact that a function knows
nothing about its context that it isn't told, and that the first
argument (conventionally "self") of an argument within a class is
used by the class to pass itself and its context to the function, and
is used by the func to "catch" everything the class has to offer. So
I did what I should have done all along:
case 5:
def date_time_stamp(self, *args, **namedargs):
timestr = ...stuff...
self.text.insert("insert", timestr)
result upon selecting the menu/or hitting the right keys:
>>> 19990726.1735
Yay. It works. Just to see if I understood what was going on here, I
tried the following (pushing my luck, I know!):
case 6:
def date_time_stamp(blah, *args, **namedargs):
timestr = ...stuff...
blah.text.insert("insert", timestr)
Yup, that worked too. So now I understand what they mean when they
say that calling the first argument "self" is just a convention.
*Having* the argument there isn't the convention, in fact, in most
cases it's *necessary*, but it can be *called* almost anything. "Aha,
the grasshopper is beginning to understand." ;^)
"The self is just an empty vessle into which...."
"The self must be empty before...."
no no no no... ;)
Ok, seriously now. Here is something I would like to know. Is it
possible for function y in a class to have access to a variable
defined in function x of that same class (without having to
explicitly pass the variable with a return statement)?:
def class something:
1 ...stuff, including __init__...
2 def funcx(self, *args, **namedargs):
3 zip = "googoo"
4 def funcy(self, *args, **namedargs):
5 print zip
Something causes me to suspect that this won't work. What would make
it work? Can I attach zip to "self" somehow in funcx, e.g., line 3:
'self.zip = "googoo"'? If I then change line 5 to 'print self.zip',
will this work? Will it only work if self.zip is defined in the
__init__ func? Until I trust myself to create a working class, I
don't think I can reliably test this out myself. In the meantime, I
will welcome any insights anyone is willing to provide (including
"read chap x, sect y of tutorial or language reference").
Ok, I hope this rambling troubleshooting log helps some other newbie
understand what the hell is going on with passing arguments to
functions, including class "context".
Thank to Greg and my friendly e-mailer for the helpful advice! With
this post and my original one, it should be possible to make a "date-
time stamp" (or any other "insert something here") menu item. If you
can't find the original post and want to do this, email me, and I'll
put it together more coherently for you.
Thanks again, and take care.
Isidor
> Isidor wrote:
> >
> > ##def date_time_stamp(self):
> > def date_time_stamp():
>
> I think the first version of that line was better.
> If it's a method of a class, it'll need a self
> argument. That would account for the "No arguments
> expected" exception - it's being called with one
> argument (self) but it's not expecting any.
Hello Greg -
Thanks for responding to my query. I also thought that having "self"
in there would help. I didn't think this because I knew what I was
doing, but, because like a good monkey, I see that most funcs in a
class have a "self" argument, so I figured, yup, better try it out.
Unfortunately, it didn't work. In fact, it brought up an "odd" error:
case 1: using: def date_time_stamp(self): ...generates...
>>> Exception in Tkinter callback
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764, in
__call__
return apply(self.func, args)
TypeError: too many arguments; expected 1, got 2
Why do I call it an "odd" error message? Well, because to the
untrained eye (e.g., mine) the previous error message is completely
at odds with the following message:
case 2: using def date_time_stamp(): ...generates...
>>> Exception in Tkinter callback
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764, in
__call__
return apply(self.func, args)
TypeError: no arguments expected
To me it sounds as if in case 1, when I gave an argument, it said I
gave too many while in case 2, when I didn't give an argument, it
said it didn't want any. (Kind of like life?..;)
But of course, what's wrong here is my totally ass-backwards
interpretation of the error messages. I would never have figured this
out if it hadn't been for an email sent to me personally by a kind
gent who shall go unnamed here (he is being bcc'ed (hello and
thanks!) (am i correct in assuming that a private emailer does not
want public acknowledgment?)). He wrote:
::::::::::::::::::::
You seem to have done everything right (I don't use TKInter enough to
help with the real debugging), then ignored the information in the
exception...
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764, in
__call__
return apply(self.func, args)
TypeError: no arguments expected
Which is trying to say: "Tkinter tried to call a function with too
many arguments"
So...
def date_time_stamp( *args, **namedargs)
:::::::::::::::::
Since at the time I understood nothing about the uses of *args,
**namedargs , I did not understand his clue. Thanks to some recent
posts and replies discussing these argument-passing-methods, I have a
better grip on what's happening here. So, with a little time on my
hands (yeah, right ;), I did a simple copy and paste from his
message, and voila, it worked. I was able to pass through the
function definition and into the interior of the function. He wasn't
giving me a *clue*, he was giving me the freakin' *answer*! (Again,
thanks.)
error messages, a newbie's eye-view:
So now that it works, I am looking back, trying to reinterpret the
error messages to fit with reality...not my ass-backwards version of
them.
case 1: def blah(self):
error: too many arguments; expected 1, got 2
case 2: def blah():
error: no arguments expected
It seems to me that the error message is being "spoken" by the
"receiving" function (i.e., the "blah" func). In case 1, it is set up
to handle one argument, but gets more than that and balks. In case 2,
it is set up to handle no arguments, gets some, and balks. You see, I
was thinking that the error was being "spoken" by something *after*
the function had been defined (um, I have mentioned several times
that I'm new at this, right?;)...so that whatever was being invoked
after the def statement was balking in a very strange way...telling
me that no arguments were expected when I didn't *give* it any
arguments. Maybe this would have been clearer to me if the error
message in case 2 were (similar to the error message in case 1): "too
many arguments; expected 0, got 2", then I would have realized that
both errors were variations on a theme rather than opposites. Of
course, this new interpretation could be totally wrong too. If that
is the case, I hope someone will point it out to me.
One thing I don't really understand here is why it is necessary to
raise an exception when an argument is passed to a function that
isn't prepared to handle it. If the argument is needed *inside* the
function, I could understand an exception being raised then (e.g.,
"hey, where's my argument"), but in my case i'm doing nothing (or at
least I *think* I'm doing nothing) with those arguments. Why do I
need to make a "landing strip" for them? To add more metaphors to the
blender, something about this reminds me of the trick of putting a
potato in a car exhaust pipe. If the exhaust has nowhere to go, it
backs up until nothing can move in or out of cylinders and the motor
dies (or at least it did in Beverly Hills Cop...or whatever that
Eddie Murphy movie was). So, maybe by allowing the unused arguments
to pass through my function, everything flows nicely and nothing gets
stopped up. Hmm, strange. Am I on basically the right track here with
this idea?
Understanding the "self" ("the toughest thing of all" - stated in a
philosophy of science seminar on reflexivity i once attended):
So, anyway, what did I have inside that function? Well, basically
just some test code to see if I was getting that far:
print "cheese"
It worked, but poorly. It pushed whatever text was already on the
line (at the command prompt) on to the next line and jumped to the
front of the line. Hmm. I suspected that using "print" was like using
a sledgehammer where a scalpel was needed. Scanning through the other
functions in EditorWindow.py, I saw a lot of things being done to/by
self.text. In the init constructor, I saw that "self.text =
Text(...lots of arguments that would make sense for a text widget
type thing...)", and I realized, aha, "text" must be the arena in
which we are actually playing when using IDLE. So, then I wondered,
what "methods" does "text" provide me to insert text? I looked at the
Tkinter text man page and found a section on insert that looked
reasonably like what I wanted to do, but it didn't look anything like
what I was seeing in EditorWindow.py (to me, at least). So then I id
a "Find in Files..." (oh my, what a wonderful feature!) for
text.insert in the idle files and found a nice example in line 51 of
Autoexpand.py. Something like:
self.text.insert("insert", newwords)
My guess is that insert is a method of text, and "insert" (first
argument) is the location of the insertion point and will be the
location where the second argument gets injected into "text". So,
just for kicks, I copied that line into my newly-functioning def,
changed "newwords" to "timestr" (which contained the date-time string
I wanted), and tried it out. (I suspected it wasn't going to work,
but I wanted to try anyway.)
case 3:
def date_time_stamp( *args, **namedargs):
timestr = ...stuff...
self.text.insert("insert", timestr)
>>> Exception in Tkinter callback
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764,
in __call__
return apply(self.func, args)
File "C:\PROGRA~1\PYTHON15\TOOLS\IDLE\EditorWindow.py", line 586,
in date_time_stamp
self.text.insert("insert", timestr)
NameError: self
I was curious: I wanted to know whether a function inside a class
could automatically see the methods and attributes of that class.
Well, this error message makes me think that the answer is no. Self
has to be "created" in the arguments of the function. Ok, so now I'm
starting to understand *why* everyone always says you have to have
"self" as the first argument. But, I wondered, maybe "self" doesn't
work here because I haven't created it within the context of this
func, but "text" would be recognized because it is created in the
class that houses the func. So I tried the following (hey, give me a
break, I'm a newbie! ;) :
case 4:
def date_time_stamp( *args, **namedargs):
timestr = ...stuff...
text.insert("insert", timestr)
>>> Exception in Tkinter callback
Traceback (innermost last):
File "C:\Program Files\Python152\Lib\lib-tk\Tkinter.py", line 764,
in __call__
return apply(self.func, args)
File "C:\PROGRA~1\PYTHON15\TOOLS\IDLE\EditorWindow.py", line 587,
in date_time_stamp
text.insert("insert", timestr)
NameError: text
Nope, as I suspected, that didn't work either. If I am correct, then,
these results point to the interesting fact that a function knows
nothing about its context that it isn't told, and that the first
argument (conventionally "self") of an argument within a class is
used by the class to pass itself and its context to the function, and
is used by the func to "catch" everything the class has to offer. So
I did what I should have done all along:
case 5:
def date_time_stamp(self, *args, **namedargs):
timestr = ...stuff...
self.text.insert("insert", timestr)
result upon selecting the menu/or hitting the right keys:
>>> 19990726.1735
Yay. It works. Just to see if I understood what was going on here, I
tried the following (pushing my luck, I know!):
case 6:
def date_time_stamp(blah, *args, **namedargs):
timestr = ...stuff...
blah.text.insert("insert", timestr)
Yup, that worked too. So now I understand what they mean when they
say that calling the first argument "self" is just a convention.
*Having* the argument there isn't the convention, in fact, in most
cases it's *necessary*, but it can be *called* almost anything. "Aha,
the grasshopper is beginning to understand." ;^)
"The self is just an empty vessle into which...."
"The self must be empty before...."
no no no no... ;)
Ok, seriously now. Here is something I would like to know. Is it
possible for function y in a class to have access to a variable
defined in function x of that same class (without having to
explicitly pass the variable with a return statement)?:
def class something:
1 ...stuff, including __init__...
2 def funcx(self, *args, **namedargs):
3 zip = "googoo"
4 def funcy(self, *args, **namedargs):
5 print zip
Something causes me to suspect that this won't work. What would make
it work? Can I attach zip to "self" somehow in funcx, e.g., line 3:
'self.zip = "googoo"'? If I then change line 5 to 'print self.zip',
will this work? Will it only work if self.zip is defined in the
__init__ func? Until I trust myself to create a working class, I
don't think I can reliably test this out myself. In the meantime, I
will welcome any insights anyone is willing to provide (including
"read chap x, sect y of tutorial or language reference").
Ok, I hope this rambling troubleshooting log helps some other newbie
understand what the hell is going on with passing arguments to
functions, including class "context".
Thank to Greg and my friendly e-mailer for the helpful advice! With
this post and my original one, it should be possible to make a "date-
time stamp" (or any other "insert something here") menu item. If you
can't find the original post and want to do this, email me, and I'll
put it together more coherently for you.
Thanks again, and take care.
Isidor