Python 面向对象模型
我有一个类似这样的情况。
一个人拥有很多颜色的同款车,这些车都属于某个州。
我设计了一个“人”的类,里面有一些属性,比如 人名
、车款
、车年份
、车所在州
和 车颜色
。其中,颜色应该是一个列表,因为一个人可以拥有多辆不同颜色但同款的车。
现在,我想知道怎么找到并打印出两个不同的人,他们的车款和颜色相同,但却来自不同的州,这在面向对象的编程中该怎么做呢?
我刚开始学习Python。
在把颜色放进“人”这个对象时,我该怎么把它放进列表里?又该怎么从列表中取出来?我知道怎么处理单个属性,但对列表操作有点困惑。
数据可能是这样的:
person1 ford [red,blue,yellow] new-york
person2 honda [red,blue] new-york
person3 ford [red,grey] california
person4 ford [red] california
person5 honda [red] new-york
现在我的结果应该只有:
[(person1,person5)] (same model car,same color, different state)
3 个回答
有很多方法可以做到这一点。如果你有很多数据,我建议你使用数据库来处理,Python自带的sqlite支持其实并不难。数据库引擎是专门用来搜索的。你需要两个表,因为每个人可以有多种颜色。第一个表是“人”表,里面有这些列:id、名字、模型、状态。第二个表是“颜色”表,里面有:personid和颜色。personid这一列会包含颜色表中对应的人的id号。这样,你可以在颜色表中有多行数据,都是同一个personid(这就相当于数据库里的一个列表)。sqlAlchemy是一个库,可以帮助你用Python对象来实现数据库,这可能更适合你想做的事情。sqlAlchemy ORM教程会带你了解如何使用sqlite数据库,里面有两个表(用户和地址),和你需要的很相似。
如果你想单纯用Python类,那你就得有一个人实例的列表,然后逐个遍历这些实例,寻找匹配的。为了简化颜色匹配,你可以把颜色列表转换成集合,然后进行交集操作。
>>> s1 = set(['red','blue','yellow'])
>>> s2 = set(['red','blue'])
>>> s1.intersection(s2)
set(['blue', 'red'])
一个简化遍历人实例列表的方法是使用Python的itertools库,利用排列生成器。
from itertools import permutations
people = ['p1', 'p2', 'p3']
for p1, p2 in itertools.permutations(people,2):
print p1, p2
p1 p2
p1 p3
p2 p1
p2 p3
p3 p1
p3 p2
希望这些信息能对你有所帮助。重新看了你的问题,感觉你可能需要多读一些关于Python编程的资料。不过,针对你关于列表的问题,这里有一段代码可能会对你有帮助。
class Person(object):
def __init__(self, name, model, colors, state):
self.name = name
self.model = model
self.colors = colors
self.state = state
p1 = Person('p1', 'ford', ['red', 'blue'], 'new-york')
p2 = Person('p2', 'honda', ['red', 'blue'], 'new-york')
persons = [p1, p2]
# or
persons = []
persons.append(p1)
persons.append(p2)
p1.color.append('yellow')
# or
persons[0].color.append('yellow')
你可能想把state
(州)和car
(车)单独建模,与person
(人)分开。这样,每个人可以拥有一辆车的列表,并且可以居住在一个州(或者根据你的模型,甚至可以有多个州)。这些都是拥有关系。这样做还可以让你以后再细分car
,比如想要创建sportsCar
(跑车)的时候。
你想了解一下列表操作的基本知识:
$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> l=[]
>>> l.append("honda")
>>> l.append("ford")
>>> l
['honda', 'ford']
>>> l[0]
'honda'
>>> l.pop(0)
'honda'
>>> l.pop(0)
'ford'
>>> l.pop(0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop from empty list
如果你想找出几个具有相同特征的人,可以进行一些循环(这里用伪代码表示,因为我觉得关注算法比关注具体的Python代码更有帮助):
results = []
foreach p1 in [list of people]
foreach p2 in [list of people]
next if p1 == p2
next if p1.state == p2.state
next unless p1.car == p2.car
foreach c1 in p1.colors
foreach c2 in p2.colors
results.append((p1,p2)) if c1 == c2
这段代码是用来比较一对对的人。它不会把一个人和自己比较,也不会比较住在同一个州的人,因为你要求的是“但属于不同州的人”。所以我们要把住在同一个州的人过滤掉。它只比较拥有相同类型汽车的人。(如果人们拥有不同类型的汽车,你只需要再加两个嵌套的循环。)然后它会记录下那些汽车颜色相同的人的配对。
这个算法有一个潜在的问题:它会报告 [(person1, person2), (person2, person1)]
。这样就会出现重复的条目。如果你不想要这种重复,可以修改算法,只搜索人们的上三角或下三角部分:
results = []
for i=0; i<people.last_index-1; i++
for j=i+1; j<people.last_index ; j++
p1 = people[i] ; p2 = people[j]
next if p1.state == p2.state
next unless p1.car == p2.car
foreach c1 in p1.colors
foreach c2 in p2.colors
results.append((p1,p2)) if c1 == c2
注意,我们可以去掉 next if p1 == p2
的检查,因为我们明确知道不会出现 i == j
的情况。j
是从 i+1
开始的。