2015-05-30 51 views
0

这看起来像类继承,但我认为它不是,并且必须有一个简单的方法来执行以下操作。看看这个简单的代码:python多重嵌套类

class Land: 
    def __init__(self): 
     print "a new Land" 
     self.farms = [] 

    def addfarm(self): 
     self.farms.append(Farm()) 


class Farm: 
    def __init__(self): 
     print "a new farm" 
     self.animals = [] 

    def addanimal(self,name): 
     self.animals.append(Animal(name)) 

class Animal: 
    def __init__(self, name): 
     print "hi, I am %s" % name 
     self.name = name 


USA = Land() 
USA.addfarm() 
USA.farms[0].addanimal('George') 
USA.farms[0].addanimal('Martin') 
USA.addfarm() 
USA.farms[1].addanimal('Polly') 
USA.farms[1].addanimal('Ralph') 

有没有让所有的动物没有做?:

for eachfarm in USA.farms: 
    for each in eachfarm.animals: 
     print each.name 

我问一个简单的方法,因为如果例如用户希望增加一个新的乔治去农场0我想很快就能说出这个名字。我也可以快速运行一个功能,让我在陆地或所有农场都可以拥有所有的动物。我应该为所有这些编写函数还是Python有自己的功能?

我也很想知道我的嵌套类结构是否不正确,并最终可能导致问题。

例如,假设我有一个功能,给定一个动物告诉我它的完美食物组合。我希望能够在我的所有动物身上运行该功能并将它们写回到它们的对象中。如果它们嵌套,恐怕功能可能会变得困惑!

谢谢!

+1

你想写什么而不是嵌套循环?此外,你是否想要让所有农场中的“被采纳”名称的全球名单是全球性的,还是仅仅是每个农场?如果用户试图向农场1添加“乔治”会怎么样? – BrenBarn

回答

2

使用像这样的嵌套类是完全正确的,而不是关于继承。但是,您可能想要选择稍微不同的数据结构。

你说在每个农场你只希望能够拥有每个名字的一个动物。但是,您使用列表来存储它们。列表允许您在任意位置拥有多个同名动物,因此当您添加另一个动物时,您需要执行检查。

但是,您可以使用dict。字典是一个无用的数据结构,它将一个键链接到一个值。在你的情况下,你可以使用动物的名称作为关键字,并使用Animal对象作为值。检查一个键是否存在可以在恒定时间内完成(与具有循环的线性时间相比),因为内部dict是一个散列表。

示例代码可能是这样的:

class Land: 
    def __init__(self): 
     print "a new Land" 
     self.farms = [] 

    def addfarm(self): 
     self.farms.append(Farm()) 


class Farm: 
    def __init__(self): 
     print "a new farm" 
     self.animals = {} 

    def addanimal(self,name): 
     if not name in self.animals: 
      self.animals[name] = Animal(name) 
      return True 
     return False 

class Animal: 
    def __init__(self, name): 
     print "hi, I am %s" % name 
     self.name = name 


USA = Land() 
USA.addfarm() 
USA.farms[0].addanimal('George') 
USA.farms[0].addanimal('Martin') 
USA.addfarm() 
USA.farms[1].addanimal('Polly') 
USA.farms[1].addanimal('Ralph') 

这会阻止您添加相同名称的两个动物一个农场,返回取决于动物是否可以添加到农场或不是布尔。

要获得所有农场上的所有动物,您仍然需要嵌套循环。但是启用迭代对象本身可以更好。如果你做到以下几点:

class Land(object): 
    def __init__(self): 
     print "a new Land" 
     self.farms = [] 

    def addfarm(self): 
     self.farms.append(Farm()) 

    def __iter__(self): 
     for farm in self.farms: 
      yield farm 


class Farm(object): 
    def __init__(self): 
     print "a new farm" 
     self.animals = {} 

    def addanimal(self,name): 
     if not name in self.animals: 
      self.animals[name] = Animal(name) 
      return True 
     return False 

    def __iter__(self): 
     for name, animal in self.animals.iteritems(): 
      yield animal 

class Animal(object): 
    def __init__(self, name): 
     print "hi, I am %s" % name 
     self.name = name 

,那么你可以:

for farm in USA: 
    for animal in farm: 
     pass #do something here 

根据您的意见,您也希望能够做到land.getAllAnimals()farm.getAllAnimals()。后者很容易完成,因为farm可以作为所有动物的迭代器。如果你想要一个列表,你可以简单地致电list(farm)
对于land.getAllAnimals()有两个很好的选择。两者都将被添加到前面的声明中。

选项1个
class Land(object): 
    def getAllAnimals(self): 
     for farm in self: 
      for animal in farm: 
       yield animal 
选项2
from itertools import chain 

class Land(object): 
    def getAllAnimals(self): 
     return chain(*self) 

双方将返回迭代器在所有的动物。要将这些转换为列表,只需在它们上面调用list即可。前者更容易理解,但后者更简洁,在我看来,更好。

+0

小小挑逗:在字典中访问一个密钥不是线性时间,它是恒定的时间。检查存在列表是线性时间。 – sberry

+0

你是绝对正确的,这或多或少是一个错字(我实际上给出了它为什么不变并且仍然写成线性的非常简短的原因)。感谢您指出:) – Cu3PO42

+0

感谢@ Cu3PO42 ...你说这不是关于继承,但我想这个概念,因为我想可能有一种方法将项目列表传递给父对象。例如,让农场有一个函数来返回所有存在的动物。我将如何传递这个函数以便它可以由Land对象运行? (所以我的想法是只写一次,如果我有'Farm.getmetheanimals()'我不想做'Farm.getmetheanimals()''但希望可以简单地做'Land.getmetheanimals()'' ...关于那个的任何想法?再次感谢! – Yona

1

嵌套你的循环没有任何问题,它只是做它的方式。您可能希望查看更具说明性的方法,或者您可能希望以不同的方式存储数据,但这只是实现细节,主要是品味的问题。