Basic question about events and arguments

This is probably a pretty basic question, so I apologize for any
eye-rolling it may cause - I'm a perl guy trying to use python, and it's
tough to get my brain going in a different direction. :slight_smile:

I've got an event in my main .py file, that looks like:

聽聽聽聽EVT_LISTBOX_DCLICK(self, 60, self.PlayAudio)

And the function is defined as:

聽聽def PlayAudio(self,event):

However, when I move that function to another .py module (I'm trying to
group like functions together in modules), import the module, and call it
like:

聽聽聽聽EVT_LISTBOX_DCLICK(self, 60, module.PlayAudio)

I get the error

TypeError: PlayAudio() takes exactly 2 arguments (1 given)

I'm assuming that the argument passed the second way is the event - how do
I get back the reference to the "self" namespace? When I try things like:

聽聽聽聽EVT_LISTBOX_DCLICK(self, 60, module.PlayAudio(self, event))

It bombs out with:

聽聽聽聽EVT_LISTBOX_DCLICK(self, 60, mrv_audio.PlayAudio(self,event))
NameError: global name 'event' is not defined

A clue-by-four showing me where I'm going wrong will be appreciated.

Thanks,
Wade

路路路

--
If you have a VCR or MP3 player, you need to read these links:

http://www.digitalconsumer.org/
http://digitalspeech.org/
http://www.libertyboard.org/

This is probably a pretty basic question, so I apologize for any
eye-rolling it may cause - I'm a perl guy trying to use python, and it's
tough to get my brain going in a different direction. :slight_smile:

I've got an event in my main .py file, that looks like:

    EVT_LISTBOX_DCLICK(self, 60, self.PlayAudio)

And the function is defined as:

  def PlayAudio(self,event):

However, when I move that function to another .py module (I'm trying to
group like functions together in modules), import the module, and call it
like:

    EVT_LISTBOX_DCLICK(self, 60, module.PlayAudio)

I get the error

TypeError: PlayAudio() takes exactly 2 arguments (1 given)

In the first case, PlayAudio is a method of your class. As a method, self
gets automagically passed in. In the second case, PlayAudio is function in
another module and doesn't get self passed in.

There are a few ways you could deal with this. However it depends on what's
acutally in PlayAudio. If PlayAudio doesn't depend on self, then just rip
self out of the argument list and you should be good to go. However, if
PlayAudio does depend on self and you want to put it in another module you
could:

(a) add a stub function _in_your_class_ and call out to the other file:

class MyClass:
   #...
   def PlayAudio(self, event):
       module.PlayAudio(self, event) # If PlayAudio doesn't care about event
you could recast this as module.PlayAudio(self)

(b) use lambda

EVT_LISTBOX_DCLICK(self, 60, lambda e, s=self : module.PlayAudio(s,e))

If PlayAudio is tightly tied to the class, I'd probably just move it back to
where it came from. If it's not, then go ahead and move it using some
variation on (a). I wouldn't use (b) in this instance, it's a bit too
obscure.

-tim

路路路

I'm assuming that the argument passed the second way is the event - how do
I get back the reference to the "self" namespace? When I try things like:

    EVT_LISTBOX_DCLICK(self, 60, module.PlayAudio(self, event))

It bombs out with:

    EVT_LISTBOX_DCLICK(self, 60, mrv_audio.PlayAudio(self,event))
NameError: global name 'event' is not defined

A clue-by-four showing me where I'm going wrong will be appreciated.

Thanks,
Wade

--
If you have a VCR or MP3 player, you need to read these links:

http://www.digitalconsumer.org/
http://digitalspeech.org/
http://www.libertyboard.org/

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwindows.org
For additional commands, e-mail: wxPython-users-help@lists.wxwindows.org

Wade Minter wrote:

> This is probably a pretty basic question, so I apologize for any
> eye-rolling it may cause - I'm a perl guy trying to use python, and it's
> tough to get my brain going in a different direction. :slight_smile:

As Yoda said: You have to unlearn what you have learned! :wink:
Python is much easier to learn than Perl (at least it was
for me) so you'll get the hang of it soon.

This isn't really a wxPython question, but rather a question
about python's namespaces etc. I'm CCing it to the python tutor
mailing list.

> EVT_LISTBOX_DCLICK(self, 60, self.PlayAudio)
>
> And the function is defined as:
>
> def PlayAudio(self,event):

Ok, then I assume that it's not a function in the scope of
the module, but a method inside the same class as the EVT_...
I guess you bind the event in __init__. Right? Otherwise the
parameter "self" seems a bit odd.

Have you used object-oriented Perl?

> However, when I move that function to another .py module (I'm trying to
> group like functions together in modules), import the module, and call it
> like:

A Python class must be defined in one file. (As in Perl, right?)
If you want to distribute the definition of a class to several
files, you have to use inheritence. But you don't normally do
that just to spread ot functions in several files. A class should
be a coherent and closely coupled unit that you keep in one file.
Rather if you have common behaviour that is shared between several
classes, you might factor out the common parts and make that a
common base class, but there are other considerations as well. OO
Design is a bit beyond the scope of this mail...

> EVT_LISTBOX_DCLICK(self, 60, module.PlayAudio)
>
> I get the error
>
> TypeError: PlayAudio() takes exactly 2 arguments (1 given)

Tim Hochberg added:

In the first case, PlayAudio is a method of your class. As a method, self
gets automagically passed in. In the second case, PlayAudio is function in
another module and doesn't get self passed in.

Or to put it another way: If you have

class C:
     def playAudio(self, event):
         ...

o = C()

Then

o.playAudio(event)

is just a shorter form of writing

C.playAudio(o, event)

The methods really belong to the class, not to the instance object,
right? There is no corresponding shortcut for functions defined
in modules as there are for methods defined in classes. This is
because no object is an instance of a module the way some objects
are instances of classes (like o of C above).

> EVT_LISTBOX_DCLICK(self, 60, mrv_audio.PlayAudio(self,event))
> NameError: global name 'event' is not defined

Yes, in this case you execute the PlayAudio function (or method?)
when you run the function above, i.e. when you init your class
or module. You want to pass it to the wxPython event handling
mechanism so that it can be called when you double-click on the
listbox. Not at all the same thing.

You have to understand that everything is a first class object in
Python. Like this:

>>> def x():
... return "function x returns a string"
...
>>> def p(f):
... print "p prints what comes out of the passed in function, namely:", f()
...
>>> p(x)
p prints what comes out of the passed in function, namely: function x returns a string
>>> p(x())
p prints what comes out of the passed in function, namely:Traceback (most recent call last):
   File "<interactive input>", line 1, in ?
   File "<interactive input>", line 2, in p
TypeError: 'str' object is not callable
>>>

(You don't even have to reference or dereference anything.)

You see? Passing a function object or a function *call* to
another function is not at all the same thing! You can get
around the problem of how to apply parameters by wrapping
the function call inside another function (a lambda is a
kind of small inline function) but in this case I think you've
got the code structured in a strange way, and should look at
that first.

>>> from __future__ import nested_scope #This feature isn't standard yet.
>>> def x2(a, b, c):
... return "%s %s %s" % (a, b, c)
...
>>> def wrap():
... return x2('Python', 'is', 'fun')
...
>>> p(wrap)
p prints what comes out of the passed in function, namely: Python is fun

路路路

--
Magnus Lycka, Thinkware AB
Alvans vag 99, SE-907 50 UMEA, SWEDEN
phone: int+46 70 582 80 65, fax: int+46 70 612 80 65
http://www.thinkware.se/ mailto:magnus@thinkware.se