簡體   English   中英

Python:類設計-列表轉換(批評我的代碼)

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

我一直在考慮一個可能對列表轉換有用的類。 這是我當前的實現:

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功能,而我沒有使用過? 您將如何改進本課程的總體設計/思想? 您將如何改進代碼?

此外,由於重新發明輪子感覺很尷尬:用什么標准工具替代此類工具?

謝謝。

不要將空列表用作默認參數。 使用None進行測試:

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

我是眾所周知的Python初學者陷阱。

考慮到一般的范圍而不是特定的用例,我將以一種更“實用”的方式來看待這個問題:

  • 不要進行轉換,而是返回新列表。 這就是函數式編程中標准函數(以及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]

另一種選擇是將轉換實現為類而不是函數。

您可以擴展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

如果您喜歡這個主意,則可以包括“過濾器”成員,以為項目創建過濾功能,並檢查轉換中的參數數量,以允許它們使用索引,甚至到達其他列表項目。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM