开发者

Calling a method on class A depending on type of parameter

class Class1(object):
    ...

class Class2(object):
    ...

class Class3(object):
    ...

class A(object):
    def _methA(parm1, parm2)
        ...

    def _methB(parm1, parm2)
        ...

    def _methC(parm1, parm2)
        ...

    def manager(parm1, method, params)
        ...
        if parm1.__class__.__name__==Class1.__name__:
            response = _methA(parm1, params)
        elif parm1.__class__.__name__==Class2.__name__:
            response = _methB(parm1, params)
        elif io_source.__class__.__name__==Class3.__name__:
            response = _methC(parm1, params)
        else:
            raise Exception, "Unsupported parm1"
        ...

I didn't like the way that if/elif block in manager() looked and refactored it to this:

def manager(parm1, method, params)
    ...
    try:
        response = {
                Class1.__name__: lambda parm1, parms: _methA(parm1, parms),
                Class2.__name__: lambda parm1, parms: _methB(parm1, parms),
                Class3.__name__: lambda parm1, parms: _methC(parm1, parms)
                }[parm1.__class__.__name__](parm1, parms)
    except KeyError:
        raise Exception, "Unsupported parm1" 

But the fact that the code is still looking at cla开发者_运维技巧ss names bothers me - I really don't know how to explain why... Should it bother me?

Is there a better way to write code to call a method in class A that, depending on the class of one of its parameters, triggers the calling of different methods in A?

PS. Sorry for the contrived example, but posting the actual code would make the question even more convoluted. I tried to distill the issue to its essence...


That's one of many wrong ways to implement polymorphism. You should never look at class names. Looking at class names should bother you because it means that you haven't delegated the responsibility correctly.

Move each method into the appropriate class.

class Class1(object):
    def method( self, theA, params ):
        theA.methA( params )

class Class2(object):
    def method( self, theA, params ):
        theA.methB( params )

class Class3(object):
    def method( self, theA, params ):
        theA.methC( params )

class A(object):
    def methA(parm1, parm2)
        ...

    def methB(parm1, parm2)
        ...

    def methC(parm1, parm2)
        ...

    def manager(parm1, method, params)
        ...
        param1.method( self, params )


You're trying to emulate what language geeks call "multiple dispatch", or "multimethods". The linked-to Wikipedia article has a good discussion, including Python examples.


I would prefer

if isinstance(parm1, Class1):
    _methA(parm1, params)
elif isinstance(parm1, Class2):
    _methB(parm1, params)
elif isinstance(parm1, Class3):
    _methC(parm1, params)

but this still smells of a design flaw. :)

Maybe your three classes ClassX should rather all have a single method meth(params), then your manager could just call parm1.meth(params).


I usually do this when processing messages, so i don't have tons of ifs ... but it still uses the class names.

Kind of a poor man's polymorphism - but, as S.Lott said, Python supports real polymorphism so why not use it :p

class Handler(object):
    # .. stuff

    def dispatch(self, msg):
        handlername = "on_%s" % type(msg)
        return getattr(self, handlername, 'on_missing_handler')(msg)

    def on_SomeClass(self, msg):
        # msg is of SomeClass here ..

    def on_SomeOtherClass(self, msg):
        # msg is of SomeOtherClass here ..

    def on_missing_handler(self, msg):
        # there is no other handler for msg
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜