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

用于委派的Java内部类的Python等价物,python,oop,python-2.7,Python,Oop,Python 2.7,我正试图找出一种最具python风格的方式来传递有限的回调,以便与复杂对象的方法进行交互。我有一个通过通信信道接收数据的程序,这些数据分为几个不同的类别。我需要将数据所属类别的确定与数据的进一步处理分离开来: class Categorizer(object): '''Determines which category data is in. There may be multiple variants of this class''' def handleDat

我正试图找出一种最具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)。。。有没有一种类似蟒蛇的处理方法


我不想将
放在我的
iamareycomplementedBeast
类的somethingxxx
方法上,原因有二:

  • 这意味着我必须按原样使用这些名字
  • 我不希望
    分类程序
    类对
    IAMAREALLYCOMPLICATEDBAST
    对象具有任意访问权限。也许这来自于通常的Java偏执狂心态,但对我来说,这似乎是一个很好的设计
您可以通过对必要的方法进行别名化,使
IAmAReallyComplicatedBeast
也成为
调度程序

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
然后你的
方法会更清晰一些:

def something(self, other_stuff):
        data = self.obtain_data()
        dispatcher = Dispatcher(self.doFoo, self.doBar, self.doBaz)
        self.categorizer.handleData(data, dispatcher)
通过对必要的方法进行别名化,您可以使
iamareallycomplectedbeast
同时成为
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
然后你的
方法会更清晰一些:

def something(self, other_stuff):
        data = self.obtain_data()
        dispatcher = Dispatcher(self.doFoo, self.doBar, self.doBaz)
        self.categorizer.handleData(data, dispatcher)

如果您有兴趣与其他类共享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)
    #...

如果您有兴趣与其他类共享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)

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

创建分派器的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的内置
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()
见:
因此,您可以将您的方法命名为
doSpecial
doReallySpecial
doMundane
,并从分类程序中调用它们。

正如@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的内置
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()
见:
因此,您可以将您的方法命名为
doSpecial
doReallySpecial
doMundane
,并从分类程序中调用它们。

我会使用
分派dict
。在Python中,dict可以保存函数。我认为内部类总是您想要的,并且可能是最好的方法。这些大腿永远不可能是pythonich,因为python不是设计用来做这些保护的。我会使用
调度dict
。在Python中,dict可以保存函数。我认为内部类总是您想要的,并且可能是最好的方法。这些大腿永远不会是pythonich,因为python不是用来做这些保护的。是的,我可以,但我不想。。。编辑后的问题。好的,谢谢更新的建议:Dispatcher wrapper。是的,我可以,但我不想。。。编辑的问题。好的,谢谢更新建议:Dispatcher wrapper。性能问题:我的分类程序调度每秒被调用数千次;与属性查找相比,dict查找的成本是多少?它们完全相同。无论如何,Dict查找都是O(1),但更重要的是,属性是作为Dict实现的。关于使用
namedtuple
而不是
Dict
有什么想法吗?我知道这不是必需的+它是不可变的,但似乎这可能是一种更好的方法(如果没有提供预期的方法,则会快速失败)。@JasonS a
namedtuple
是一个好主意。以下是一些CPython 2性能结果:。关于性能的问题:我的分类程序调度每秒被调用数千次;与属性查找相比,dict查找的成本是多少?它们完全相同。无论如何,Dict查找都是O(1),但更重要的是,属性是作为Dict实现的。关于使用
namedtuple
而不是
Dict
有什么想法吗?我知道这不是必需的+它是不可变的,但似乎这可能是一种更好的方法(如果没有提供预期的方法,则会快速失败)。@JasonS a
namedtuple
是一个好主意。以下是一些CPython 2性能结果:。