1

Question

Within the same class, how can one access a function from within a method?

Background

Hello World! I am currently working on a GUI IM program using Tkinter. To send messages over the socket, I need to access functions from methods. My self.network method has a function called send_message() which I want to access.

Code

To access it, I have tried to use this code:

def messageFun(self):

    //Other widgets are here//

    self.send = Button (self.messageFrame, text = "Send",
                        command = self.network(send_message()))
    self.send.grid(row = 1, column = 1, sticky = S)

The self.network method and send_message function are as follows:

def network(self):

    def send_message():   
            #Send some data to the remote server
            message = self.message.get("0.0",END)

            try:
                 #set the whole string
                 s.sendall(message)
            except socket.error:
            #Send Failed
                print "Send failed"
                sys.exit()

Despite my efforts to debug the code, I am always rewarded with this message:

Traceback (most recent call last):
  File "D:\Python Programs\Sockets\First Project\IM Project\Server GUI InDev.py", line 178, in <module>
    app = Application(root)
  File "D:\Python Programs\Sockets\First Project\IM Project\Server GUI InDev.py", line 73, in __init__
    self.messageFun()
  File "D:\Python Programs\Sockets\First Project\IM Project\Server GUI InDev.py", line 156, in messageFun
    command = self.network(send_message()))
NameError: global name 'send_message' is not defined
xxmbabanexx
  • 8,256
  • 16
  • 40
  • 60
  • Hello. I've updated my answer. However, I think you are in an XY problem because it seems to me you try to do something in a manner that isn't clear, and I saw your user's page in which you say _"I am just starting out with programming"_. Why do you think that putting a function inside a method will give you the way to send messages ? I think the conception of your class is not good. But we do not see your class, just the Y problem you present to us – eyquem Feb 28 '13 at 18:29
  • 1
    Th XY problem (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). And in (http://mywiki.wooledge.org/XyProblem) we read _"The X-Y Problem, as it is sometimes called, is a mental block which leads to enormous amounts of wasted time and energy, both on the part of people asking for help, and on the part of those providing help."_ – eyquem Feb 28 '13 at 18:34
  • 1
    As @eyquem has mentioned and explained in his answer, a function inside a method is a wrong practice. I'm not sure why Python even allows that. What is wrong with just extracting that function and write it as a method and then access it wherever in the class you want? – jurgenreza Mar 10 '13 at 07:47

2 Answers2

2

network(send_message()) is a strange syntax to try to trigger the function send_message()

I propose either this manner:

def send_message(instance):   
        #Send some data to the remote server
        message = instance.message.get("0.0",END)

        try:
             #set the whole string
             s.sendall(message)
        except socket.error:
        #Send Failed
            print "Send failed"
            sys.exit()

def network(self,what,send_message=send_message):
    if what =='send message":
        send_message(self)


self.send = Button (self.messageFrame, text = "Send",
                    command = self.network("send message"))

either this one:

class NENE:
    def __init__(self):
        self.network.__dict__['send'] = send_message

    def send_message(self):   
        #Send some data to the remote server
        message = self.message.get("0.0",END)
        try:
             #set the whole string
             s.sendall(message)
        except socket.error:
        #Send Failed
            print "Send failed"
            sys.exit()

    def network(self):
        pass


self.send = Button (self.messageFrame, text = "Send",
                    command = self.network.send_message())

In this second code, I've put pass in the network() function because I don't know the content of your real function but you'll put this content in place of this pass

I've put the methods in a class NENE to show how it works. Because send_message() MUST be a method for the same instance as the instance of which network() is a method.
Then, at each creation of a new instance, send_message() is made an attribute of the network() method too.
Consequently, send_message() is altogether an attribute of the instance and of one of its methods; but it doesn't matter, except that it fulfills your aim: send_message() is now a an attribute of network() that may be called through network attribute and it knows what is the instance for which it works.

Excuse my poor english

eyquem
  • 26,771
  • 7
  • 38
  • 46
  • What does `__dict__` mean? Also, what do you mean by `instance`? – xxmbabanexx Mar 01 '13 at 14:23
  • The attribute named ``__dict__`` is the dictionary that represents the namespace of an object, that is to say a mapping between all the attributes of the object and the identifiers (=names) of these attributes. Python makes a huge use of dictionaries to represent the namespaces. The comprehension of Python needs the comprehension of this aspect. The instruction ``self.network.__dict__['send'] = send_message`` creates a new attribute in the ``network``'s namespace: the object **send_message** is assigned to the identifier ``send`` which is made part of the ``network``'s namspace's keys. – eyquem Mar 01 '13 at 15:42
  • @xxmbabanexx ``instance`` is only a name, an identifier. It is named so because the object that must be passed to the function ``send_message()`` as an argument is intended to really be an instance of your class (you don't you what is this class, then I called it NENE in my second code). ``send_message()`` isn't a method in the first code, it isn't in a class, that's why I'm authorized to name the parameter ``instance`` instead of the common ``self`` name. – eyquem Mar 01 '13 at 15:48
0

If send_message needs to be accessed outside of network, then it should be defined outside of network.

def send_message(self):   
    #Send some data to the remote server
    message = self.message.get("0.0",END)

    try:
        #set the whole string
        s.sendall(message)
    except socket.error:
    #Send Failed
        print "Send failed"
        sys.exit()
def network(self):
    #do network stuff...

def messageFun(self):

    //Other widgets are here//

    self.send = Button (self.messageFrame, text = "Send",
                        command = self.send_message)
    self.send.grid(row = 1, column = 1, sticky = S)

If send_message requires access to variables that are local to network, and network currently does not return anything, then you can define send_message inside network, and return it at the end.

def network(self):
    #create the socket needed for send_message
    s = Socket()

    def send_message():   
        #Send some data to the remote server
        message = self.message.get("0.0",END)

        try:
            #set the whole string
            s.sendall(message)
        except socket.error:
        #Send Failed
            print "Send failed"
            sys.exit()

    #do other network stuff...
    return send_message

def messageFun(self):

    //Other widgets are here//

    self.send = Button (self.messageFrame, text = "Send",
                        command = self.network()
    self.send.grid(row = 1, column = 1, sticky = S)

If network already has a return value, then you can put network's local variables in class scope so send_message can see them.

def send_message(self):   
    #Send some data to the remote server
    message = self.message.get("0.0",END)

    try:
        #set the whole string
        self.s.sendall(message)
    except socket.error:
    #Send Failed
        print "Send failed"
        sys.exit()

def network(self):
    #create the socket needed for send_message
    self.s = Socket()
    #do other network stuff

def messageFun(self):

    //Other widgets are here//

    self.send = Button (self.messageFrame, text = "Send",
                        command = self.send_message
    self.send.grid(row = 1, column = 1, sticky = S)
Kevin
  • 74,910
  • 12
  • 133
  • 166
  • The issue with that is that when I try to do that, the socket is not defined. Isn't there an easier way to do this? Could I create a network class which the GUI class inherits from?? – xxmbabanexx Feb 28 '13 at 15:23
  • Is `s` the socket? Where is that defined? – Kevin Feb 28 '13 at 15:27
  • `s` is the socket indeed. Is there any way for me to simply access a function from within a method. Short of that, could I create two classes, a `GUI` class and a `Network` class which would access each other when sending stuff was needed? – xxmbabanexx Feb 28 '13 at 21:36