Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I want to call some function depend on event code how can I do it in Python?

I made such code but it not works and I am user that only one step to make it working.

class Thing(object):
    @classmethod
    def do1(cls):
        print 'do1'

    @classmethod
    def do2(cls):
        print 'do2'

    eventToMethod = {'1': do1,
                     '2': do2}

    @classmethod
    def onEvent(cls, name):
        method = cls.eventToMethod.get(name)
        if method != None:
            method()

Thing.onEvent('1')

Whatever I get such errors and has not idea how to call classmethods in Python way.

TypeError: 'classmethod' object is not callable

Can you help with this simple problem?

share|improve this question

3 Answers 3

You need to make some changes to changes to eventToMethod first, don't assign do1, do2 to it, better assign strings. You can always access class attributes using strings. The problem with storing references to do1 and do2 in dictionary is that they are not bound methods yet(they're simply classmethod objects(non-data descriptors)) when you store them in dictionary, it's only after the completion of class definition that they're converted to fully bound class methods.

eventToMethod = {'1': 'do1',
                 '2': 'do2'}

And then use getaattr to get the method:

@classmethod
def onEvent(cls, name):
    method = getattr(cls, cls.eventToMethod.get(name))
    ...

Note that you can also directly pass 'do1' to onEvent instead of keeping a dictionary to store names and then simply use:

method = getattr(cls, name)

You can still get away with your current approach if you call __get__ method of do1, do2 descriptors explicitly.:

method = cls.eventToMethod.get(name)
if method != None:
    method.__get__(None, cls)()

This works because this is exactly what Python does under the hood, classmethod is a non-data descriptor and when you do Thing.do1 Python actually calls __get__ method of do1 with first agument as None and second as type:

>>> Thing.do1.__get__(None, Thing)
<bound method type.do1 of <class '__main__.Thing'>>
>>> Thing.do1.__get__(None, Thing)
<bound method type.do1 of <class '__main__.Thing'>>
>>> Thing.do1
<bound method type.do1 of <class '__main__.Thing'>>
>>> Thing.eventToMethod['1'].__get__(None, Thing)   #Using OP's code.
<bound method type.do1 of <class '__main__.Thing'>>
share|improve this answer
    
First solution is need redeclaration. Second is insecure. Third is O.K. Please remove other solutions especially direct method call from string this is insecure code. I will score you after change. Thank you for very good help. –  Chameleon 9 hours ago

While I understand that this doesn't answer your question directly, I thought it might be useful to see an alternative.

Often it's possible to use reflection to calculate the correct method at runtime. For example:

    @classmethod
    def onEvent(cls, name):
        try:
            method = getattr(cls, 'do%s'%name)
        except AttributeError:
            return

        method()

This approach may be useful if you are able to follow a strict naming convention in your methods (as in the example, where you seem to prefix them with 'do'). It's similar to how PyUnit detects the set of test cases to run.

This avoids the need to maintain a dict, which may get out of sync with the actual methods on the object. It also arguably leads to clearer code.

share|improve this answer
    
This code is unsecured. Never do such code - is allow execute anything. –  Chameleon 9 hours ago
    
@Chameleon - reflection and introspection aren't necessarily insecure. This example in particular doesn't allow for the execution of arbitrary code, and will only allow the execution of an arbitrary method if you're silly enough to pass a user-controlled string into it. Entire frameworks (hello, Ruby on Rails) are based on this concept. –  sapi 8 hours ago
    
Such code pattern lead to security holes but not always as you said. –  Chameleon 4 hours ago

It's worth pointing out as well that if you are attempting to do some kine of event-driven programming -- There are libraries/frameworks that help facilitate this:

Example:

#!/usr/bin/env python

from circuits import Component, Event


class Thing(Component):

    def do1(self):
        print("do1")

    def do2(self):
        print("do2")

    def started(self, manager):
        self.fire(Event.create("do1"))
        self.fire(Event.create("do2"))
        raise SystemExit(0)


Thing().run()

Output:

$ python foo.py
do1
do2

Disclaimer: I'm the author of circuits

share|improve this answer
    
Too complex I think it not need modules. –  Chameleon 9 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.