简体   繁体   English

Python:类设计-列表转换(批评我的代码)

[英]Python: Class design - List Transformations (critique my code)

I have been thinking about a class which could be useful for list transformations. 我一直在考虑一个可能对列表转换有用的类。 Here is my current implementation: 这是我当前的实现:

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() 

This works well, however, the feeling of implementing something in a substandard manner bothers me. 这很好,但是,以一种不合标准的方式实现某些东西的感觉使我感到困扰。

What Python features would you use in this implementation, I haven't used? 您将在此实现中使用哪些Python功能,而我没有使用过? How would you improve the overall design/ideas behind this class? 您将如何改进本课程的总体设计/思想? How would you improve the code? 您将如何改进代码?

Also, since reinventing the wheel feels awkward: what are the standard tools replacing this class? 此外,由于重新发明轮子感觉很尴尬:用什么标准工具替代此类工具?

Thanks. 谢谢。

Do not use an empty list as default argument. 不要将空列表用作默认参数。 Use None and test for it: 使用None进行测试:

def some_method(self, arg=None):
    if arg is None:
        arg = []
    do_your_thing_with(arg)

I's a well known Python's beginner pitfall. 我是众所周知的Python初学者陷阱。

Having a general scope and not a particular use case in mind, I would look at this in a more "functional" way: 考虑到一般的范围而不是特定的用例,我将以一种更“实用”的方式来看待这个问题:

  • Don't make the tranformations in place -- rather return new lists. 不要进行转换,而是返回新列表。 This is how standard functions in functional programming work (and also map() , filter() and reduce() in Python). 这就是函数式编程中标准函数(以及Python中的map()filter()reduce() )的工作方式。

  • Concentrate on the transformations rather than on the data. 专注于转换而不是数据。 In particular, I would not create a class like your ListTransform at all, but rather only have some kind of transformation objects that can be chained. 特别是,我根本不会像ListTransform那样创建一个类,而只会创建一些可以链接的转换对象。

To code this having functional programming in mind, the transforms would simply be functions, just like in your design. 为了在编写代码时考虑到函数式编程,就像在您的设计中一样,转换将只是函数。 All you would need in addition is some kind of composition for the transforms: 您所需要的只是这些转换的某种组合:

def compose(f, g):
    return lambda lst: f(g(lst))

(For the sake of simplicity the given implementation has only two parameters instead of an arbitrary number.) Your example would now be very simple: (为简单起见,给定的实现只有两个参数,而不是一个任意数字。)您的示例现在非常简单:

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]

An alternative would be to implement the transforms as classes instead of functions. 另一种选择是将转换实现为类而不是函数。

You could extend the list class itself, and apply the transforms lazily as the elements are needed. 您可以扩展list类本身,并在需要元素时延迟应用转换。 Here is a short implementation - it does not allow for index manipulation on the transforms, but you can apply any mapping transform in a stack. 这是一个简短的实现-不允许对转换进行索引操作,但是您可以在堆栈中应用任何映射转换。

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("'")

And you are ready to go: 然后您就可以开始了:

>>> 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]'

Ok - I may have overreached with the "reduce" call in the getitem method - but that is the fun part. 好的-我可能已经超出getitem方法中的“ reduce”调用了-但这是有趣的部分。 :-) Feel free to rewrite it in more lines for readability: :-)为了便于阅读,请多行重写:

def __getitem__(self, index):
   item = list.__getitem__(self, index)
   for t in self.transforms:
       item = t(item)
   return item

If you like the idea, you could include a "filter" member to create filtering functions for the items, and check for the number of parameters on the transforms to allow them to work with indexes, and even reach other list items. 如果您喜欢这个主意,则可以包括“过滤器”成员,以为项目创建过滤功能,并检查转换中的参数数量,以允许它们使用索引,甚至到达其他列表项目。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM