我正在编写解析Twitter机器人的API,对OOP来说是一个新手。我有一些现有的Python代码依赖于全局变量,并认为我可以借此机会学习。
我有以下Team类,在解析API时会更新,并且在类属性更改时能够调用完全不相关的(外部)方法。
class Team(object):
def __init__(self, team_name, tri_code, goals, shots, goalie_pulled):
self.team_name = team_name
self.tri_code = tri_code
self.goals = goals
self.shots = shots
self.goalie_pulled = goalie_pulled
为goalie_pulled
的现有实例更改Team
时,我希望调用以下方法(伪代码):
def goalie_pulled_tweet(team):
tweet = "{} has pulled their goalie with {} remaining!".format(team.team_name, game.period_remain)
send_tweet(tweet)
两件事 -
goalie_pulled_tweet
属性发生了变化,如何从我的Team
课程中拨打goalie_pulled
?Game
对象的实例,还是需要将其传递给该变量?答案 0 :(得分:2)
你应该看一下property课程。基本上,它允许您封装行为和私有成员,而消费者甚至不会注意到它。
在您的示例中,您可能拥有goalie_pulled
属性:
class Team(object):
def __init__(self, team_name, tri_code, goals, shots, goalie_pulled):
# Notice the identation here. This is very important.
self.team_name = team_name
self.tri_code = tri_code
self.goals = goals
self.shots = shots
# Prefix your field with an underscore, this is Python standard way for defining private members
self._goalie_pulled = goalie_pulled
@property
def goalie_pulled(self):
return self._goalie_pulled
@goalie_pulled.setter
def goalie_pulled(self, new_value):
self._goalie_pulled = new_value
goalie_pulled_tweet(self) #self is the current Team instance
从消费者的角度来看:
team = create_team_instance()
# goalie_pulled_tweet is called
team.goalie_pulled = 'some_value'
我建议你尽可能地使用属性,因为它们是一种很好的抽象方式。
答案 1 :(得分:1)
从设计的角度来看,拥有/
方法会更有意义。
类是创建更有意义的抽象的工具。拉守门员是一种行动。如果你认为pull_goalie
代表了一支真实的球队,那么说#34;球队拉出他们的守门员更有意义!"而不是"球队将他们的守门员属性设置为X球员!"
Team
我打算推荐一个房产,但我认为如果不考虑更广泛的设计清晰度,这将解决眼前的问题。
注意:没有"私人" Python中的属性。有一个约定,以单个下划线(class Team(object):
...
def pull_goalie(self, player):
self.pulled_goalie = player
tweet = '<your format string>'.format(
self.pulled_goalie,
# Yes, your Team *could* store a reference to the current game.
# It's hard to tell if that makes sense in your program without more context.
self.game.period_remaining
)
)开头的属性被视为是私有的,但这只是为了让使用您的代码的人知道他们可以&#39;总是依靠这个价值做他们认为会做的事情。 (即,它不是代码的公共合同的一部分,您可以在不发出警告的情况下进行更改。)
编辑:要在self._pulled_goalie
对象上创建register_team
方法,您可能会执行以下操作:
Game
请注意,通过使用字典,可以多次调用class Game(object):
def __init__(<stuff>):
...
self.teams = {}
...
def register_team(self, team):
if len(self.teams) > 1:
raise ValueError(
"Too many teams! Cannot register {} for {}"
.format(team, game)
)
self.teams[team] = team
team.game = self
def unregister_team(self, team):
try:
del self.teams[team]
except KeyError:
pass
team.game = None
和register_team
而不会产生不良影响。