用于委派的Java内部类的Python等价物

2024-10-04 11:30:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试找出一种最具python风格的方法来传递有限的回调,以便与复杂对象的方法进行交互。我有一个通过通信信道接收数据的程序,这些数据分为几个不同的类别。我需要将数据所属类别的确定与数据的进一步处理分离开来:

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)。。。有没有一种Python式的处理方法?你知道吗


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

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

Tags: 数据对象方法selffordataobjectdef
3条回答

如果您对与其他类共享dispatcher感兴趣,可以执行以下操作:

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)
    #...

做调度员的python方法是使用字典。请记住,在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的:内部类没有获得对外部类的特殊访问权,并且不建议这样做。你知道吗

正如@ch3ka已经指出的,dict在这里是pythonic的选择。 事情可能是这样的:

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的内置函数中,调用BaseHTTPServerdo_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,并从分类程序中调用它们。你知道吗

相关问题 更多 >