<p>有很多方法可以解决这样的问题。许多代表着简单性(也许还有效率)和方便性(或“魔力”)之间的折衷。有时候,直截了当、直截了当确实是最好的,即使它看起来很笨拙</p>
<p>也就是说。。。实现这一点的一种方法是给<code>Team</code>一个class属性,它是一个字典,列出所有<code>team</code>实例及其关联的<code>driver</code>实例。我从你的问题推断,一个车手一次只能在一个车队,如果可能的话,你希望尽可能“自动”地执行。我不确定您是否希望代码强制执行“每个团队不超过两个驱动程序”,如果您尝试添加第三个驱动程序,可能会抛出一个错误,因此我暂时不考虑这一方面</p>
<pre><code>class Team:
_membership = {} # Stores all teams and their members at the class level.
# The underscore indicates it's only intended to be used
# internally by the Team class.
def __init__(self, name, drivers=None):
self.name = name
Team._membership[self] = [] # Create an entry in the dictionary, with no drivers
if drivers is None:
drivers = []
for driver in drivers:
self.add_driver(driver) # Defined below
def __repr__(self):
"""Define how to represent this object in output."""
return f"<Team '{self.name}', drivers: {self.drivers}>"
</code></pre>
<p>我们需要实现<code>add_driver()</code>方法。它将检查驾驶员当前是否在其他团队,如果是,则将其删除:</p>
<pre><code> def add_driver(self, driver):
old_team = Team.find_team_for_driver(driver) # Defined below
if old_team == self:
# If the driver is already on this team, we're done.
return
if old_team is not None:
# If it was on a different team, remove it from that team.
old_team.drivers.remove(driver)
# Lastly, add it to this team.
Team._membership[self].append(driver)
</code></pre>
<p><code>find_team_for_driver()</code>不是附加到特定实例,而是用于<code>Team</code>类的常规簿记的方法,因此它是<a href="https://www.tutorialsteacher.com/python/classmethod-decorator" rel="nofollow noreferrer">class method</a>:</p>
<pre><code> @classmethod
def find_team_for_driver(cls, driver):
for team, drivers in cls._membership.items():
if driver in drivers:
return team
# Return None if the driver was not found in a team.
return None
</code></pre>
<p>我们可以使用<a href="https://www.programiz.com/python-programming/property" rel="nofollow noreferrer">property decorator</a>来轻松查看团队的驱动因素:</p>
<pre><code> @property
def drivers(self):
return Team._membership[self]
@drivers.setter
def drivers(self, drivers):
Team._membership[self] = []
for driver in drivers:
Team.update_membership(self, driver)
</code></pre>
<p>这意味着我们仍然可以使用<code>team.drivers</code>的简单语法,<code>Team</code>类的内部将处理从<code>_membership</code>字典中获取它。请注意,虽然您可能会认为您可以将驱动程序添加到具有<code>team.drivers.append(new_driver)</code>的团队中,但他们不知道如何从以前的团队中删除驱动程序(如果有的话)。请确保改用<code>team.add_driver(new_driver)</code></p>
<p>(注意<code>team.drivers.remove(driver_to_remove)</code><em>确实可以</em>工作,但是如果需要,我们可以定义一个<code>remove_driver()</code>方法,以保持一致。)</p>
<p>好的,我们终于到了<code>Driver</code>类,它变化很小。(我删除了除<code>name</code>之外的所有属性,只是为了使示例代码更简单一些。)我们可以使用属性来找出驱动程序所在的团队,并将其重新分配给新团队:</p>
<pre><code>class Driver:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"<Driver '{self.name}'>"
@property
def team(self):
return Team.find_team_for_driver(self)
@team.setter
def team(self, team):
team.add_driver(self)
</code></pre>
<hr/>
<p>测试它:</p>
<pre><code>bob = Driver('Bob')
lisa = Driver('Lisa')
kaya = Driver('Kaya')
red = Team('Red Team', [bob, lisa])
print(red)
=> <Team 'Red Team', drivers: [<Driver 'Bob'>, <Driver 'Lisa'>]>
blue = Team('Blue Team')
blue.add_driver(kaya)
print(blue)
=> <Team 'Blue Team', drivers: [<Driver 'Kaya'>]>
</code></pre>
<p>重新分配驱动程序:</p>
<pre><code>lisa.team = blue
red.add_driver(kaya)
print(red)
=> <Team 'Red Team', drivers: [<Driver 'Bob'>, <Driver 'Kaya'>]>
print(blue)
=> <Team 'Blue Team', drivers: [<Driver 'Lisa'>]>
</code></pre>
<hr/>
<p>对于一定规模和复杂程度的项目,这种基础设施非常方便。对于更小、更简单的事情,您最好明确定义和设置对象之间的链接。(请注意,通过<code>Team._membership</code>进行的所有迭代都比引用显式对象属性慢。在许多情况下,这可能不够重要。)</p>
<p>另一方面,随着项目变得越来越复杂,像<a href="https://www.djangoproject.com/" rel="nofollow noreferrer">Django</a>这样的现有系统开始变得更有意义,而不是实现越来越多的这类东西。Django的总体目标是成为一个web框架,但即使您没有做任何与web相关的事情,它的对象关系系统也实现了各种关系(一对一、一对多、多对多),具有许多方便的选项,如双向性和唯一性的实施。如果您想尝试一下,请参见此<a href="https://stackoverflow.com/questions/302651/use-only-some-parts-of-django">question</a>。(我相信<a href="https://www.sqlalchemy.org/" rel="nofollow noreferrer">SQLAlchemy</a>实现了类似的功能,但我自己还没有尝试过。)</p>