Python相当于Java内部类的委托

时间:2014-10-28 16:35:36

标签: python oop python-2.7

我试图弄清楚传递有限回调的最Pythonic方法,以便与复杂对象的方法进行交互。我有一个通过通信渠道接收数据的程序,该数据分为几个不同的类别。我需要从数据的进一步处理中去除数据所在类别的确定:

class Categorizer(object):
    '''Determines which category data is in. 
       There may be multiple variants of this class'''
    def handleData(self, data, callback):
        if self.somethingReallySpecial(data):
            callback.onSomethingReallySpecial(data)
        elif self.somethingSpecial(data):
            callback.onSomethingSpecial(data)
        else:
            callback.onSomethingMundane(data)
    # ... other methods ...

class IAmAReallyComplicatedBeast(object):
    def __init__(self, categorizer, other_stuff):
        self.categorizer = categorizer
        # ...
    # ... lots of other methods ...
    def something(self, other_stuff):
        data = self.obtain_data()
        # this is probably wrong, but here's what I want to do:
        beast = self
        class Dispatcher(object):
            def onSomethingMundane(data):
                beast.doFoo(data)
            def onSomethingSpecial(data):
                beast.doBar(data)
            def onSomethingReallySpecial(data):
                beast.doBaz(data)
        self.categorizer.handleData(data, Dispatcher())
    def doFoo(self, data):
        # for mundane data
    def doBar(self, data):
        # for special data
    def doBaz(self, data):
        # for really special data

在Java中,我会使用内部类(如此处的Dispatcher)...是否有Pythonic方法来处理它?<​​/ p>


我不想将onSomethingXXX方法直接放在我的IAmAReallyComplicatedBeast课程上,原因有两个:

  • 这意味着我必须按原样使用这些名称
  • 我不希望Categorizer类具有对IAmAReallyComplicatedBeast对象的任意访问权限。也许这来自于通常的Java偏执狂心态,但对我来说这似乎是一个很好的设计。

4 个答案:

答案 0 :(得分:2)

制作调度员的Pythonic方法是使用字典。请记住,Python函数是第一类对象,因此可以是dict中的值。

class IAmAReallyComplicatedBeast(object):
    def something(self, other_stuff):
        data = self.obtain_data()
        dispatcher = {
            'something_mundane': self.do_foo,
            'something_special': self.do_bar,
            'something_really_special': self.do_baz
        }
        self.categorizer.handleData(data, dispatcher)

class Categorizer(object):
    '''Determines which category data is in. 
       There may be multiple variants of this class'''
    def handleData(self, data, callback):
        if self.somethingReallySpecial(data):
            dispatcher['something_really_special'](data)

注意:我知道你没有提出这个,但是内部类实际上是非Pythonic:内部类没有获得外部类的特殊访问权限,并且不建议这样做。

答案 1 :(得分:1)

可以通过别名必要的方法<{1}} IAmAReallyComplicatedBeast

Dispatcher

或者,您可以创建一个包装方法的类,只需创建它的实例,而不是每次都创建一个新类:

class IAmAReallyComplicatedBeast(object):
    # ... snip ...

    # In something we can just pass ourself because we are a dispatcher
    self.categorizer.handleData(data, self)
    # ... snip ...
    def doFoo(self, data):
        # Do mundane things here

    onSomethingMundane = doFoo

    # ... etc. ...

然后你的class Dispatcher(object): __slots__ = ('onSomethingMundane', 'onSomethingSpecial', 'onSomethingVerySpecial') def __init__(self, mundane, special, very_special): self.onSomethingMundane = mundane self.onSomethingSpecial = special self.onSomethingReallySpecial = very_special 方法会更清楚一点:

something

答案 2 :(得分:1)

如果您有兴趣与其他课程共享调度员,您可以执行以下操作:

class Dispatcher(object):
    def __init__(self,f1,f2,f3):
        self.onSomethingMundane=f1
        self.onSomethingSpecial=f2
        self.onSomethingReallySpecial=f3


class IAmAReallyComplicatedBeast(object):
    #...
    def something(self, other_stuff):
        data = self.obtain_data()
        # this is probably wrong, but here's what I want to do:
        beast = self
        beast_dispatcher = Dispatcher(beast.doFoo,beast.doBar,beast.doBaz)
        self.categorizer.handleData(data, beast_dispatcher)
    #...

答案 3 :(得分:1)

正如@ ch3ka已经暗示的那样,dict将是这里的pythonic选择imho。 事情可能就是这样:

class Categorizer(object):
    '''Determines which category data is in. 
       There may be multiple variants of this class'''
    def handleData(self, data, callback_mapping):
        # get the category
        category = self.categorize(data)
        # invoke the corresponding handler
        callback_mapping[category](data)


class IAmAReallyComplicatedBeast(object):
    def __init__(self, categorizer, other_stuff):
        self.categorizer = categorizer
        # ...
    # ... lots of other methods ...
    def something(self, other_stuff):
        data = self.obtain_data()
        self.categorizer.handleData(data,
                                    dict(mundane=self.doFoo, 
                                         special=self.doBar,
                                         really_special=self.doBaz)
    def doFoo(self, data):
        # for mundane data
    def doBar(self, data):
        # for special data
    def doBaz(self, data):
        # for really special data

经常使用的另一种模式是为动态调用的方法创建名称。 例如。在python的内置BaseHTTPServer do_XXX被调用,其中XXX是请求HTTP方法的占位符:

    mname = 'do_' + self.command
    if not hasattr(self, mname):
        self.send_error(501, "Unsupported method (%r)" % self.command)
        return
    method = getattr(self, mname)
    method()

请参阅:https://hg.python.org/cpython/file/2.7/Lib/BaseHTTPServer.py#l323 因此你可以例如为您的方法doSpecialdoReallySpecialdoMundane命名,然后从分类程序中调用它们。