[Tutor] Problem with calling class methods stored in a list

Peter Otten __peter__ at web.de
Fri Jan 11 10:58:51 CET 2013


Tobias M. wrote:

> Am 10.01.2013 15:15, schrieb Peter Otten:
>> Of course handle_1_42() is not exactly the method name one would hope
>> for. You could, again, strive for simplicity and add a lookup table that
>> maps protocol tuples to function /names/ , but as simplicity doesn't seem
>> to be your cup of tea:
>>
>> class HandlersType(type):
>>      def __init__(cls, name, bases, classdict):
>>          cls.lookup_protocol = lookup = {}
>>          for k, v in classdict.items():
>>              if isinstance(v, protocol_method):
>>                  lookup[v.protocol] = getattr(cls, k)
>>
>> class protocol_method(classmethod):
>>      pass
>>
>> def protocol(x, y):
>>      def attach_protocol(f):
>>          f = protocol_method(f)
>>          f.protocol = x, y
>>          return f
>>      return attach_protocol
>>
>> class D:
>>      __metaclass__ = HandlersType
>>
>>      @protocol(42, 17)
>>      def foo(cls):
>>          print "Hi"
>>
>> D.lookup_protocol[42, 17]()
>>
>> ;)
>>
> In my eyes this is anything but simple.
> Correct me if I'm wrong:
> I already use a lookup table in my code, called "method_list" in my
> first post. The advantage of your above code is that I don't need to
> manually take care of the lookup table and extension by subclassing is
> easier.

You are right; the misunderstanding is that I wasn't advertising the above 
"fancy" solution (which is buggy, btw).

I have now implemented what I had in mind with the protocol to function name 
mapping, and I think /that/ is reasonably complex. I'm using instance 
methods in the demo, but it should work with class methods as well.

class Error(Exception):
    def __init__(self, protocol):
        Exception.__init__(self, self.template.format(protocol))

class UnknownProtocolError(Error):
    template = "Unknown protocol {}"

class ProtocolNotSupportedError(Error):
    template = "Protocol {} not supported"

FOO = (42, 17)
BAR = (1, 2)
BAZ = (3, 4)
HAM = (4, 5)
SPAM = (5, 6)

class HandlersBase(object):
    protocol_to_methodname = {
        FOO: "foo",
        BAR: "bar",
        BAZ: "baz",
        HAM: "ham",
        }
    def get_handler(self, protocol):
        try:
            methodname = self.protocol_to_methodname[protocol]
        except KeyError:
            raise UnknownProtocolError(protocol)
        
        method = getattr(self, methodname, None)
        if method is None:
            raise ProtocolNotSupportedError(protocol)
        return method

class A(HandlersBase):
    def foo(self): print "A.foo"
    def bar(self): print "A.bar"
    def baz(self): print "A.baz"
    
class B(A):
    def bar(self): print "B.bar"
    baz = None # hide parent implementation

if __name__ == "__main__":

    for Class in A, B:
        inst = Class()
        print "---", Class.__name__, "---"
        for protocol in FOO, BAR, BAZ, SPAM:
            try:
                inst.get_handler(protocol)()
            except Error as err:
                print err




More information about the Tutor mailing list