I'm writing an API parsing Twitter bot and am very new to OOP. I have some existing Python code that relies on global variables and figured I could take this opportunity to learn.
I have the following Team class that gets updated when the API is parsed and is like to be able to call a totally unrelated (external) method when a class attribute changes.
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
When goalie_pulled
is changed for an existing instance of Team
I'd like the following method to be called (pseudo code):
def goalie_pulled_tweet(team):
tweet = "{} has pulled their goalie with {} remaining!".format(team.team_name, game.period_remain)
send_tweet(tweet)
Two things -
goalie_pulled_tweet
from within my Team
class once I detect that goalie_pulled
attribute has changed? Game
object from anywhere or does it need to be passed to that variable as well? You should take a look at the property class. Basically, it lets you encapsulate behaviour and private members without the consumer even noticing it.
In your example, you may have a goalie_pulled
property:
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
From the consumer's point of view:
team = create_team_instance()
# goalie_pulled_tweet is called
team.goalie_pulled = 'some_value'
I'd recommend you to use properties whenever you can (and must), as they are a nice way of abstraction.
From a design standpoint, it would make more sense to have a pull_goalie
method.
Classes are a tool to create more meaningful abstractions. Pulling a goalie is an action. If you think of Team
as representing a real-life team, it makes more sense to say "The team pulled their goalie!" rather than "The team set their pulled-goalie attribute to X player!"
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
)
I was going to recommend a property, but I think that would solve the immediate problem without considering broader design clarity.
NOTE: There is no such thing as a "private" attribute in Python. There is a convention that attributes beginning with a single underscore ( self._pulled_goalie
) is treated as private, but that's just so that people using your code know that they can't depend on that value always doing what they think it will. (ie, it's not part of the public contract of your code, and you can change it without warning.)
EDIT: To create a register_team
method on a Game
object, you might do something like this:
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
Note that by using a dictionary, register_team
and unregiser_team
can be called multiple times without ill effect.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.