假设我有一个实现方法(Rectangle
)的类(describe
),如下所示:
class Rectangle(object):
def __init__(self, height, width):
self.height = height
self.width = width
def describe(self):
return 'Rectangle with height {:0.2f} and width {:0.2f}'.format(float(self.height),
float(self.width))
这可以按预期工作:
r = Rectangle(5, 3)
r.describe()
>>> 'Rectangle with height 5.00 and width 3.00'
我希望能够在实例化时指定一个代替describe
的替代函数。我相信以下工作:
import functools as ft
class RectangleEnhanced(object):
def __init__(self, height, width, description_function=None):
self.height = height
self.width = width
if description_function is None:
self.describe = self.default_describe
else:
self.describe = ft.partial(description_function, self)
def default_describe(self):
return 'Rectangle with height {:0.2f} and width {:0.2f}'.format(float(self.height),
float(self.width))
那样:
s = RectangleEnhanced(5, 3)
s.describe()
>>> 'Rectangle with height 5.00 and width 3.00'
继续像以前一样工作,但另外:
def area_description(enh_rect):
return 'Rectangle with area {:0.2f}'.format(float(enh_rect.height * enh_rect.width))
t = RectangleEnhanced(5, 3, area_description)
t.describe()
>>> 'Rectangle with area 15.00'
这是解决这个问题的合理方法吗?我无法想象我是第一个想要这样做的人,所以我很紧张下面的方法是次优的/ unpythonic / bad / etc。有没有"权利"处理这个的方法?
修改
这是一个更接近我的用例的例子:
class FilterableCollection(object):
def __init__(self, items, owner, purpose, filterfunc=None):
self.items = set(items)
self.owner = owner
self.purpose = purpose
if filterfunc is None:
self.filterfunc = lambda x: True
else:
self.filterfunc = ft.partial(filterfunc, self)
def filtered(self):
return filter(self.filterfunc, self.items)
items = ['fun_ball', 'boring_ball', 'fun_bear', 'boring_bear']
owner = 'Bill'
purpose = 'fun'
f = FilterableCollection(items, owner, purpose)
print f.filtered()
def is_applicable(self, item):
return self.purpose in item
g = FilterableCollection(items, owner, purpose, is_applicable)
print g.filtered()
返回:
['fun_bear', 'fun_ball', 'boring_ball', 'boring_bear']
['fun_bear', 'fun_ball']
正如所料。因此,我们的想法是,当您创建FilterableCollection
的特定实例时,您可以创建自定义过滤器(可能取决于该特定FitlerableCollection
的其他属性),然后可以随时调用该过滤器。因此,可能会有10 FilterableCollections
个浮动,并且可以通过调用.filtered
方法对每个过滤器进行过滤。
我对通过继承或任何其他技术做到这一点的想法非常开放。但是在这种情况下如何适用?
答案 0 :(得分:1)
您的实施是有道理的。一个类通常在其__init__
中采用可选参数,并且如果没有传递,则使用可感知的默认值。在您的情况下该参数是一个函数。
所以这是一个很好的实现,因为你真的真的想要这样做。
然而,正如许多其他评论员指出的那样,这听起来不是一个好主意。获取简单值和使用函数覆盖此类方法之间的区别在于函数参数会影响实例的行为。 相同类型的实例不应该有不同的行为。
因此,使用不同类型(例如使用继承)是最直接的方法。
既然你问过,这里是你如何使用继承:
class FilterableCollection(object):
def __init__(self, items, owner, purpose):
self.items = set(items)
self.owner = owner
self.purpose = purpose
def filtered(self):
return self.items
class ApplicabilityFilterableCollection(FilterableCollection):
def filtered(self):
return [ item for item in self.items if self.purpose in item ]
f = FilterableCollection(items, owner, purpose)
print f.filtered()
g = ApplicabilityFilterableCollection(items, owner, purpose)
print g.filtered()
答案 1 :(得分:1)
本质是,对于每个类的实例,我希望能够 对附加到的一些数据执行某种过滤 实例。根据上下文,所需的过滤类型 可能差异很大。
您在此处描述的内容称为strategy pattern,您的示例实现几乎与pythonic一样 - Python函数是对象,相当多的设计模式需要完整的#34;仿函数"大多数主流语言中的类都是用Python中的普通函数实现的。
唯一的改进"我可以看到将摆脱部分 - Python函数确实知道如何成为实例方法:
if description_function is None:
self.describe = self.default_describe
else:
self.describe = description_function.__get__(self)
您可以阅读此内容以了解有关此行为的更多信息:https://wiki.python.org/moin/FromFunctionToMethod
并不是说这会改变任何纯粹的功能(没有双关语),但它肯定会让你看起来像PythonGuru(tm)