我一直在考虑一个可用于列表转换的类。 这是我目前的实施:
class ListTransform(object):
"""Specs: stores original list + transformations.
Transformations are stored in a list.
Every transformation is a func call, with
one parameter, transformations are done in place.
"""
def __init__(self, _list):
self.orig_list = _list
self.reset()
def addtransform(self,t):
self.transforms.append(t)
def reset(self, ts = []):
self.transforms = ts
def getresult(self):
li = self.orig_list[:] # start from a copy from the original
# call all the in-place transform functions in order
for transform in self.transforms:
transform(li)
return li
def pick_transform(pickindexes):
"""Only includes elements with specific indexes
"""
def pt(li):
newli = []
for idx in pickindexes:
newli.append(li[idx])
del li[:] # clear all the elements
li.extend(newli)
return pt
def map_transform(fn_for_every_element):
"""Creates a transformation, which will call a specific
function for every element in a list
"""
def mt(li):
newli = map(fn_for_every_element, li)
del li[:] # clear
li.extend(newli)
return mt
# example:
# the object which stores the original list and the transformations
li = ListTransform([0,10,20,30,40,50,60,70,80,90])
# transformations
li.addtransform(map_transform(lambda x: x + (x/10)))
li.addtransform(pick_transform([5,6,7]))
# getting result, prints 55, 66, 77
print li.getresult()
这很有效,然而,以不合规格的方式实施某些事情的感觉困扰着我。
您在此实现中将使用哪些Python功能,我还没有使用过?您如何改进本课程背后的整体设计/理念?你会如何改进代码?
此外,由于重新发明轮子感觉很尴尬:取代这门课程的标准工具是什么?
答案 0 :(得分:2)
不要使用空列表作为默认参数。使用无并测试它:
def some_method(self, arg=None):
if arg is None:
arg = []
do_your_thing_with(arg)
我是众所周知的Python的初学者陷阱。
答案 1 :(得分:2)
考虑到一般范围而不是特定用例,我会以更“实用”的方式看待这个:
不要进行转换 - 而是返回新列表。这就是函数式编程中的标准函数(以及Python中的map()
,filter()
和reduce()
)。
专注于转换而不是数据。特别是,我根本不会像你的ListTransform
那样创建一个类,而只是有一些可以链接的转换对象。
为了编写具有函数式编程的代码,转换只是函数,就像在你的设计中一样。此外,你需要的只是变换的某种组合:
def compose(f, g):
return lambda lst: f(g(lst))
(为简单起见,给定的实现只有两个参数而不是任意数。)您的示例现在非常简单:
from functools import partial
map_transform = partial(map, lambda x: x + (x/10))
pick_transform = lambda lst: [lst[i] for i in (5,6,7)]
transform = compose(pick_transform, map_transform)
print transform([0,10,20,30,40,50,60,70,80,90])
# [55, 66, 77]
另一种方法是将变换实现为类而不是函数。
答案 2 :(得分:0)
您可以扩展list
类本身,并在需要元素时懒惰地应用变换。这是一个简短的实现 - 它不允许对变换进行索引操作,但是您可以在堆栈中应用任何映射变换。
class ListTransform(list):
def __init__(self, *args):
list.__init__(self, *args)
self.transforms = []
def __getitem__(self, index):
return reduce(lambda item, t: t(item), self.transforms, list.__getitem__(self, index))
def __iter__(self):
for index in xrange(len(self)):
yield self[index]
def __repr__(self):
return "'[%s]'" % ", ".join(repr(item) for item in self)
__str__ = lambda s: repr(s).strip("'")
你准备好了:
>>> a = ListTransform( range(10))
>>> a
'[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'
>>> a.transforms.append(lambda x: 2 * x)>>> a
'[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]'
>>> a.transforms.append(lambda x: x + 5)
>>> a
'[5, 7, 9, 11, 13, 15, 17, 19, 21, 23]'
>>> a.append(0)
>>> a
'[5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 5]'
好的 - 我可能已经超越了 getitem 方法中的“reduce”调用 - 但这是有趣的部分。 :-) 为了便于阅读,请随意将其重写为更多行:
def __getitem__(self, index):
item = list.__getitem__(self, index)
for t in self.transforms:
item = t(item)
return item
如果您喜欢这个想法,可以包含一个“过滤器”成员来为项目创建过滤功能,并检查变换上的参数数量以允许它们使用索引,甚至可以到达其他列表项目。