IDLE mini-hack & ? (adding menu items, understanding *args, self)

Martijn Faassen m.faassen at vet.uu.nl
Wed Jul 28 08:02:33 EDT 1999


Isidor <rodisi01 at my-deja.com> wrote:

[monstrous snip]
> 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?

def myfunction(foo, bar):
     print foo
     print bar

myfunction(1, 2, 3)

You send '3' to myfunction. If myfunction now just ignored '3' silently,
you'd be endlessly confused why your program doesn't work, especially if
you didn't write myfunction yourself. But luckily, you get an exception
stating that you do something wrong. Python just tells you when you do
something that *can't* be right.

Unrelated to this, a common confusion with Python occurs with methods
(as opposed to functions):

class Myclass:
    def mymethod(self, foo, bar):
        print foo
        print bar

myobj = Myclass()
myobj.mymethod(1, 2, 3)

This is going to give an exception that too many arguments were passed.
This is because according to Python, *4* arguments were passed instead of
3.

If you call a method on an object, that object is always passed as the
first argument to that object, implicitly (usually it's called 'self'). 
Inside the method you can then use self to do various things to the
object (for instance, call other methods on it, or set attributes).

[snip]
> 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? 
[big snip]

Actually, you can make functions that allow extra arguments -- but only when
you explicitly tell Python:

(file: test.py)
def foo(a, b, *rest):
    print a
    print b
    print rest

>>> from test import foo
>>> foo(1, 2)
1
2
()
>>> foo(1, 2, 3)
1
2
(3,)
>>> foo(1, 2, 3, 4, 5)
1
2
(3, 4, 5)
 
You can also do this (this only works with keyword arguments):

(file: test2.py)
def foo(a, b, **rest):
    print a
    print b
    print rest

>>> from test2 import foo
>>> foo(1, 2)
1
2
{}
>>> foo(1, 2, 3)
Traceback (innermost last):
  File "<stdin>", line 1, in ?
TypeError: too many arguments; expected 2, got 3
>>> foo(1, 2, something=3)
1
2
{'something': 3}
>>> foo(1, 2, something=3, other=4)
1
2
{'other': 4, 'something': 3}

So, as long as you tell Python what you want, Python allows lots of
flexibility. But if you don't tell Python that you want it, Python assumes
you don't want it -- it gives an error, which is good, as it probably
*was* an error.

Some languages take this further and also require you to add the *types* of
the arguments you espect in your function (they are strongly typed). So, if
you have a function argument 'foo', you need to specify in your function
definition if 'foo' is a string, or a number, or an object made from some
class, etc. This can also be used to prevent errors (and compile into
faster code); the language compiler can detect if you do something that's
not intended (pass a number where you specified only a string could go).

But dynamic typing like Python has other advantages -- you
have more flexibility and you don't get caught up messing with argument
types all the time (it can cost lots of time early in development, and it's
harder to change something).

The last discussion is just for random information and does not have much
to do with Python. :)

I hope my explanation was useful.

Regards,

Martijn





More information about the Python-list mailing list