我试图弄清楚传递有限回调的最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偏执狂心态,但对我来说这似乎是一个很好的设计。答案 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
因此你可以例如为您的方法doSpecial
,doReallySpecial
和doMundane
命名,然后从分类程序中调用它们。