簡體   English   中英

Python:如何在對象列表列表上鏈接方法?

[英]Python: How do you chain methods on lists of lists of objects?

我希望能夠在具有子節點和孫子節點的節點實例上鏈接方法。 當我在該頂級節點上調用方法時,我希望能夠返回該對象的子孫。 我還希望能夠從最頂層的節點獲得這些子孫的屬性。 我有以下數據模型:

class GrandParent(object):
    def __init__(self,name='',age=0,is_retired=True,children=[]):
        self.name = name
        self.age = age
        self.is_retired = is_retired

        if children:
            self.children = children

    def print_mychildren(self):
       for child in self.children:
            print "Child: ",child

    def mychildren(self):
        return self.children

    def __str__(self):
        return "name: %s age: %s is_retired:%s" %(self.name,self.age,self.is_retired)


class Parent(object):
    def __init__(self,name='',age=0,has_mortgage=True,children=[]):
        self.name = name
        self.age = age
        self.has_mortgage = has_mortgage

        if children:
            self.children = children

    def print_mychildren(self):
       for child in self.children:
            print "Child: ",child

    def __str__(self):
        return "name: %s age: %s has_mortgage: %s" %(self.name,self.age,self.has_mortgage)


class Child(object):
    def __init__(self,name='',age=0,has_toys=True):

        self.name = name
        self.age = age
        self.has_toys = has_toys

    def __str__(self):
        return "name: %s age: %s has_toys:%s" %(self.name,self.age,self.has_toys)



if __name__ == '__main__':

    beaver = Child('Beaver',12,True)
    ward = Child('Ward',16,False)

    june = Parent('June',38,True,[beaver,ward])

    grandpa = GrandParent('Grandpa',61,True,[june])

    print grandpa

    grandpa.print_mychildren() # print June

    # Doesn't work
    grandpa.mychildren().print_mychildren() #  I want it to print Ward and Beaver
    # Doesn't work
    print grandpa.mychildren().mychild('Beaver').age # I want it to return an age

請注意,我希望將GrandParent,Parent和Child類分開,因為我想為每個類提供不同的屬性,例如has_mortgage或is_retired。

從上面的數據模型中,我希望能夠鏈接方法以遍歷頂級節點的子節點。 它看起來像這樣:

grandpa.children # returns a list of children
print grandpa.mychild('June').has_mortgage # returns the value
grandpa.mychildren().mychildren() # prints a list of grandchildren
print grandpa.mychildren().mychild('Ward').has_toys # return the value

換句話說,我可以發表聲明:

print grandpa.mychildren().mychildren()

表現得像:

for child in grandpa.children:
        for grandchild in child.children:
            print grandchild

我很感激你的回答。 謝謝。

保羅
伊利諾伊州芝加哥

你可以做你想做的事,但這需要一些工作。 您需要將ParentGrandparent類的children值設置為將方法和成員變量的訪問映射到其內容的自定義容器。

這是一個可能的實現。 它可能有一些奇怪的角落案例,我還沒有解決,但它適用於我嘗試過的基本內容:

from operator import attrgetter

class mappingContainer(object):
    def __init__(self, contents):
        self.contents = contents

    # sequence protocol methods    
    def __getitem__(self, index):
        return self.contents[index]

    def __setitem__(self, index, value):
        self.contents[index] = value

    def __iter__(self):
        return iter(self.contents)

    def __contains__(self, o):
        return o in self.contents

    def __len__(self):
        return len(self.contents)

    # map attribute access and method calls
    def __getattr__(self, name):
        return mappingContainer(map(attrgetter(name), self.contents))

    def __call__(self, *args, **kwargs):
        return mappingContainer([o(*args, **kwargs) for o in self.contents])

    # string conversions
    def __repr__(self):
        return "mappingContainer(%s)" % repr(self.contents)

這是一個簡單的“人”類,我曾用它來測試它。 每個人在mappingContainer都有一個名稱,零個或多mappingContainer以及一個任意命名的方法,它打印一些東西並返回一個值。

class Person(object):
    def __init__(self, name, children = None):
        self.name = name
        if not children:
            children = []
        self.children = mappingContainer(children)

    def __repr__(self):
        return self.name

    def someMethod(self):
        print "%s's someMethod()" % str(self)
        return "%s's return value" % str(self)

這是我測試它的方式(長線包裹,顯示在這里):

>>> c1 = Person("Adam")
>>> c2 = Person("Albert")
>>> c3 = Person("Alice")
>>> c4 = Person("Agnes")
>>> p1 = Person("Bob", [c1, c2])
>>> p2 = Person("Betty", [c3,c4])
>>> gp = Person("Charles", [p1, p2])
>>> gp
Charles
>>> gp.children
mappingContainer([Bob, Betty])
>>> gp.children.children
mappingContainer([mappingContainer([Adam, Albert]),
                  mappingContainer([Alice, Agnes])])
>>> gp.children.children.someMethod()
Adam's someMethod()
Albert's someMethod()
Alice's someMethod()
Agnes's someMethod()
mappingContainer([mappingContainer(["Adam's return value",
                                    "Albert's return value"]),
                  mappingContainer(["Alice's return value",
                                    "Agnes's return value"])])

現在這可能不是你想要的,因為你不能通過gp.children.children直接迭代孫子gp.children.children (雖然函數調用會一直向下冒泡,但它們的結果仍然會嵌套在兩層容器中) 。 我認為mappingContainer可能會以某種方式進行調整以解決這個問題,但我不確定它是否值得。

如果出現任何問題,這類鏈式調用將成為調試的噩夢(除非你是超人,否則你的代碼中的某些內容在開發的某些時候總會出錯)。 如果您明確地迭代或遞歸您擁有的關系層次結構,那么您的代碼將更容易編寫和理解。

一種方法是為列表集合創建一個包裝器(與jQuery處理方法鏈接的方式略有相似)

碼:

class ChainList(list):
    def __getattribute__(self, name):
        try:
            return object.__getattribute__(self, name)
        except:
            pass

        return ChainList([getattr(child, name) 
            for child in self if name in dir(child)])

    def __call__(self, *args, **kwargs):       
        return ChainList([child(*args, **kwargs)
            for child in self if callable(child)])

class GrandParent(object):
    def __init__(self,name='',age=0,is_retired=True,children=[]):
        self.name = name
        self.age = age
        self.is_retired = is_retired

        if children:
            self.children = ChainList(children)

    def print_mychildren(self):
       for child in self.children:
            print "Child: ",child

    def mychildren(self):
        return self.children

    def __str__(self):
        return "name: %s age: %s is_retired:%s" %(self.name,self.age,self.is_retired)

class Parent(object):
    def __init__(self,name='',age=0,has_mortgage=True,children=[]):
        self.name = name
        self.age = age
        self.has_mortgage = has_mortgage

        if children:
            self.children = ChainList(children)

    def print_mychildren(self):
       for child in self.children:
            print "Child: ",child

    def __str__(self):
        return "name: %s age: %s has_mortgage: %s" %(self.name,self.age,self.has_mortgage)

    def mychild(self, name):
        for child in self.children:
            if child.name == name:
                return child

class Child(object):
    def __init__(self,name='',age=0,has_toys=True):

        self.name = name
        self.age = age
        self.has_toys = has_toys

    def __str__(self):
        return "name: %s age: %s has_toys:%s" %(self.name,self.age,self.has_toys)



if __name__ == '__main__':

    beaver = Child('Beaver',12,True)
    ward = Child('Ward',16,False)

    june = Parent('June',38,True,[beaver,ward])

    grandpa = GrandParent('Grandpa',61,True,[june])

    print grandpa

    grandpa.print_mychildren() # print June

    # Doesn't work
    grandpa.mychildren().print_mychildren() #  I want it to print Ward and Beaver
    # Doesn't work
    print grandpa.mychildren().mychild('Beaver').age # I want it to return an age

主要思想是ChainList類並重寫__getattribute____call__並包裝需要與此類鏈接的所有列表。

我還將mychild()添加到Parent以使示例正常工作。

對我來說,這聽起來非常像你在談論模型和模型關系。 看看Django。 Django模型將完全按照您的要求進行操作,您可以定義模型之間的關系以及跨這些關系查詢

暫無
暫無

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

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